Paket Storage

Vorteile einer Storage Engine

  • Objektorientiertes Arbeiten mit verscheidenen Datenquellen durch gemeinsame Schnittstellen
  • Record und RecordList um Daten strukturiert und einfach zu verwalten
  • Nicht überladen mit Features durch SQL Abstraktion. SQL ist effektiv und kann verwendet werden

Einstellung einer Datenbankverbindung

  • Erstellen der Konfigurationsdatei '/config/dragonx/storage/database.php' durch Umbenennen und Anpassen der 'database.php.template' Datei
    return array(
        'adapter' => '%adapter%',
        'config' => array(
            'host' => '%host%',
            'username' => '%username%',
            'password' => '%password%',
            'dbname' => '%dbname%',
        ),
    );
  • In der Konfigurationsdatei können auch mehrere Datenbankverbindungen mit den Keys für die Zend Registry hinterlegt werden. Folgende Einstellungen sind daher gleichbedeutend zur ersten Datei
    return array(
        'Zend_Db_Adapter' => array(
    	    'adapter' => '%adapter%',
    	    'config' => array(
    	        'host' => '%host%',
    	        'username' => '%username%',
    	        'password' => '%password%',
    	        'dbname' => '%dbname%',
    	    ),
        )
    );

Einstellung einer Storage Engine

  • Erstellen der Konfigurationsdatei '/config/dragonx/storage/engine.php'
    return array(
        'engine' => function() {
            return new DragonX_Storage_Engine_ZendDbAdataper(Zend_Registry::get('Zend_Db_Adapter'));
        },
    );
  • In der Konfigurationsdatei können auch mehrere Storage Engines mit den Keys für die Zend Registry hinterlegt werden. Folgende Einstellungen sind daher gleichbedeutend zur ersten Datei
    return array(
        'DragonX_Storage_Engine' => array(
    	    'engine' => function() {
    	        return new DragonX_Storage_Engine_ZendDbAdataper(Zend_Registry::get('Zend_Db_Adapter'));
    	    },
        )
    );

Erstellung einer Recordklasse

  • Definition der Recordklasse im eigenen Paket
    class %packagenamespace%_%packagename%_Record_%recordname% extends DragonX_Storage_Record_Abstract
    {
        public $attribute;
    }
  • Es stehen mit 'DragonX_Storage_Record_Created_Abstract' und 'DragonX_Storage_Record_CreatedModified_Abstract' auch abstrakte Recordklassen zur Verfügung welche ein Erstellungs- und Änderungszeitpunkt definieren. Davon abgeleitete Records erhalten beim Speichern in eine Storage Engine automatisch die Zeitpunkte
  • Mit der Implementierung von 'DragonX_Storage_Record_ReadOnly_Interface' können Recordklassen definiert werden, welche nicht in persistenten Storage Engines gespeichert werden können
  • Verwendung von geschützten Attributen mit Settern/Gettern
  • Die geschützten Attribute stehen nach aussen wie öffentliche Attribute zur Verfügung
    class %packagenamespace%_%packagename%_Record_%recordname% extends DragonX_Storage_Record_Abstract
    {
        protected $_attribute;
        public function setAttribute($attribute)
        {
            $this->_attribute = $attribute;
        }
        public function getAttribute()
        {
            return $this->_attribute;
        }
    }
  • Instanzierung von Records
    //Neue leere Records
    $record = new %packagenamespace%_%packagename%_Record_%recordname%();
    
    //Records mit einer ID zum späteren Laden
    $record = new %packagenamespace%_%packagename%_Record_%recordname%(%id%);
    
    //Records mit Daten zum späteren Speichern
    $data = array('attribut' => 'value');
    $record = new %packagenamespace%_%packagename%_Record_%recordname%($data);
    
    //Records mit Daten aus anderen Records
    $record = new %packagenamespace%_%packagename%_Record_%recordname%($record);

Verwendung von Records und Storage Engine

  • Datensätze hinzufügen
    $record = new %packagenamespace%_%packagename%_Record_%recordname%(array(
        'attribute' => 'value',
    ));
    Zend_Registry::get('DragonX_Storage_Engine')->save($record);
  • Datensätze laden
    $record = Zend_Registry::get('DragonX_Storage_Engine')->load(
        new %packagenamespace%_%packagename%_Record_%recordname%(%id%)
    );
  • Datensätze verändern
    $storage = Zend_Registry::get('DragonX_Storage_Engine');
    $record = $storage->load(
        new %packagenamespace%_%packagename%_Record_%recordname%(%id%)
    );
    $record->attribute = 'value';
    $storage->save($record);
  • Datensätze löschen
    Zend_Registry::get('DragonX_Storage_Engine')->delete(
        new %packagenamespace%_%packagename%_Record_%recordname%(%id%)
    );

