php activerecord что это

Active Record против Data Mapper-а для сохранения данных

Эти 2 шаблона проектирования описаны в книге Мартина Фаулера «Шаблоны корпоративных приложений» и представляют собой способы работы с сохранением данных в объектно-ориентированном программировании.

Пример шаблона Active Record

В этом упрощенном примере, дескриптор базы данных вводится в конструкторе Foo (Использование инъекции зависимостей здесь позволяет тестировать объект без использования реальной базы данных), и Foo использует его, чтобы сохранять свои данные. Do_something — просто метод-заглушка, заменяющий бизнес логику.

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

Недостатки Active Record

Пример Data Mapper-а

В данном случае, класс Foo намного проще и должен беспокоиться только о своей бизнес-логике. Он не только не должен сохранять собственные данные, он даже не знает и не заботится о том, все ли его данные были сохранены.

Преимущества Data Mapper-а

Недостатки Data Mapper-а

Сервис-объекты

При использовании шаблона проектирования Data Mapper, вызывающий код должен выбрать Mapper и бизнес-объект и связать их вместе. Если это код вызова в контроллере, то в конечном счете ваша модель «утекает» в контроллер, что может вызвать большие проблемы при поддержке и юнит-тестировании. Эта проблема может быть решена путем введения объекта-сервиса. Сервис является воротами между контроллером и моделью и связывает доменный объект с Mapper-ом по мере необходимости.

Следует помнить, что M в MVC, представляет собой слой абстракции модели, а не объект модели. Так может быть несколько типов объектов в одной модели (в приведенном выше примере, у вас может быть объект сервиса, доменный объект и объект Mapper-а, выступающие в роли единой модели). С другой стороны, если вы используете модели Active Record, ваша модель может быть представлена лишь одним объектом.

Варианты использования

Объекты Active Record исторически были очень популярны из-за того, что они проще, легче в понимании и быстрее в написании, поэтому многие фреймворки и ORM используют Active Record по умолчанию.

Если вы уверены, что вам никогда не понадобиться менять слой сохранения данных (если вы имеете дело с объектом, который представляет из себя INI-файл, например), или вы имеете дело с очень простыми объектами, в которых не так много бизнес-логики, или просто предпочитаете держать все в небольшом количестве классов, тогда шаблон Active Record это то, что вам нужно.

Использование Data Mapper-а хотя и ведет к более чистому, простому в тестировании и поддержке коду, и обеспечивает большую гибкость, — цена этому, — повышение сложности. Если вы еще не пробовали его использовать, то дайте ему шанс, — вам должно понравиться.

Источник

Прикручиваем ActiveRecord к сайту

Введение
Как работает ActiveRecord?

Компонент представляет из себя набор основных классов, необходимых для работы(Model,Config, ConnectionManager и др.), набор адаптеров для подключения к конкретной СУБД и точки входа, файла инициализации ActiveRecord.php который содержит функцию автозагрузки классов наших моделей проекта. Все классы определенны в пространстве имен ActiveRecord, наш проект скорее всего будет находится в другом пространстве или в глобальном, поэтому, чтобы при наследовании классов каждый раз не писать конструкции вроде extends \ActiveRecord\Model или использовать директиву use ActiveRecord, имеет смысл создать собственную обертку над ActiveRecord. Это также позволит расширить возможности нашей ORM не затрагивая компонент AR.

Итак, чтобы воспользоваться всеми методами AR, нам необходимо подключить файл инициализации ActiveRecord.php к проекту, создать для каждой таблицы в БД класс-модель и унаследовать его от \ActiveRecord\Model(например class Book extends \ActiveRecord\Model <> ), инициализировать подключение к БД с помощью конструкции:

После этого мы можем обращаться к нашим моделям и вызывать необходимые методы, например Book::first() — вернет первую строку из таблицы определенной в модели Book.

Создание обертки AR

В проекте возможно потребуется обращение к БД из разных файлов, да и конфигурация обычно храниться в отдельном файле, стандартных возможностей AR не всегда хватает и сама форма записи через пространство имен \ActiveRecord не очень красиво. Эта тема тянет на несколько статьей, поэтому здесь я постараюсь изложить суть вопроса.

В простом случае нам потребуется создать всего 2 класса, один мы наследуем от \ActiveRecord\Model и другой будет основным, в котором мы будем проводить инициализацию и конфигурацию AR. Создадим 2 файла-класса:

