php 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 в PHP
Сегодня мы изучим ещё один паттерн проектирования – Active Record. Этот шаблон говорит о том, что сущность (объекты класса статьи или пользователя) сами должны управлять работой с базой данных. То есть весь остальной код, который эти сущности использует, не должен знать о базе данных. Наши контроллеры не должны работать с базой данных, получая данные и заполняя ими сущности. Они должны знать только о сущностях. Сущность сама должна позаботиться о работе с базой данных. О том, как это реализовать – читайте далее.
Для начала нужно вообще понять, как стоит работать с сущностями при помощи такой концепции. Самое простое, что мы можем реализовать – это чтение из базы данных. И мы должны сделать это, обращаясь напрямую к сущностям-объектам. То есть мы должны сказать: «Эй, Article, дай мне все статьи». Но согласитесь, глупо будет для этого создать сущности, а после этого попросить чтобы они заполнили себя данными из базы. Нам нужно сделать это как-то по другому. Например, обратиться к сущности, не создавая её, но чтобы она при этом вернула нам созданные сущности. Вспоминаем статические методы – их ведь можно вызывать, не создавая объекта. То, что нам нужно!
Давайте добавим в Article статический метод, возвращающий нам все статьи.
Теперь, чтобы получить статьи в контроллере, нам нужно сделать следующее:
Заметили, как сразу упростился наш контроллер? Пропала зависимость от базы данных. Если вы сейчас попробуете выполнить этот код, то он успешно отработает.
А теперь давайте посмотрим на код этого статического метода.
Согласитесь, можно заменить Article::class на self::class – и сюда автоматически подставится класс, в котором этот метод определен. А можно заменить его и вовсе на static::class – тогда будет подставлено имя класса, у которого этот метод был вызван. В чём разница? Если мы создадим класс-наследник SuperArticle, он унаследует этот метод от родителя. Если будет использоваться self:class, то там будет значение “Article”, а если мы напишем static::class, то там уже будет значение “SuperArticle”. Это называется поздним статическим связыванием – благодаря нему мы можем писать код, который будет зависеть от класса, в котором он вызывается, а не в котором он описан.
Итак, давайте изменим этот метод:
А теперь давайте попробуем избавиться от зависимости от таблицы “articles”. Вынесем получение названия таблицы в отдельный метод. Вот так:
А теперь внимательно посмотрите на содержимое класса Article. Не кажется ли вам, что методы findAll(), __set(), underscoreToCamelCase() можно вот хоть сейчас взять и скопировать в сущность User, и начать их использовать? Только не нужно ничего копировать, мы ведь пишем на объектно-ориентированном языке, и можем использовать наследование! Мы можем просто вынести всю эту логику в отдельный класс, а там где она нужна, просто от него наследоваться. Давайте так и поступим.
Создадим отдельный класс, реализующий всю эту логику.
Так как создание объектов этого класса нам не нужно, то делаем его абстрактным. А теперь переносим в него универсальный код из класса Article.
Давайте по порядку.
Давайте теперь посмотрим на то, во что у нас превратится класс Article. Наследуемся от полученного класса и убираем лишнее.
Вот так вот он у нас значительно упростился. Проверим, что всё работает. И. Всё работает!
Давайте теперь добавим метод, который будет возвращать одну статью по id. Проще простого! Добавляем в наш класс ActiveRecordEntity ещё один метод getById().
Этот метод вернёт либо один объект, если он найдётся в базе, либо null – что будет говорить об его отсутствии.
Тогда наш контроллер статей, где мы получаем только одну статью приведется к виду:
А шаблон станет таким:
А теперь давайте в нашем классе User добавим свойства, которые будут соответствовать его полям в базе данных.
А теперь внимание, просто наследуемся от нашего ActiveRecordEntity и получаем все эти возможности, что есть у сущности Article! Просто добавляем несколько строк и указываем нужную таблицу, где хранятся пользователи.
Да это же магия! =)
Попробуем вывести автора статьи, для этого у статьи добавляем геттер для этого поля:
Добавляем в контроллере получение нужного юзера:
И выводим никнейм автора в шаблоне:
Смотрим на результат:
Круто, да? Но можно ещё круче! Можно ведь попросить статью давать нам не id автора, а сразу автора! Для этого просто меняем геттер в статье:
Вот так просто! Прямо в геттере просим сущность юзера выполнить запрос в базу и получить нужного пользователя, по id, который хранится в статье. При этом запрос будет выполнен только если мы вызовем этот геттер, это называется LazyLoad (ленивая загрузка) – это когда данные не подгружаются до тех пор, пока их не запросят.
Код нашего контроллера снова упрощается:
А в шаблоне мы можем напрямую запросить пользователя:
Насыщенный получился урок. Надеюсь, всё было понятно. Если нет – вы знаете, что я всегда подскажу, не стесняйтесь, обращайтесь. До следующего урока!
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.
Прикручиваем ActiveRecord к сайту
Вступление
В процессе создания больше ли мене трудного сайта доводится задумываться об организации доступа к БД(базе данных). Если сайт создается на базе присутствующего фреймворка либо CMS, то там как правило имеются встроенные механизмы ORM (с англ. — Объектно-реляционное отображение, подробнее в вики). В данной статье я расскажу как дозволено прикрутить знаменитую и примитивную ORM систему 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.