Pull to refresh

Интеграция Doctrine2 и ZendFramework

Reading time 10 min
Views 4.6K
Время не стоит на месте, и надо бежать за временем.
Вот уже и ZF2 на подходе. Выпущен первый milestone. Zend Framework 2.0.0dev1 Release. Doctrine2 BETA3 — был в пятницу.
А хороший программист никогда не стоит на месте — времени нету. Отстанет и вперёд — делай таблицы — «Code for the Food».

Дело было вечером делать было нечего…

Скачав исходные коды библиотек начали играться. Цель — получить возможность создание моделей сохраняя структуру ZF и работать через подключение Doctrine2.
Для начала нам нужно поместить в include_path классы, которые являются частью Doctrine2.

library/Doctrine
libray/Symfony


Symfony нужно будет, что бы использовать инструмент из коробки для работы Doctrine2 (два компонента Console и Yaml).
В configs/application.ini прописываем данные для авто загрузчика.
autoloadernamespaces.doctrine = "Doctrine"
autoloadernamespaces.symfony = "Symfony"


Продолжение под катом. Какие опции нужно прописать в application.ini. Как подключить Doctrine2, исходный код ресурс плагина.


Для своего приложения я выбрал
appnamespace = "Ecom"

На данный момент я не нашёл более «красивого» способа прописать путь к ресурс плагинам.
pluginpaths.Ecom\Application\Resources = APPLICATION_PATH "/resources"


Параметры конфигурации Doctrine2, для меня это просто конфигурация конекта к базе данных (пока мне большеего и не нужно).
resources.doctrine2.connection.driver = "pdo_mysql"
resources.doctrine2.connection.host = "localhost"
resources.doctrine2.connection.user = "root"
resources.doctrine2.connection.password = ""
resources.doctrine2.connection.dbname = "doctrinedb"


В плагине ресурса обязательно должен быть namespace — Ecom\Application\Resources; И название класса должно совпадать с названием в application.ini.

<?php
 
namespace Ecom\Application\Resources;
 
use Doctrine\Common\Util;
 
use Ecom\Document;
 
use Doctrine\ORM;
use Doctrine\DBAL;
use Doctrine\Common;
use Doctrine\Common\Cache;
use Zend\Application\Resource;
 
class Doctrine2 extends Resource\AbstractResource {
 
    public function init() {
 
        $front = $this->getBootstrap()->getResource('frontcontroller');
        $modules = $front->getControllerDirectory();
        $entityModels = array();
        foreach ($modules as $module => $moduleDirectory) {
            $dir = dirname($moduleDirectory) . "/models";
            if (is_dir($dir)) {
                $entityModels[] = $dir;
            }
        }
 
        $options = $this->getOptions();
 
        $config = new ORM\Configuration();
 
        $config->setProxyDir(APPLICATION_PATH . '/proxies');
        $config->setProxyNamespace('Ecom\Proxy');
        $config->setAutoGenerateProxyClasses($this->getBootstrap()->getEnvironment() == "development");
 
        $driverImpl = $config->newDefaultAnnotationDriver($entityModels);
        $config->setMetadataDriverImpl($driverImpl);
 
        if ($this->getBootstrap()->getEnvironment() == "development") {
            $cache = new Cache\ArrayCache();
        } else {
            $cache = new Cache\ApcCache();
        }
 
        $config->setMetadataCacheImpl($cache);
        $config->setQueryCacheImpl($cache);
 
        $evm = new Common\EventManager();
        $entityManager = ORM\EntityManager::create($options['connection'], $config, $evm);
 
        $eventDocument = new EventDocument($entityManager->getEventManager());
 
        return $entityManager;
    }
}
 
 
class EventDocument {
 
    private $evm;
 
    public $preFooInvoked = false;
    public $postFooInvoked = false;
 
    public function __construct($evm)
    {
        $this->evm = $evm;
//        $evm->addEventListener(array(ORM\Events::preRemove), $this);
//        $evm->addEventListener(array(ORM\Events::postRemove), $this);
//        $evm->addEventListener(array(ORM\Events::prePersist), $this);
        $evm->addEventListener(array(ORM\Events::postPersist, ORM\Events::postUpdate), $this);
//        $evm->addEventListener(array(ORM\Events::preUpdate), $this);
//        $evm->addEventListener(array(ORM\Events::postUpdate), $this);
//        $evm->addEventListener(array(ORM\Events::postLoad), $this);
//        $evm->addEventListener(array(ORM\Events::loadClassMetadata), $this);
//        $evm->addEventListener(array(ORM\Events::onFlush), $this);
    }
 