От класса Model мы будем наследовать все модели существующих таблиц. Также предположим, что вся конфигурация приложения хранится в отдельном файле Configuration.php:

В конструкторе класса Orm(этот код взят из ActiveRecord.php) подключаем необходимые классы и регестрируем автозагрузчик, в самом конце инициализируем подключение к БД.

Особое внимание стоит уделить формату времени, если его оставить по дефолту, то во время операций записей данных в БД поля типа datetime будут генерировать ошибку, т.к. AR генерирует строки в формате 2000-02-03 16:23:27 MSK, т.е. указывает индекс часового пояса. Изменить конфиг не достаточно, не знаю почему, но разработчики AR используют в других классах формат даты и времени не из конфига, а явно указывают его в требуемых методах, поэтому придется внести еще измения в следующие файлы:
/lib/Column.php метод cast

Аналогично в файлах /lib/Connection.php методы datetime_to_string() string_to_datetime(), и /lib/Model.php метод assign_attribute().

Теперь приведу пример как можно всем этим пользоваться. Сначала нам нужно создать переменную в которой мы будем хранить объект нашего класса Orm, эта переменная должна быть доступна в любом нужном нам месте любого скрипта, поэтому ее лучше объявлять как статическую главного Контроллера или глобальную. После создания объекта необходимо в массив _models поместить массив всех моделей используемых в проекте, формат массива можно узнать в комментарии в коде. Вот возможный пример реализации всего сказанного:

Конечно, данный способ требует еще доработки, например можно сделать статические методы у Orm класса, тогда при запуске проекта нам нужно будет инициализировать его, а дальше везде использовать конструкцию вроде Orm::getModel(‘Имя модели’);
AR довольно мощный и гибкий инструмент, в нем поддерживаются кроме стандартных операций CRUD, также и связи между таблицами(включая сложные связи через — through), имеется SQLBuilder для построения SQL запросов, валидация, конвертация и др.

Официальная документация на английском и в ней освещены элементарные вопросы, есть также форум, на котором можно найти большинство ответов по работе с AR, но я так и не смог нагуглить более мене нормального источника с информацией о внедрении AR в собственный фреймворк или простой движек сайта.

По ходу своей работы мне пришелось в плотную сталкнуться с данной библиотекой, и если эта тема интересна, то я продолжу данный цикл статьей по ActiveRecord.

Источник

В PHP 5.3 появился ActiveRecord аналогичный Ruby on Rails

Поиски решения активной записи в php были изнурительны до того момента, как один из источников в google не предложил вариант ActiveRecord аналогичный Ruby on Rails. Читатель заметит, что вышеупомянутые результаты слишком устаревшие и большая часть из них мало общего с действенностью.

В конце концов, PHP получит более надежный способ активной записи аналогичный способу применяемому в RoR. И, к счастью, это время настало! Спасибо PHP 5. 3 и его новым полезным функциям: схлопыванию, позднему статистическому связыванию и пространству имен.

Я со своим другом Каеном, внесли улучшения в раннюю версию на базе ORM, которую он написал до появления PHP 5. 3. Мы создали ActiveRecord вдохновленные Ruby on Rails и попытались сохранить его возможности, насколько это было возможно. Нашей основной целью в этом проекте – дать возможность PHP-разработчикам создавать крупные проекты с большей гибкостью.

Обзор ActiveRecord

Позвольте мне согласиться с тем фактом, что мы пытались сохранить сходство между нашим детящем и ActiveRecord на базе Ruby on rails, чтобы избежать головной боли и повысить работоспособность программиста. Сохраняя это сходство, мы постарались воссоздать многие функции. Вот список этих функций:

Также здесь есть и другие возможности, как пространства имен, дополнительные драйверы, транзакции (то чего мы хотели бы пораньше) и многое другое мы добавим в будущем, но для начала я думаю совсем неплохо. Мы надеемся, запустить сайт с документацией и разместить исходники на сервисе исходных кодов в течении 2-3х недель. Не забывайте следить за обновлениями, которые вскоре появятся.

Конфигурация

Установка проста и линейна. Здесь есть всего 2 типа конфигурации, которые вы можете выбрать:

