SlideShare ist ein Scribd-Unternehmen logo
1 von 40
Downloaden Sie, um offline zu lesen
Doctrine 2
Who am I?
Валерий Рабиевский
Team lead веб-студии stfalcon.com
Активный разработчик Open Source
движка ZFEngine (ZF + Doctrine)
Более 4 лет опыта работы с PHP
Почему?
Doctrine 2
Библиотеки
— Common
— DBAL (включает Common)
— ORM (включает DBAL+Common)
— Migrations (часть DBAL)
— Object Document Mapper:
MongoDB
CouchDB
github.com/doctrine
Entities
— Легкая модель (самый простой PHP класс)
— Не нужно наследование от базового класса
— Есть возможность наследовать модель от
своих базовых классов
— Конструктор модели можно использовать
для своих нужд
— Данные хранятся непосредственно в
свойствах объекта
Пример модели
namespace Entities;
class User
{
private $id;
private $name;
public function getId() { return $this->id; }
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
}
namespace Entities;
class User
{
private $id;
private $name;
public function getId() { return $this->id; }
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
}
EntityManager
EntityManager является центральной
точкой доступа к функциям ORM
— Управление обновлением сущностей
— Доступ к репозиториям сущностей
— Используется паттерн UnitOfWork
ZF2 + D2
protected function _initAutoload()
{
$loader = new ZendLoaderStandardAutoloader();
$loader->registerNamespace('Doctrine', '/path/to/Doctrine');
$loader->registerNamespace('Symfony', '/path/to/Symfony');
$loader->register();
}
protected function _initAutoload()
{
$loader = new ZendLoaderStandardAutoloader();
$loader->registerNamespace('Doctrine', '/path/to/Doctrine');
$loader->registerNamespace('Symfony', '/path/to/Symfony');
$loader->register();
}
Добавляем автозагрузку в Bootstrap
Настройка Doctrine 2
./application/configs/application.xml
<!-- production -->
<doctrine>
<connection><!-- user, password, database, etc --></connection>
<paths>
<entities>path/to/entities</entities>
<proxies>path/to/proxies</proxies>
</paths>
<proxiesNamespace value="ApplicationModelProxies" />
<autogenerateProxyClasses value="0" />
<cacheAdapter value="DoctrineCommonCacheApcCache" />
</doctrine>
<!-- development -->
...
<autogenerateProxyClasses value="1" />
<cacheAdapter value="DoctrineCommonCacheArrayCache" />
…
<!-- production -->
<doctrine>
<connection><!-- user, password, database, etc --></connection>
<paths>
<entities>path/to/entities</entities>
<proxies>path/to/proxies</proxies>
</paths>
<proxiesNamespace value="ApplicationModelProxies" />
<autogenerateProxyClasses value="0" />
<cacheAdapter value="DoctrineCommonCacheApcCache" />
</doctrine>
<!-- development -->
...
<autogenerateProxyClasses value="1" />
<cacheAdapter value="DoctrineCommonCacheArrayCache" />
…
Подключение EntityManager
protected function _initEntityManager() {
if (is_null($this->_em)) {
$options = $this->getOption('doctrine');
$cache = new $options['cacheAdapter'];
$config = new Configuration();
$driverImpl = $config
->newDefaultAnnotationDriver($options['paths']['entities']);
$config->setMetadataCacheImpl($cache);
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCacheImpl($cache);
$config->setProxyNamespace($options['proxiesNamespace']);
$config->setProxyDir($options['paths']['proxies']);
$config->setAutoGenerateProxyClasses(
$options['autogenerateProxyClasses']
);
$this->_em =
EntityManager::create($options['connection'], $config);
}
return $this->_em;
}
protected function _initEntityManager() {
if (is_null($this->_em)) {
$options = $this->getOption('doctrine');
$cache = new $options['cacheAdapter'];
$config = new Configuration();
$driverImpl = $config
->newDefaultAnnotationDriver($options['paths']['entities']);
$config->setMetadataCacheImpl($cache);
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCacheImpl($cache);
$config->setProxyNamespace($options['proxiesNamespace']);
$config->setProxyDir($options['paths']['proxies']);
$config->setAutoGenerateProxyClasses(
$options['autogenerateProxyClasses']
);
$this->_em =
EntityManager::create($options['connection'], $config);
}
return $this->_em;
}
Mapping
Basic Mapping
— Docblock Annotations
— XML
— YAML
— PHP
Association Mapping
— One-To-One & Many-To-Many:
— Unidirectional
— Bidirectional
— Self-referencing
— Many-To-One, Unidirectional
— One-To-Many:
— Unidirectional with Join Table
— Bidirectional
— Self-referencing
Inheritance Mapping
— Mapped Superclasses
— Single Table Inheritance
— Class Table Inheritance
Mapping
...
/**
* @ManyToOne(targetEntity="Address", inversedBy="users")
* @JoinColumn(name="address_id", referencedColumnName="id")
*/
private $address;
...
...
/**
* @ManyToOne(targetEntity="Address", inversedBy="users")
* @JoinColumn(name="address_id", referencedColumnName="id")
*/
private $address;
...
...
/** @OneToMany(targetEntity="User", mappedBy="address") */
private $user;
...
...
/** @OneToMany(targetEntity="User", mappedBy="address") */
private $user;
...
Entities/User
Entitites/Address
Console
Console
...
$em = $application->getBootstrap()->getResource('EntityManager');
...
$helpers = array(
'db' => new DBALHelperConnectionHelper($em->getConnection()),
'em' => new ORMHelperEntityManagerHelper($em),
'dialog' => new SymfonyComponentConsoleHelperDialogHelper(),
);
...
$cli = new SymfonyComponentConsoleApplication(
'Doctrine Command Line Interface', DoctrineCommonVersion::VERSION);
$cli->setCatchExceptions(true);
...
$cli->addCommands(array(
new DBALCommandRunSqlCommand(),
new ORMCommandValidateSchemaCommand(),
new MigrationsCommandVersionCommand()
));
$cli->run();
...
$em = $application->getBootstrap()->getResource('EntityManager');
...
$helpers = array(
'db' => new DBALHelperConnectionHelper($em->getConnection()),
'em' => new ORMHelperEntityManagerHelper($em),
'dialog' => new SymfonyComponentConsoleHelperDialogHelper(),
);
...
$cli = new SymfonyComponentConsoleApplication(
'Doctrine Command Line Interface', DoctrineCommonVersion::VERSION);
$cli->setCatchExceptions(true);
...
$cli->addCommands(array(
new DBALCommandRunSqlCommand(),
new ORMCommandValidateSchemaCommand(),
new MigrationsCommandVersionCommand()
));
$cli->run();
Console
$ ./doctrine
Doctrine Command Line Interface version 2.0.0RC3-DEV
Usage:
[options] command [arguments]
dbal
:import
:run-sql
orm
:convert-d1-schema
:convert-mapping
:generate-proxies
:generate-repositories
:run-dql
:validate-schema
orm:clear-cache
:metadata
:query
:result
$ ./doctrine
Doctrine Command Line Interface version 2.0.0RC3-DEV
Usage:
[options] command [arguments]
dbal
:import
:run-sql
orm
:convert-d1-schema
:convert-mapping
:generate-proxies
:generate-repositories
:run-dql
:validate-schema
orm:clear-cache
:metadata
:query
:result
Console: ORM
$ ./doctrine orm:ensure-production-settings
Proxy Classes are always regenerating.
$ ./doctrine orm:ensure-production-settings
SQLSTATE[28000] [1045] Access denied for user 'root'@'localhost'
$ ./doctrine orm:ensure-production-settings
Environment is correctly configured for production.
$ ./doctrine orm:ensure-production-settings
Proxy Classes are always regenerating.
$ ./doctrine orm:ensure-production-settings
SQLSTATE[28000] [1045] Access denied for user 'root'@'localhost'
$ ./doctrine orm:ensure-production-settings
Environment is correctly configured for production.
Проверка корректности настроек
для production
Console: ORM
Валидация модели
$ ./doctrine orm:validate-schema
[Mapping] FAIL - The entity-class 'EntitiesAddress' mapping is invalid:
* The field EntitiesAddress#user is on the inverse side of a
bi-directional Relationship, but the specified mappedBy association
on the target-entity EntitiesUser#address does not contain the
required 'inversedBy' attribute.
[Database] FAIL - The database schema is not in sync with the
current mapping file.
$ ./doctrine orm:validate-schema
[Mapping] FAIL - The entity-class 'EntitiesAddress' mapping is invalid:
* The field EntitiesAddress#user is on the inverse side of a
bi-directional Relationship, but the specified mappedBy association
on the target-entity EntitiesUser#address does not contain the
required 'inversedBy' attribute.
[Database] FAIL - The database schema is not in sync with the
current mapping file.
Migrations
Migrations
Что нужно:
— стандартный скрипт для подключения консоли
— в папку с скриптом добавить migrations.xml (или yaml)
<doctrine-migrations>
<name>Doctrine Migrations</name>
<migrations-namespace>
DoctrineMigrations
</migrations-namespace>
<table name="migration_versions" />
<migrations-directory>/path/to/migrations/</migrations-directory>
</doctrine-migrations>
<doctrine-migrations>
<name>Doctrine Migrations</name>
<migrations-namespace>
DoctrineMigrations
</migrations-namespace>
<table name="migration_versions" />
<migrations-directory>/path/to/migrations/</migrations-directory>
</doctrine-migrations>
Migrations
Доступные команды
$ ./doctrine
...
migrations
:diff :generate :status
:execute :migrate :version
...
$ ./doctrine
...
migrations
:diff :generate :status
:execute :migrate :version
...
Migrations
Фиксируем изменения в миграции
$ ./doctrine migrations:diff
Generated new migration class
to "path/to/migrations/Version20101124201328.php" from schema differences.
$ ./doctrine migrations:diff
Generated new migration class
to "path/to/migrations/Version20101124201328.php" from schema differences.
namespace DoctrineMigrations;
class Version20101124201328 extends AbstractMigration
{
public function up(Schema $schema) {
$this->_addSql('CREATE TABLE users (...) ENGINE = InnoDB');
}
public function down(Schema $schema) {
$this->_addSql('DROP TABLE users');
}
}
namespace DoctrineMigrations;
class Version20101124201328 extends AbstractMigration
{
public function up(Schema $schema) {
$this->_addSql('CREATE TABLE users (...) ENGINE = InnoDB');
}
public function down(Schema $schema) {
$this->_addSql('DROP TABLE users');
}
}
Migrations
Накатывание миграции
$ ./doctrine migrations:migrate --dry-run
Executing dry run of migration up to 20101124201328 from 0
++ migrating 20101124201328
-> CREATE TABLE users ( ... ) ENGINE = InnoDB
++ migrated (0.01s)
------------------------
++ finished in 0.01
++ 1 migrations executed
++ 1 sql queries
$ ./doctrine migrations:migrate --dry-run
Executing dry run of migration up to 20101124201328 from 0
++ migrating 20101124201328
-> CREATE TABLE users ( ... ) ENGINE = InnoDB
++ migrated (0.01s)
------------------------
++ finished in 0.01
++ 1 migrations executed
++ 1 sql queries
Migrations
Генерируем заготовку миграции
$ ./doctrine migrations:generate --editor-cmd=netbeans
Generated new migration class to "path/to/migrations/Version20101124201328.php"
$ ./doctrine migrations:generate --editor-cmd=netbeans
Generated new migration class to "path/to/migrations/Version20101124201328.php"
namespace DoctrineMigrations;
class Version20101124201328 extends AbstractMigration
{
public function up(Schema $schema) {
// $this->_addSql('CREATE TABLE users (...) ENGINE = InnoDB');
$table = $schema->createTable('users');
$table->addColumn('username', 'string');
}
public function down(Schema $schema) {
$schema->dropTable('users');
}
}
namespace DoctrineMigrations;
class Version20101124201328 extends AbstractMigration
{
public function up(Schema $schema) {
// $this->_addSql('CREATE TABLE users (...) ENGINE = InnoDB');
$table = $schema->createTable('users');
$table->addColumn('username', 'string');
}
public function down(Schema $schema) {
$schema->dropTable('users');
}
}
Использование
Пример работы с моделями
$em = $this->getInvokeArg('bootstrap')
->getResource('EntityManager');
$address = new EntitiesAddress();
$address->setStreet('Киевская, 1');
$user = new EntitiesUser();
$user->setName('Ваня');
$user->setAddress($address);
$em->persist($address);
$em->persist($user);
$em->flush();
$em = $this->getInvokeArg('bootstrap')
->getResource('EntityManager');
$address = new EntitiesAddress();
$address->setStreet('Киевская, 1');
$user = new EntitiesUser();
$user->setName('Ваня');
$user->setAddress($address);
$em->persist($address);
$em->persist($user);
$em->flush();
Использование
Пример работы с моделями
$user = $em->find('EntitiesUser', 1);
$user->getAddress();
// → object ProxiesEntitiesAddressProxy
$user->getName(); // Ваня
$user->setName('Петя');
$em->flush();
...
$user = $em->find('EntitiesUser', 1);
$user->getName(); // Петя
$user = $em->find('EntitiesUser', 1);
$user->getAddress();
// → object ProxiesEntitiesAddressProxy
$user->getName(); // Ваня
$user->setName('Петя');
$em->flush();
...
$user = $em->find('EntitiesUser', 1);
$user->getName(); // Петя
Doctrine Query Language
Doctrine 1
— Не было реального парсера DQL
Doctrine 2
— Abstract Syntax Tree
Behaviors
Behaviors
Нет и не будет
расширений «из коробки»
Events & Subscribers+
−
Events
namespace Entities;
/**
* @HasLifecycleCallbacks
*/
class User {
…
/** @PrePersist */
public function updateCreatedAt()
{
$this->createdAt = date('Y-m-d H:m:s');
}
}
namespace Entities;
/**
* @HasLifecycleCallbacks
*/
class User {
…
/** @PrePersist */
public function updateCreatedAt()
{
$this->createdAt = date('Y-m-d H:m:s');
}
}
Lifecycle Events
— pre/postRemove
— pre/postPersist
— pre/postUpdate
— postLoad
— loadClassMetadata
— onFlush
Event Listeners
Простейший подписчик на события
class MyEventSubscriber implements EventSubscriber
{
public function getSubscribedEvents() {
return array(
Events::preUpdate
);
}
public function preUpdate(PreUpdateEventArgs $eventArgs) {
if ($eventArgs->getEntity() instanceof User) {
if ($eventArgs->hasChangedField('name')) { /*наш код*/ }
}
}
}
$entityManager->getEventManager()
->addEventSubscriber(new MyEventSubscriber());
class MyEventSubscriber implements EventSubscriber
{
public function getSubscribedEvents() {
return array(
Events::preUpdate
);
}
public function preUpdate(PreUpdateEventArgs $eventArgs) {
if ($eventArgs->getEntity() instanceof User) {
if ($eventArgs->hasChangedField('name')) { /*наш код*/ }
}
}
}
$entityManager->getEventManager()
->addEventSubscriber(new MyEventSubscriber());
Behavioral Extensions
goo.gl/Mgnwg
(www.doctrine-project.org/blog/doctrine2-behavioral-extensions)
...
/**
* @gedmo:Timestampable(on="create")
* @Column(type="date")
*/
private $created;
/**
* @gedmo:Timestampable(on="update")
* @Column(type="datetime")
*/
private $updated;
...
...
/**
* @gedmo:Timestampable(on="create")
* @Column(type="date")
*/
private $created;
/**
* @gedmo:Timestampable(on="update")
* @Column(type="datetime")
*/
private $updated;
...
Репликация
Doctrine 1
$connections = array(
'master' => 'mysql://root:@master/dbname',
'slave_1' => 'mysql://root:@slave1/dbname',
'slave_2' => 'mysql://root:@slave2/dbname',
);
foreach ($connections as $name => $dsn) {
Doctrine_Manager::connection($dsn, $name);
}
$connections = array(
'master' => 'mysql://root:@master/dbname',
'slave_1' => 'mysql://root:@slave1/dbname',
'slave_2' => 'mysql://root:@slave2/dbname',
);
foreach ($connections as $name => $dsn) {
Doctrine_Manager::connection($dsn, $name);
}
Репликация
Doctrine 1
Doctrine 2
:(
$connections = array(
'master' => 'mysql://root:@master/dbname',
'slave_1' => 'mysql://root:@slave1/dbname',
'slave_2' => 'mysql://root:@slave2/dbname',
);
foreach ($connections as $name => $dsn) {
Doctrine_Manager::connection($dsn, $name);
}
$connections = array(
'master' => 'mysql://root:@master/dbname',
'slave_1' => 'mysql://root:@slave1/dbname',
'slave_2' => 'mysql://root:@slave2/dbname',
);
foreach ($connections as $name => $dsn) {
Doctrine_Manager::connection($dsn, $name);
}
Репликация
В Doctrine 2 все действия с моделью
происходят через EntityManager
Значит можно:
— создать несколько EM на каждое
подключение;
— расширить стандартный EM поддержкой
репликаций;
Предпоследняя
Исходный код моих экспериментов с ZF2 и
Doctrine 2 скоро появится на GitHub'e:
github.com/ftrrtf
Спасибо за внимание!
Есть вопросы?
Валерий Рабиевский
mail@ftrrtf.com
twitter.com/ftrrtf
facebook.com/ftrrtf

Weitere ähnliche Inhalte

Was ist angesagt?

Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsPierre MARTIN
 
Future of HTTP in CakePHP
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHPmarkstory
 
Drupal II: The SQL
Drupal II: The SQLDrupal II: The SQL
Drupal II: The SQLddiers
 
Php tips-and-tricks4128
Php tips-and-tricks4128Php tips-and-tricks4128
Php tips-and-tricks4128PrinceGuru MS
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretssmueller_sandsmedia
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
Drupal Field API. Practical usage
Drupal Field API. Practical usageDrupal Field API. Practical usage
Drupal Field API. Practical usagePavel Makhrinsky
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Fabien Potencier
 
PHP tips and tricks
PHP tips and tricks PHP tips and tricks
PHP tips and tricks Damien Seguy
 

Was ist angesagt? (19)

Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
 
Future of HTTP in CakePHP
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHP
 
CakeFest 2013 keynote
CakeFest 2013 keynoteCakeFest 2013 keynote
CakeFest 2013 keynote
 
Drupal II: The SQL
Drupal II: The SQLDrupal II: The SQL
Drupal II: The SQL
 
Php tips-and-tricks4128
Php tips-and-tricks4128Php tips-and-tricks4128
Php tips-and-tricks4128
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secrets
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Drupal Field API. Practical usage
Drupal Field API. Practical usageDrupal Field API. Practical usage
Drupal Field API. Practical usage
 
Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3
 
Drupal 8 migrate!
Drupal 8 migrate!Drupal 8 migrate!
Drupal 8 migrate!
 
Drupal Render API
Drupal Render APIDrupal Render API
Drupal Render API
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
jQuery secrets
jQuery secretsjQuery secrets
jQuery secrets
 
Field api.From d7 to d8
Field api.From d7 to d8Field api.From d7 to d8
Field api.From d7 to d8
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3
 
Current state-of-php
Current state-of-phpCurrent state-of-php
Current state-of-php
 
PHP tips and tricks
PHP tips and tricks PHP tips and tricks
PHP tips and tricks
 

Andere mochten auch

Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...zfconfua
 
Применение Scrum и Kanban для разработки web-приложений
Применение Scrum и Kanban для разработки web-приложенийПрименение Scrum и Kanban для разработки web-приложений
Применение Scrum и Kanban для разработки web-приложенийKirill Klimov
 
Преимущества использования полнотекстового поиска в интернет-магазинах
Преимущества использования полнотекстового поиска в интернет-магазинахПреимущества использования полнотекстового поиска в интернет-магазинах
Преимущества использования полнотекстового поиска в интернет-магазинахMagecom Ukraine
 
Все дороги ведут в Checkout
Все дороги ведут в CheckoutВсе дороги ведут в Checkout
Все дороги ведут в CheckoutMagecom Ukraine
 
Эволюция ZF: архитектура, шаблоны, рефакторинг
Эволюция ZF: архитектура, шаблоны, рефакторингЭволюция ZF: архитектура, шаблоны, рефакторинг
Эволюция ZF: архитектура, шаблоны, рефакторингzfconfua
 
Встречайте Zend Framework 2.0
Встречайте Zend Framework 2.0Встречайте Zend Framework 2.0
Встречайте Zend Framework 2.0zfconfua
 
1000 миллисекунд из жизни Magento
1000 миллисекунд из жизни Magento1000 миллисекунд из жизни Magento
1000 миллисекунд из жизни MagentoMagecom Ukraine
 
Мобильные клиенты интернет-магазинов
Мобильные клиенты интернет-магазиновМобильные клиенты интернет-магазинов
Мобильные клиенты интернет-магазиновMagecom Ukraine
 
Реализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoРеализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoMagecom Ukraine
 
Применение компонент-ориентированной архитектуры для написания Magento Extens...
Применение компонент-ориентированной архитектуры для написания Magento Extens...Применение компонент-ориентированной архитектуры для написания Magento Extens...
Применение компонент-ориентированной архитектуры для написания Magento Extens...Magecom Ukraine
 
Юнит тестирование в Zend Framework 2.0
Юнит тестирование в Zend Framework 2.0Юнит тестирование в Zend Framework 2.0
Юнит тестирование в Zend Framework 2.0zfconfua
 
NoSQL и Zend Framework (Никита Грошин)
NoSQL и Zend Framework (Никита Грошин)NoSQL и Zend Framework (Никита Грошин)
NoSQL и Zend Framework (Никита Грошин)zfconfua
 
Ключ успеха – процесс или продукт?
Ключ успеха – процесс или продукт?Ключ успеха – процесс или продукт?
Ключ успеха – процесс или продукт?Magecom Ukraine
 
Управление продуктом в стиле Magento Unified Process
Управление продуктом в стиле Magento Unified ProcessУправление продуктом в стиле Magento Unified Process
Управление продуктом в стиле Magento Unified ProcessMagecom Ukraine
 
Применение TDD при разработке веб-сервисов
Применение TDD при разработке веб-сервисовПрименение TDD при разработке веб-сервисов
Применение TDD при разработке веб-сервисовMagecom Ukraine
 
Индексирование в Magento
Индексирование в MagentoИндексирование в Magento
Индексирование в MagentoMagecom Ukraine
 
NoSQL и Zend Framework (Ростислав Михайлив)
NoSQL и Zend Framework (Ростислав Михайлив)NoSQL и Zend Framework (Ростислав Михайлив)
NoSQL и Zend Framework (Ростислав Михайлив)zfconfua
 

Andere mochten auch (17)

Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
 
Применение Scrum и Kanban для разработки web-приложений
Применение Scrum и Kanban для разработки web-приложенийПрименение Scrum и Kanban для разработки web-приложений
Применение Scrum и Kanban для разработки web-приложений
 
Преимущества использования полнотекстового поиска в интернет-магазинах
Преимущества использования полнотекстового поиска в интернет-магазинахПреимущества использования полнотекстового поиска в интернет-магазинах
Преимущества использования полнотекстового поиска в интернет-магазинах
 
Все дороги ведут в Checkout
Все дороги ведут в CheckoutВсе дороги ведут в Checkout
Все дороги ведут в Checkout
 
Эволюция ZF: архитектура, шаблоны, рефакторинг
Эволюция ZF: архитектура, шаблоны, рефакторингЭволюция ZF: архитектура, шаблоны, рефакторинг
Эволюция ZF: архитектура, шаблоны, рефакторинг
 
Встречайте Zend Framework 2.0
Встречайте Zend Framework 2.0Встречайте Zend Framework 2.0
Встречайте Zend Framework 2.0
 
1000 миллисекунд из жизни Magento
1000 миллисекунд из жизни Magento1000 миллисекунд из жизни Magento
1000 миллисекунд из жизни Magento
 
Мобильные клиенты интернет-магазинов
Мобильные клиенты интернет-магазиновМобильные клиенты интернет-магазинов
Мобильные клиенты интернет-магазинов
 
Реализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoРеализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в Magento
 
Применение компонент-ориентированной архитектуры для написания Magento Extens...
Применение компонент-ориентированной архитектуры для написания Magento Extens...Применение компонент-ориентированной архитектуры для написания Magento Extens...
Применение компонент-ориентированной архитектуры для написания Magento Extens...
 
Юнит тестирование в Zend Framework 2.0
Юнит тестирование в Zend Framework 2.0Юнит тестирование в Zend Framework 2.0
Юнит тестирование в Zend Framework 2.0
 
NoSQL и Zend Framework (Никита Грошин)
NoSQL и Zend Framework (Никита Грошин)NoSQL и Zend Framework (Никита Грошин)
NoSQL и Zend Framework (Никита Грошин)
 
Ключ успеха – процесс или продукт?
Ключ успеха – процесс или продукт?Ключ успеха – процесс или продукт?
Ключ успеха – процесс или продукт?
 
Управление продуктом в стиле Magento Unified Process
Управление продуктом в стиле Magento Unified ProcessУправление продуктом в стиле Magento Unified Process
Управление продуктом в стиле Magento Unified Process
 
Применение TDD при разработке веб-сервисов
Применение TDD при разработке веб-сервисовПрименение TDD при разработке веб-сервисов
Применение TDD при разработке веб-сервисов
 
Индексирование в Magento
Индексирование в MagentoИндексирование в Magento
Индексирование в Magento
 
NoSQL и Zend Framework (Ростислав Михайлив)
NoSQL и Zend Framework (Ростислав Михайлив)NoSQL и Zend Framework (Ростислав Михайлив)
NoSQL и Zend Framework (Ростислав Михайлив)
 

Ähnlich wie Doctrine 2

Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperJonathan Wage
 
Drupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary EditionDrupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary Editionddiers
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
15. CodeIgniter editarea inregistrarilor
15. CodeIgniter editarea inregistrarilor15. CodeIgniter editarea inregistrarilor
15. CodeIgniter editarea inregistrarilorRazvan Raducanu, PhD
 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?Alexandru Badiu
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Symfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 IntegrationSymfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 IntegrationJonathan Wage
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7chuvainc
 
Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!Herman Peeren
 
Zend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching loggingZend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching loggingTricode (part of Dept)
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency InjectionRifat Nabi
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)Night Sailer
 
