Pull to refresh

Правильная интеграция Doctrine в CodeIgniter

Reading time 7 min
Views 5.3K
Здравствуйте, на днях занялся интеграцией популярного PHP-ORM Doctrine с не менее популярным PHP-фрэймворком CodeIgniter и обнаружил, что официальный способ интеграции, озвученный в кукбуке Doctrine и на вики CodeIgniter вызывает у меня, по меньшей мере, негодование.

Почему? Потому что в инструкции предлагается:
  1. Изменять содержимое файла index.php;
  2. Использовать конфигурационный файл application/config/database.php для инициализации соединения и подключения CI.

Что в этом плохого? То, что при обновлении фрэймворка, нам из раза в раз придется лезть в файл index.php и вносить изменения. То, что в конфигурационных файлах не должно выполняться системных действий. А также то, что в итоге мы подключаем конфигурационный файл database.php через index.php, полностью игнорируя гибкие средства фрэймворка.

Я предлагаю на суд хабраюзеров свой способ подключения Doctrine к CodeIgniter, лишеннный вышеуказанных недостатков. Итак, начнем:
  1. Первым делом скачиваем последнюю версию Doctrine отсюда;
  2. Копируем из скачанного архива содержимое директории lib в директорию system/database/doctrine/;
  3. Я стараюсь всегда мыслить логично, поэтому, для подключения ORM библиотеки, мы используем механизм библиотек в CI. В директорию application/libraries мы помещаем файл doctrineORM.php со следующим кодом:

    1. <?php if (!defined('BASEPATH')) exit('No direct script access allowed');
    2.  
    3. /**
    4. * Doctrine initialization class
    5. */
    6. class DoctrineORM
    7. {
    8.  function __construct() {
    9.     // Получаем конфиг базы данных
    10.     require_once(APPPATH . 'config/database.php');
    11.  
    12.     // Создаем DSN из полученной инфы
    13.     $db['default']['dsn'] = $db['default']['dbdriver'] .
    14.                             '://' . $db['default']['username'] .
    15.                             ':' . $db['default']['password'].
    16.                             '@' . $db['default']['hostname'] .
    17.                             '/' . $db['default']['database'];
    18.  
    19.     // Подключаем Doctrine.php
    20.     require_once(BASEPATH . 'database/doctrine/Doctrine.php');
    21.  
    22.     // Устанавливаем autoloader
    23.     spl_autoload_register(array('Doctrine', 'autoload'));
    24.  
    25.     // Инициализируем соединение
    26.     Doctrine_Manager::connection($db['default']['dsn'], $db['default']['database']);
    27.  
    28.     // Устанавливаем тип загрузки моделей в "conservative/lazy"
    29.     Doctrine_Manager::getInstance()->setAttribute('model_loading', 'conservative');
    30.  
    31.     // Загружаем модели в autoloader
    32.     Doctrine::loadModels(APPPATH . 'models');
    33.  }
    34. }
    * This source code was highlighted with Source Code Highlighter.

    Этот файл будет отвечать за инициализацию Doctrine внутри нашего проекта. Получается своеобразный loader;
  4. В корень нашего application помещаем файлы doctrine и doctrine.php

    doctrine:
    1. #!php
    2. <?php
    3.  
    4.  // Директории system и application относительно текущей
    5.  $sys_folder = '../';
    6.  $app_folder = '.';
    7.  
    8.  include('doctrine.php');
    * This source code was highlighted with Source Code Highlighter.


    doctrine.php:
    1. <?php
    2.  
    3. define('BASEPATH', str_replace('\\', '/', $sys_folder) . '/');
    4. define('APPPATH',  str_replace('\\', '/', $app_folder) . '/');
    5.  
    6. require_once(APPPATH . 'libraries/doctrineORM.php');
    7. new DoctrineORM();
    8.  
    9. // Конфигурируем "Doctrine Cli"
    10. $config = array(
    11.                 'data_fixtures_path' => APPPATH . '/fixtures',
    12.                 'models_path'         => APPPATH . '/models',
    13.                 'migrations_path'     => APPPATH . '/migrations',
    14.                 'sql_path'            => APPPATH . '/sql',
    15.                 'yaml_schema_path'    => APPPATH . '/schema'
    16.               );
    17.  
    18. $cli = new Doctrine_Cli($config);
    19. $cli->run($_SERVER['argv']);
    * This source code was highlighted with Source Code Highlighter.

    Эти файлы будут отвечать за CLI интерфейс библиотеки Doctrine. Общаться с Doctrine мы сможем через консольную инструкцию «php doctrine», выполненную из директории application;
  5. Создать в директории application поддиректории:
    • application/fixtures;
    • application/migrations;
    • application/schema;
    • application/sql.

  6. Ввнести верные данные для соединения с СУБД в application/config/database.php. Это следует делать так же, как если бы вы работали с нативным ORM CodeIgniter;
  7. Занести библиотеку doctrineORM в список автозагружаемых библиотек в конфигурационном файле application/config/autoloader.php

    Пример:
    1. $autoload['libraries'] = array('doctrineORM', 'session');
    * This source code was highlighted with Source Code Highlighter.