Как только вы настроите два этих параметра ваша работа окончена. ActiveRecord заботится о вас и берет остальную часть работы на себя. Она не требует проводить какую либо дополнительную работу со схемами ваших yaml/xml файлов. Также запросы к базу данных для получения информации и кэш-файлов будет проходить без лишних вызовов для одной схемы.

Методы поиска

ActiveRecord поддерживает несколько методов, с помощью которых, вы можете найти записи либо по первичному ключу, либо сконструировав свой собственный с набором опций, к примеру: сортировка, лимит, выбор, группировка.

Методы динамического поиска

Методы записи

Какой смысл иметь объект, который инкапсулирует запись из БД, если вы не можете ничего сделать с этим?

Отношения

Объединения — сложная часть ActiveRecord. Они используют те же самые опции, что в RoR.

Верификация

Название говорит само за себя. До того как сохранить/обновить/извлечь к каждому определению, которое вы создали, будет применена верификация и только после её удачного прохождения модель будет возвращена. В противном случае, вы увидите сообщение об ошибке и сможете вернуться обратно для ее исправления.

Обратные вызовы

Обратные вызовы дают вам возможность управлять вашей моделью до/после какого-то события на протяжении ее существования. Вы можете выбрать методы, которые будут вызваны как callback до или после других методов примененных в модели. К сожалению, даже PHP 5.3 имеет ограничения — вы не можете иcпользовать callback в виде статических методов, они должны быть динамическими.

Сериализация

Поддержка различных драйверов

В настоящее время существует поддержка только для MySQL (через mysqli) и sqlite3. Однако мы надеемся ввести большее число драйверов в проект, что должно помочь в работе с такими БД как PostgresSQL и Oracle. Соедиение/адаптер — сделан так, что не возникнет никаких затруднений при создании большего числа драйверов, когда будет нужно.

Другие параметры

При декларировании модели вы также можете указать primary_key и table_name.
Защищенные/доступные определения уже доступны, так что вы можете справится со многими распространенными проблемами. Атрибуты могут быть псевдонимами, чтобы вам было легче получить доступ к ним через разные имена.

Будущее

Как я уже отмечал ранее, в самое ближайшее время данный код будет доступен на сервисах исходного кода. Мы также работаем над созданием сайта с учебными пособиями и документациями к коду. Я буду сообщать о новых успехах.
Спасибо за прочтение!

Источник

Active Record

Active Record обеспечивает объектно-ориентированный интерфейс для доступа и манипулирования данными, хранящимися в базах данных. Класс Active Record соответствует таблице в базе данных, объект Active Record соответствует строке этой таблицы, а атрибут объекта Active Record представляет собой значение отдельного столбца строки. Вместо непосредственного написания SQL-выражений вы сможете получать доступ к атрибутам Active Record и вызывать методы Active Record для доступа и манипулирования данными, хранящимися в таблицах базы данных.

Вышеприведённый код аналогичен использованию следующего SQL-выражения в MySQL, которое менее интуитивно, потенциально может вызвать ошибки и даже проблемы совместимости, если вы используете различные виды баз данных:

Yii поддерживает работу с Active Record для следующих реляционных баз данных:

Кроме того Yii поддерживает использование Active Record со следующими NoSQL базами данных:

В этом руководстве мы в основном будем описывать использование Active Record для реляционных баз данных. Однако большая часть этого материала также применима при использовании Active Record с NoSQL базами данных.

Объявление классов Active Record #

Для начала объявите свой собственный класс, унаследовав класс yii\db\ActiveRecord.

Настройка имени таблицы #

По умолчанию каждый класс Active Record ассоциирован с таблицей в базе данных. Метод tableName() получает имя таблицы из имени класса с помощью yii\helpers\Inflector::camel2id(). Если таблица не названа соответственно, вы можете переопределить данный метод.

Классы Active record называются «моделями» #

Объекты Active Record являются моделями. Именно поэтому мы обычно задаём классам Active Record пространство имён app\models (или другое пространство имён, предназначенное для моделей).

Т.к. класс yii\db\ActiveRecord наследует класс yii\base\Model, он обладает всеми возможностями моделей, такими как атрибуты, правила валидации, способы сериализации данных и т.д.

Подключение к базам данных #

По умолчанию Active Record для доступа и манипулирования данными БД использует компонент приложения db в качестве компонента DB connection. Как сказано в разделе Объекты доступа к данным (DAO), вы можете настраивать компонент db на уровне конфигурации приложения как показано ниже:

