Zend Framework 2 mit Doctrine ORM

Avatar von Florian Eibeck

Das Modul-Konzept von Zend Framework 2 macht es einfach, Doctrine2 als ORM zu verwenden. Der Artikel soll zeigen, wie man mit den offiziellen Modulen Doctrine2 in die eigene Zend Framwork Anwendung integriert.

Die Basis: Die ZF Skeleton Application

Als Basis für die eigene Anwendung wird das Zend Framework Skeleton verwendet. Mit dem Befehl

git clone https://github.com/zendframework/ZendSkeletonApplication.git

wird die Skeleton-Anwendung auf die eigene Platte geklont. Hierbei handelt es sich allerdings nur um den Code der Skeleton-Anwendung, das Zend Framework ist nicht enthalten. Es ist jedoch alles vorbereitet, um mittels Composer die benötigten Abhängigkeiten herunterzuladen. Die beiden Befehle

php composer.phar self-update

und

php composer.phar update

aus dem Root-Verzeichnis der Skeleton-Anwendung aktualisieren das mitgelieferte Composer-Skript und laden das aktuelle Zend Framework herunter. Nun lässt sich die Skeleton Application zum Beispiel mit dem PHP 5.4 Webserver mit dem folgenden Aufruf im public-Verzeichnis der Anwendung starten.

php -S localhost:8000

Hinzufügen der Doctrine-Module

Das Doctrine-Projekt stellt selbst fertige Module bereit, die einfach per Composer in das eigene Zend Framework Projekt übernommen werden können. Hierzu wird in der composer.json das Doctrine-ORM-Module unterhalb von „require“ als Abhängigkeit eingetragen:

"doctrine/doctrine-orm-module": "dev-master"

Zusätzlich muss momentan noch die minimale Stabilität auf „alpha” gesetzt werden, da die Pakete noch nicht als stabil markiert sind. Die composer.json muss nun folgendermaßen aussehen:

{
    "name": "zendframework/skeleton-application",
    "description": "Skeleton Application for ZF2",
    "license": "BSD-3-Clause",
    "keywords": [
        "framework",
        "zf2"
    ],
    "homepage": "http://framework.zend.com/",
    "minimum-stability": "alpha",
    "require": {
        "php": ">=5.3.3",
        "zendframework/zendframework": "2.*",
        "doctrine/doctrine-orm-module": "dev-master"
    }
}

Mit einem weiteren

php composer.phar update

wird nun das DoctrineORMModule selbst und weitere nötige (Doctrine-) Module heruntergeladen. Anschließend müssen die Module DoctrineModule und DoctrineORMModule in der application.config.php im Ordner config eingetragen werden:

 array(
        'Application',
        'DoctrineModule',
        'DoctrineORMModule'
    ),     // ...
)

Konfiguration

Um Doctrine verwenden zu können muss noch etwas Konfigurationsarbeit erledigt werden. Als erstes empfiehlt es sich, die Verbindung zur Datenbank zu konfigurieren. Die folgenden Zeilen in die Datei config/autoload/global.php stellen eine Verbindung zu einer SQLite Datenbank her:

return array(
     //...
    'doctrine' => array(
        'connection' => array(
            'orm_default' => array(
                'driverClass' => 'Doctrine\DBAL\Driver\PDOSqlite\Driver',
                'params' => array(
                    'charset' => 'utf8',
                    'path'    =>  'data/db.sqlite',
                )
            )
        )
    )
     //...
);

Selbstverständlich kann auch ein anderer Datenbanktreiber verwendet werden. Die Konfigurationsparameter der einzelnen Parameter kann in der Dokumentation von Doctrine nachgelesen werden.

Da direkt im Application-Modul Entities für Doctrine angelegt werden sollen, muss in der Konfigurationsdatei des eigenen Moduls (Application) noch der Pfad und der Treiber für die Entity-Klassen angegeben werden:

'doctrine' => array(
    'driver' => array(
        'ApplicationDriver' => array(
            'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
            'cache' => 'array',
            'paths' => array(__DIR__ . '/../src/Application/Entity')
        ),
        'orm_default' => array(
            'drivers' => array(
                 'Application\Entity' => 'ApplicationDriver'
            )
        )
    )
)

Es können selbstverständlich noch viele weitere Aspekte von Doctrine über die Konfigurationsdateien eingestellt werden. Für Produktivsysteme ist vor allem auch ein vernünftiger Cache für Doctrine nötig. Weitere Informationen zu den einzelnen Konfigurationsparametern liefert das Handbuch von Doctrine.

Anlegen der Entities

Die Entities müssen nun im Namespace Application\Entity und damit im Verzeichnis src/Application/Entity im Application-Modul angelegt sein. Ein einfaches Entity für eine Notiz könnte zum Beispiel so aussehen:


Das Doctrine Kommandozeilentool

Mit dem Herunterladen des Doctrine-Moduls wurde auch das Kommandozeilentool von Doctrine in das Projekt gezogen. Mit einem Aufruf von