CodeIgniter Class Reference
CodeIgniter Class ReferenceCodeIgniter Class Reference
CodeIgniter Class ReferenceJamshid Hashimi
 

Ähnlich wie Doctrine 2 (20)

Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document Mapper
 
Drupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary EditionDrupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary Edition
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
15. CodeIgniter editarea inregistrarilor
15. CodeIgniter editarea inregistrarilor15. CodeIgniter editarea inregistrarilor
15. CodeIgniter editarea inregistrarilor
 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?
 
Doctrine and NoSQL
Doctrine and NoSQLDoctrine and NoSQL
Doctrine and NoSQL
 
Spl Not A Bridge Too Far phpNW09
Spl Not A Bridge Too Far phpNW09Spl Not A Bridge Too Far phpNW09
Spl Not A Bridge Too Far phpNW09
 
Doctrine for NoSQL
Doctrine for NoSQLDoctrine for NoSQL
Doctrine for NoSQL
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Symfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 IntegrationSymfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 Integration
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7
 
Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!Jooctrine - Doctrine ORM in Joomla!
Jooctrine - Doctrine ORM in Joomla!
 
Zend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching loggingZend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching logging
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)
 
Fatc
FatcFatc
Fatc
 
Laravel doctrine
Laravel doctrineLaravel doctrine
Laravel doctrine
 