Получение данных #

После объявления класса Active Record вы можете использовать его для получения данных из соответствующей таблицы базы данных. Этот процесс, как правило, состоит из следующих трёх шагов:

Как вы могли заметить, эти шаги очень похожи на работу с построителем запросов. Различие лишь в том, что для создания объекта запроса вместо оператора new используется метод yii\db\ActiveRecord::find(), возвращающий новый объект запроса, являющийся представителем класса yii\db\ActiveQuery.

Ниже приведено несколько примеров использования Active Query для получения данных:

Info: Т.к. класс yii\db\ActiveQuery наследует yii\db\Query, вы можете использовать в нём все методы построения запросов и все методы класса Query как описано в разделе Построитель запросов.

Т.к. извлечение данных по первичному ключу или значениям отдельных столбцов достаточно распространённая задача, Yii предоставляет два коротких метода для её решения:

Оба метода могут принимать параметры в одном из следующих форматов:

Нижеследующий код демонстрирует, каким образом эти методы могут быть использованы:

Warning: Если вам нужно передать в эти методы данные, полученные от пользователя, убедитесь что передаваемое значение – это скаляр, а если необходимо указать условия в формате массива – убедитесь, что пользовательские данные не могут изменить структуру этого массива.

Помимо использования методов построения запросов вы можете также писать запросы на «чистом» SQL для получения данных и заполнения ими объектов Active Record. Вы можете делать это посредством метода yii\db\ActiveRecord::findBySql():

Не используйте дополнительные методы построения запросов после вызова метода findBySql(), т.к. они будут проигнорированы.

Доступ к данным #

Как сказано выше, получаемые из базы данные заполняют объекты Active Record и каждая строка результата запроса соответствует одному объекту Active Record. Вы можете получить доступ к значениям столбцов с помощью атрибутов этих объектов. Например так:

Note: Атрибуты объекта Active Record названы в соответствии с названиями столбцов связной таблицы с учётом регистра. Yii автоматически объявляет для каждого столбца связной таблицы атрибут в Active Record. Вы НЕ должны переопределять какие-либо из этих атрибутов.

Преобразование данных #

Tip: Вышеприведённый пример демонстрирует общий способ преобразования данных в различные форматы. Если вы работаете с датами и временем, вы можете использовать DateValidator и DatePicker, которые проще в использовании и являются более мощными инструментами.

Получение данных в виде массива #

Несмотря на то, что получение данных в виде Active Record объектов является удобным и гибким, этот способ не всегда подходит при получении большого количества данных из-за больших накладных расходов памяти. В этом случае вы можете получить данные в виде PHP-массива, используя перед выполнением запроса метод asArray():

Note: В то время как этот способ бережёт память и улучшает производительность, он ближе к низкому слою абстракции базы данных и вы потеряете многие возможности Active Record. Важное отличие заключается в типах данных значений столбцов. Когда вы получаете данные в виде объектов Active Record, значения столбцов автоматически приводятся к типам, соответствующим типам столбцов; с другой стороны, когда вы получаете данные в массивах, значения столбцов будут строковыми (до тех пор, пока они являются результатом работы PDO-слоя без какой-либо обработки), несмотря на настоящие типы данных соответствующих столбцов.

Пакетное получение данных #

В главе Построитель запросов мы объясняли, что вы можете использовать пакетную выборку для снижения расходов памяти при получении большого количества данных из базы. Вы можете использовать такой же подход при работе с Active Record. Например:

Сохранение данных #

Используя Active Record, вы легко можете сохранить данные в базу данных, осуществив следующие шаги:

Вы можете различать два состояния Active Record объекта с помощью проверки значения его свойства isNewRecord. Это свойство также используется внутри метода save() как показано ниже:

Tip: Вы можете вызвать insert() или update() непосредственно, чтобы вставить или обновить строку данных в таблице.

Валидация данных #

Т.к. класс yii\db\ActiveRecord наследует класс yii\base\Model, он обладает такими же возможностями валидации данных. Вы можете объявить правила валидации переопределив метод rules() и осуществлять валидацию данных посредством вызовов метода validate().

Массовое присваивание #

Как и обычные модели, объекты Active Record тоже обладают возможностью массового присваивания. Как будет показано ниже, используя эту возможность, вы можете одним PHP выражением присвоить значения множества атрибутов Active Record объекту. Запомните однако, что только безопасные атрибуты могут быть массово присвоены.

