Abstrakte Klasse: Mysqli_Entity

  • Hinweis vorweg:
    Ich habe mir diese Klasse für kleinere private Projekte geschrieben, für die ich kein ORM nutze. Sie ist auf meine persönlichen Vorlieben beim Entwickeln abgestimmt. An einigen Stellen lässt sie den Kindklassen durch Sichtbarkeit protected (bzw. den Objekten einer Kindklasse durch Sichtbarkeit public) genug Spielraum um Funktionalitäten zu zerschießen.
    Das ist mir bequßt und ich nehme das aus Gründen der Komfortabilität beim Coden in Kauf. Wer auch immer diese Klasse verwenden möchte muss selber darauf achten, beim direkten Schreiben von protected-Eigenschaften aus einer Kindklasse heraus die Werte angemessen zu prüfen.
    Falls gewünscht kann ich bei Gelegenheit auch noch ein Beispiel zur Verwendung posten.
    ______________________________________________________


    Bei der Mysqli_Entity handelt es sich um eine abstrakte Klasse, die Standardfunktionen wie getter, setter, load, save, delete für Klassen bereitstellt, die eine Entitäten-Tabelle abbilden.
    Eine konkrete Klasse die von Mysqli_Entity erbt kann die nötigen Informationen für die Datenbank-Operationen (Mysqli-Objekt, Tabellenname, Felder, PrimaryKey-Informationen etc.) an die Elternklasse Mysqli_Entity übergeben und anfallende Datenbank-Operationen komfortabel an diese delegieren.
    Sämtliche Werte werden von Mysqli_Entity vor dem Eintragen in die Datenbank mit real_escape_string behandelt, und nach dem Auslesen mit stripslashes.
    Backticks `` um Tabellen- und Feldnamen werden von Mysqli_Entity ebenfalls automatisch gesetzt, sollten also bei Übergabe der entsprechenden Werte von der Tochterklasse nicht gesetzt werden.

    Mysqli_Entity stellt folgende Eigenschaften und Methoden bereit (kompletter Code im zweiten Post):

    Die Eigenschaften und Methoden im Einzelnen:

    Eigenschaften:
    private $loadPropertyOnDemand = false;
    Mit dieser Eigenschaft wird festgelegt, ob der Inhalt einer property bei Anforderung automatisch geladen werden soll, wenn dieser noch nicht gesetzt ist.
    Default ist false, dies kann über die Methode loadPropertyOnDemand() geändert werden.

    private $autosave = false;
    Mit dieser Eigenschaft wird festgelegt, ob Änderungen an Objekt-Eigenschaften beim zerstören des Objektes automatisch gespeichert werden sollen. Mit dieser Eigenschaft auf true braucht die save()-Methode also nicht mehr explizit aufgerufen werden.
    Default ist false, dies kann über die Methode autosave() geändert werden.

    private $isUpdated = false;
    Diese Eigenschaft wird nur intern verwendet um beim Aufruf der save()-Methode zu prüfen, ob Eigenschaften geändert wurden und ein UPDATE der Tabellenzeile nötig ist.

    protected $db = null;
    In dieser Eigenschaft wird das Mysqli-Objekt abgelegt. Dies kann entweder über eine direkte Zuweisung in der Tochterklasse geschehen, oder als Parameter an die Methode setup() übergeben werden.

    protected $table = null;
    In dieser Eigenschaft wird der Name der Tabelle abgelegt, von der das Objekt eine Zeile abbilden soll. Kann entweder über eine direkte Zuweisung in der Tochterklasse geschehen, oder als Parameter an die Methode setup() übergeben werden.

    protected $pkField = null;
    In dieser Eigenschaft wird der Feldname des PrimaryKeys der Tabelle abgelegt. Kann entweder über eine direkte Zuweisung in der Tochterklasse geschehen, oder über die Methode loadSchemeFromTable() (bzw. über die Methode setup() in welcher loadSchemeFromTable() aufgerufen wird) automatisch ermittelt werden.

    protected $pkValue = false;
    In dieser Eigenschaft wird der PrimaryKey-Wert der konkreten Tabellenzeile hinterlegt, die von dem Objekt abgebildet wird. Kann entweder über eine direkte Zuweisung in der Tochterklasse geschehen, oder als (optionaler) Parameter an die Methode setup() übergeben werden, oder explizit über die Methode setPrimaryKey() gesetzt werden.
    Wird der Wert in der Tochterklasse direkt zugewiesen, so ist zu beachten, dass sich die Tochterklasse vorher selber um ein ausreichendes escapen des Wertes kümmern muss, sofern dieser vom Client kommt.

    protected $properties = array();
    In dieser Eigenschaften werden die Feldnamen der Objekteigenschaften hinterlegt (nicht die Werte). Der Array kann automatisch über die Methoden loadSchemeFromTable() (bzw. indirekt über die Methode setup(), welche loadSchemeFromTable() aufruft) gefüllt werden.
    Alternativ (wenn nicht alle Felder der Tabelle verfügbar sein sollen) kann er manuell über die Methode addProperty() gefüllt werden. Hierbei ist zu beachten, dass die übergebenen Properties exakt den Spaltennamen der Tabelle entsprechen müssen (ohne Backticks ``, diese werden von der Klasse Mysqli_Entity automatisch ergänzt).

    protected $data = array();
    In dieser Eigenschaften werden die Werte der Properties hinterlegt. Der Array kann entweder automatisch über Aufruf der Methode load() aus der Datenbank gefüllt werden (mit allen Properties die zu diesem Zeitpunkt gesetzt sind) oder manuell über die Methode setProperty($property,$value).

    Methoden:
    protected function setup(mysqli $db,$table,$pkValue=false) {}
    Über diese Methode können alle relevanten Informationen für Datenbank-Operationen gesetzt werden. Der PrimaryKey $pkValue ist hierbei ein optionaler Parameter, um das Einfügen neuer Zeilen in die Tabelle zu ermöglichen.
    Diese Methode ruft die Methode loadSchemeFromTable() auf, in welcher der properties-Array automatisch mit allen Feldern der übergebenen Tabelle gefüllt wird.

    protected function addProperty($property) {}
    Mit dieser Methode können Properties zum properties-Array hinzugefügt werden. Wird nicht benötigt wenn dieser automatisch über Aufruf der Methode loadSchemeFromTable() (bzw. setup()) gefüllt wird.

    protected function setAutosave($autosave=true) {}
    Setter-Methode für die private Eigenschaft $autosave.

    protected function loadPropertyOnDemand($loadPropertyOnDemand=true) {}
    Setter-Methode für die private Eigenschaft $loadPropertyOnDemand.

    protected function loadSchemeFromTable() {}
    Diese Methode holt sich das Tabellenschema von der Datenbank und befüllt den $properties-Array mit allen Feldern der Tabelle. Ermittelt und setzt außerdem den Namen des Feldes, das als PrimaryKey fungiert.

    public function setPrimaryKey($value) {}
    Über diese Methode kann der PrimaryKey-Wert gesetzt werden. Der übergebene Wert wird mir real_escape_string behandelt.

    public function getProperty($property) {}
    Liefert den Wert einer Property. Ist der Wert für die angeforderte Property noch nicht gesetzt und die Eigenschaft $loadPropertyOnDemand steht auf false, so wird eine Exception geschmissen.

    public function setProperty($property,$value) {}
    Mit dieser Methode kann man einer Property einen Wert zuweisen.

    public function load() {}
    Diese Methode läd alle Property-Werte für das aktuelle Objekt in den $data-Array.

    public function save() {}
    Diese Methode speichert alle getätigten Änderungen. Wenn die Eigenschaft $autosave auf true steht wird diese Methode in __destruct() automatisch aufgerufen.

    public function delete() {}
    Löscht das aktuelle Objekt aus der Datenbank.

    public function __destruct() {}
    Magische Methode, wird automatisch vor dem Zerstören des Objektes aufgerufen. Prüft ob $autosave und $isUpdated auf true stehen und speichert gegebenenfalls alle getätigten Änderungen.

    private function checkTableInfo($checkPrimaryKey=true) {}
    Interne Methode die vor jeder Datenbank-Operation prüft, ob alle relevanten Eigenschaften gesetzt sind ($db, $table, $pkField, gegebenenfalls $pkValue)


    Kompletter Code:

    "Programming today is a race between software engineers
    striving to build bigger and better idiot-proof programs,
    and the universe trying to build bigger and better idiots.
    So far, the universe is winning."
    Rick Cook

  • sehr schön :)
    Für diejenigen, dies interessiert: Das ist eine klassische Umsetzung des Active-Record-Patterns, wie es Doctrine früher benutzt hat.
    Das nur zur Vollständigkeit, damit Nutzer auch in etwa wissen worauf sie sich einlassen.
    Mein erster und bisher einziger ORM-Mapping Versuch sah fast exakt genau so aus :)