    public function postPersist(Common\EventArgs $e)
    {
        \Doctrine\Common\Util\Debug::dump($e->getEntity());
        echo __METHOD__;
    }
 
    public function postUpdate(Common\EventArgs $e)
    {
        echo __METHOD__;
    }
 
 
}

$entityModels содержит в себе список существующих модулей в системе, такой же механизм используется в ресурс плагине Frontcontroller-a для загрузки модулей.
$options['connection'] — параметры подключения к базе данных для Doctrine2.
При генерации схемы Doctrine2 будет искать данные в папке ModuleName/Model, использовать схему для базы данных основываясь на php-doc класса модели.

Создание контроллера и пример создания нового объекта модели.

  1. <?php
  2.  
  3. namespace Catalog;
  4. use Zend\Controller;
  5. use Core\Model\Entity;
  6. use Catalog\Model;
  7.  
  8.  
  9. class IndexController extends Controller\Action
  10. {
  11.  
  12.     public function init()
  13.     {
  14.         /* Initialize action controller here */
  15.     }
  16.  
  17.     public function indexAction() {
  18.  
  19.  
  20.         $product = new Model\Product();
  21.         $product->setName('test');
  22.         $product->setSku('test'.mktime());
  23.  
  24.         /* @var $em Doctrine\ORM\EntityManager */
  25.         $em = $this->getInvokeArg('bootstrap')->getResource('doctrine2');
  26.  
  27.         $em->persist($product);
  28.         $em->flush();
  29.  
  30.         $this->_helper->layout->setLayout('layout');
  31.     }
  32. }


Тут должно быть всё просто и понятно. Стоит обратить внимание только на то что, обязательно использование namespace Catalog; — имя модуля.

Класс самой модели продукта

  1. <?php
  2.  
  3. namespace Catalog\Model;
  4.  
  5. use Core\Model\Entity;
  6. /**
  7.  * @Entity
  8.  * @HasLifecycleCallbacks
  9.  * @Table(name="catalog_product")
  10.  */
  11. class Product extends Model\Entity {
  12.     /**
  13.      * @var integer
  14.      * @Id @Column(type="integer")
  15.      * @GeneratedValue(strategy="AUTO")
  16.      */
  17.     private $id;
  18.  
  19.     /**
  20.      * @var string
  21.      * @Column(type="string", length=255)
  22.      */
  23.     private $name;
  24.  
  25.     /**
  26.      * @var string
  27.      * @Column(type="string", length=255, unique=true, nullable=false)
  28.      */
  29.     private $sku;
  30.  
  31.     /**
  32.      * @var string
  33.      * @Column(type="datetime", nullable=true)
  34.      */
  35.     private $created;
  36.  
  37.     /**
  38.      * @var string
  39.      * @Column(type="datetime", nullable=true)
  40.      */
  41.     private $updated;
  42.  
  43.     /**
  44.      * @return integer the $id
  45.      */
  46.     public function getId() {
  47.         return $this->id;
  48.     }
  49.  
  50.     /**
  51.      * @return string the $name
  52.      */
  53.     public function getName() {
  54.         return $this->getProperty('name');
  55.     }
  56.  
  57.     /**
  58.      * @param string $name the $name to set
  59.      */
  60.     public function setName($name) {
  61.         $this->name = $name;
  62.         return $this;
  63.     }
  64.  
  65.     /**
  66.      * @return string the $created
  67.      */
  68.     /**
  69.      * @return the $sku
  70.      */
  71.     public function getSku(){
  72.         return $this->getProperty('sku');
  73.     }
  74.  
  75. /**
  76.      * @param $sku the $sku to set
  77.      */
  78.     public function setSku($sku){
  79.         $this->sku = $sku;
  80.         return $this;
  81.     }
  82.  
  83. public function getCreated(){
  84.     return $this->getProperty('created');
  85.     }
  86.  
  87.     /**
  88.      * @param $created the $created to set
  89.      */
  90.     public function setCreated($created){
  91.         $this->created = $created;
  92.         return $this;
  93.     }
  94.  
  95.     /**
  96.      * @return the $updated
  97.      */
  98.     public function getUpdated(){
  99.         return $this->getProperty('updated');
  100.     }
  101.  
  102.     /**
  103.      * @param $updated the $updated to set
  104.      */
  105.     public function setUpdated($updated){
  106.         $this->updated = $updated;
  107.         return $this;
  108.     }
  109.  
  110. }


Опять же, стоит заметить — namespace Catalog\Model; обязательная инструкция для класса модели.

Мои мысли — мне всё это нравится. PHP поднялся на ещё одну ступеньку выше как язык для корпоративного сектора.
Tags:
Hubs:
+17
Comments 26
Comments Comments 26

Articles