Hallo ursus,
das zeitweilige Minus war von mir, ich habe nicht richtig hingeschaut. Darum ist es wieder weg. Sorry.
Als generische Reflection-Lösung ist das nicht schlecht, allerdings hatte der OP auch geschrieben, dass er nicht alle Attribute mappen will. Deswegen halte ich die Reflection-Lösung hier für suboptimal. Besser wäre - meiner Meinung nach - ein generischer SQL Builder, dem Du einen Satz Spaltennamen und Werte vor die Füße kübelst und der daraus ein INSERT Statement baut.
Übrigens bin ich der Meinung, dass man es sich gar nicht erst angewöhnen sollte, Stringliterale in einem SQL Statement in "Anführungszeichen" zu setzen. Der Standard-Delimiter für ANSI SQL Stringliterale ist das 'Hochkomma'. Es gibt in MYSQL und auch MSSQL Schalter, die "Literale" erlauben, aber eigentlich verwendet man diese Notation für Tabellen- oder Spaltennamen, die Sonderzeichen enthalten. Also das, wofür MYSQL auch den `Backtick` anbietet und MSSQL die [eckigen Klammern].
Meine Idee, wie man einen SQL Builder einsetzen könnte:
function saveInDatabase() {
SQLBuilder::createInsert('books', [
"title" => $this->DBH->escape_string($this->title),
"price" => $this->DBH->escape_string($this->title),
"description" => $this->DBH->escape_string($this->description)
]);
}
Wenn man an diesem Punkt ist, fragt man sich natürlich, warum man überhaupt das DB-Handle im Datenobjekt hat, eigentlich weiß der SQL Builder damit viel mehr anzufangen. Warum nicht gleich einen SQL Handler draus machen? Das ist jetzt auch ein Schnellschrieb zur Veranschaulichung, keine Garantie auf Funktion :)
function saveInDatabase() {
SQLHandler::insert('books')
->AddString('title', $this->title)
->AddNumber('price', $this->price)
->AddString('description', $this->description)
->execute();
}
Ich bin ein Fan von verkettbaren APIs. Man baut das so, dass SQLHandler::insert() ein Objekt erzeugt, das den Insert erzeugen kann. Dieses Objekt hat Methoden, die die Daten ergänzen und das Objekt wieder zurückgeben. Dadurch kann man die Aufrufe verketten. Der letzte Aufruf erzeugt dann den INSERT und führt ihn auch gleich aus.
class SQLHandler {
public static $DB; // Hier das MYSQLI-Objekt speichern
public static function insert($DB, $table) {
return new SQLInsertFactory($table);
}
}
class SQLInsertFactory {
private $db;
private $table;
private $columns;
private $values;
public function __construct($db, $table) {
$this->db = $db;
$this->table = $table;
$this->columns = [];
$this->values = [];
}
private function addColumnAndValue($col, $val) {
array_push($this->columns, "`$col`");
array_push($this->values, $val);
}
public function AddString($col, $val) {
$this->addColumnAndValue($col, "'".$db->escape_string($val)."'");
return $this;
}
public function AddNumber($col, $val) {
$this->addColumnAndValue($col, floatval($val));
return $this;
}
public function execute() {
$sql = "INSERT INTO `$this->table` ("
. implode(", ", $this->columms)
. ") VALUES ("
. implode(", ", $this->values) . ")";
return $this->db->query($sql);
}
}
Sowas kann man noch ausfeilen zu einem InsertOrUpdate, mit Zusatzmethoden um die Key-Columns für den Update zu definieren. Die üblichen CRUD-Statements kann man damit generisch erzeugen.
Und wenn man irgendwann von mysqli auf mssql oder postgre wechseln will, lädt man bloß einen anderen SQLHandler ins Projekt.
Rolf
sumpsi - posui - clusi