vendor/bin/doctrine-module orm:validate-schema

aus dem Root-Verzeichnis der Anwendung lassen sich zum Beispiel die Entities auf Fehler prüfen. Die Datenbank selbst kann man mit dem Befehl

vendor/bin/doctrine-module orm:schema-tool:create

anlegen lassen. Alle möglichen Befehle zeigt das CLI-Tool wenn man es ohne Parameter aufruft.

Zugriff auf den EntityManager

Über den ServiceManager kann nun zum Beispiel im IndexController der Doctrine EntityManager geholt werden, um die Notizen aus der Datenbank auszulesen und an ein View-Skript zu übergeben.

public function indexAction()
{
     $sm = $this->getServiceLocator();
     /** @var $em \Doctrine\ORM\EntityManager */
     $em = $sm->get('doctrine.entitymanager.orm_default');
     $notes = $em->getRepository('\Application\Entity\Note')->findAll();
     return array('notes' => $notes);
}

Die elegantere Variante ist allerdings, den EntityManager per Dependency-Injection in den Controller zu geben. Hierzu wird der Controller um eine Klassenvariable $em und einen Konstruktor erweitert, der den EntityManager übergeben bekommt. In den einzelnen Actions des Controllers kann man nun bequem auf $this->em zugreifen.

    /**
     * @var \Doctrine\ORM\EntityManager
     */
    protected $em;

    public function __construct(\Doctrine\ORM\EntityManager $em)    
    {
        $this->em = $em;
    }

In der Modul-Konfiguration muss die Konfiguration des IndexController wie folgt geändert werden um den EntityManager beim Erstellen der Controller-Instanz mitzugeben:

    'controllers' => array(
        'factories' => array(
            'Application\Controller\Index' => function(Zend\Mvc\Controller\ControllerManager $cm) {
                $sm = $cm->getServiceLocator();
                return new \Application\Controller\IndexController(
                    $sm->get("doctrine.entitymanager.orm_default")
                );
            }
        ),
    ),

Fazit

Dank der neuen Modulstruktur des Zend Framework 2 und den vom Doctrine-Projekt zur Verfügung gestellten Modulen für den Doctrine ORM lassen sich die beiden Projekte einfach miteinander in der eigenen Anwendung verwenden. Die Konfiguration wird bequem in den bestehenden Dateien vorgenommen und durch den ServiceManager lässt sich überall in der Anwendung schnell auf den EntityManager von Doctrine zugreifen.

Avatar von Florian Eibeck

Kommentare

7 Antworten zu „Zend Framework 2 mit Doctrine ORM“

  1. Lesenswert: Zend Framework 2 mit Doctrine ORM http://t.co/PizSXwGV

  2. […] über “User Research“. Bei Mayflower lässt man sich heute über “Zend Framework 2 mit Doctrine ORM” […]

  3. Danke für die gute Anleitung. Leider hänge ich beim letzten Schritt, wo man in der Modul-Konfiguration den Entity-Manager übergeben soll.

    Ich erhalte immer folgenden Fehler:

    Catchable fatal error: Argument 1 passed to Application\Controller\IndexController::__construct() must be an instance of Doctrine\ORM\EntityManager, none given, called in /home/zend.house.dev/mm/vendor/zendframework/zendframework/library/Zend/ServiceManager/AbstractPluginManager.php on line 170 and defined in /home/zend.house.dev/mm/module/Application/src/Application/Controller/IndexController.php on line 23

    Würde mich über Hilfe freuen!

    1. Nachdem ich diese Zeile

      'invokables' => array(
      'Application\Controller\Index' => 'Application\Controller\IndexController'
      ),

      aus der Konfiguration entfernt habe, klappt es nun.

    2. Avatar von Florian Eibeck
      Florian Eibeck

      Hallo Roman!

      Es scheint, als würde die Modulkonfiguration für die Controller nicht passen. Kann es sein, dass für den IndexController zwei Einträge vorhanden sind, einer über die Factory wie oben im Beitrag und der Originale aus der Skeleton-Application als „invokeable”? Dies würde das Verhalten erklären, da anscheinend der Konfigurationsabschnitt aus der Skeleton-App weiter oben steht und beim Instanziieren des Controllers verwendet wird.

  4. Avatar von Maximilian Berghoff
    Maximilian Berghoff

    ganz genau, dass was ich gerade gebraucht habe :-)

    Weiß hier einer, warum unter ZF2 die sog. „ManagerRegistry“ nicht zur Verfügung steht. Ich kenne sie von Symfony2, weiß dort auch wie die aufgebaut wird, aber in der ZF2-Version gibt es diese nicht. Generell ist diese sehr sinnvoll wenn man mit mehreren managern arbeitet.

    1. Avatar von Florian Eibeck
      Florian Eibeck

      Hallo Maximilian,

      vielleicht hilft dir das weiter: https://github.com/eddiejaoude/zf2-doctrine2-manager-registry-service.

      Viele Grüße,
      Florian

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.