Your SlideShare is downloading. ×
0
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

ZFConf 2010: Zend Framework and Doctrine

4,233

Published on

0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
4,233
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
89
Comments
0
Likes
4
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. <ul>Zend Framework и Doctrine Степан Танасийчук [email_address] </ul>
  • 2. Чем я занимаюсь? <ul><li>Web разработкой занялся в 2003 году
  • 3. С Zend Framework начал работать в 2008 году
  • 4. Руковожу собственной веб-студией с 2009 года
  • 5. Активный участник сообщества zendframework.ru
  • 6. Люблю прикольные смайлы :] </li></ul>
  • 7. Содержание доклада <ul><li>Подключение Doctrine к ZF проекту
  • 8. Скрипт для работы с Doctrine_Cli
  • 9. Генерация моделей по YAML схемам
  • 10. Механизм миграций
  • 11. Наследование в моделях
  • 12. Шаблоны расширений
  • 13. Адаптер для Zend_Auth
  • 14. Адаптер для Zend_Paginator
  • 15. ZFEngine и использование Doctrine в модульном ZF приложении </li></ul>
  • 16. Несколько слов о Doctrine <ul><li>ORM библиотека для PHP 5.2.3+
  • 17. Использует паттерны Active Record, Data Mapper и Metadata Mapping
  • 18. Собственный язык запросов — DQL (по мотивам HQL)
  • 19. Связи один-к-одному, один-ко-многим и многие-к-многим
  • 20. Автогенерация моделей по yaml схемам
  • 21. Экспорт и импорт из/в yaml
  • 22. Механизм миграций
  • 23. Шаблоны поведений (l18n, Versionable, NestedSet, etc.) </li></ul>
  • 24. Подключаем Doctrine к ZF проекту <ul><li>Размещаем Doctrine в library/Doctrine:
  • 25. $ svn export http://svn.doctrine-project.org/tags/1.2.1/lib/Doctrine/ ./library/Doctrine
  • 26. Прописываем следующие настройки в application.ini:
  • 27. autoloadernamespaces[] = &quot;Doctrine&quot; </li></ul>
  • 28. Parables_Application_Resource_Doctrine <ul>Matthew Lurz добавил в Zend Framework proposal application-ресурс для подключения Doctrine. Его класс называется Parables_Application_Resource_Doctrine и лежит здесь http://github.com/mlurz71/parables </ul>
  • 29. ZFEngine_Application_Resource_Doctrine <ul>Мы немного изменили код Parables_Application_Resource_Doctrine для работы с Doctrine 1.2.x и храним его в репозитории ZFEngine как ZFEngine_Application_Resource_Doctrine ZFEngine это сборная солянка классов, которые мы используем при разработке проектов на ZF. Лежит все здесь: http://zfengine.com В основном код наш. Также есть чужой, но с некоторыми изменениями. Надеюсь, что это все в рамках закона ^_~. </ul>
  • 30. Подключаем ZFEngine к ZF проекту <ul><li>Размещаем ZFEngine в library/ZFEngine:
  • 31. $ svn export http://svn2.assembla.com/svn/zfengine/trunk/library/ZFEngine/ ./library/ZFEngine
  • 32. Прописываем следующие настройки в application.ini:
  • 33. autoloadernamespaces[] = &quot;ZFEngine&quot;
  • 34. pluginPaths.ZFEngine_Application_Resource = &quot;ZFEngine/Application/Resource&quot; </li></ul>
  • 35. Настраиваем подключение к БД <ul>resources.doctrine.connections.primary.dsn.adapter = &quot;mysql&quot; resources.doctrine.connections.primary.dsn.username = &quot;root&quot; resources.doctrine.connections.primary.dsn.password = &quot;******&quot; resources.doctrine.connections.primary.dsn.host = &quot;localhost&quot; resources.doctrine.connections.primary.dsn.dbname = &quot;zfconf&quot; resources.doctrine.connections.primary.options.charset = &quot;utf8&quot; resources.doctrine.connections.primary.options.collate = &quot;utf8_unicode_ci&quot; </ul>
  • 36. Настраиваем Doctrine_Manager <ul>resources.doctrine.manager.attributes.attr_autoload_table_classes = 1 resources.doctrine.manager.attributes.attr_use_native_enum = 1 resources.doctrine.manager.attributes.attr_quote_identifier = 1 resources.doctrine.manager.attributes.attr_auto_free_query_objects = 1 resources.doctrine.manager.attributes.attr_auto_accessor_override = 1 resources.doctrine.manager.attributes.attr_model_loading = &quot;model_loading_conservative&quot; </ul>
  • 37. <ul>MODEL_LOADING_PEAR </ul><ul>В Doctrine 1.2 появился новый режим для автозагрузки моделей — MODEL_LOADING_PEAR , но при использовании этого режима не работает generate-migration-diff :(. Я заметил это уже в процессе подготовки доклада и пока просто написал в багрепорт Doctrine. </ul>
  • 38. Для проектов с НЕмодульной структурой <ul><li>Указываем путь к директории с моделями:
  • 39. resources.doctrine.manager.models_path = APPLICATION_PATH &quot;/models&quot; </li></ul>
  • 40. Настраиваем кеширование <ul><li>resources.doctrine.manager.*
  • 41. .attributes.attr_result_cache.driver = &quot;memcache&quot;
  • 42. .attributes.attr_result_cache.lifespan = 3600
  • 43. .attributes.attr_result_cache.options.servers.host = &quot;localhost&quot;
  • 44. .attributes.attr_result_cache.options.servers.port = 11211
  • 45. .attributes.attr_result_cache.options.servers.persistent = 1
  • 46. .attributes.attr_result_cache.options.compression = 0 </li></ul>
  • 47. Настраиваем Doctrine_Cli <ul>doctrine_cli.data_fixtures_path = APPLICATION_PATH &quot;/configs/doctrine/data/fixtures&quot; doctrine_cli.models_path = APPLICATION_PATH &quot;/models&quot; doctrine_cli.migrations_path = APPLICATION_PATH &quot;/configs/doctrine/migrations&quot; doctrine_cli.sql_path = APPLICATION_PATH &quot;/configs/doctrine/data/sql&quot; doctrine_cli.yaml_schema_path = APPLICATION_PATH &quot;/configs/doctrine/schema&quot; doctrine_cli.generate_models_options.generateBaseClasses = 1 doctrine_cli.generate_models_options.baseClassesDirectory = &quot;Base&quot; doctrine_cli.generate_models_options.generateTableClasses = 1 </ul>
  • 48. Cкрипт для работы с Doctrine_Cli <ul>./application/sripts/common.php <?php define( 'APPLICATION_ENV' , 'development' ); define( 'APPLICATION_PATH' , realpath(dirname(__FILE__) . '/..' )); set_include_path(implode(PATH_SEPARATOR, array ( realpath(APPLICATION_PATH . '/../library' ), get_include_path(), ))); </ul>
  • 49. Cкрипт для работы с Doctrine_Cli <ul>./application/sripts/doctrine #!/usr/bin/env php <?php require_once 'common.php' ; require_once 'Zend/Application.php' ; $application = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini' ); $application ->getBootstrap() ->bootstrap(); $cli = new Doctrine_Cli( $application ->getOption( 'doctrine_cli' )); $cli ->run($_SERVER[ 'argv' ]); </ul>
  • 50. Проверяем как работает <ul><li>Запускаем скрипт без параметров:
  • 51. $ ./application/sripts/doctrine
  • 52. Doctrine Command Line Interface
  • 53. ./application/sripts/doctrine generate-sql
  • 54. ./application/sripts/doctrine create-db
  • 55. ./application/sripts/doctrine generate-yaml-models
  • 56. ./application/sripts/doctrine dql
  • 57. ./application/sripts/doctrine generate-migrations-models
  • 58. ./application/sripts/doctrine generate-yaml-db
  • 59. ./application/sripts/doctrine generate-models-yaml
  • 60. ./application/sripts/doctrine generate-migrations-diff
  • 61. ./application/sripts/doctrine generate-migration
  • 62. ./application/sripts/doctrine create-tables
  • 63. ./application/sripts/doctrine drop-db
  • 64. ./application/sripts/doctrine generate-migrations-db
  • 65. ... и ещё 9ть команд, которые не поместились на этом слайде (: </li></ul>
  • 66. Создадим схему модели User <ul>./application/configs/doctrine/schema/User.yml User : tableName : users options : type : INNODB collate : utf8_unicode_ci charset : utf8 columns : id : type : integer(4) primary : true autoincrement : true login : string(32) email : string(255) </ul>
  • 67. Генерируем модели по YAML схемам <ul><li>Запускаем скрипт с параметром generate-models-yaml :
  • 68. $ ./application/sripts/doctrine generate-models-yaml
  • 69. generate-models-yaml - Generated models successfully from YAML schema
  • 70. Получаем готовые модели:
  • 71. ./application/models
  • 72. |-- Base
  • 73. | `-- BaseUser.php
  • 74. |-- User.php
  • 75. `-- UserTable.php
  • 76. Важная деталь: сами YAML схемы можно сгенерировать непосредственно с структуры БД используя команду generate-yaml-db . </li></ul>
  • 77. Сгенерированный код базовой модели User ./application/models/Base/BaseUser.php <?php abstract class BaseUser extends Doctrine_Record { public function setTableDefinition() { $this ->setTableName( 'users' ); $this ->hasColumn( 'id' , 'integer' , 4, array ( 'type' => 'integer' , 'unsigned' => true , 'primary' => true , 'autoincrement' => true , 'length' => '4' )); // Здесь было описание полей login и email ... $this ->option( 'type' , 'INNODB' ); $this ->option( 'collate' , 'utf8_unicode_ci' ); $this ->option( 'charset' , 'utf8' ); } public function setUp() { parent::setUp(); } }
  • 78. Сгенерированный код модели User и маппера UserTable <ul>./application/models/User.php <?php class User extends BaseUser { } ./application/models/UserTable.php <?php class UserTable extends Doctrine_Table { } </ul>
  • 79. Напишем свой сеттер для поля email <ul>./application/models/User.php <?php /** * User model */ class User extends BaseUser { /** * Set email adress into lowercase * * @param string $email * @return void */ public function setEmail( $email ) { $this ->_set( 'email' , strtolower( $email )); } } </ul>
  • 80. Пишем экшн для проверки работы <ul>./application/controllers/IndexController.php <?php class IndexController extends Zend_Controller_Action { /** * Simple action * * @return void */ public function indexAction() { $user = new User(); $user -> login = 'stfalcon' ; $user -> email = 'CEO@STFalcon.COM ' ; Zend_Debug:: dump ( $user ->toArray()); } } </ul>
  • 81. Запускаем в браузере array 'id' => null 'login' => string 'stfalcon' (length=8) 'email' => string 'ceo@stfalcon.com' (length=16)
  • 82. Миграции <ul><li>Сгенерируем первый класс миграций. Его можно генерировать из классов моделей или БД (см. мануал к Doctrine).
  • 83. $ ./application/sripts/doctrine generate-migrations-models
  • 84. generate-migrations-models - Generated migration classes successfully from models
  • 85. Получаем готовую модель миграций:
  • 86. ./application/configs/doctrine/
  • 87. |-- data
  • 88. | |-- fixtures
  • 89. | `-- sql
  • 90. |-- migrations
  • 91. | `-- 1268942153_adduser.php
  • 92. `-- schema
  • 93. `-- User.yml </li></ul>
  • 94. Сгенерированный код первой модели миграций <ul>./application/configs/doctrine/migrations/1268942153_adduser.php <?php class Adduser extends Doctrine_Migration_Base { public function up() { $this ->createTable( 'user' , array ( 'id' => array ( 'type' => 'integer' , 'unsigned' => true , 'primary' => true , 'autoincrement' => true , 'length' => 4), // Здесь были параметры для создания полей login и email ... ), array ( 'type' => 'INNODB' , 'indexes' => array (), 'primary' => array (0 => 'id' ), 'collate' => 'utf8_unicode_ci' , 'charset' => 'utf8' )); } public function down() { $this ->dropTable( 'user' ); } } </ul>
  • 95. Создадим БД и накатим на неё наши изменения <ul><li>Создаем БД (например на production сервере):
  • 96. mysql> CREATE DATABASE `zfconf`;
  • 97. Query OK, 1 row affected (0,00 sec)
  • 98. Накатываем на неё миграцию:
  • 99. $ ./application/sripts/doctrine migrate
  • 100. migrate - migrated successfully to version #1
  • 101. Выведем список таблиц:
  • 102. mysql> SHOW TABLES ;
  • 103. migration_version
  • 104. users </li></ul>
  • 105. Проверяем работу скрипта <ul><li>Структура таблицы в которой хранится номер миграции:
  • 106. mysql> SHOW CREATE TABLE `migration_version`;
  • 107. CREATE TABLE `migration_version` (
  • 108. `version` int (11) DEFAULT NULL
  • 109. ) ENGINE =InnoDB DEFAULT CHARSET =latin1
  • 110. Структура таблицы пользователей:
  • 111. mysql> SHOW CREATE TABLE `users`;
  • 112. CREATE TABLE `users` (
  • 113. `id` int (10) NOT NULL AUTO_INCREMENT ,
  • 114. `login` varchar (32) COLLATE utf8_unicode_ci DEFAULT NULL ,
  • 115. `email` varchar (255) COLLATE utf8_unicode_ci DEFAULT NULL ,
  • 116. PRIMARY KEY (`id`)
  • 117. ) ENGINE =InnoDB DEFAULT CHARSET =utf8 COLLATE =utf8_unicode_ci </li></ul>
  • 118. Наследование в YAML схемах <ul>./application/configs/doctrine/schema/Administrator.yml ## Administrator schema Administrator : tableName : administrators inheritance : extends : User type : concrete columns : password_hash : string(32) password_salt : string(8) actAs : [Timestampable] </ul>
  • 119. Работаем с Doctrine_Cli <ul><li>В первую очередь делаем migration-diff — он генерирует классы миграций на основе различий между кодом моделей и YAML схемами:
  • 120. $ ./application/sripts/doctrine generate-migrations-diff
  • 121. generate-migrations-diff - Generated migration classes successfully from difference
  • 122. ./application/configs/doctrine
  • 123. |-- data
  • 124. | |-- fixtures
  • 125. | `-- sql
  • 126. |-- migrations
  • 127. | |-- 1268942153_adduser.php
  • 128. | `-- 1268942505_version2.php
  • 129. `-- schema
  • 130. |-- Administrator.yml
  • 131. `-- User.yml </li></ul>
  • 132. Работаем с Doctrine_Cli <ul><li>Генерируем код моделей:
  • 133. $ ./application/sripts/doctrine generate-models-yaml
  • 134. generate-models-yaml - Generated models successfully from YAML schema
  • 135. Накатываем изменения на БД:
  • 136. $ ./application/sripts/doctrine migrate
  • 137. migrate - migrated successfully to version #2 </li></ul>
  • 138. Работаем с Doctrine_Cli <ul><li>Смотрим, что получилось:
  • 139. mysql> SHOW CREATE TABLE `administrators`;
  • 140. CREATE TABLE `administrators` (
  • 141. `id` int (10) NOT NULL AUTO_INCREMENT ,
  • 142. `login` varchar (32) COLLATE utf8_unicode_ci DEFAULT NULL ,
  • 143. `email` varchar (255) COLLATE utf8_unicode_ci DEFAULT NULL ,
  • 144. `password_hash` varchar (32) COLLATE utf8_unicode_ci DEFAULT NULL ,
  • 145. `password_salt` varchar (8) COLLATE utf8_unicode_ci DEFAULT NULL ,
  • 146. `created_at` datetime NOT NULL ,
  • 147. `updated_at` datetime NOT NULL ,
  • 148. PRIMARY KEY (`id`)
  • 149. ) ENGINE =InnoDB DEFAULT CHARSET =utf8 COLLATE =utf8_unicode_ci </li></ul>
  • 150. По-моему пора сделать авторизацию <ul><li>Сначала напишем сеттер для password:
  • 151. ./application/models/Administrator.php
  • 152. <?php
  • 153. class Administrator extends BaseAdministrator
  • 154. {
  • 155. // Здесь был phpDoc блок ...
  • 156. public function setPassword( $password )
  • 157. {
  • 158. if (strlen( $password )) {
  • 159. $passwordSalt = substr(md5(mktime()), 0, rand(5,8));
  • 160. $passwordHash = md5( $password . $passwordSalt );
  • 161. $this ->_set( 'password_hash' , $passwordHash );
  • 162. $this ->_set( 'password_salt' , $passwordSalt );
  • 163. }
  • 164. }
  • 165. } </li></ul>
  • 166. Сгенерируем аккаунт для админа и сохраним его в БД <ul>./application/controllers/IndexController.php <?php class IndexController extends Zend_Controller_Action { // Здесь был phpDoc блок ... public function indexAction() { $administrator = new Administrator(); $administrator -> email = 'CEO@STFalcon.COM' ; $administrator -> login = 'stfalcon' ; $administrator -> password = 'qwerty' ; $administrator ->save(); Zend_Debug:: dump ( $administrator ->toArray()); } } </ul>
  • 167. Проверяем содержимое таблицы administrators <ul>mysql> SELECT * FROM `administrators`; +----+----------+------------------+----------------------------------+---------------+---------------------+---------------------+ | id | login | email | password_hash | password_salt | created_at | updated_at | +----+----------+------------------+----------------------------------+---------------+---------------------+---------------------+ | 1 | stfalcon | [email_address] | bcd3987603a947d54480285c16f06fde | fc1ed | 2010-03-18 23:04:11 | 2010-03-18 23:04:11 | </ul>
  • 168. ZendX_Doctrine_Auth_Adapter <ul>./application/controllers/IndexController.php public function indexAction() { $authAdapter = new ZendX_Doctrine_Auth_Adapter( Doctrine_Core:: getConnectionByTableName ( 'Administrator' )); $authAdapter ->setTableName( 'Administrator a' ) ->setIdentityColumn( 'a.login' ) ->setCredentialColumn( 'a.password_hash' ) ->setCredentialTreatment( 'MD5(CONCAT(?,a.password_salt))' ) ->setIdentity( 'stfalcon' )->setCredential( 'qwerty' ); $auth = Zend_Auth:: getInstance (); $result = $auth ->authenticate( $authAdapter ); if ( $result ->isValid()) { echo '<h1>OK</h1>' ; } else { echo '<h1>FAIL</h1>' ; } } </ul>
  • 169. Открываем страницу в браузере <ul><li>Все ОК :)
  • 170. И не забудьте сохранить данные авторзации в хранилище:
  • 171. $data = $authAdapter ->getResultRowObject( null , array ( 'password_hash' , 'password_salt' ));
  • 172. $auth ->getStorage()->write( $data ); </li></ul>
  • 173. Увековечим учетную запись администратора <ul>./application/configs/doctrine/data/fixtures/users.yml Administrator : Admin_1 : login : stfalcon email : mymail@gmail.com password_hash : bcd3987603a947d54480285c16f06fde password_salt : fc1ed # Admin_ 2 : # login: stfalcon # ... </ul>
  • 174. Сделаем глобальный reload <ul>$ ./application/sripts/doctrine build-all-reload build-all-reload - Are you sure you wish to drop your databases? (y/n) y build-all-reload - Successfully dropped database for connection named 'primary' build-all-reload - Generated models successfully from YAML schema build-all-reload - Successfully created database for connection named 'primary' build-all-reload - Created tables successfully build-all-reload - Data was successfully loaded mysql> SELECT * FROM `administrators`; | id | login | email | password_hash | password_salt | created_at | updated_at | +----+----------+------------------+----------------------------------+---------------+---------------------+---------------------+ | 1 | stfalcon | [email_address] | bcd3987603a947d54480285c16f06fde | fc1ed | 2010-03-18 23:04:11 | 2010-03-18 23:04:11 | </ul>
  • 175. Адаптер для Zend_Paginator <ul>Мы используем ZFEngine_Paginator_Adapter_Doctrine , это немного переработанный с учетом наших потребностей и изменений в Doctrine 1.2 SmartL_Zend_Paginator_Adapter_Doctrine http://code.google.com/p/smart-framework/ Ещё раз пропиарю наш ZFEngine :) http://zfengine.com </ul>
  • 176. ZFEngine_Paginator_Adapter_Doctrine <ul><li>Давайте выведем список администраторов с постраничной навигацией. Для этого создадим в таблице administrators 10 случайных записей: </li></ul>
  • 177. Расширяем функционал AdministratorTable <ul><li>Создадим метод getQueryToFetchAll(), который будет возвращать запрос на выборку всех администраторов:
  • 178. ./application/models/AdministratorTable.php
  • 179. <?php
  • 180. class AdministratorTable extends UserTable
  • 181. {
  • 182. /**
  • 183. * Query to fetch all administrators
  • 184. * @return Doctrine_Query
  • 185. */
  • 186. public function getQueryToFetchAll()
  • 187. {
  • 188. return $this ->createQuery( 'a' )
  • 189. ->orderBy( 'a.created_at' );
  • 190. }
  • 191. } </li></ul>
  • 192. Работаем с пагинатором <ul>./application/controllers/IndexController.php <?php class IndexController extends Zend_Controller_Action { public function indexAction() { $query = Doctrine_Core:: getTable ( 'Administrator' ) ->getQueryToFetchAll(); $paginator = new Zend_Paginator( new ZFEngine_Paginator_Adapter_Doctrine( $query )); $paginator ->setCurrentPageNumber( $this ->_getParam( 'page' , 1)); $paginator ->setItemCountPerPage(4); $this -> view -> paginator = $paginator ; } } </ul>
  • 193. Оформляем вывод списка в view шаблоне <ul>./application/views/scripts/index/index.phtml <h1> <?php echo $this ->translate( 'Администраторы' ); ?>: </h1> <?php if (count( $this -> paginator )): ?> <ul> <?php foreach ( $this -> paginator as $administrator ): ?> <li> <?php echo $administrator -> login ; ?>&nbsp; &lt;<?php echo $administrator -> email ; ?>&gt; </li> <?php endforeach ; ?> </ul> <?php endif ; ?> <?php echo $this ->paginationControl( $this -> paginator , 'Sliding' , 'digg.phtml' ); ?> </ul>
  • 194. digg.phtml <ul><li>digg.phtml я выложил здесь — http://pastie.org/832023 (за основу взят шаблон с ZendPaginationHelper ) </li></ul>
  • 195. Открываем страницу в браузере <ul><li>И наслаждаемся результатом :) </li></ul>
  • 196. ZFEngine и использование Doctrine в модульном ZF приложении <ul><li>Мы написали несколько тасков (собственно таски написал Валерий Рабиевский , а я только немного порефакторил) для Doctrine, которые позволяют генерировать модели и использовать механизм миграций в ZF проектах с модульной архитектурой.
  • 197. При этом между моделями разных модулей работает связывание и наследование.
  • 198. Также работает механизм миграций для проекта в целом. </li></ul>
  • 199. Пример структуры модульного ZF проекта <ul>./application/ |-- Bootstrap.php |-- configs | `-- application.ini |-- layouts | `-- scripts | |-- admin.phtml | `-- index.html `-- modules |-- products `-- users </ul>
  • 200. Настройки для модульной структуры <ul><li>Прописываем следующие настройки в application.ini:
  • 201. ; Указываем, где находятся наши модули для Zend
  • 202. resources.frontController.moduleDirectory =
  • 203. APPLICATION_PATH &quot;/modules&quot;
  • 204. ; и для Doctrine_Cli
  • 205. doctrine_cli.modules_path = APPLICATION_PATH &quot;/modules/&quot;
  • 206. ; а также прописываем путь к папке, где будут хранится yaml-схемы предыдущих версий (old), и новые (temp), собранные с модулей в одну папку. Именно по различиям между ними и будут генерироваться миграции.
  • 207. doctrine_cli.old_schema_path = APPLICATION_PATH &quot;/configs/doctrine/schema/old/&quot;
  • 208. doctrine_cli.temp_schema_path = APPLICATION_PATH &quot;/../tmp/schema/&quot;
  • 209. resources.modules[] = &quot;&quot; ; подгружаем ресурс для подержки модулей
  • 210. ; И убираем строки, где задавали расположение моделей:
  • 211. ; resources.doctrine.manager.models_path = APPLICATION_PATH &quot;/models&quot;
  • 212. ; doctrine_cli.models_path = APPLICATION_PATH &quot;/models&quot;
  • 213. ; так как теперь модели подгружаются самим Zend'ом </li></ul>
  • 214. Cтруктура модуля users <ul>./application/modules/users/ |-- Bootstrap.php |-- configs | `-- doctrine | |-- data | | |-- fixtures | | `-- sql | `-- schema | `-- User.yml |-- controllers | `-- IndexController.php |-- models `-- views `-- scripts `-- index `-- index.phtml </ul>
  • 215. Схема User.yml ## User schema Users_Model_User : tableName : users options : type : INNODB collate : utf8_unicode_ci charset : utf8 columns : id : type : integer(4) unsigned : true primary : true autoincrement : true login : string(32) email : string(255)
  • 216. Cтруктура модуля products <ul>./application/modules/products/ |-- Bootstrap.php |-- configs | |-- acl.php | |-- doctrine | | `-- schema | | `-- Product.yml | `-- routes.xml |-- controllers | `-- IndexController.php |-- forms |-- models `-- views |-- helpers `-- scripts `-- index `-- index.phtml </ul>
  • 217. Схема Product.yml <ul>## Product schema Products_Model_Product : tableName : products options : <ul>... </ul>columns : id : type : integer(4) unsigned : true primary : true autoincrement : true user_id : type : integer(4) unsigned : true name : string(255) description : string actAs : [Timestampable] ... </ul>
  • 218. Схема Product.yml (продолжение) <ul>... # Прописываем связь один-ко-многим # User и Products – алиасы, через которые мы сможем обращаться # из одной модели к другой relations : User : class : Users_Model_User foreign : id local : user_id foreignAlias : Products onUpdate : CASCADE onDelete : CASCADE </ul>
  • 219. Новый скрипт для Doctrine_Cli <ul><li>Скрипт для работы с Doctrine_Cli в модульном ZF приложении лежит в репозитории ZFEngine.
  • 220. Единственное его отличие от обычного скрипта, это наличие кода для подключения тасков с ZFEngine и справка по командам ZFEngine при запуске скрипта с ключем info :
  • 221. $ ./application/scripts/doctrine info
  • 222. zfengine-generate-migrations-models -> для генерации новой миграций
  • 223. zfengine-generate-migrations-diff -> для генерации изменений миграций
  • 224. zfengine-generate-models-yaml -> для генерация моделей из yaml-файлов
  • 225. zfengine-prepare-schema-files-for-migrations -> для копирования shema-файлов для сравнения при генерации миграций
  • 226. Очередность действий:
  • 227. При создании новой миграции:
  • 228. zfengine-generate-models-yaml
  • 229. zfengine-generate-migrations-models
  • 230. migrate
  • 231. При создании изменений миграции: ... </li></ul>
  • 232. Генерируем модели по YAML схемам <ul><li>Все также как в предыдущих примерах, только команда с префиксом zfengine :
  • 233. $ ./application/sripts/doctrine zfengine-generate-models-yaml
  • 234. Generated models for module &quot;Products&quot; successfully
  • 235. Generated models for module &quot;Users&quot; successfully
  • 236. Generated models finished
  • 237. Получаем готовые модели:
  • 238. ./application/modules/users/
  • 239. |-- models
  • 240. |-- Base
  • 241. | `-- User.php
  • 242. |-- User.php
  • 243. `-- UserTable.php
  • 244. Только теперь модели именуются согласно стандартам ZF и подгружаются родным автозагрузчиком:
  • 245. BaseUser -> Users_Model_Base_User
  • 246. User -> Users_Model_User </li></ul>
  • 247. Сгенерированые модели <ul>Между моделями из разных модулей сгенерировались связи: ./application/modules/users/models/Base/User.php <?php ... public function setUp() { $this-> hasMany( 'Products_Model_Product as Products' , array( 'local' => 'id' , 'foreign' => 'user_id' )); } ./application/modules/products/models/Base/Product.php <?php ... public function setUp() { $this-> hasOne( 'Users_Model_User as User' , array( 'local' => 'user_id' , 'foreign' => 'id' , 'onDelete' => 'CASCADE' , 'onUpdate' => 'CASCADE' )); } При работе с моделью пользователя коллекция моделей продуктов будет подгружена только при необходимости. Например при получении всех продуктов пользователя: $products = $user-> Products ; </ul>
  • 248. Миграции <ul><li>Сгенерируем миграции:
  • 249. Первую миграцию (на новом проекте) делаем через:
  • 250. $ ./application/sripts/doctrine zfengine-generate-migrations-models
  • 251. Так миграции генерируются на основании существующих классов моделей, а последующие — уже на основании изменений в yaml-схемах командой:
  • 252. $ ./application/sripts/doctrine zfengine-generate-migrations-diff
  • 253. И накатываем миграции на базу:
  • 254. $ ./application/sripts/doctrine migrate
  • 255. migrate - migrated successfully to version #3 </li></ul>
  • 256. Структура таблицы `products` <ul><li>Смотрим, что получилось в БД:
  • 257. mysql> SHOW CREATE TABLE `products`;
  • 258. CREATE TABLE `products` (
  • 259. `id` int (10) unsigned NOT NULL AUTO_INCREMENT ,
  • 260. `user_id` int (10) unsigned DEFAULT NULL ,
  • 261. `name` varchar (255) COLLATE utf8_unicode_ci DEFAULT NULL ,
  • 262. `description` text COLLATE utf8_unicode_ci,
  • 263. `created_at` datetime NOT NULL ,
  • 264. `updated_at` datetime NOT NULL ,
  • 265. PRIMARY KEY (`id`),
  • 266. KEY `products_user_id_users_id` (`user_id`),
  • 267. CONSTRAINT `products_user_id_users_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
  • 268. ) ENGINE =InnoDB DEFAULT CHARSET =utf8 COLLATE =utf8_unicode_ci </li></ul>
  • 269. На этом все ;) <ul>Благодарю за внимание! Задавайте вопросы. Степан Танасийчук [email_address] </ul>

×