Обновление счётчиков #

Распространённой задачей является инкремент или декремент столбца в таблице базы данных. Назовём такие столбцы столбцами-счётчиками. Вы можете использовать метод updateCounters() для обновления одного или нескольких столбцов-счётчиков. Например:

Note: Если вы используете метод yii\db\ActiveRecord::save() для обновления столбца-счётчика, вы можете прийти к некорректному результату, т.к. вполне вероятно, что этот же счётчик был сохранён сразу несколькими запросами, которые читают и записывают этот же столбец-счётчик.

Dirty-атрибуты #

Когда вы вызываете save() для сохранения Active Record объекта, сохраняются только dirty-атрибуты. Атрибут считается dirty-атрибутом, если его значение было изменено после чтения из базы данных или же он был сохранён в базу данных совсем недавно. Заметьте, что валидация данных осуществляется независимо от того, имеются ли dirty-атрибуты в объекте Active Record или нет.

Active Record автоматически поддерживает список dirty-атрибутов. Это достигается за счёт хранения старых значений атрибутов и сравнения их с новыми. Вы можете вызвать метод yii\db\ActiveRecord::getDirtyAttributes() для получения текущего списка dirty-атрибутов. Вы также можете вызвать yii\db\ActiveRecord::markAttributeDirty(), чтобы явно пометить атрибут в качестве dirty-атрибута.

Если вам нужны значения атрибутов, какими они были до их изменения, вы можете вызвать getOldAttributes() или getOldAttribute().

Значения атрибутов по умолчанию #

Некоторые столбцы ваших таблиц могут иметь значения по умолчанию, объявленные в базе данных. Иногда вы можете захотеть предварительно заполнить этими значениями вашу веб-форму, которая соответствует Active Record объекту. Чтобы избежать повторного указания этих значений, вы можете вызвать метод loadDefaultValues() для заполнения соответствующих Active Record атрибутов значениями по умолчанию, объявленными в базе данных:

Приведение типов атрибутов #

При заполнении результатами запроса yii\db\ActiveRecord производит автоматическое приведение типов для значений атрибутов на основе информации из схемы базы данны. Это позволяет данным, полученным из колонки таблицы объявленной как целое, заноситься в экземпляр ActiveRecord как значение целого типа PHP, булево как булево и т.д. Однако, механизм приведения типов имеет несколько ограничений:

Совет: вы можете использовать поведение yii\behaviors\AttributeTypecastBehavior для того, чтобы производить приведение типов для ActiveRecord во время валидации или сохранения.

Начиная с 2.0.14, Yii ActiveRecord поддерживает сложные типы данных, такие как JSON или многомерные массивы.

JSON в MySQL и PostgreSQL #

После заполнения данных, значение из столбца JSON будет автоматически декодировано из JSON в соответствии со стандартными правилами декодирования JSON.

Чтобы сохранить значение атрибута в столбец JSON, ActiveRecord автоматически создаст объект JsonExpression, который будет закодирован в строку JSON на уровне QueryBuilder.

Массивы в PostgreSQL #

Чтобы сохранить значение атрибута в столбец массива, ActiveRecord автоматически создаст объект [[yii\db\Array Expression|ArrayExpression]], который будет закодирован QueryBuilder в строковое представление массива PgSQL.

Можно также использовать условия для столбцов JSON:

Обновление нескольких строк данных #

Методы, представленные выше, работают с отдельными Active Record объектами, инициируя вставку или обновление данных для отдельной строки таблицы. Вместо них для обновления нескольких строк одновременно можно использовать метод updateAll(), который является статическим.

Подобным образом можно использовать метод updateAllCounters() для обновления значений столбцов-счётчиков в нескольких строках одновременно.

Удаление данных #

Для удаления одной отдельной строки данных сначала получите Active Record объект, соответствующий этой строке, а затем вызовите метод yii\db\ActiveRecord::delete().

Вы можете вызвать yii\db\ActiveRecord::deleteAll() для удаления всех или нескольких строк данных одновременно. Например:

Note: будьте очень осторожны, используя метод deleteAll(), потому что он может полностью удалить все данные из вашей таблицы, если вы сделаете ошибку при указании условий удаления.

Жизненные циклы Active Record #

