ORM Doctrine

Первое, что делает мудрый человек, это спрашивает себя - зачем мне это нужно, вот и я решил поступить таким же образом, при знакомстве с ORM Doctrine (по факту реализующую спецификацию JPA).

Для начала я процитирую Википедию, потому что это базовые знания, без них никак.

Doctrine — объектно-реляционный проектор (ORM) для PHP, который базируется на слое абстракции доступа к БД (DBAL). Одной из ключевых возможностей Doctrine является запись запросов к БД на собственном объектно-ориентированном диалекте SQL, называемый DQL (Doctrine Query Language) и базирующийся на идеях HQL (Hibernate Query Language).

Коротко, паттерны из которых состоит:

  • EntityManager
  • - Data Mapper
  • - Identity Map
  • - Unit of Work

Преимущества

Существует несколько мнений, почему ORM значительно упрощает поддержку БД, например:

  1. удобно дебажить, когда переименовали или удалили поле "name" из таблицы — придется каким-то хитрым образом найти во всем проекте все места в коде, в которых запросы могут использовать это поле (в случае с ORM мы сможем поставить брейкопин на геттер и узнать, какой скрипт попытался выполнить неправильный запрос
  2. удобно переименовать поля — при использовании ORM можем воспользоваться всеми возможностями таких штук как Resharper, и автоматом переименовывать сразу во всем проекте (IDE позволяет находить все места использования поля)
  3. из коробки есть MasterSlaveConnection (конечно можно вручную можно разрулить проверяя substr(sql,0,6) == select, но зачем)
  4. Migrations Tools - инструмент управления версиями схемы бд
  5. можно переходить на другие БД — например можно перенести часть таблиц на NoSQL, и сделать это так, что ни один программист не заметит этого. По сути позволяет абстрагироваться от способа хранения объектов вообще, с лёгкостью переходя от SQL к NoSQL, memcache, файлам или REST/RPC API на удалённом сервере, оперируя на уровне модели (но такие манипуляии резко сокращают функционал работы с данными, например уже не получится сделать джоин таблиц из разных типов БД)
  6. можно настроить логирование и запросы в логах будут в виде SELECT * FROM product WHERE id IN (:ids), напомню, что PDO генерирует разные варианты одного и того же запроса, в зависимости от переданного кол-ва идентификаторов IN (?,?,?)
  7. можно кэшировать метаданные бд (схему), запросы и результаты — не самая высокая оптимальность запросов через ORM, частично компенсируется возможностью кэширования объектов с помощью своего или готово кэш-драйвера, например APCu (если у вас класстер из приложений - будьте осторожны, ведь на каждом сервере APCu свой)
  8. ORM это инструмент облегчения разделения труда разработчиков: кто хорошо шарит в SQL вообще и особенностях конкретного движка в частности — работает по «ту сторону» ORM, оптимизирует его как хочет, может нормализовывать и денормализовывать, а тот, кому дали определенную задачу создания интерфейса в программе или сайте, может вообще ничего не знать об SQL, ему лишь нужно знать, что он всегда может получить объект или коллекцию объектов, обратившись к методам вроде findById() или findAll() и сохранить результат работы методом save() или flush();
  9. EntityManager который использует паттер Data mapper (жаль, что в php при каждом запросе EntityManager пересоздается), но все равно, это лучше Active Record который нарушает принцип единственной ответственности (SRP)
  10. есть встроенная реализация транзакций — когда Вы создаете/изменяете ряд объектов и в нужный момент сохраняете их
  11. автоматическая валидация значений с помощью анотаций к полям в описании сущностей, например @Assert\Range
  12. возможность мультиязычного указания ошибки валидации, например @Assert\Type(type="integer", message="divisionKindId.integer")
  13. Doctrine может возвращать объекты частично, целиком и даже умеет возвращать данные согласно указанному PDO Fetch Modes
  14. Doctrine умеет делать принудительную или ленивую загрузку связанных сущностей (объектов):

    $query = $em ->createQuery("SELECT s FROM ASBillingBundle:Subscription s")->setFetchMode(
            "ASBillingBundle:Subscription",
            "user",
            DoctrineORMMappingClassMetadata::FETCH_EAGER
    );

  15. а еще удобно писать сложные запросы с помощю построителя запросов ORM, например выборка товаров:

$select = $db->select()->from('goods');
$select->join('pages', 'pages.idPage = goods.idPage');

if ($content) {
    $select->join('content', 'content.idContentPack = pages.idContentPack');
    $select->where('content.idLang = ?', Kernel_Locale::getCurrent()->getId());
    if ($search) {
        $select->where('content.contentName = ?', $search);
    }
}
if (!$expired) {
    $select->where('goods.goodExpirationDate > ?', time());

И давайте на чистоту - если Вы завтра решите добавить еще кое-какие поля в пару таблиц, немного поменять логику - вы легко измените ваши 38 написанных ручками запросов. Проблемы начинаются тогда, когда у вас в проекте полсотни-сотня таблиц со своими связями. Что вы сделаете в случае 462 "ручных" запросов? Правильно, вы запасетесь свободной неделькой, прошерстите все запросы, добавите/измените нужные, также поменяете обработчики данных для валидации, покопаетесь в формах, полезете в базу и добавите там все необходимое. Как следствие вы допустите массу ошибок и опечаток и еще неделю после будете отлавливать баги, из которых минимум пять все равно останутся незамеченными и всплывут уже в рабочем проекте в самое неподходящее время.

Что вы сделаете в случае с ОРМ — Вы залезете в описание схемы, добавите нужные модели/свойства, перегенерируете все, получите на выходе измененные формы, модели и структуру БД, допишете немного кода, поправите отображение форм и пойдете пить пиво с друзьями.

Кэш

Закешируем какой-нибудь запрос

$query = $em->createQuery($dql);
$query->useResultCache(true);

Очистим кэш без рестарта приложения, в котором хранится кэш:

php app/console doctrine:cache:clear-metadata
php app/console doctrine:cache:clear-query
php app/console doctrine:cache:clear-result

Недостатки

Недостатков фактически нет, но есть рекомендации, когда не стоит использовать ORM:

  1. когда Вам нужно вытащить из базы огромное количество данных, ведь создание объектов влечет расходы RAM и процессора
  2. когда вы работаете с огромным количеством запросов только на чтение, опять же, сэкономите на RAM и процессоре
  3. когда у Вас в проекте много аналитики, и нужно писать сложные SQL-запросы (делаете запросы через PDO и радуетесь приросту скорости)
  4. когда вам уже сейчас нужна полная поддержка всех фич базы, которая используется
  5. если не хотите слишком много времени тратить на изучение реализации нативных фич Вашей б.д. в ORM

Решаемые проблемы

  1. все поля (которые foreign keys) при выборке данных, оказываются Proxy-объектами (можно побороть используя Hydration Modes или $object->getValue()->getFieldName())
  2. при сохранении объектов, все поля с foreign key, должный быть объектами, т.е. нельзя явно указать user_id, значением должен быть именно объект User с заполненным значением свойства user_id ( говорят можно побороть так: EntityManager->getreference($class, $id) )

Источники: 1 - 2 - 3 - 4 - 5 - 6

Оцени публикацию:
  • 10,37
Оценили человек: 10
Теги : ORM, Doctrine

Похожие статьи:

Справочники и учебники:


Предложения и пожелания:
Ваше имя:
Ваш E-mail:
Сколько будет Οдин + Τри
Главная
X

youtube.com/watch?v=7hFivbgIEqk

При полном или частичном использовании материалов данного сайта, ссылка на сайт "yapro.ru" обязательна как на источник информации.
Автоматический импорт материалов и информации с сайта запрещен.
Copyrights © 2007 - 2019 YaPro.Ru

Главная » Веб-мастеру » PHP »