Всё. Теперь мы спокойно можем использовать Doctrine внутри контроллеров и вьюшек, относящихся к данному приложению.
Опробуем простенький пример приложения с применением нашего вновь прибывшего ORM =)
  1. Создадим в директории application/schema файл user.yml со следующей структурой:

    1. ---
    2. User:
    3.  columns:
    4.     id:
    5.      primary: true
    6.      autoincrement: true
    7.      type: integer(4)
    8.     username: string(255)
    9.     password: string(255)
    10.  relations:
    11.     Groups:                    # Relation alias or class name
    12.      class: Group             # Class name. Optional if alias is the class name
    13.      local: user_id          # Local: User.id = UserGroup.user_id. Optional
    14.      foreign: group_id        # Foreign: Group.id = UserGroup.group_id. Optional
    15.      refClass: UserGroup     # xRefClass for relating Users to Groups
    16.      foreignAlias: Users     # Opposite relationship alias. Group hasMany Users
    17.  
    18. Group:
    19.  tableName: groups
    20.  columns:
    21.     id:
    22.      primary: true
    23.      autoincrement: true
    24.      type: integer(4)
    25.     name: string(255)
    26.  
    27. UserGroup:
    28.  columns:
    29.     user_id:
    30.      type: integer(4)
    31.      primary: true
    32.     group_id:
    33.      type: integer(4)
    34.      primary: true
    35.  relations:
    36.     User:
    37.      local: user_id        # Local key
    38.      foreign: id          # Foreign key
    39.      onDelete: CASCADE     # Database constraint
    40.     Group:
    41.      local: group_id
    42.      foreign: id
    43.      onDelete: CASCADE
    * This source code was highlighted with Source Code Highlighter.

  2. Откроем консоль (или командную строку) и перейдем в директорию нашего приложения (application);
  3. Выполнение следующей команды создаст модели в директории application/models на основе структуры user.yml
    $ php doctrine generate-models-yaml<br>generate-models-yaml - Generated models successfully from YAML schema<br><br>* This source code was highlighted with Source Code Highlighter.

  4. Теперь можно создать немного фиктивных данных для вноса их в СУБД. Для этого создайте файл application/fixtures/users.yml
    1. ---
    2. User:
    3.  jwage:
    4.     username: jwage
    5.     password: test
    * This source code was highlighted with Source Code Highlighter.

  5. Теперь запустите задание build-all-reload, чтобы очистить базу данных, создать модели и пересоздать структуру в базе
    $ php doctrine build-all-reload<br>build-all-reload - Are you sure you wish to drop your databases? (y/n)<br>y<br><br>* This source code was highlighted with Source Code Highlighter.

  6. Теперь можно использовать Doctrine для получения/записи данных напрямую из нашего контроллера. В контроллер welcome, метод index() добавьте следующий код и откройте
    главную страницу проекта в браузере
    1. $user = new User();
    2. $user->username = 'zYne-';
    3. $user->setPassword('password');
    4. $user->save();
    5.  
    6. $userTable = Doctrine::getTable('User');
    7. $user = $userTable->findOneByUsername('zYne-');
    8.  
    9. echo $user->username; // prints 'zYne-'
    * This source code was highlighted with Source Code Highlighter.


Надеюсь, кому-нибудь помог. Извиняюсь, что в личный блог, а не в «CodeIgniter» — не хватает кармы.
UPD: перенес в «CodeIgniter»
UPD2: в config/autoload.php обязательно надо выключить «database» из списка загружаемых библиотек

Tags:
Hubs:
+31
Comments 31
Comments Comments 31

Articles