Важно понимать как устроены жизненные циклы Active Record при использовании Active Record для различных целей. В течение каждого жизненного цикла вызывается определённая последовательность методов, которые вы можете переопределять, чтобы получить возможность тонкой настройки жизненного цикла. Для встраивания своего кода вы также можете отвечать на конкретные события Active Record, которые срабатывают в течение жизненного цикла. Эти события особенно полезны, когда вы разрабатываете поведения, которые требуют тонкой настройки жизненных циклов Active Record.

Ниже мы подробно опишем различные жизненные циклы Active Record и методы/события, которые участвуют в жизненных циклах.

Жизненный цикл создания нового объекта #

Жизненный цикл получения данных #

Когда происходит получение данных посредством одного из методов получения данных, каждый вновь создаваемый объект Active Record при заполнении данными проходит следующий жизненный цикл:

Жизненный цикл сохранения данных #

Когда вызывается метод save() для вставки или обновления объекта Active Record, следующий жизненный цикл имеет место:

Жизненный цикл удаления данных #

Когда вызывается метод delete() для удаления объекта Active Record, следующий жизненный цикл имеет место:

Note: Вызов следующих методов НЕ инициирует ни один из вышеприведённых жизненных циклов:

Работа с транзакциями #

Есть два способа использования транзакций при работе с Active Record.

Первый способ заключается в том, чтобы явно заключить все вызовы методов Active Record в блок транзакции как показано ниже:

Второй способ заключается в том, чтобы перечислить операции с базой данных, которые требуют тразнакционного выполнения, в методе yii\db\ActiveRecord::transactions(). Например:

Метод yii\db\ActiveRecord::transactions() должен возвращать массив, ключи которого являются именами сценариев, а значения соответствуют операциям, которые должны быть выполнены с помощью транзакций. Вы должны использовать следующие константы для обозначения различных операций базы данных:

Используйте операторы | для объединения вышеприведённых констант при обозначении множества операций. Вы можете также использовать вспомогательную константу OP_ALL, чтобы обозначить одной константой все три вышеприведённые операции.

Оптимистическая блокировка #

Оптимистическая блокировка решает вышеприведённую проблему за счёт использования отдельного столбца для сохранения номера версии каждой строки данных. Когда строка данных сохраняется с использованием устаревшего номера версии, выбрасывается исключение yii\db\StaleObjectException, которое предохраняет строку от сохранения. Оптимистическая блокировка поддерживается только тогда, когда вы обновляете или удаляете существующую строку данных, используя методы yii\db\ActiveRecord::update() или yii\db\ActiveRecord::delete() соответственно.

Для использования оптимистической блокировки:

Работа со связными данными #

Объявление связей #

Для работы со связными данными посредством Active Record вы прежде всего должны объявить связи в классе Active Record. Эта задача решается простым объявлением методов получения связных данных для каждой интересующей вас связи как показано ниже:

При объявлении связи, вы должны указать следующую информацию:

Доступ к связным данным #

После объявления связей вы можете получать доступ к связным данным с помощью имён связей. Это происходит таким же образом, каким осуществляется доступ к свойству объекта объявленному с помощью метода получения связных данных. По этой причине, мы называем его свойством связи. Например:

Динамические запросы связных данных #

Т.к. метод получения связных данных возвращает объект запроса yii\db\ActiveQuery, вы можете в дальнейшем перед его отправкой в базу данных настроить этот запрос, используя методы построения запросов. Например:

В отличие от доступа к данным с помощью свойства связи, каждый раз при выполнении такого динамического запроса посредством метода получения связных данных будет выполняться SQL-запрос, даже если тот же самый динамический запрос был отправлен ранее.

Иногда вы можете даже захотеть настроить объявление связи таким образом, чтобы вы могли более просто осуществлять динамические запросы связных данных. Например, вы можете объявить связь bigOrders как показано ниже:

После этого вы сможете выполнять следующие запросы связных данных:

Связывание посредством промежуточной таблицы #

При объявлении подобных связей вы можете пользоваться методом via() или методом viaTable() для указания промежуточной таблицы. Разница между методами via() и viaTable() заключается в том, что первый метод указывает промежуточную таблицу с помощью названия связи, в то время как второй метод непосредственно указывает промежуточную таблицу. Например:

Использовать связи, объявленные с помощью промежуточных таблиц, можно точно также, как и обычные связи. Например:

Отложенная и жадная загрузка #