Besonderheit bei Records mit Arrays

  • Wenn in einem Records Arrays definiert sind dann wird der besteht der Name der Datenbankspalte aus Arrayname, '_' und dem Key
    class %packagenamespace%_%packagename%_%classname% extends DragonX_Storage_Record_Abstract
    {
        public $array = array('key' => 'value');
    }
    //Spaltenname in der Datenbank wäre in diesem Fall 'array_key'
    

Verwendung von RecordList

  • Datensätze zu einer Liste hinzufügen
    $list = new DragonX_Storage_RecordList();
    $list[] = new %packagenamespace%_%packagename%_Record_%recordname%();
    $list[] = new %packagenamespace%_%packagename%_Record_%recordname%();
  • Datensätze in Sublisten strukturieren
    //Sublist über Klassenname
    $sublist = $list->indexByClassname();
    list($record) = $sublist['%classname%'];
    
    //Sublist über Namespace
    $sublist = $list->indexByNamepsace();
    list($record) = $sublist['%namespace%'];
    
    //Sublist über einzelnes Attribut
    $sublist = $list->indexBy('attributename');
    list($record) = $sublist['attribute'];
    
    //Sublist über mehrere Attribute
    $sublist = $list->indexBy(array('attributenameA', 'attributenameB'));
    list($record) = $sublist['attributeA']['attributeB'];
  • Listen können wie Records mit der Storage Engine mit 'saveList()' gespeichert, mit 'loadList()' geladen und mit 'deleteList' gelöscht werden
  • SQL Statements können ebenfalls Listen befüllen
    $storage = Zend_Registry::get('DragonX_Storage_Engine');
    $list = $storage->loadBySqlStatement(
        new %packagenamespace%_%packagename%_Record_%recordname%(),
        "SELECT columnnameA, columnnameB FROM tablenameA INNER JOIN tablenameB USING(id) WHERE conditionname = :conditionname",
        array('conditionname' => 'conditionvalue')
    );
    foreach ($list as $record) {
        $record->columnnameB += 1;
    }
    $storage->saveList($list);

Verschachtelte Transaktionskontrolle

  • 'beginTransaction()' kann mehrfach verschachtelt aufgerufen werden und zählt die Verschachtelungstiefe mit. Beim ersten Aufruf wird "true" zurück gegeben, sonst "false"
  • Bei jedem Commit wird der Zähler runtergesetzt. Nur in der ersten Ebene wird ein Commit wirklich durchgeführt
  • Bei einem Rollback wird der Rollback durchgeführt unabhängig von der Verschachtelungstiefe und der Zähler zurückgesetzt. Nachfolgende SQL Statements werden ohne Transaktionskontrolle ausgeführt um das Loggen von Fehlern zu ermöglichen

Datenbankstrukturen der Pakete verwalten

  • Jedes Paket wird mit seiner Versionsnummer in der Datenbank gespeichert
  • Wenn Pakete hinzugefügt oder geupdated werden kann man die Datenbankstruktur mit der '/install.php' updaten
    $logicDatabase = new DragonX_Storage_Logic_Database();
    $logicDatabase->installPackages();
  • Die Pakete müssen dafür Plugins der Install Schnittstelle bereit stellen
  • Das Plugin bekommt die Version des Paketes das bisher verwendet wurde und kann somit auf seine aktuelle Version updaten
    class %packagenamespace%_%packagename%_Plugin_Install_%tablename%
        implements DragonX_Storage_Plugin_Install_Interface
    {
        public function install($storage, $version = '0.0.0')
        {
            if (version_compare($version, '1.0.0', '<')) {
                $storage->executeSqlStatement("%sqlstatement%");
            }
        }
    }
  • Ein Plugin kann über die Schnittstelle 'DragonX_Storage_Plugin_GetStoragekey_Interface' eine andere Storage Engine angeben auf der es installiert wird
    class %packagenamespace%_%packagename%_Plugin_Install_%tablename%
        implements DragonX_Storage_Plugin_GetStoragekey_Interface,
                   DragonX_Storage_Plugin_Install_Interface
    {
        public function getStoragekey()
        {
            return '%storagekey%';
        }
    
        public function install($storage, $version = '0.0.0')
        {
            if (version_compare($version, '1.0.0', '<')) {
                $storage->executeSqlStatement("%sqlstatement%");
            }
        }
    }
  • Die Logikklasse Database speichert danach alle Plugins mit ihren aktuellen Versionsnummer in der Datenbank für das nächste Update