CodeIgniter Class Reference
CodeIgniter Class ReferenceCodeIgniter Class Reference
CodeIgniter Class Reference
 

Doctrine 2

  • 2. Who am I? Валерий Рабиевский Team lead веб-студии stfalcon.com Активный разработчик Open Source движка ZFEngine (ZF + Doctrine) Более 4 лет опыта работы с PHP
  • 4. Библиотеки — Common — DBAL (включает Common) — ORM (включает DBAL+Common) — Migrations (часть DBAL) — Object Document Mapper: MongoDB CouchDB github.com/doctrine
  • 5. Entities — Легкая модель (самый простой PHP класс) — Не нужно наследование от базового класса — Есть возможность наследовать модель от своих базовых классов — Конструктор модели можно использовать для своих нужд — Данные хранятся непосредственно в свойствах объекта
  • 6. Пример модели namespace Entities; class User { private $id; private $name; public function getId() { return $this->id; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } } namespace Entities; class User { private $id; private $name; public function getId() { return $this->id; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } }
  • 7. EntityManager EntityManager является центральной точкой доступа к функциям ORM — Управление обновлением сущностей — Доступ к репозиториям сущностей — Используется паттерн UnitOfWork
  • 8. ZF2 + D2 protected function _initAutoload() { $loader = new ZendLoaderStandardAutoloader(); $loader->registerNamespace('Doctrine', '/path/to/Doctrine'); $loader->registerNamespace('Symfony', '/path/to/Symfony'); $loader->register(); } protected function _initAutoload() { $loader = new ZendLoaderStandardAutoloader(); $loader->registerNamespace('Doctrine', '/path/to/Doctrine'); $loader->registerNamespace('Symfony', '/path/to/Symfony'); $loader->register(); } Добавляем автозагрузку в Bootstrap
  • 9. Настройка Doctrine 2 ./application/configs/application.xml <!-- production --> <doctrine> <connection><!-- user, password, database, etc --></connection> <paths> <entities>path/to/entities</entities> <proxies>path/to/proxies</proxies> </paths> <proxiesNamespace value="ApplicationModelProxies" /> <autogenerateProxyClasses value="0" /> <cacheAdapter value="DoctrineCommonCacheApcCache" /> </doctrine> <!-- development --> ... <autogenerateProxyClasses value="1" /> <cacheAdapter value="DoctrineCommonCacheArrayCache" /> … <!-- production --> <doctrine> <connection><!-- user, password, database, etc --></connection> <paths> <entities>path/to/entities</entities> <proxies>path/to/proxies</proxies> </paths> <proxiesNamespace value="ApplicationModelProxies" /> <autogenerateProxyClasses value="0" /> <cacheAdapter value="DoctrineCommonCacheApcCache" /> </doctrine> <!-- development --> ... <autogenerateProxyClasses value="1" /> <cacheAdapter value="DoctrineCommonCacheArrayCache" /> …
  • 10. Подключение EntityManager protected function _initEntityManager() { if (is_null($this->_em)) { $options = $this->getOption('doctrine'); $cache = new $options['cacheAdapter']; $config = new Configuration(); $driverImpl = $config ->newDefaultAnnotationDriver($options['paths']['entities']); $config->setMetadataCacheImpl($cache); $config->setMetadataDriverImpl($driverImpl); $config->setQueryCacheImpl($cache); $config->setProxyNamespace($options['proxiesNamespace']); $config->setProxyDir($options['paths']['proxies']); $config->setAutoGenerateProxyClasses( $options['autogenerateProxyClasses'] ); $this->_em = EntityManager::create($options['connection'], $config); } return $this->_em; } protected function _initEntityManager() { if (is_null($this->_em)) { $options = $this->getOption('doctrine'); $cache = new $options['cacheAdapter']; $config = new Configuration(); $driverImpl = $config ->newDefaultAnnotationDriver($options['paths']['entities']); $config->setMetadataCacheImpl($cache); $config->setMetadataDriverImpl($driverImpl); $config->setQueryCacheImpl($cache); $config->setProxyNamespace($options['proxiesNamespace']); $config->setProxyDir($options['paths']['proxies']); $config->setAutoGenerateProxyClasses( $options['autogenerateProxyClasses'] ); $this->_em = EntityManager::create($options['connection'], $config); } return $this->_em; }
  • 12. Basic Mapping — Docblock Annotations — XML — YAML — PHP
  • 13. Association Mapping — One-To-One & Many-To-Many: — Unidirectional — Bidirectional — Self-referencing — Many-To-One, Unidirectional — One-To-Many: — Unidirectional with Join Table — Bidirectional — Self-referencing
  • 14. Inheritance Mapping — Mapped Superclasses — Single Table Inheritance — Class Table Inheritance
  • 15. Mapping ... /** * @ManyToOne(targetEntity="Address", inversedBy="users") * @JoinColumn(name="address_id", referencedColumnName="id") */ private $address; ... ... /** * @ManyToOne(targetEntity="Address", inversedBy="users") * @JoinColumn(name="address_id", referencedColumnName="id") */ private $address; ... ... /** @OneToMany(targetEntity="User", mappedBy="address") */ private $user; ... ... /** @OneToMany(targetEntity="User", mappedBy="address") */ private $user; ... Entities/User Entitites/Address
  • 17. Console ... $em = $application->getBootstrap()->getResource('EntityManager'); ... $helpers = array( 'db' => new DBALHelperConnectionHelper($em->getConnection()), 'em' => new ORMHelperEntityManagerHelper($em), 'dialog' => new SymfonyComponentConsoleHelperDialogHelper(), ); ... $cli = new SymfonyComponentConsoleApplication( 'Doctrine Command Line Interface', DoctrineCommonVersion::VERSION); $cli->setCatchExceptions(true); ... $cli->addCommands(array( new DBALCommandRunSqlCommand(), new ORMCommandValidateSchemaCommand(), new MigrationsCommandVersionCommand() )); $cli->run(); ... $em = $application->getBootstrap()->getResource('EntityManager'); ... $helpers = array( 'db' => new DBALHelperConnectionHelper($em->getConnection()), 'em' => new ORMHelperEntityManagerHelper($em), 'dialog' => new SymfonyComponentConsoleHelperDialogHelper(), ); ... $cli = new SymfonyComponentConsoleApplication( 'Doctrine Command Line Interface', DoctrineCommonVersion::VERSION); $cli->setCatchExceptions(true); ... $cli->addCommands(array( new DBALCommandRunSqlCommand(), new ORMCommandValidateSchemaCommand(), new MigrationsCommandVersionCommand() )); $cli->run();
  • 18. Console $ ./doctrine Doctrine Command Line Interface version 2.0.0RC3-DEV Usage: [options] command [arguments] dbal :import :run-sql orm :convert-d1-schema :convert-mapping :generate-proxies :generate-repositories :run-dql :validate-schema orm:clear-cache :metadata :query :result $ ./doctrine Doctrine Command Line Interface version 2.0.0RC3-DEV Usage: [options] command [arguments] dbal :import :run-sql orm :convert-d1-schema :convert-mapping :generate-proxies :generate-repositories :run-dql :validate-schema orm:clear-cache :metadata :query :result
  • 19. Console: ORM $ ./doctrine orm:ensure-production-settings Proxy Classes are always regenerating. $ ./doctrine orm:ensure-production-settings SQLSTATE[28000] [1045] Access denied for user 'root'@'localhost' $ ./doctrine orm:ensure-production-settings Environment is correctly configured for production. $ ./doctrine orm:ensure-production-settings Proxy Classes are always regenerating. $ ./doctrine orm:ensure-production-settings SQLSTATE[28000] [1045] Access denied for user 'root'@'localhost' $ ./doctrine orm:ensure-production-settings Environment is correctly configured for production. Проверка корректности настроек для production
  • 20. Console: ORM Валидация модели $ ./doctrine orm:validate-schema [Mapping] FAIL - The entity-class 'EntitiesAddress' mapping is invalid: * The field EntitiesAddress#user is on the inverse side of a bi-directional Relationship, but the specified mappedBy association on the target-entity EntitiesUser#address does not contain the required 'inversedBy' attribute. [Database] FAIL - The database schema is not in sync with the current mapping file. $ ./doctrine orm:validate-schema [Mapping] FAIL - The entity-class 'EntitiesAddress' mapping is invalid: * The field EntitiesAddress#user is on the inverse side of a bi-directional Relationship, but the specified mappedBy association on the target-entity EntitiesUser#address does not contain the required 'inversedBy' attribute. [Database] FAIL - The database schema is not in sync with the current mapping file.
  • 22. Migrations Что нужно: — стандартный скрипт для подключения консоли — в папку с скриптом добавить migrations.xml (или yaml) <doctrine-migrations> <name>Doctrine Migrations</name> <migrations-namespace> DoctrineMigrations </migrations-namespace> <table name="migration_versions" /> <migrations-directory>/path/to/migrations/</migrations-directory> </doctrine-migrations> <doctrine-migrations> <name>Doctrine Migrations</name> <migrations-namespace> DoctrineMigrations </migrations-namespace> <table name="migration_versions" /> <migrations-directory>/path/to/migrations/</migrations-directory> </doctrine-migrations>
  • 23. Migrations Доступные команды $ ./doctrine ... migrations :diff :generate :status :execute :migrate :version ... $ ./doctrine ... migrations :diff :generate :status :execute :migrate :version ...
  • 24. Migrations Фиксируем изменения в миграции $ ./doctrine migrations:diff Generated new migration class to "path/to/migrations/Version20101124201328.php" from schema differences. $ ./doctrine migrations:diff Generated new migration class to "path/to/migrations/Version20101124201328.php" from schema differences. namespace DoctrineMigrations; class Version20101124201328 extends AbstractMigration { public function up(Schema $schema) { $this->_addSql('CREATE TABLE users (...) ENGINE = InnoDB'); } public function down(Schema $schema) { $this->_addSql('DROP TABLE users'); } } namespace DoctrineMigrations; class Version20101124201328 extends AbstractMigration { public function up(Schema $schema) { $this->_addSql('CREATE TABLE users (...) ENGINE = InnoDB'); } public function down(Schema $schema) { $this->_addSql('DROP TABLE users'); } }
  • 25. Migrations Накатывание миграции $ ./doctrine migrations:migrate --dry-run Executing dry run of migration up to 20101124201328 from 0 ++ migrating 20101124201328 -> CREATE TABLE users ( ... ) ENGINE = InnoDB ++ migrated (0.01s) ------------------------ ++ finished in 0.01 ++ 1 migrations executed ++ 1 sql queries $ ./doctrine migrations:migrate --dry-run Executing dry run of migration up to 20101124201328 from 0 ++ migrating 20101124201328 -> CREATE TABLE users ( ... ) ENGINE = InnoDB ++ migrated (0.01s) ------------------------ ++ finished in 0.01 ++ 1 migrations executed ++ 1 sql queries
  • 26. Migrations Генерируем заготовку миграции $ ./doctrine migrations:generate --editor-cmd=netbeans Generated new migration class to "path/to/migrations/Version20101124201328.php" $ ./doctrine migrations:generate --editor-cmd=netbeans Generated new migration class to "path/to/migrations/Version20101124201328.php" namespace DoctrineMigrations; class Version20101124201328 extends AbstractMigration { public function up(Schema $schema) { // $this->_addSql('CREATE TABLE users (...) ENGINE = InnoDB'); $table = $schema->createTable('users'); $table->addColumn('username', 'string'); } public function down(Schema $schema) { $schema->dropTable('users'); } } namespace DoctrineMigrations; class Version20101124201328 extends AbstractMigration { public function up(Schema $schema) { // $this->_addSql('CREATE TABLE users (...) ENGINE = InnoDB'); $table = $schema->createTable('users'); $table->addColumn('username', 'string'); } public function down(Schema $schema) { $schema->dropTable('users'); } }
  • 27. Использование Пример работы с моделями $em = $this->getInvokeArg('bootstrap') ->getResource('EntityManager'); $address = new EntitiesAddress(); $address->setStreet('Киевская, 1'); $user = new EntitiesUser(); $user->setName('Ваня'); $user->setAddress($address); $em->persist($address); $em->persist($user); $em->flush(); $em = $this->getInvokeArg('bootstrap') ->getResource('EntityManager'); $address = new EntitiesAddress(); $address->setStreet('Киевская, 1'); $user = new EntitiesUser(); $user->setName('Ваня'); $user->setAddress($address); $em->persist($address); $em->persist($user); $em->flush();
  • 28. Использование Пример работы с моделями $user = $em->find('EntitiesUser', 1); $user->getAddress(); // → object ProxiesEntitiesAddressProxy $user->getName(); // Ваня $user->setName('Петя'); $em->flush(); ... $user = $em->find('EntitiesUser', 1); $user->getName(); // Петя $user = $em->find('EntitiesUser', 1); $user->getAddress(); // → object ProxiesEntitiesAddressProxy $user->getName(); // Ваня $user->setName('Петя'); $em->flush(); ... $user = $em->find('EntitiesUser', 1); $user->getName(); // Петя
  • 29. Doctrine Query Language Doctrine 1 — Не было реального парсера DQL Doctrine 2 — Abstract Syntax Tree
  • 31. Behaviors Нет и не будет расширений «из коробки» Events & Subscribers+ −
  • 32. Events namespace Entities; /** * @HasLifecycleCallbacks */ class User { … /** @PrePersist */ public function updateCreatedAt() { $this->createdAt = date('Y-m-d H:m:s'); } } namespace Entities; /** * @HasLifecycleCallbacks */ class User { … /** @PrePersist */ public function updateCreatedAt() { $this->createdAt = date('Y-m-d H:m:s'); } }
  • 33. Lifecycle Events — pre/postRemove — pre/postPersist — pre/postUpdate — postLoad — loadClassMetadata — onFlush
  • 34. Event Listeners Простейший подписчик на события class MyEventSubscriber implements EventSubscriber { public function getSubscribedEvents() { return array( Events::preUpdate ); } public function preUpdate(PreUpdateEventArgs $eventArgs) { if ($eventArgs->getEntity() instanceof User) { if ($eventArgs->hasChangedField('name')) { /*наш код*/ } } } } $entityManager->getEventManager() ->addEventSubscriber(new MyEventSubscriber()); class MyEventSubscriber implements EventSubscriber { public function getSubscribedEvents() { return array( Events::preUpdate ); } public function preUpdate(PreUpdateEventArgs $eventArgs) { if ($eventArgs->getEntity() instanceof User) { if ($eventArgs->hasChangedField('name')) { /*наш код*/ } } } } $entityManager->getEventManager() ->addEventSubscriber(new MyEventSubscriber());
  • 35. Behavioral Extensions goo.gl/Mgnwg (www.doctrine-project.org/blog/doctrine2-behavioral-extensions) ... /** * @gedmo:Timestampable(on="create") * @Column(type="date") */ private $created; /** * @gedmo:Timestampable(on="update") * @Column(type="datetime") */ private $updated; ... ... /** * @gedmo:Timestampable(on="create") * @Column(type="date") */ private $created; /** * @gedmo:Timestampable(on="update") * @Column(type="datetime") */ private $updated; ...
  • 36. Репликация Doctrine 1 $connections = array( 'master' => 'mysql://root:@master/dbname', 'slave_1' => 'mysql://root:@slave1/dbname', 'slave_2' => 'mysql://root:@slave2/dbname', ); foreach ($connections as $name => $dsn) { Doctrine_Manager::connection($dsn, $name); } $connections = array( 'master' => 'mysql://root:@master/dbname', 'slave_1' => 'mysql://root:@slave1/dbname', 'slave_2' => 'mysql://root:@slave2/dbname', ); foreach ($connections as $name => $dsn) { Doctrine_Manager::connection($dsn, $name); }
  • 37. Репликация Doctrine 1 Doctrine 2 :( $connections = array( 'master' => 'mysql://root:@master/dbname', 'slave_1' => 'mysql://root:@slave1/dbname', 'slave_2' => 'mysql://root:@slave2/dbname', ); foreach ($connections as $name => $dsn) { Doctrine_Manager::connection($dsn, $name); } $connections = array( 'master' => 'mysql://root:@master/dbname', 'slave_1' => 'mysql://root:@slave1/dbname', 'slave_2' => 'mysql://root:@slave2/dbname', ); foreach ($connections as $name => $dsn) { Doctrine_Manager::connection($dsn, $name); }
  • 38. Репликация В Doctrine 2 все действия с моделью происходят через EntityManager Значит можно: — создать несколько EM на каждое подключение; — расширить стандартный EM поддержкой репликаций;
  • 39. Предпоследняя Исходный код моих экспериментов с ZF2 и Doctrine 2 скоро появится на GitHub'e: github.com/ftrrtf
  • 40. Спасибо за внимание! Есть вопросы? Валерий Рабиевский mail@ftrrtf.com twitter.com/ftrrtf facebook.com/ftrrtf