В разделе Доступ к связным данным, мы показывали, что вы можете получать доступ к свойству связи объекта Active Record точно также, как получаете доступ к свойству обычного объекта. SQL-запрос будет выполнен только во время первого доступа к свойству связи. Мы называем подобный способ получения связных данных отложенной загрузкой. Например:

Отложенная загрузка очень удобна в использовании. Однако этот метод может вызвать проблемы производительности, когда вам понадобится получить доступ к тем же самым свойствам связей для нескольких объектов Active Record. Рассмотрите следующий пример кода. Сколько SQL-запросов будет выполнено?

Для решения этой проблемы производительности вы можете, как показано ниже, использовать подход, который называется жадная загрузка:

Посредством вызова метода yii\db\ActiveQuery::with(), вы указываете объекту Active Record вернуть заказы первых 100 покупателей с помощью одного SQL-запроса. В результате снижаете количество выполняемых SQL-запросов от 101 до 2!

Когда связь жадно загружается, вы можете настроить соответствующий запрос получения связных данных с использованием анонимной функции. Например:

Note: Если вы вызываете метод select() в процессе жадной загрузки связей, вы должны убедиться, что будут выбраны столбцы, участвующие в объявлении связей. Иначе связные модели будут загружены неправильно. Например:

Использование JOIN со связями #

Note: Материал этого раздела применим только к реляционным базам данных, таким как MySQL, PostgreSQL, и т.д.

Запросы на получение связных данных, которые мы рассмотрели выше, ссылаются только на столбцы основной таблицы при извлечении основной информации. На самом же деле нам часто нужно ссылаться в запросах на столбцы связных таблиц. Например, мы можем захотеть получить покупателей, для которых имеется хотя бы один активный заказ. Для решения этой проблемы мы можем построить запрос с использованием JOIN как показано ниже:

Однако лучшим подходом является использование имеющихся объявлений связей с помощью вызова метода yii\db\ActiveQuery::joinWith():

Оба подхода выполняют одинаковый набор SQL-запросов. Однако второй подход более прозрачен и прост.

Подобно методу with() вы можете объединять данные с одной или несколькими связями; вы можете настроить запрос на получение связных данных «на лету»; вы можете объединять данные с вложенными связями; вы можете смешивать использование метода with() и метода joinWith(). Например:

Иногда во время объединения двух таблиц вам может потребоваться указать некоторые дополнительные условия рядом с оператором ON во время выполнения JOIN-запроса. Это можно сделать с помощью вызова метода yii\db\ActiveQuery::onCondition() как показано ниже:

Вышеприведённый запрос вернёт всех покупателей и для каждого покупателя вернёт все активные заказы. Заметьте, что это поведение отличается от нашего предыдущего примера, в котором возвращались только покупатели, у которых был как минимум один активный заказ.

Псевдонимы связанных таблиц #

Как уже было отмечено, при использовании в запросе JOIN-ов, приходится явно решать конфликты имён. Поэтому часто таблицам дают псевдонимы. Задать псевдоним для реляционного запроса можно следующим образом:

Обратные связи #

Теперь рассмотрим следующий участок кода:

Теперь, после этих изменений в объявлении связи, получим:

Note: обратные связи не могут быть объявлены для связей, использующих промежуточную таблицу. То есть, если связь объявлена с помощью методов via() или viaTable(), вы не должны вызывать после этого метод inverseOf().

Сохранение связных данных #

Во время работы со связными данными вам часто требуется установить связи между двумя разными видами данных или удалить существующие связи. Это требует установки правильных значений для столбцов, с помощью которых заданы связи. При использовании Active Record вам может понадобится завершить участок кода следующим образом:

Active Record предоставляет метод link(), который позволяет выполнить эту задачу более красивым способом:

Метод link() требует указать название связи и целевой объект Active Record, с которым должна быть установлена связь. Метод изменит значения атрибутов, которые связывают два объекта Active Record, и сохранит их в базу данных. В вышеприведённом примере, метод присвоит атрибуту customer_id объекта Order значение атрибута id объекта Customer и затем сохранит его в базу данных.

Note: Невозможно связать два свежесозданных объекта Active Record.

Преимущество метода link() становится ещё более очевидным, когда связь объявлена посредством промежуточной таблицы. Например, вы можете использовать следующий код, чтобы связать объект Order с объектом Item :

