З версії 5.4 php стає більш стабільним, я вирішив поекспериментувати з “traits” та їх використанням в реальних умовах.
Давайте поглянемо як їх можна використати з Doctrine2 сутностями.
Трейти
Трейти в php є лише гілками властивостей та методів котрі ви можете скопіювати в клас.
Все це робиться на рівні інтерпретатора і повністю прозоре для Doctrine.
Вони спроектовані для горизонтального багаторазового використання, що є ідеальним рішенням для спільного використання спільної поведінки на різних сутностях.
Звичайні біхейвери
На приклад на спільних запитах для автоматичного проставляння дат для сутностей, використовуючи created_at та updated_at властивості дати.
Це те, що може бути використане на будь-якому типу сутності.
Це правило гарного тону використовувати "горизонтальне повторне використання".
Це також той випадок, коли ви питаєте себе: “Як я можу не повторювати код?”
Введення в біхейвор Timestampable
Timestampable це простий трейт котрий ви застосовуєте до сутності doctrine:
use DoctrineORMMapping as ORM; use KnpDoctrineBehaviorsORM as ORMBehaviors; /** * @ORMEntity */ class Category { use ORMBehaviorsTimestampableTimestampable; /** * @ORMId * @ORMColumn(type="integer") * @ORMGeneratedValue(strategy="NONE") */ protected $id; }
Зверніть увагу на оголошення "use" в тілі класу.
Це додасть дві властивості doctrine тип DateTime і два публічних методи до сутності, ви отримаєте поля createdAt та updatedAt:
$category = new Category; $entityManager->persist($category); $category->getCreatedAt(); $category->getUpdatedAt();
Як тільки ви оновите сутності, getUpdatedAt поверне нову дату - дату та час оновлення сутності.
Встановлення
Timestampable та інші трейти доступні в пакеті в репозиторію KNP Labs/DoctrineBehaviors на github.
Ви можете легко встановити їх використовуючи composer.
Просто додайте це в файл composer.json в кореневій директорії вашого проекту.
{ "require": { "knplabs/doctrine-behaviors": "dev-master", } }
Потім виконайте composer:
curl -s http://getcomposer.org/installer | php php composer.phar install
Слухачі (Listeners)
Все це можливо завдяки слухачам Doctrine, котрі слухають події збереження або оновлення для кожної сутності, що використовує Timestampable.
Але, щоб це запрацювало, вам необхідно зареєструвати їх.
Використовуючи Symfony2, це дійсно легко! Просто імпортуйте файл визначення сервісів:
# app/config/config.yml imports: - { resource: ../../vendor/knplabs/doctrine-behaviors/config/orm-services.yml }
Translatable біхейвор
Насправді проста вимога це зробити сутність, що може бути перекладена. Ми постаралися зробити це якомога простіше завдяки простому і логічній згоді іменування.
Для того, щоб мати робочу translatable сутність, пройдіть ці 2 кроки:
− використовуйте трейт Translatable:
use DoctrineORMMapping as ORM; use KnpDoctrineBehaviorsORM as ORMBehaviors; /** * @ORMEntity */ class Category { use ORMBehaviorsTranslatableTranslatable; /** * @ORMId * @ORMColumn(type="integer") * @ORMGeneratedValue(strategy="NONE") */ protected $id; }
− Визначте сутність CategoryTranslation за допомогою трейту Translation:
<?php use DoctrineORMMapping as ORM; use KnpDoctrineBehaviorsORM as ORMBehaviors; /** * @ORMEntity */ class CategoryTranslation { use ORMBehaviorsTranslatableTranslation; /** * @ORMColumn(type="string") */ protected $name; }
Ось і все!
TranslatableListener виявить зв'язок між цими двома сутностями без необхідності вам втручатися.
Все, що вам потрібно зробити зараз, це попрацювати з ним через зв'язок OneToMany, а це значить, що ви, на приклад, можете легко зробити left join ваших перекладів.
<?php $category = new Category; $category->translate('fr')->setName('Chaussures'); $category->translate('en')->setName('Shoes'); $em->persist($category); $category->translate('en')->getName();
Tree
Tree використовує матеріалізовану реалізацію шляху для представлення у вигляді дерев.
Усі вузли містять їх повний шлях від їх кореня:
| id | name | path | +-----+------------+------------+ | 1 | fr | /1 | | 2 | villes | /1/2 | | 4 | subNantes | /1/2/3/4 | | 7 | en | /7 | | 8 | villes | /7/8 | | 9 | Nantes | /7/8/9 | | 10 | subNantes | /7/8/9/10 | | 11 | Lorient | /7/8/11 | | 12 | Rouen | /7/8/12 | | 6 | Rouen | /1/2/6 | | 3 | Nantes | /1/2/3 | | 5 | Lorient | /1/2/5 |
Щоб відтворити ваші сутності в виді дерева, все що вам потрібно зробити це використати трейт TreeNode:
use DoctrineORMMapping as ORM; use KnpDoctrineBehaviorsORM as ORMBehaviors; /** * @ORMEntity(repositoryClass="CategoryRepository") */ class Category { use ORMBehaviorsTreeNode; /** * @ORMId * @ORMColumn(type="integer") * @ORMGeneratedValue(strategy="NONE") */ protected $id; }
Ви також місите використовувати трейт TreeTree на відповідній EntityRepository:
use DoctrineORMEntityRepository; use KnpDoctrineBehaviorsORM as ORMBehaviors; class CategoryRepository extends EntityRepository { use ORMBehaviorsTreeTree; }
Ця сутність тепер має потужний api для керування своїми нащадками, батьками, переносити їх, …
$root = $em->getRepository('Category')->getTree(); $root->getParentNode(); $root->getChildren(); $root[0][1]; // array access of children $root->isLeafNode(); $root->isRootNode();