2. Who am I?
Валерий Рабиевский
Team lead веб-студии stfalcon.com
Активный разработчик Open Source
движка ZFEngine (ZF + Doctrine)
Более 4 лет опыта работы с PHP
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;
}
}
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.
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();
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());
38. Репликация
В Doctrine 2 все действия с моделью
происходят через EntityManager
Значит можно:
— создать несколько EM на каждое
подключение;
— расширить стандартный EM поддержкой
репликаций;