Info: Метод link() не осуществляет какую-либо валидацию данных во время сохранения целевого объекта Active Record. На вас лежит ответственность за валидацию любых введённых данных перед вызовом этого метода.

Связывание объектов из разных баз данных #

Active Record позволяет вам объявить связи между классами Active Record, которые относятся к разным базам данных. Базы данных могут быть разных типов (например, MySQL и PostgreSQL или MS SQL и MongoDB), и они могут быть запущены на разных серверах. Вы можете использовать тот же самый синтаксис для осуществления запросов выборки связных данных. Например:

Вы можете использовать большую часть возможностей запросов получения связных данных, которые были описаны в этой главе.

Note: Применимость метода joinWith() ограничена базами данных, которые позволяют выполнять запросы между разными базами с использованием оператора JOIN. По этой причине вы не можете использовать этот метод в вышеприведённом примере, т.к. MongoDB не поддерживает операцию JOIN.

Тонкая настройка классов Query #

По умолчанию все запросы данных для Active Record поддерживаются с помощью класса yii\db\ActiveQuery. Для использования собственного класса запроса вам необходимо переопределить метод yii\db\ActiveRecord::find() и возвращать из него объект вашего собственного класса запроса. Например:

Tip: В больших проектах рекомендуется использовать собственные классы запросов, которые будут содержать в себе большую часть кода, связанного с настройкой запросов, таким образом классы Active Record удастся сохранить более чистыми.

Вы можете настроить класс запроса большим количеством различных способов для улучшения методик построения запросов. Например, можете объявить новые методы построения запросов в собственном классе запросов:

Note: Вместо вызова метода where() старайтесь во время объявления новых методов построения запросов использовать andWhere() или orWhere() для добавления дополнительных условий, в этом случае уже заданные условия выборок не будут перезаписаны.

Это позволит вам писать код построения запросов как показано ниже:

Вы также можете использовать новые методы построения запросов, когда объявляете связи для класса Comment или осуществляете запрос для выборки связных данных:

Info: В Yii версии 1.1 была концепция с названием scope. Она больше не поддерживается в Yii версии 2.0, и вы можете использовать собственные классы запросов и собственные методы построения запросов, чтобы добиться той же самой цели.

Получение дополнительных атрибутов #

Когда объект Active Record заполнен результатами запроса, его атрибуты заполнены значениями соответствующих столбцов из полученного набора данных.

Вы можете получить дополнительные столбцы или значения с помощью запроса и сохранить их внутри объекта Active Record. Например, предположим, что у нас есть таблица ‘room’, которая содержит информацию о доступных в отеле комнатах. Каждая комната хранит информацию о её геометрических размерах с помощью атрибутов ‘length’, ‘width’, ‘height’. Представьте, что вам требуется получить список всех доступных комнат, отсортированных по их объёму в порядке убывания. В этом случае вы не можете вычислять объём с помощью PHP, потому что нам требуется сортировать записи по объёму, но вы также хотите отображать объем в списке. Для достижения этой цели, вам необходимо объявить дополнительный атрибут в вашем Active Record классе ‘Room’, который будет хранить значение ‘volume’:

Далее вам необходимо составить запрос, который вычисляет объём комнаты и выполняет сортировку:

Возможность выбирать дополнительные атрибуты может быть особенно полезной для агрегирующих запросов. Представьте, что вам необходимо отображать список покупателей с количеством их заказов. Прежде всего вам потребуется объявить класс Customer со связью ‘orders’ и дополнительным атрибутом для хранения расчётов:

После этого вы сможете составить запрос, который объединяет заказы и вычисляет их количество:

Недостаток этого подхода заключается в том, что если данные для поля не загружены по результатам SQL запроса, то они должны быть вычисленны отдельно. Это означает, что запись, полученная посредством обычного запроса без дополнительных полей в разделе ‘select’, не может вернуть реальное значения для дополнительного поля. Это же касается и только что сохранненой записи.

Использование магических методов __get() и __set() позволяет эмулировать поведение обычного поля:

Если результат запроса на выборку данных не содержит поле ‘volume’, то модель сможет расчитать его автоматически используя имеющиеся атрибуты.

Вы также можете вычислять агрегируемые поля используя объявленные отношения:

Этот подход также можно использовать для быстрого доступа к некоторым данным отношений, в особенности для агрегации. Например:

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *