Orm php: ORM на php для MySQL, реальность (часть первая) / Хабр

Содержание

Что такое ORM

Любой, кто имеет опыт разработки web приложений или использования
какого-либо PHP фреймворка, безусловно, сталкивался с реляционными базами
данных,
такими как MySQL или PostgreSQL. Работа с SQL напрямую, может
быть достаточно сложной, особенно при работе с данными сразу из нескольких
таблиц и при применении различных фильтров. А это как раз та сфера, где на сцену
выходит ORM.


Так, что же такое ORM?


ORM – это аббревиатура для Object Relational Mapping (Объектно-реляционное
отображение)
. Это такая методика или техника программирования, предназначенная
для преобразования между несовместимыми типами данных в
объектно-ориентированных языках программирования.
Суть этого достаточно
сложного определения заключается в том, что создается некая абстракция -
виртуальная объектная база”, запросы к которой, преобразуются в SQL
команды,
т. е. больше не нужно писать SQL-запросы к базе данных вручную
(хотя в некоторых, достаточно нетривиальных случаях, писать запрос вручную
все-таки придется, благо таких случаев не так много).


ORM фреймворк может быть написан на каком-либо объектно-ориентированном
языке ( PHP, Python, Ruby ) и представлять обертку над некой реляционной
базой данных. Классы будут соответствовать таблицам в базе, а экземпляры этих
классов – конкретным строкам таблицы
.


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

Далее обсудим преимущества концепции ORM. Стоит также отметить, что не все
библиотеки, реализующие данную концепцию, обладают всеми рассмотренными здесь
преимуществами.


Независимость от вида базы данных

Это, пожалуй, главнейшая особенность и преимущество использования ORM в
приложении. Так как нет необходимости писать специфический код под конкретный
вид базы данных. Поэтому, вы можете начать проект с использования SQLite,
затем можете поменять ее на MySQL или PostgreSQL. И все это делается
редактированием пары строчек кода в настройках адаптера базы данных.


Моделирование предметной области

При использовании ORM для построения приложения, бизнес-логика приложения
работает с объектами языка, а не с самой структурой базы данных. Это возможно
благодаря соответствию между бизнес-моделью и самой базой данных.


Меньше кода и больше эффективности


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


Развитый интерфейс запросов к базе

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


Управление зависимостями


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


Параллелизм, кэширование и транзакции


ORM поддерживает возможность параллельной работы, позволяя нескольким
пользователям одновременно изменять один и тот же объект.

Другая особенность – объекты могут быть сохранены в кэше, сокращая нагрузку на
базу и вцелом увеличивая скорость работы приложения.

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


Недостатки


Накладные расходы


ORM фреймворк добавляет слой абстракции, ускоряющий процесс разработки и
снижающий сложность создания конечного продукта. Однако, ничто не проходит даром
– приложение начинает потреблять больше памяти и нагрузка на процессор также
увеличивается.


Кривая изучения

Применение ORM в PHP приложении предполагает, что у разработчика есть опыт
работы с каким либо PHP фреймворком. И поэтому здесь без дополнительных
знаний будет обойтись нелегко. Хотя вы можете значительно сократить время
изучения ORM в PHP, если воспользуетесь моим курсом Фреймворк Yii 2.0 с
нуля. Пример создания
сайта.
Там, в уроке номер 3 “Создание моделей”, я как раз рассказываю о создании
объектов базы данных с помощью шаблона проектирования ActiveRecord.


Производительность

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


Поверхностное знание SQL

Несмотря на то, что ORM облегчает жизнь, это часто приводит к тому, что
разработчики не очень стремятся учить SQL или разбираются в нем слабо.

На сегодня все. Всего доброго!


  • Создано 21.11.2017 08:11:10



  • Михаил Русаков

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk. com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

Какой фреймворк ORM проще всего использовать для PHP?

Я ищу активную запись Ruby для PHP. Что-то настолько простое, что я просто определяю свои поля, расширяю базовый класс ORM и получаю ACID операции бесплатно. Я должен получить геттеры и сеттеры по умолчанию без написания какого-либо кода, но переопределить дефолт getter или setter так же просто, как объявить функции get$fieldName или set$fieldName с тем поведением, которое я хочу. Symphony заставляет вас создавать около 5 файлов на объект, и все определенные объекты всегда загружаются, насколько я могу судить. Что может быть лучшей альтернативой? Почему это лучше? Не могли бы вы привести простые примеры в своих ответах, пожалуйста?

Doctrine-это еще один ORM, на который я смотрел помимо симфонии . Там же вам нужно создать yaml файлов, описывающих ваши структуры данных. База данных уже определяет этот материал. Что будет просто читать мою таблицу defs без необходимости генерировать и хранить конфигурационные файлы повсюду?

php

orm

Поделиться

Источник


Zak    

20 октября 2008 в 22:54

13 ответов


  • Какой фреймворк ruby ORM использовать в автономном приложении ruby?

    Я хотел бы использовать postgresql с внешними ключами для определения отношений в данных, чтобы другие платформы/приложения также могли легко использовать ту же базу данных. Наличие какого-то ruby DSL для определения схемы базы данных с поддержкой миграции также было бы здорово. Какой фреймворк вы…

  • Какой бэк — энд фреймворк лучше всего подходит для Android приложений?

    Я занимаюсь разработкой приложения, android, и я хочу, чтобы реализовать PHP в качестве бэкэнда. Мне нравится спрашивать о том, какой фреймворк PHP подходит для разработки с приложением Android. Мое приложение android будет использовать JSON. Кроме того, приложение использует аутентификацию,…



11

Я большой поклонник Doctrine , который является полнофункциональным ORM, который заменит Propel как Symfony по умолчанию ORM.

В нем есть ваш базовый материал ORM, который вы ожидаете, а также полнофункциональный конструктор запросов, который я нашел замечательным.

Он поставляется с полным набором инструментов командной строки для управления вашими базами данных. Например, вы можете создать свои схемы и приспособления в YAML, заставить Doctrine генерировать классы на основе вашей схемы, создать базу данных, создать схему на основе моделей, а затем заполнить базу данных вашими приспособлениями все с помощью одного . /doctrine build-all-reload .

Он также включает в себя поддержку миграции баз данных и недавно обновленные миграции для автоматического diff и создания ваших моделей миграции.

В соответствии с вашими жалобами doctrine вы можете запустить команду ./doctrine generate-models-db или ./doctrine generate-yaml-db для автоматического создания моделей и файлов yaml соответственно из текущей настройки базы данных.

Другие тонкости включают в себя «поведение», которое значительно облегчает жизнь при реализации определенных, ну, поведений в вашей схеме. Например, вы можете добавить поведение «Timestampable» в свой файл класса. Doctine автоматически добавляет столбцы ‘created_at’ и ‘updated_at’, заполняет их, и каждый запуск $object->save() автоматически обновляет столбец ‘updated_at’. Более сложное поведение включает в себя i18n, управление версиями таблиц и деревья (хотя на самом деле только NestedSet).

Лично я был чрезвычайно очарован Doctrine и бредил им при каждом удобном случае.

Поделиться


dcousineau    

21 октября 2008 в 22:48



9

Я использую малоизвестный слой orm под названием redbean.
вы можете найти его здесь: http:/ / www.redbeanphp.com .
он абсолютно уникален в том смысле, что просто создает столбцы таблиц и индексы сам по себе, без каких-либо конфигурационных файлов вообще. Я считаю, что это огромная экономия времени!

Поделиться


Unknown    

18 сентября 2009 в 09:30


Поделиться


jakber    

20 октября 2008 в 23:33




5

Я создал свой собственный,без раздувания. (Хотя мне нужно обновить свои локальные источники)

Я создал его именно с теми точками, о которых вы упомянули: никаких десятков файлов xml, никакого огромного фреймворка, просто простые конструкторы с базой данных для сопоставления свойств, и он делает ваши основные вещи CRUD / Find / Join. Для большинства вещей, которые я делаю, мне даже не нужно писать пользовательские запросы.

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

Следующая версия, которую я выпущу, поставляется с рабочим однострочным соединением при соединении при соединении (чтобы пройти ‘path’ через вашу базу данных), настройками базы данных на основе ini, поддержкой кросс-баз данных, супер-простой абстракцией базы данных и стандартным регистратором, который возвращается к SQLite, если ваша база данных не работает.

Просто крикните, если вас интересуют новости, и тогда я потороплюсь.

Ах да, и не забывайте, что есть еще хороший визуальный генератор скаффолдов под названием Pork.Generator . Он пытается проанализировать структуру вашей базы данных и найти отношения 1:1 1:many и many:many, а также может автоматически генерировать классы для вас 🙂

(источник: schizofreend. nl )

Поделиться


SchizoDuckie    

20 октября 2008 в 23:35



4

Zend_Db_Table и Zend_Db_Table_Row довольно хороши в том, что вы описываете. Вам не нужен никакой конфигурационный файл, большинство метаданных-это «discovered» из самой базы данных.

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

Но, как и в случае с любым ORM, неизбежно существуют некоторые SQL запросов и операций, которые вы не можете выполнить через интерфейс OO. Никакой ORM не может служить универсальной покупкой.

Сноска: я работал над проектом Zend Framework чуть больше года, особенно над компонентом Zend_Db. Но я больше на них не работаю.

Поделиться


Bill Karwin    

20 октября 2008 в 23:21



1

Другой вариант, который следует за реализацией Ruby DataMapper, — это phpDataMapper . Очевидно, это картограф данных, а не ActiveRecord :).

Поделиться


Vance Lucas    

20 августа 2009 в 21:31



1

Я бы рекомендовал Doctrine с Symfony. Несмотря на то, что есть еще что узнать, вы обнаружите, что у него есть функции, которые вам понадобятся, как только проект вырастет (CRUD, структура форм, Шаблоны записей, DQL, поддержка плагинов, поведение). Оба проекта имеют очень активное сообщество, и вы не должны оказаться в тупике, потому что на большинство ваших вопросов уже были даны ответы в официальных учебниках или на форуме.

Если вам не нравятся определения баз данных в YAML, вы всегда можете использовать ORM Designer или MySQL Workbench.

Поделиться


Frantisek Troster    

15 января 2010 в 10:45



1

Проверьте ремонтопригодный фреймворк. Хотя я предпочитаю генерацию кода над ActiveRecord (runtime reflection), я нашел поддерживаемый фреймворк простым в использовании, особенно с точки зрения функций ORM.

http://framework.maintainable.com/MVC, о/3_model.php#С3.7

Если вам нужен фреймворк, основанный на генерации кода, попробуйте QCodo. Что бы ни сказал дкузино для Doctrine, я могу сказать и для Qcodo. Это управляемый событиями полноценный фреймворк, имитирующий .NET/Delphi., однако вы можете просто использовать функцию генерации кода и найти способы отделить свой сгенерированный класс от rest фреймворка. Таким образом, вы можете встраивать сгенерированные классы в другие фреймворки.

Поделиться


Unknown    

25 ноября 2008 в 00:16



0

Я рекомендую QCubed . Это невероятно мощный фреймворк PHP5-only ORM, который фокусируется на генерации кода, создании лесов UI и быстрой разработке приложений. Взгляните на обучающие видео: http://qcu.be/content/video-screencasts

Поделиться


Alex Weinstein    

02 февраля 2011 в 05:10



0

http://dbphp.net

Плюсы

  • Генерирует/изменяет атрибуты таблицы / поля databases/tables/fields/various на лету.
  • Не требует установки.
  • Не имеет никакой конфигурации вообще.
  • Для начала работы достаточно включить библиотеку и указать параметры ссылки на БД.
  • Он имеет встроенную поддержку локализации.
  • Он имеет различные уровни кэша и позволяет расширить механизм кэширования.
  • Он работает со многими различными подключениями к базе данных одновременно.
  • Он может создавать отношения между таблицами, расположенными на других серверах баз данных.
  • Он извлекает атрибуты таблицы/поля с помощью комментариев класса и переменной doc.

Аферы

  • Он работает только с объектами, т. е. вы должны иметь определенный класс и иметь экземпляр класса для сохранения нагрузки или т. д.
  • У него нет сайта,но есть папка с примерами.

Поделиться


BIOHAZARD    

19 октября 2013 в 21:02



0

Мне нравятся Idiorm и Paris , и я использую их в крошечных проектах. Подключения idiorm является фактическим ORM, а Париж-это активная запись реализации. Вы можете использовать любой из них, который вам больше нравится.

Существует также a fork под названием Granada, который построен над Idiorm и Paris и добавляет поддержку, такую как нетерпеливая загрузка и т. д.

Поделиться


Arda    

07 сентября 2015 в 21:34



0

Если вам нужна модель «on the fly» DB, где таблицы автоматически подстраиваются под данные, которые вы выталкиваете из кода, взгляните на FoxORM для DataMapper подхода или RedBean для ActiveRecord подхода

Поделиться


Jo-Go    

26 октября 2016 в 18:20



0

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

Поделиться


Sunil Kumar Sain    

04 октября 2016 в 05:34


Похожие вопросы:

Какой фреймворк использовать для разработки игр iPhone?

Я хочу построить игру, похожую на iPhone Doodle jump. Может ли кто-нибудь сказать мне, какой фреймворк лучше всего использовать для его разработки, который будет быстрее и проще? Я путаюсь между…

Что лучше всего использовать ORM с codeigniter (фреймворк php) и почему?

Что лучше всего использовать ORM с codeigniter (фреймворк php) и почему?

Какой ORM использовать?

Я разрабатываю приложение, которое будет иметь эти классы: class Shortcut { public string Name { get; } public IList<Trigger> Triggers { get; } public IList<Action> Actions { get; } }. ..

Какой фреймворк ruby ORM использовать в автономном приложении ruby?

Я хотел бы использовать postgresql с внешними ключами для определения отношений в данных, чтобы другие платформы/приложения также могли легко использовать ту же базу данных. Наличие какого-то ruby…

Какой бэк — энд фреймворк лучше всего подходит для Android приложений?

Я занимаюсь разработкой приложения, android, и я хочу, чтобы реализовать PHP в качестве бэкэнда. Мне нравится спрашивать о том, какой фреймворк PHP подходит для разработки с приложением Android. Мое…

фреймворк лучше всего подходит для переноса существующего сайта пожертвований на фреймворк php?

какой фреймворк лучше всего перенести с существующего сайта обработки пожертвований php на фреймворк php ?? пожалуйста, предоставьте некоторые обоснования для вашего ответа .. У меня в голове три…

Это хорошая идея использовать фреймворк Yii с Doctrine 2 ORM?

Я люблю фреймворк Yii, он работает быстро,довольно круто и легко разрабатывается. Но теперь у меня есть проблема — я собираюсь разработать систему управления обучением со сложной доменной логикой, и…

PHP: ORM фреймворк или библиотека, которую я могу использовать со структурой таблицы базы данных

Я использовал KohanaPHP ORM, но я не могу использовать его со структурой таблицы базы данных. Итак, мне нужен фреймворк или библиотека ORM для использования с ним. С Коханой мне нужно следовать…

Какой фреймворк ORM лучше всего использовать с NodeJS и Informix DB. Также поддержка управления транзакциями

На самом деле я планирую использовать NodeJS для разработки веб-приложений, Мой бэк-энд DB-это Informix, я ищу фреймворк ORM, который лучше всего подходит для Nodejs, а также поддерживает транзакции…

ORM фреймворк для реактивных приложений

Я искал spring-data-r2dbc для реактивного доступа DB. Но, похоже, он не предоставляет никакого суппорта ORM, как указано на странице проекта, это не фреймворк ORM. Какие варианты существуют или…

Заглянем под капот Doctrine 2

Пожалуй, я не совру, если скажу, что в экосистеме Symfony наиболее часто используемой ORM является Doctrine. Поэтому изучение этой библиотеки крайне важно для Symfony-разработчика. В данной статье предлагаю заглянуть «под капот» этого Мустанга в мире ORM-ок и выяснить, на базе каких абстракций и паттернов построена эта библиотека.

Когда я впервые услышал о Doctrine, это была еще 1-я версия. Докладчик, которого я слушал, жаловался, какая это «бяка» и сколько головной боли она доставляла команде на проекте. Но с тех пор утекло много воды, и на момент написания статьи активно ведется разработка уже 3-ей версии библиотеки, существенно отличающейся от того, что она представляла собой изначально. Сами посудите, над библиотекой работают почти 600 контрибьюторов, которые зафиксировали уже почти 12 000 коммитов…однозначно, Doctrine достойна вашего внимания.

Об ORM в целом

Перед тем как углубиться в Doctrine 2, я бы хотел поговорить, как ни странно, о проблеме как о причине. Дело в том, что программные продукты не появляются просто так, это всегда следствие некоей проблемы, с которой мы столкнулись и которая существенно замедляет разработку проекта (а в ряде случае даже удорожает за счет усложнения кода и дальнейшей его поддержки).

Классический пример веб-приложения в плане компонентов — это UI, через который пользователь взаимодействует с приложением, backend, содержащий бизнес-логику, и persistence-уровень, в котором хранятся данные и в качестве которого выступает реляционная база данных (БД).

Учитывая, что знакомые нам реляционная БД и классические классы в ООП предполагают разные подходы к хранению данных, а также механизмы управления этими данными, возникает задача синхронизации изменений между этими уровнями.

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

ORM (Object Relational Mapper) — это как раз тот инструмент, который берет решение всех этих задач на себя. Помимо этого он предоставляет ряд дополнительных полезных возможностей, таких как Events, QueryBuilder, DQL для быстрого построения запросов и т. д.

Архитектура Doctrine 2

В основе Doctrine лежат паттерны и абстракции, понимание которых поможет лучше разобраться в принципах работы этой ORM. Начнем, пожалуй, с самого главного — Data mapper, т. к. Doctrine в общем виде и есть реализация этого паттерна.

Data Mapper pattern

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

Data mapper решает эту задачу за счет изоляции объектов и БД относительно друг друга и в качестве основной, концептуальной абстракции использует Entity.

По факту, Entity — это обычный PHP класс, где свойства сопоставлены с полями таблицы из базы данных, для которой и создавалась Entity (далее «сущность»). Всю же работу по маппингу полей, вычислению изменений и т.д. берет на себя mapper.

EntityManager

EntityManager (EM) — это классическая реализация паттерна Facade. Через его легкий API мы работаем с рядом подсистем: Unit Of Work, Query language и Repository API. Управление сущностями выполняется исключительно через API EntityManager-а.

Entity states

Сущность всегда находится в одном из 4-х состояний: New, Managed, Removed или Detached.

Когда вы только создали объект сущности и выполнили persist($entity), начальное состояние сущности будет New, которое после отработки логики persist (диспатч события, генерация идентификатора) EM переключает в Managed. Это означает, что теперь все изменения в объекте этой сущности будут отслеживаться EM и после вызова flush зафиксированы в БД. Также состояние Managed получают сущности, которые были получены из БД.

Состояние Detach используется не так часто, но бывают ситуации, когда есть необходимость обратиться к одной и той же сущности в контексте разных EM — тогда оно и может пригодиться. Сущность в состоянии Detach не отслеживается EM. Подчеркну, это не означает, что сущность удаляется, просто все изменения в объекте после вызова detach($entity) не будут никак отражены в базе данных, даже после вызова flush. Также важно помнить, что Doctrine позволяет каскадно применить Detach для всех связанных сущностей (ассоциаций).

И последнее состояние, Removed. Очевидно, что переключение сущности в это состояние имеет смысл только в случае, если сущность находится уже в Managed. Важно понимать, что после переключения сущности в Removed состояние, EM еще отслеживает изменения, но после выполнения flush сущность будет удалена из БД. По аналогии с Detach, также есть возможность управлять каскадным удалением ассоциаций.

Identity Map Pattern

Представьте ситуацию, когда в приложении вам по какой-то причине необходимо два раза запросить один и тот же объект из БД. Стоит ли в этом случае повторно обращаться к БД? Очевидно, что это нецелесообразно, по крайней мере в большинстве ситуаций.

Более логичным выглядит использование подхода, который позволял бы задействовать результаты первой выборки. Паттерн Identity Map (карта соответствий / присутствия) как раз решает эту задачу.

Давайте рассмотрим пример из официальной документации:

public function testIdentityMap()
{
    $objectA = $this->entityManager->find('EntityName', 1);
    $objectB = $this->entityManager->find('EntityName', 1);
 
    $this->assertSame($objectA, $objectB)
}

Второй вызов find не приведет к повторному обращению к БД. Напротив, ORM-ка в карте соответствий обнаружит объект с ID = 1 и вернет уже его.

Другое дело, когда в выборке задействованы критерии:

public function testIdentityMapRepositoryFindBy()
{
    $repository = $this->entityManager->getRepository('Person');
    $objectA = $repository->findOneBy(array('name' => 'Benjamin'));
    $objectB = $repository->findOneBy(array('name' => 'Benjamin'));
 
    $this->assertSame($objectA, $objectB);
}

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

Стоит упомянуть, что все же некая оптимизация и в этом случае присутствует: после выполнения второго запроса к БД новый объект сущности создан не будет, задействуется объект, который уже сохранен в карте.

Lazy Loading Pattern

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

Когда это полезно? Представьте: вы работаете с системой типа «форум», где пользователи могут оставлять посты в топиках. У вас возникла необходимость запросить сущность топика из БД, и поскольку комментарии являются связанными сущностями, можно предположить, что Doctrine запросит данные по ним, в том числе. Очевидно, что это лишний, неоправданный overhead на передачу данных, лишние запросы, кроме этого, приложению потребуется больше памяти для хранения объектов комментариев.

Эту проблему Doctrine решает с помощью механизма ленивой загрузки (Lazy Loading). По умолчанию, кстати, этот механизм активирован для всех ассоциаций, всего же доступно три варианта:

  • LAZY (по умолчанию) — в память будет загружен только управляемый объект, а ассоциации будут подгружены только при первом обращении к ним;

  • EAGER — в память будет загружен как управляемый объект, так и все ассоциации;

  • EXTRA LAZY — в некоторых случаях, подгрузка всех связанных объектов нецелесообразна, даже если это происходит только при первом обращении. Скажем, вы хотите получить только количество связанных объектов Collection#count(). Для оптимального решения этой задачи можно задействовать EXTRA_LAZY опцию. В этом случае при выполнении любого из представленных ниже методов Doctrine не будет подгружать всю коллекцию в память:
Collection#contains($entity)
Collection#containsKey($key) (доступно начиная с Doctrine 2.5)
Collection#count()
Collection#get($key) (доступно начиная с Doctrine 2.4)
Collection#slice($offset, $length = null)

Proxy pattern

Для реализации lazy-механизма, а также решения partial object problematic, Doctrine на более низких уровнях оперирует, на самом деле, прокси-объектами.

Proxy-объект — это объект, который используется по месту или вместо реального объекта. Когда я говорю «по месту», имеется в виду, что мы можем запросить у EM не оригинальный объект сущности, а его прокси-вариант, и использовать аналогично оригиналу. Какие преимущества это нам дает?

Рассмотрим пример из документации. Допустим, мы знаем идентификатор $item и нам хотелось бы добавить его в коллекцию, желательно без загрузки этого элемента из БД, скажем, в качестве каких-то оптимизационных мероприятий. Это можно сделать довольно просто:

$item = $em->getReference('MyProject\Model\Item', $itemId);
$cart->addItem($item);

Если же попытаемся вызвать любой метод из $item, его состояние будет полностью инициализировано из БД. В этом примере $item является экземпляром proxy-класса, который был сгенерирован для Item сущности. Причем обратите внимание: нам не нужно писать дополнительную логику для прокси или реального объекта, Doctrine это делает прозрачно для нас.

Partial object problematic

Partial object — это объект, состояние которого полностью не инициализировано.

С коробки подобная ситуация невозможна, так как Doctrine инициализирует сущность полностью (за исключением ассоциаций). Но у вас вполне может возникнуть желание запрашивать в качестве оптимизации не все поля сущности. Это возможно для DQL с помощью ключевого слова partial:

<?php $q = $em->createQuery("select partial u.{id,name} from MyApp\Domain\User u");

Или напрямую через EM:

$reference = $em->getPartialReference('MyApp\Domain\User', 1);

Несмотря на то что в документации даются рекомендации не использовать partial objects, я не вижу в этом проблемы в случаях, когда нужно просто отдать конкретные поля клиенту через REST API и мы точно знаем, что объект больше никак не будет использоваться.

Transactional write-behind

Представьте, если бы каждый раз изменения какого-либо свойства сущности приводили бы к отправке запроса в БД. Очевидно, что в большинстве случаев это нежелательное поведение.

Transactional write-behind подход позволяет решить эту проблему за счет задержки между тем, когда изменились данные и когда они реально обновляются в БД. Мы можем вносить множество изменений, что-то добавлять, удалять или обновлять, но только после вызова flush все изменения уйдут в БД.

Причем Doctrine беспокоится о том, чтобы это происходило оптимальным способом. К примеру, довольно часто возникает ситуация, когда есть необходимость массовой вставки, обновления или удаления записей в таблице. Это так называемый Batch processing. За счет механизма Transactional write-behind, Doctrine справляется с этой задачей максимально эффективно.

Unit of Work pattern

Говоря о Unit of Work, необходимо упомянуть понятие бизнес-транзакции (или бизнес-действия). В контексте PHP это время от начала запуска runtime до его завершения. Задача Unit of Work следить за всеми действиями приложения, которые могут изменить БД в рамках одной бизнес-транзакции. Когда бизнес-транзакция завершается, Unit of Work выявляет все изменения и вносит их в БД, параллельно оптимизируя этот процесс.

Подведем итог

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

Спасибо, что читали, буду рад фидбеку и предложениям. Всех благ!

Как Doctrine 2 помогает повысить производительность проекта на Symfony, читайте здесь.

Stfalcon.com обладает солидной экспертизой в разработке проектов на Symfony, и мы всегда готовы поделиться опытом. Пишите нам — будем рады сотрудничеству!

ORM — Русская документация kohana 3

Одним из самых важных модулей Kohana является ORM, неотъемлемая часть любого серьезного фреймворка. ORM позволяет представить работу с базой данных как взаимодействие объектов, выкидывая из кода большинство операций чтения, удаления, создания и изменения данных.

ORM в Kohana

Реализация ORM в Kohana позволяет представить запись из базы данных в виде экземпляра объекта, который имеет различные методы взаимодействия, такие как изменение, сохранение, удаление и некоторые другие. Помимо того, с помощью незагруженного (пустого) экземпляра объекта может производится поиск (загрузка) одной или нескольких записей. Каждый объект представляется в виде PHP-класса, унаследованного от класса ORM и должен располагаться в папке classes/model/.

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

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

Стандарты именования

Рекомендуется соблюдать следующие стандарты именования таблиц, полей и классов при работе с ORM:

  • Название модели должно быть в единственном числе. Например, Model_Post, Model_Category, Model_User_Token. Однако, существуют некоторые исключения, связанные с особенностью английского языка, например, Model_News.

  • Название таблицы должно быть во множественном числе. К примеру, posts, categories, users_tokens.

  • Название полей, предназначенных для связи с другими таблицами, должны быть в единственном числе и оканчиваться на _id. Например, не post.category, а post.category_id, не token.user, а token.user_id, не product.default_photo, а product.default_photo_id.

Базовое использование

Базовое использование подразумевает простейшие действия с объектами — чтение, изменение, запись.

Определение модели

Чтобы определить модель ORM, создайте в папке classes/module класс, унаследованный от ORM:

class Model_City extends ORM { }

На этом, формально, создание модели можно окончить. Остальные настройки (название таблицы, первичный ключ, названия столбцов и т.д. Kohana сгенерирует сама, исходя из названия модели (в данном случае, это — city). Тем не менее, мы рассмотрим их далее.

Название таблицы

Название таблицы хранится во внутреннем параметре объекта _table_name:

protected $_table_name = 'custom_table';

Первичный ключ

Названия поля первичного ключа находится в параметре _primary_key и по умолчанию оно установлено в id:

protected $_primary_key = 'custom_pk';

Первичные ключи, состоящие из нескольких полей, в данный момент не поддерживаются. Их реализация должна появиться с выходом Kohana 3.3

База данных

По умолчанию используется стандартная БД, но это можно поменять в параметре _db_group:

protected $_db_group = 'customdb';

Создание модели

Создание модели происходит с помощью метода ORM::factory($model), где $model — название модели, либо прямым созданием экземпляра объекта:

$city = ORM::factory('city');
$city = new Model_City;

После выполнения кода будет создана пустая модель сity.

Рекомендуется использовать именно первый вариант, т.к. с помощью него можно создавать конструкции вида

ORM::factory('city')->method1()->method2()->...

Доступ к модели

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

$city = ORM::factory('city');
echo $city->name;

Также, мы можем преобразовать объект в массив:

$city = ORM::factory('city')->as_array();
echo $city['name'];

Загрузка модели

Чтобы загрузить модель, зная ее первичный ключ, можно использовать тот же ORM::factory($model, $id), где $model — название модели, а $id — значение первичного ключа, либо через стандартный конструктор классов:

$product = ORM::factory('product_photo', 4);
$product = new Model_Product_Photo(13);

Если первичный ключ неизвестен, и нужно подобрать запись, соответствующую некоторым условиям, можно использовать метод find():

$city = ORM::factory('city')->find();

В данном случае, условий нет, и будет возвращена первая запись из таблицы. Условия ставятся напрямую к таблице используя Kohana Query Builder с помощью методов where, having, order_by, join, select, group_by, limit, offset и т.д. Пример использования:

$city = ORM::factory('category')
	->where('name', '=', 'Dresses')
	->where('active', '=', TRUE)
	->limit(20)
	->order_by('posted', 'DESC')
	->find();

Также, условия можно передавать в метод ORM::factory или конструктор через массив:

$city = ORM::factory('category', array('name' => 'Dresses', 'active' => TRUE));

В этом случае все переданные условия будут вставлены с помощью AND WHERE.

Если для заданного условия не нашлось ни единой записи, то будет возвращен пустой объект. Когда нужно проверить, загружен ли объект из базы или нет, нужно использовать метод loaded():

$category = ORM::factory('category', 10);
 
if( ! $category->loaded())
{
	throw new HTTP_Exception_404('Category not found');
}

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

Загрузка нескольких моделей

Практически всегда требуется загрузить несколько моделей, отвечающим условиям, для этого Kohana предоставляет метод find_all():

$dogs = ORM::factory('dog')
	->where('name', '=', 'Bob')
	->find_all();

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

$dogs = ORM::factory('dog')
	->where('home', '!=', NULL)
	->limit(15)
	->find_all();
 
foreach($dogs as $dog)
{
	echo $dog->name;
}

Более подробно об использовании Database_Result можно прочитать в руководстве по базам данных.

Изменение модели

Для изменения модели доступно несколько методов. Первый из них — прямое обращение к публичным параметрам модели:

$city->name = 'Moscow';

Также доступен метод set($column, $value), где $column — имя столбца, а $value — устанавливаемое значение, в основном используется для создания подобных конструкций:

$city = ORM::factory('city')
	->set('name', 'Moscow')
	->set('popularity', 20000000);

И для массовой загрузки значений доступен метод values($data, $excepted), где $data — массив, индексами которого являются названия столбцов, а элементами — их значения, и необязательный параметр $excepted — массив значений, которые будут взяты из массива, если параметр пустой, то будут взяты все значения:

$city = ORM::factory('country')->values(array(
	'name' => 'Russia',
	'popularity' => 140000000,
));

Второй параметр полезен для случаев, когда данные вставляются в модель сразу от пользователя (например, из $_POST):

$account = ORM::factory('account')
	->set('balance', 0);
	->values($_POST, array('name', 'country'));

В данном примере, из всех пользовательских данных в модель попадут только name и country, а balance, даже если и будет присутствовать в $_POST, все равно установится в 0.

Сохранение модели

После изменения модели, чаще всего, требуется ее сохранять. Для этого есть методы update(), который обновляет запись, create(), который создает запись в базе данных, и save(), который обновляет запись, если она уже существует, либо создает ее. Пример использования:

ORM::factory('user', 6)
	->set('balance', 60)
	->save();

Удаление модели

Для удаления существует единственный метод delete() — который производит удаление записи из базы данных и стирание объекта. пример:

$users = ORM::factory('user')
	->where('last_activity', '<', time() - Date::YEAR)
	->find_all();
 
foreach($users as $user)
{
	$user->delete();
}

Подсчет всех записей

Чтобы подсчитать количество всех записей в базе доступен метод count_all():

$active_users = ORM::factory('user')
	->where('last_activity', '>', time() - Date::MONTH)
	->count_all();

В результате будет сгенерирован следующий запрос:

SELECT COUNT(*) AS `records_found` FROM `users` AS `user` WHERE `last_activity` > 1323458064

Будьте аккуратны с условиями having, group_by и limit. Они могут неоднозначно повлиять на результат подсчета.

Связи

Связи в ORM позволяют строить связи между таблицами как вложенные параметры объектов. Например, существуют таблицы city (город) и country (страна). При должной настройке ORM-связей, вы сможете производить действия над моделью country напрямую из city:

$city = ORM::factory('city', 8);
echo $city->title.', '.$city->country->title;

Результатом может быть строка Mosow, Russia. Чтобы создать связь, необходимо, чтобы все связываемые таблицы имели объявление модели ORM.

Kohana предоставляет 4 типа связей для объектов:

  1. Один к одному (has one). Данный тип связей используется, когда для одной записи из одной таблицы имеется одна запись из другой. Пример реализации: у каждого автора из таблицы users есть 1 запись из таблицы passports.

  2. Много к одному (belongs to). Этот тип связи используется, когда для многих записей из одной таблицы имеется одна запись из другой. Пример: для каждой записи из таблицы posts имеется одна категория из таблицы categories. Другими словами, можно сказать, что запись (posts) принадлежит (англ. belongs to) к категории (categories).

  3. Один к многим (has many). Тип связи подразумевает, что у одной записи есть много записей из другой таблицы, причем принадлежащие только ей. Например, у одного города (cities) может быть несколько жителей (users). Тем не менее, один житель может принадлежать только к одному городу.

  4. Много ко многому (has many through). Связь используется, когда у многих записей из одной таблицы может быть много записей из другой. Например, у каждой записи в блоге (posts) существуют теги (tags). Причем, один и тот же тег может принадлежать нескольким записям одновременно. Для построения подобной связи используется вспомогательная таблица, название которой составляется из двух соединяемых таблиц. В этом случае, например, название может быть posts_tags.

Настройка связей производится с помощью внутренних (protected) параметров класса _has_one, _belongs_to и _has_many при определении модели. Параметры должны быть заданы в виде массива, где индексы — это названия связей, а элементами — настройки для связи, которые мы разберем ниже. Таким образом, мы можем настраивать неограниченное количество связей разного типа:

class Model_City extends ORM {
	protected $_belongs_to = array(
		'country' => array(...),
	);
 
	protected $_has_many = array(
		'users' => array(...),
		'houses' => array(...),
	);
}

Таким образом, приведенная в примере модель города city может принадлежать стране (country) и содержать несколько пользователей (users) и домов (houses). После составления модели, мы сможем обращаться к связям, как к параметрам объекта:

$city = ORM::factory('city')->where('name', '=', 'London')->find();
echo $city->country->name;
$users_list = $city->users;

Один к одному

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

  • model — имя модели ORM связываемой таблицы.

  • foreign_key — название столбца в связываемой таблице, по которому будет проходить связь с первичным ключом первой таблицы. По умолчанию, это поле устанавливается в значение «имя первой таблицы в единственном числе + _id». Например, при связи таблицы users с passports, это поле по умолчанию установится в user_id.

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

Пример реализации:

class Model_User extends ORM {
	protected $_has_one = array(
		'passport' => array(
			'model' => 'passport',
			'foreign_key' => 'user_id',
		),
	);
}
class Model_Passport extends ORM {}
$user = ORM::factory('user', 63);
echo $user->passport->id; // 1
echo $user->passport->registration_date; // 2012-01-25

В данном случае, будет сгенерировано два sql запроса:

SELECT `user`.* FROM `users` AS `user` WHERE `user`.`id` = 63 LIMIT 1;
SELECT `passport`.* FROM `passports` AS `passport` WHERE `passport`.`user_id` = '63' LIMIT 1;

Много к одному

Настройки этих связей хранятся в параметре _belongs_to, каждый из элементов также имеет свои настройки:

  • model — имя модели ORM связываемой таблицы.

  • foreign_key — название столбца в первой таблице, по которому происходит связь с первичным ключом второй таблицы. По умолчанию, также генерируется имя, состоящее из «названия второй таблицы в единственном числе + суффикс _id». Например, для связи posts с categories установится значение category_id.

Дальнейшая логика происходит примерно также, как и в связи «один к одному». Рассмотрим сразу пример реализации:

class Model_Post extends ORM {
	protected $_belongs_to = array(
		'category' => array(
			'model' => 'category',
			'foreign_key' => 'category_id',
		),
	);
}
class Model_Category extends ORM {}
$post = ORM::factory('post', 2);
echo $post->category->name; // Auto
echo $post->category->id; // 4

После запуска этого примера, будет выполнены следующие sql-запросы:

SELECT `post`.* FROM `posts` AS `post` WHERE `post`.`id` = 2 LIMIT 1
SELECT `category`.* FROM `categories` AS `category` WHERE `category`.`id` = '4' LIMIT 1

Один ко многим

Для хранения настроек этого типа связи используется параметр _has_many. Доступные настройки при этом следующие:

  • model — имя модели ORM связываемой таблицы.

  • foreign_key — название столбца во второй таблице, по которому будет идти связь с первичным ключом первого. По умолчанию, оно устанавливается в «название первой таблицы в единственном числе + суффикс _id». Примером для связи cities с users будет значение city_id.

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

class Model_City extends ORM {
	protected $_has_many = array(
		'users' => array(
			'model' => 'user',
			'foreign_key' => 'city_id',
		),
	);
}
class Model_User extends ORM {}
$city = ORM::factory('city', 1);
$users = $city->users->find_all();
foreach($users as $user)
{
	echo 'user '.$user->id.' ';
} // user 63

После выполнения этого кода, будет сгенерированы следующие sql-запросы:

SELECT `city`.* FROM `cities` AS `city` WHERE `city`.`id` = 1 LIMIT 1
SELECT `user`.* FROM `users` AS `user` WHERE `user`.`city_id` = '1'

Многие ко многим

Для создания данного типа связи используется параметр _has_many, как и для связи «Один ко многим», с единственным отличием, что настроек больше:

  • model — имя модели ORM связываемой таблицы.

  • through — имя промежуточной таблицы, через которую будет осуществляться связь между первичными ключами двух моделей. Является обязательной для указания, иначе выполнится связь «Один ко многим». Принято имена таблиц указывать в стиле «название первой таблицы во множественном числе _ название второй таблицы во множественном числе». В нашем примере для связи между posts и tags это будет posts_tags.

  • foreign_key — имя столбца в промежуточной таблице, который будет выполнять связь с первичным ключом первой таблицы. Если параметр не указать, он будет составлен из «названия первой таблицы в единственном числе + суффикс _id», например, post_id.

  • far_key — имя столбца в промежуточной таблице, который будет выполнять связь с первичным ключом второй таблицы. Если параметр не указать, он будет составлен из «названия второй таблицы в единственном числе + суффикс _id», например, tag_id.

Логика этой связи строится на выборе из второй таблицы всех записей, для которых существует запись посредством связи их первичного ключа и far_key в промежуточной таблице такая, что foreign_key равен первичному ключу найденного объекта.

С помощью языка sql это можно объяснить следующим образом (first — имя первой таблицы, second — имя второй таблицы, through — имя промежуточной таблицы, а 63 — первичый ключ найденного объекта):

SELECT `second`.* FROM `second` JOIN `through` ON (`through`.`far_key` = `second`.`id`) WHERE `through`.`foreign_key` = 63

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

Например:

class Model_Post extends ORM {
	protected $_has_many = array(
		'tags' => array(
			'model' => 'tag',
			'through' => 'posts_tags',
		),
	);
}
class Model_Tag extends ORM {}
$post = ORM::factory('post', 63);
$tags = $post->tags->find_all();
foreach($tags as $tag)
{
	echo $tag->id.', ';
} // 1, 2, 3, 

В данном случае, будет сгенерированы следующие sql-запросы:

SELECT `post`.* FROM `posts` AS `post` WHERE `post`.`id` = 2 LIMIT 1
SELECT `tag`.* FROM `tags` AS `tag` JOIN `posts_tags` ON (`posts_tags`.`tag_id` = `tag`.`id`) WHERE `posts_tags`.`post_id` = '2'

Добавление связи

Чтобы добавить к текущему объекту связь с другом объектом, доступен метод add($alias, $far_keys), где $alias — имя связи, а $far_keys — объект (объекты) для связи. Последний параметр можно указать несколькими способами:

  • Первичный ключ объекта

  • Массив первичных ключей нескольких объектов

  • Сам объект (загруженный)

Пример добавления связи с загруженным объектом:

$post = ORM::factory('post', 63);
$tag = ORM::factory('tag')
	->where('name', '=', 'Breaking bad')
	->find();
$post->add('tag', $tag);

После добавления связи сохранять объект не нужно, запрос к базе данных генерируется в момент запуска метода add.

Удаление связи

Чтобы удалить связь с другим объектом, доступен метод remove($alias, $far_keys), где $alias — имя связи и $far_keys — объект или объекты. Пследний параметр также можно задать несколькими способами:

  • Первичный ключ объекта

  • Массив первичных ключей нескольких объектов

  • Сам объект (загруженный)

  • NULL, в этом случае удалятся связи со всеми объектами

Пример удаления связей с несколькими объектами:

$post = ORM::factory('post', 63);
$post->remove('tag', array(555, 666));

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

Проверка наличия связи

Для того, чтобы проверить, существует ли у объекта связь с другим или другими, совершенно необязательно производить поиск. Kohana предоставляет метод has($alias, $far_keys), который позволяет проверить, существует ли у текущего объекта связь с объектами $far_keys через связь $alias. Параметр $far_keys, опять же, можно задать любым удобным способом:

  • Первичный ключ объекта

  • Массив первичных ключей нескольких объектов

  • Сам объект (загруженный)

Метод возвращает TRUE, если существует связь сразу со всеми заданными объектами, и FALSE в другом случае.

Пример реализации проверки связи:

$post = ORM::factory('post', 63);
if($post->has('tag', 4))
{
	// Запись с id = 63 имеет связь с тегом с id = 4
}

Подгрузка связей

Подгрузка связей работает только со связями типа «Один к одному» (has one) и «Много к одному» (belongs to).

Генерация еще одного sql запроса при каждом обращении к связям не всегда может устраивать, поэтому kohana предоставляет метод with($target_path), позволяющий подгрузить связь $target_path в одном запросе к базе данных, используя конструкцию sql JOIN. Пример подгрузки связи «много к одному»:

$posts = ORM::factory('post')
	->with('category')
	->find_all();
foreach($posts as $post)
{
	echo $post->category->name;
	echo $post->category->id;
}

В данном случае сгенерируется всего 1 sql-запрос:

SELECT `category`.`id` AS `category:id`, `category`.`name` AS `category:name`, `post`.* FROM `posts` AS `post`
LEFT JOIN `categories` AS `category` ON (`category`.`id` = `post`.`category_id`)

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

class Model_Post extends ORM {
	protected $_load_with = array('category');
	...

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

$posts = ORM::factory('post')->find_all();
foreach($posts as $post)
{
	echo $post->category->name;
	echo $post->category->id;
}

У связанного объекта тоже могут быть связи. Чтобы подгрузить в одном запросе и их, необходимо указать их методу with() через двоеточие ::

$posts = ORM::factory('post')
	->with('category:country')
	->find_all();

Можно комбинировать и подгружать несколько связей вместе:

$cities = ORM::factory('city')
	->with('region:country')
	->with('category')
	->find_all();
foreach($cities as $city)
{
	echo $city->region->country;
	echo $city->category;
}

Вложенность и количество этих связей ничем не ограничена.

Валидация

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

Составление правил

Составление правил происходит в публичном методе rules() при определении модели. Метод должен отдавать массив, индексами которого должны являться названия полей объекта, а элементами — массивы правил для них. Приведем пример:

class Model_Post extends ORM {
	public function rules()
	{
		return array(
			'title' => array(
				array('not_empty'), array('max_length', array(':value', 200)),
			);
		);
	}
}

В этой модели для поля title будут установлены два правила: not_empty(:value) и max_length(:value, 200) (:value — значение поля).

Зачем объявление правил сделано в методе, а не в параметре объекта? Дело в том, что с помощью метода можно реализовать наследование правил при наследовании классов. Это бывает очень полезно, например, в реализации класса Model_Account (аккаунт) объявить правила для полей логина и пароля, а в классе Model_Account_User extends Model_Account (аккаунт пользователя) добавить правила для имени и фамилии.

Пример:

class Model_Account {
	public function rules()
	{
		return array(
			'password' => array(...),
			'username' => array(...),
		);
	}
}
class Model_Account_User extends Model_Account {
	public function rules()
	{
		return array_merge(parent::rules(), array(
			'firstname' => array(...),
			'lastname' => array(...),
		));
	}
}

В итоге, в классе Model_Account_User будут правила для полей password, username, firstname и lastname.

Проверка

Проверка запускается автоматически при сохранении объекта (методы save, update, create), а также через отдельный метод check. Вне зависимости, какие поля были изменены, проверка идет полностью по всем заданным правилам. Пример:

$user = ORM::factory('user')
	->set('email', '[email protected]');
$user->check();

Если после последней проверки вы не изменяли объект, то при сохранении новой проверки не будет.

Для всех вышеперечисленных методов существует единственный опциональный аргумент $extra_validation — произвольный объект валидации, который будет проверен вместе с объектом.

Для чего он нужен? Часто, в самой модели невозможно предусмотреть проверку некоторых полей. Например, таких, как поле с проверочными символами (captcha), чекбокс о принятии пользовательского соглашения и т.д.

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

Приведем пример:

$extra_validation = Validation::factory($_POST)
	->rule('terms_agree', 'not_empty'); // Дополнительная валидация, что поле terms_agree не пустое
$user = ORM::factory('user')
	->values($_POST, array('username', 'email', 'password')); // достаем из $_POST поля username, email, password
$user->save($extra_validation); // Обе валидации запускаются в этом методе

В этом примере, помимо валидации данных модели, идет проверка, что пользователь отметил чекбокс terms_agree (пользовательское соглашение). В случае, если чекбокс не отмечен, либо какое-то другое поле не заполнено (в зависимости от внутренних правил модели user), будет вызвана ошибка валидации.

Перехват ошибок

При возникновении ошибки Kohana генерирует исключение ORM_Validation_Exception, которое содержит методы для получения списка ошибок и работы с ними. Поэтому, метод, содержащий проверку всегда нужно заключать в конструкцию try … catch:

try
{
	$model->save();
	echo 'Модель успешно сохранена';
}
catch(ORM_Validation_Exception $e)
{
	echo 'Произошла ошибка';
}

Перехватываемое исключение содержит метод errors($directory, $translate), с двумя необязательными аргументами $directory — директорию, из которой брать сообщения ошибок (messages) и $translate — флаг, при котором будет произведен еще и перевод сообщений.

Пример:

try
{
	$model->save($some_extra_validation);
	$this->request->redirect('successpage');
}
catch(ORM_Validation_Exception $e)
{
	$errors = $e->errors();
	// выводим список ошибок $errors в своем представлении
}

Проверка нескольких моделей одновременно

Иногда встает задача, которая требует сохранения нескольких моделей, только если все они валидны. Реализацию проверки и красивый вывод ошибок можно реализовать с помощью использования некоторых функций исключения ORM_Validation_Exception.

Для начала, создадим пустой объект исключения:

$error = new ORM_Validation_Exception('', Validation::factory(array()));

В первом аргументе мы передаем пустое имя валидации, а во втором — пустой объект валидации. Таким образом, у нас есть исключение об ошибке, не содержащее никаких ошибок. Затем, мы создаем сами модели и вставляем в них значения:

$ticket = ORM::factory('support_ticket')->values($_POST, array('subject', 'category_id'));
$reply = ORM::factory('support_reply')->values($_POST, array('message'));

Как должно быть понятно из названий объектов и параметров в этом коде, мы создаем тикет (support_ticket) в систему поддержки, и сразу же добавляем к нему одно сообщение (support_reply). Понятно, что данные из формы должны удовлетворять правилам как тикета support_ticket (это поля категории category_id и темы subject), так и первого в нем сообщения support_reply (поле сообщения message).

Далее нам потребуется созданное нами исключение. Мы будем проверять обе модели с помощью метода check(), и в случае перехвата ошибки, объединять ее с нашим пустым исключением с помощью метода исключения merge:

try
{
	$ticket->check();
}
catch(ORM_Validation_Exception $e)
{
	$error->merge($e);
}
try
{
	$reply->check();
}
catch(ORM_Validation_Exception $e)
{
	$error->merge($e);
}

Чтобы проверить, какие появились ошибки, нужно вызвать метод errors(), который мы разбирали выше. В случае, если ошибок не возникало, этот массив будет пустым, иначе ошибки для каждого объекта будут записаны в отдельном элементе. Поэтому, завершить этот код можно следующим образом:

$errors = $error->errors();
if( ! $errors)
{
	$ticket->save();
	$reply->set('ticket', $ticket)->save();
	// Сохранение прошло успешно
}
else
{
	// Массив $errors содержит все допущенные ошибки
}

Фильтры

Нередко, перед сохранением записи в базу данных, нужно совершить определенные действия над ее полями. Например, перекодировать строку, сохранить файл на диске сервера, преобразовать произвольную дату в понятный базе данных тип timestamp и т.д. Для этого существует фильтры — функции (методы), которые выполнятся перед сохранением записи, и результат выполнения которых будет значением определенных полей. Как и правила валидации, фильтры объявляются через специальный публичный метод filters(), который должен возвратить массив, индексами которого будут названия полей, а элементами — массивы фильтров для них.

Фильтр задается в виде массива, первый элемент которого — название функции, и, опциональный второй — массив аргументов, передаваемых функции.

Название фильтра можно указать несколькими способами:

  • Название php функции, например, intval или trim.

  • Статический метод класса через ::, например, Text::random

  • Массив, первым элементом которого является экземпляр класса, а вторым — строковое название его метода, например, array($this, 'some_method').

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

  • :field — название поля.

  • :model — текущая модель.

  • :value — значение поля.

Пример задания фильтров:

class Model_Post extends ORM {
public function filters() 
{
	return array(
		'posted' => array(
			array('strtotime'),
		),
		'title' => array(
			array('Custom_Class::clean', array(':model', ':value')),
		),
	);
}

В данном случае, поле posted преобразуется из произвольного формата времени в unix timestamp с помощью функции strtotime, а поле title обработается статическим методом clean класса Custom_Class.

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

class Model_Post extends ORM {
public function filters() 
{
	return array(
		TRUE => array(
			array('trim'),
		),
	);
}

В данном случае, все поля подвергнутся обработке их функцией trim.

Кеширование

Кеширование запросов к БД — одна из первых задач, возникающих при работе приложения. С помощью Kohana можно реализовать несколько способов кеширования.

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

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

Полное кеширование

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

class Model_Track extends ORM {
	protected $_reload_on_wakeup = FALSE;

Реализация непосредственного кеширования выглядит так:

// Проверяем, есть ли эти записи в кеше.
if( ! $most_active_users = unserialize(Cache::instance()->get('widget.most_active_users')))
{
	// Записей нет, поэтому выбираем их из БД
	$most_active_users = ORM::factory('user')
		->limit(5)
		->order_by('activity_sum', 'DESC')
		->find_all();
 
	// Сохраняем записи в кеш на 10 минут
	Cache::instance()->set('widget.most_active_users', serialize($most_active_users), Date::MINUTE * 10);
}
else
{
	// Записи получены из кеша. В этом блоке можно что-нибудь с ними сделать
}
// В этом участке кода записи будут загружены в любом случае

После выполнения этого кода нужные данные будут доступны в переменной $most_active_users.

Кеширование по id

Для реализации этого типа кеширования нужно установить тот же самый внутренний параметр _reload_on_wakeup в TRUE. Собственно, так он и стоит по умолчанию:

class Flower extends ORM {
	protected $_reload_on_wakeup = TRUE;

Базы данных — Всё о базах данных: разработка, пакеты, ORM, конфигурирование, оптимизация

Базы данных

Оптимизация MySQL: индексы, медленные запросы, конфигурация

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

Оптимизация конфигурации

Первое, что каждый пользователь MySQL должен сделать для повышения производительности — это настроить конфигурацию. Однако, большинство этот шаг пропускают. В 5.7 (текущая версия) настройки по умолчанию стали намного лучше, чем у её предшественников, но улучшить их по-прежнему можно и несложно.

Базы данных

[Квест] Как хакнуть форму? Sql инъекции.

Эта статья является статьёй-квестом. Мы желаем вам успехов в его прохождении. Итоги вашего прохождения будут опубликованы позже (следите за новостями в соц. сетях), а также всем прошедшим в дальнейшем будет выслан инвайт для регистрации на сайте.


Ставьте лайки, делитесь с друзьями и коллегами, репостите в соц.сетях.

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

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

Базы данных

Кэширование запросов с помощью PHP и MySQLnd


Несмотря на то что у MySQL есть встроенное кэширование запросов, оно всё равно имеет некоторые проблемы:






Плюсы

Минусы

Простота использования: просто включить в конфиге MySQL

Упрощённый: он ничего не знает о ваших нуждах

Прозрачно: не требуются изменения в приложении.

Легко аннулируется: любые изменения в таблице сбросят все связанные с ней данные, даже если это не нужно

(см. Упрощённый)

 

Однопоточный: так как кэш однопоточный, он может в действительности вредить производительности


Мы можем решить эти проблемы, используя кэширование на уровне приложения, но как нам достичь простоты и прозрачности использования, не создавая себе новых проблем?


И вот тут на сцену выходит плагин mysqlnd_qc.

Базы данных

Введение в интерфейс Мemcached для MySQL InnoDB


В предыдущих статьях серии:


В MySQL 5.6 появилось memcache-совместимое хранилище ключ-значение на базе движка Innodb.


InnoDB Memcache Daemon предоставляет вам стабильность innodb для данных вида ключ-значение, доступ к которым может быть организован через более быстрый и оптимизированный протокол memcached. При использовании данного протокола будут пропущены: парсинг запроса, его оптимизация и остальные части обработки, которые не требуются.


С помощью mysqlnd_memcache, вы можете прозрачно направлять ваши запросы к такому memcache-совместимому интерфейсу.

Базы данных

Продвинутое разделение чтения и записи с помощью MySQLnd в PHP. Часть 2.


Продолжение статьи


Шардинг и секционирование


Запросы на запись очень трудно распределить на множество машин (например, мульти-мастер репликация) традиционными средствами MySQL (т.е. не используя MySQL Cluster). Поэтому зачастую используется секционирование или шардинг. Это позволит вам равномерно распределить запросы среди множества ведущих серверов, записывая разные данные на каждый из них.

Базы данных

Продвинутое разделение чтения и записи с помощью MySQLnd в PHP. Часть 1.


От переводчика: нам показалось, что эту статью долго не только переводить, но и читать. Поэтому мы решили разбить её на две части.


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


Множественные конфигурации


Те, кто внимательно читал первую часть могли заметить, что в файле конфигурации mysqlnd_ms имеется ключ первого уровня (в дальнейшем примере «appname»), который содержит все наши настройки. Это позволяет задать несколько вариантов конфигураций в одном файле.

Базы данных

Простое разделение чтения и записи с помощью MySQLnd в PHP


MySQL всегда был основной базой данных для работы с PHP, так сложилось исторически, практически с самого начала. Конечно, некоторые используют PostgreSQL, SQL Server, или Oracle, но для интернет-проектов MySQL обычно является предпочтительной реляционной БД.


Это было связано, в основном, с легкостью внедрения и применения MySQL. Libmysqlclient шел в комплекте с PHP до тех пор, пока эта библиотека не была повторно лицензирована под GPL. После чего она была удалена из-за невозможности распространения вместе с PHP.


Это сделало процесс сборки для PHP немного более сложным, потому что теперь Libmysqlclient должна была быть доступна на хостинге.

ORM OM NOM NOM или тайны ORM в 1С-Битрикс

О чем и для кого эта статья

Эта статья – одна из самых популярных страниц нашего сайта. Несколько сотен человек каждый день читают ее. Мы опубликовали важнейшую для мира Битрикс-разработки справочную информацию за полгода до появления официальной документации.

Статья будет вам интересна, если Вы уже видели и слышали что-то про ORM в

1С-Битрикс: Управление сайтом

, и даже пробовали

разрабатывать сайты на 1С-Битрикс

с собственными ORM-классами. Статья состоит из трех частей:

  • Краткое напоминание о базовых возможностях ORM в БУС
  • Генератор ORM-классов
  • Подробно про работу ORM c БД. Реальный случай из практики: использование ORM для подключения из linux’а к MSSQL БД и выбора данных из хранимых процедур вместо таблиц

Базовые возможности ORM в 1С-Битрикс: Управление сайтом

Согласно

SRP

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

В такой серьезной системе, как

1С-Битрикс: Управление сайтом

классов и обязанностей должно быть немало. Моя IDE подсказывает, что в Интернет-магазине версии 16.0.1 объявлено 2759 классов. Я точно уверен, что самая многочисленная “группа” — классы для работы с таблицами в БД.

CIBlockElement

для работы с таблицей b_iblock_element (элементы инфоблоков),

CSaleOrder

для таблицы b_sale_order (заказы),

CUser

для работы с b_user (пользователи) и т.д. В БД сейчас 413 таблиц. Выходит, должно быть 413 классов для работы с каждой из них.

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

GetList

”, но это не более чем соглашение. Это нигде не было закреплено и никем не проверялось.

Более того, несмотря на общее название, эти методы вполне могли работать по-разному. вспомните 3 метода, имеющих одинаковое название:

  1. CUser::GetList

  2. CIBlockElement::GetList

  3. CSaleOrder::GetList

Пожалуй, только опытный программист сможет сходу назвать особенности их применения без подглядывания в справку. А ведь есть еще такие острые вопросы, как добавление в БД, обработка ошибок и т.п. И, зачастую, каждый класс решает “сам за себя”.

Но сейчас ситуация меняется. Появилось

новое ядро D7

, с новыми идеями, механизмами и концепциями. Поговорим об одной из них, краеугольной — ORM (Object Relation Model). Об ORM подробно рассказывают в

блоге разработчиков

и есть отличное руководство в

документации

. Постараюсь не повторяться и буду считать, что вы уже написали пару ORM-классов, ориентируясь на эти статьи.

Я выделю только основное. Если класс отвечает за доступ к таблице БД, он должен быть наследником класса

Bitrix\Main\Entity\DataManager

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


  1. getTableName

    для получения имени таблицы


  2. getMap

    для получения массива колонок таблицы — объектов

    Bitrix\Main\Entity\Field

Метод

getFilePath

, который упоминается в блоге, больше не является обязательным!

Хочется похвалить разработчиков за ORM. Это не просто слова и планы на будущее. На момент написания этого текста (декабрь 2015) переведено на “новые рельсы” 215 классов. То есть, больше половины всех классов для работы с БД уже имеют D7-аналоги и используются.


Выводы по базовым возможностям ORM в 1С-Битрикс: УС

. У нас появился очень мощный API для работы с БД с правильной современной архитектурой. Стоит незамедлительно переводить все свои старые классы на “ORM-рельсы”.

Руководство по разработке

этих классов достаточно подробное и отвечает на главные вопросы.

Автоматическая генерация ORM-классов

Первое, о чем хочется рассказать в этой статье об ORM — генератор ORM классов. По неизвестной мне причине он тщательно скрыт в недрах панели управления сайтом. Когда пользуешься им, возникает ощущение, что прикасаешься к чему-то запретному 🙂 Хотя в среде разработчиков о нем часто говорят: и на сайте

идей

, и в

блогах

.

Чтобы его использовать, нужно открыть страницу

Настройки > Производительность > Таблицы

и добавить GET-параметр orm=y. Адрес будет выглядеть так: /bitrix/admin/perfmon_tables.php?lang=ru&orm=y

После этого для любой таблицы в БД сайта можно автоматически создавать ORM-класс. Для примера выберем штатную таблицу шаблонов сайта

b_site_template

.

После перезагрузки страницы имеем следующий код:

код в Gist

. Результат после небольших преобразований может быть сведен к настоящему классу для работы с шаблонами, расположенному по пути

/bitrix/modules/main/lib/sitetemplate.php

.

Важная особенность генератора: поля описываются не объектами-потомками

Bitrix\Main\Entity\Field

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

Отличное подспорье для создателей модулей: генератор позволит поставить производство классов на поток.

Работа с удаленными БД

Помимо очевидного, есть под капотом ORM и куда более интересные возможности. Например, работа с разными БД (

вертикальный шардинг

)! Теперь, заканчивая работу по созданию класса никто не мешает сказать “ах да, эта таблица лежит в другой БД с другим логином и паролем”.

Никаких ограничений по сравнению с “локальными” таблицами нет. По таблицам внешней БД можно точно так же делать выборки, изменять записи, группировать и т.п. Нельзя только пытаться сделать JOIN таблиц в разных БД.

Чтобы указать, в какой БД требуется искать таблицу, в ORM-классе требуется переопределить метод

getConnectionName

. Здесь указывается псевдоним подключения (по умолчанию “default” — главное подключение, та же БД, в которую установлены штатные таблицы).

Само подключение должно быть вручную прописано в настройках ядра D7 (файл

/bitrix/.settings.php

), узел

connections > value > имя подключения

.

Если с host, database, login, password вопросов, в принципе, нет, то первый параметр className заслуживает отдельного внимания. Для этого потребуется сделать небольшое отступление и рассказать об организации работы с БД в новом ядре.

Нюансы работы с разными типами БД

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

работа с БД

. “Главными” по этому вопросу стали классы в пространстве имен

Bitrix\Main\DB

. Конкретно за подключение к БД и выполнение всех запросов отвечают классы семейства

Bitrix\Main\DB\Connection

, а именно:

Наверное, для 95% сайтов хватает этого набора (а для 90% только

Bitrix\Main\DB\MysqliConnection

). А что же делать, если подключение к БД очень экзотическое?

Например, у заказчика чрезвычайно устаревшая (или наоборот, слишком свежая) версия СУБД и невозможно использовать встроенный драйвер для PHP. В таких случаях на помощь спешат, конечно же, программисты.

Чтобы добавить в 1С-Битрикс: Управление сайтом поддержку нового типа БД, необходимо следовать простой инструкции:

  1. Создать класс подключения (наследник

    Bitrix\Main\DB\Connection

    ). В нем определить все “базовые” операции с БД: подключение, отключение, выполнение произвольного запроса, работу с транзакциями.
  2. Создать класс SQL-хелпер (наследник

    Bitrix\Main\DB\SqlHelper

    ) и возвращать его экземпляр в методе

    createSqlHelper

    . Класс предназначен для самой низкоуровневой работы с БД — он добавляет экранирование, работает с датами, предоставляет доступ к базовым SQL-функциям и т.п.
  3. Создать класс для результата выборки (наследник

    Bitrix\Main\DB\Result

    ). В нем требуется определить методы-обертки над традиционными функциями работы с результатом выборки.

Теперь вы знаете, какие className можно указывать в

/bitrix/.settings.php

и как создавать собственные подключения к БД.

Реальный пример: использование ORM для подключения из PHP к MSSQL в Linux

Как уже было отмечено выше, класс

Bitrix\Main\DB\MssqlConnection

основан на расширении sqlsrv, которое доступно только на windows-сервере. В одном из наших проектов возникла необходимость подключиться к MSSQL с linux-сервера, то есть решение от 1C-Битрикс нам не подходило (а компиляция драйвера в linux ничем хорошим не закончилась). Помогла природная смекалка и знание ООП.

На сервер было установлено расширение mssql (

http://php.net/manual/ru/book.mssql.php

) и была разработана следующая архитектура:

Был разработан собственный набор MSSQL-классов, многие методы были унаследованы от стандартных

Bitrix\Main\DB\Mssql*

. Пришлось буквально в паре десятков мест произвести замены вроде sqlsrv_query => mssql_query. К этому пакету (и способу его получения) вернемся в завершении статьи.

Выбор данных из хранимых процедур вместо таблиц

ORM подходит даже для таких экзотических запросов, как выборка данных не из таблицы, а из хранимых процедур. Такие процедуры могут быть созданы в MSSQL-базе данных. Что ж, попробуем “обмануть” ORM и подсунуть ей процедуру вместо имени таблицы.

Укажем название функции в методе

getTableName

.

Однако, сразу такой код работать не будет. Дело в том, что при использовании подключения

Bitrix\Main\DB\MssqlConnection

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

MS Sql query error: Invalid object name ‘foo_table_procedure()’. (400)

SELECT

[base].[bar] AS [BAR],

[base].[baz] AS [BAZ],

FROM [foo_table_procedure()] [base]

Увы, не получилось. На самом деле, мы в одном шаге от успеха, помешали только знаки “[“ и “]”, которыми

MssqlSqlHelper

защитил имя используемой “таблицы”. Проблема решается “в лоб” созданием собственного подключения (

Connection

) и

SqlHelper

’а.

На сервер было установлено расширение mssql (

http://php.net/manual/ru/book.mssql.php

) и была разработана следующая архитектура:

Где

self::isKnownFunctionCall

— метод проверки, который возвращает true, если в $identifier находится “foo_table_procedure()”.

Выводы

Новое ядро D7 уже здесь. Каждый месяц появляются все новые и новые классы, они постепенно заменяют старые. Если в Ваших проектах или модулях есть классы, чья ответственность — предоставление доступа к 1 таблице в БД (локальной или сторонней) — требуется его переписать, поставить “на рельсы» одной из ключевых фич в новом 1С-Битрикс: Управлении сайтом.

Что касается пакета классов для подключения с linux-сервера к MSSQL БД. Если Вы хотите получить этот пакет (3 класса:

MssqlConnection

,

MssqlSqlHelper

,

MsssqlResult

), поделитесь статьей в соц.сетях и заполните форму в конце страницы. Ссылка для скачивания файлов придёт вам на почту. 

Оцените статью:

Спасибо, ваш голос успешно добавлен!

Введение в ORM

Пока мы с вами рассмотрели два способа работы с базами данных в Кохане: с помощью SQL-запросов и с помощью Query Builder-а. В этом и последующих уроках мы поговорим о еще одном способе — взаимодействие с базой данных с помощью ORM (Объектно-реляционное отображение). ORM очень любят новички, а вот продвинутые программисты не всегда рекомендуют его использовать. Вообще все это напоминает ситуацию с ООП. Перед тем как перейти к объектно-ориентированному подходу, рекомендуется сначала нормально изучить процедурный подход. Но речь сейчас не об этом. ORM любят не зря — он очень прост и удобен. При использовании SQL-запросов приходится фактически учить еще один язык — SQL (хотя это тоже надо!). Правда проблема даже не в составлении этих запросов. А в том, что сейчас нам понадобилось вытащить все записи из таблицы, потом только одну с определенным id, через какое-то время — запись с определенными условиями, а в конце вообще связать две таблицы через JOIN и получить записи из обеих. Это получается в модели нам нужно под каждый запрос писать свой метод ? И начинаются танцы с бубном. Создается модель CRUD для четырех базовых запросов SQL, создаются условия вроде «если мы передали id, то вытаскиваем запись с этим id, а иначе вытаскиваем все записи» и так далее. Сплошная головная боль и проблемы. Query Builder немножко упрощает все это дело, но не сильно.
А теперь представьте, что таблица — это объект и нужную запись мы можем получить просто написав:

echo $название_таблицы->название поля;

то есть что-то вроде

Хотим изменить имя текущей записи на другое, просто пишем

$article->name = 'Работа с сессиями в Kohana';

Вот примерно таким образом ORM и работает. Фактически мы манипулируем данными БД как обычными объектами PHP. То есть нас избавляют от необходимости писать все эти «лишние» методы по вставке, удалению, обновлению и выборке данных.
Что мне больше всего понравилось — организация связей между таблицами. Не нужно прописывать миллион JOIN с условиями ON table1.id = table2.category_id. Достаточно один раз указать в каждой таблице эту связь (имя связанной таблицы и названия ключей для связи) и все, можно получать значения сразу из нескольких таблиц.
Как и модуль database, который мы включали в файле bootstrap.php, ORM тоже является модулем и его тоже нужно раскомментировать для подключения:

'orm'        => MODPATH.'orm',        // Object Relationship Mapping

Необходимо помнить еще о том, что модуль ORM не может работать без включенного модуля database, так как использует его методы. По этой же причине для модуля ORM не требуется свой конфигурационный файл. И наши Модели теперь будут наследовать не класс Model, как раньше, а класс ORM, то есть выглядеть наша новая Модель будет примерно так:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Model_Article extends ORM {
}

Фактически то, что мы видим — это уже рабочая модель, которая работает с таблицей articles. При этом данная таблица обязательно должна содержать поле первичного ключа.
Вообще при работе с ORM нужно придерживаться нескольких правил:
— Название модели должно быть в единственном числе. Например: Model_Article, Model_Category, Model_User.
— Название таблицы должно быть во множественном числе. Например: articles, users, roles.
Но в английском языке бывают слова, в которых образование множественного числа происходит не по общим правилам: слова в единственном и множественном числе пишуться одинаково (news, clothes, chess), слова-исключения (man-men, foot-feet) и так далее. Даже в нашем случае category станет categories, а не categorys. Чтобы избежать проблем есть возможность указывать название таблицы вручную. Делается это так:

protected $_table_name = 'categories';

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

protected $_primary_key = 'my_id';

— Поля для связи с другими таблицами должны быть в единственном числе и заканчиваться на _id. Например: article_id, category_id, user_id. Я лично такие поля с самого начала изучения SQL так именую, поэтому у меня проблем с привыканием не возникло.
В случае, если для работы Модели нужно использовать не стандартную БД, а какую-то другую, достаточно указать ее название:

protected $_db_group = 'my_db';

В конечном итоге ваша модель может выглядеть вот так:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Model_Category extends ORM {
    protected $_table_name = 'categories';
    protected $_primary_key = 'cat_id';
    protected $_db_group = 'my_db';
}

Если же вы пользуетесь дефолтной БД и правилами именования ORM для таблиц и полей, то все эти свойства можно опустить (что и происходит в 99% случаев).
В следующем уроке мы уже вплотную займемся практикой и будем получать записи из БД, причем вы увидите, что основная работа уже будет вестись внутри контроллера, а не модели.

| Вперед >> | Обсудить на форуме

К записи оставлено 8 коммент.

Оставить комментарий или два

Propel, невероятно быстрый PHP 5.5 ORM

с открытым исходным кодом

Установка

Через Composer

  "требуется": {
    "propel / propel": "~2.0@dev"
}
  

Все выпуски на packagist.org: packagist.org/packages/propel/propel

Все выпуски на github.com: github.com/propelorm/Propel2/releases

Статус сборки Propel

Propel тщательно протестирован и разработан в рамках непрерывного
Интеграция с подходом к разработке через тестирование.

Мы используем Travis-CI для автоматической сборки наших проектов,
а вот статусы наших главных веток:

Кодовый климат Propel2:

Что такое Propel?

Propel — это объектно-реляционное отображение (ORM) с открытым исходным кодом для баз данных SQL в PHP 5.5.
Он позволяет вам получить доступ к вашей базе данных с помощью набора объектов, предоставляя простой API для хранения и извлечения данных.

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

Почему «Пропел»?

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

  • Двигатель молниеносно
  • Конструктор запросов
  • IDE дружественный благодаря генерации кода
  • Генерация методов для всех столбцов и отношений
  • Перенос схемы базы данных
  • Схема обратного проектирования
  • Настраиваемый
  • Хорошо документировано
  • Propel имеет общие «поведения»

Как?

Вам необходимо записать определение ваших таблиц как xml, экспортировать его из существующей базы данных с помощью нашей команды «database: reverse» или
создайте его с помощью такого инструмента, как ORM-Designer.

  

  
    
    
    
    <внешний ключ foreignTable = "author">
      
    
  

Подробнее пожалуйста!

Он использует PDO в качестве уровня абстракции и генерации кода, чтобы снять бремя самоанализа во время выполнения для достижения быстрого времени выполнения.

Propel реализует все ключевые концепции зрелых уровней ORM: шаблон ActiveRecord , валидаторы , поведения , наследование таблиц ,
обратное проектирование существующей базы данных , вложенных наборов , вложенных транзакций , ленивая загрузка , LOB , вы называете это.

Propel создан для разработчиков, которым необходимо контролировать свой код:

  • Расширяемость лежит в основе дизайна Propel; все, что вам нужно, Propel позволяет сделать это в мгновение ока.
  • Propel может уйти от вас, когда вам нужны индивидуальные запросы или гипероптимизированные транзакции.
  • Если вам нужно изменить вашу СУБД в ходе проекта, перестройте свою модель, и вы готовы к работе. Propel поддерживает MySQL,
    PostgreSQL, SQLite, MSSQL и Oracle. Первые три полностью интегрированы в наш набор тестов.
  • Код, созданный Propel, хорошо прокомментирован, удобен для IDE и прост в использовании.
  • Проект Propel стартовал в 2005 году и уже поддерживает тысячи веб-сайтов.Тщательно задокументировано, подкреплено множеством руководств
    в Интернете он также пользуется преимуществами сообщества энтузиастов, которое обеспечивает быструю поддержку как для начинающих, так и для опытных разработчиков.

Propel выпущен под лицензией MIT. Его можно использовать бесплатно даже в коммерческих приложениях.

Хотите узнать больше? Перейдите на вкладку «Документация» или начните изучать код в репозитории GitHub.

Установка Propel — Propel, молниеносно быстрый PHP с открытым исходным кодом 5.5 ORM

Propel доступен как клон из официального репозитория Github, как выписка из Subversion через Github и как «традиционный» пакет tgz или zip. Какой бы метод установки вы ни выбрали, заставить Propel работать довольно просто.

Предварительные требования

Propel требуется:

  • PHP 5.5 или новее, с включенным модулем DOM (libxml2)
  • Поддерживаемая база данных (MySQL, MS SQL Server, PostgreSQL, SQLite, Oracle)

Propel также использует некоторые компоненты Symfony2 для правильной работы:

  • Config: используется в исходном коде для управления и проверки конфигурации.
  • Консоль: которая управляет генераторами, которые использует двигатель.
  • Ямл
  • Validator: способ управления валидациями с помощью Propel.
  • Finder: используется в исходном коде для управления файлами.

Tip Propel использует компоненты PDO и SPL, которые объединены и включены по умолчанию в PHP7.

Настройка

Через Composer

Мы советуем вам положиться на Composer в управлении зависимостями ваших проектов.Если вы хотите установить Propel через Composer, просто создайте новый файл composer.json в корне каталога вашего проекта со следующим содержимым:

  {
    "требовать": {
        "propel / propel": "~2.0@dev"
    }
}
  

Затем вам нужно загрузить сам Composer, поэтому в терминале просто введите следующее:

  $ wget http://getcomposer.org/composer.phar
# Если у вас нет wget на вашем компьютере
$ curl -s http://getcomposer.org/installer | php
  

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

  $ php композитор.phar install
  

через Git

При желании вы также можете настроить Propel с помощью Git, клонируя репозиторий Github:

  $ git clone git: //github.com/propelorm/Propel2 vendor / propel
  

Propel хорошо протестирован на юнит-тестах, поэтому клонированная версия должна быть довольно стабильной. Если вы хотите обновить Propel, просто зайдите в репозиторий и вытащите пульт:

  $ cd myproject / vendor / propel
$ git pull
  

Использование Tarball или Zipball

В качестве альтернативы, чтобы использовать tarball, введите следующие команды на платформах unix:

  $ cd myproject / vendor
$ wget http: // файлы.propelorm.org/propel-2.0.0.tar.gz
$ tar zxvf propel-2.0.0.tar.gz
пропел-2.0.0 $ мв
  

Или в Windows загрузите ZIP-архив с files.propelorm.org, распакуйте его в каталог vendor / и переименуйте в propel .

Структура каталогов Propel

Корневой каталог библиотеки Propel включает следующие папки:

Папки Пояснения
бункер Содержит три сценария, управляющих инструментом командной строки propel (в зависимости от вашей операционной системы)
особенности Тесты, написанные на платформе Behat
ресурсов Содержит некоторые файлы, такие как база данных XSD или DTD
src Исходный код Propel.Откажитесь, если вы просто хотите использовать Propel, а не вносить свой вклад.
пробы Propel unit tests. Не обращайте на это внимания, если не хотите вносить свой вклад в Propel.

Испытания ходовой установки

Компонент генератора Propel включает в себя сценарий propel sh (и сценарий propel.bat для Windows). Этот сценарий упрощает выполнение команд сборки. Вы можете проверить, правильно ли установлен этот компонент, вызвав сценарий propel из интерфейса командной строки:

  $ cd myproject
$ vendor / bin / propel
  

Команда должна вывести версию propel, за которой следует список опций и доступных команд.Мы научимся использовать эти команды позже.

Совет Чтобы упростить выполнение сценария, вы также можете добавить
переместите каталог bin / генератора в ваш PATH или создайте символическую ссылку. Для
пример:

  $ cd myproject
$ ln -s vendor / bin / propel propel
  

Или просто отредактируйте файл .bashrc или .zshrc:

  экспорт ПУТЬ = $ ПУТЬ: / путь / к / поставщику / bin /
  

В Windows вы можете установить ПУТЬ для открытой команды с помощью:

  установить PATH =% PATH%; C: / path / to / vendor / bin /
  

Чтобы глобально определить ПУТЬ, настройте его в «Переменных среды», которые
вы можете найти в панели расширенных настроек вашей системы.

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

Поиск и устранение неисправностей

Получение справки

Если вам не удается установить Propel, не стесняйтесь обращаться за помощью. Видеть
Поддержка для получения подробной информации о получении помощи.


Далее: Создание проекта →

Скачать Propel — Propel, молниеносная скорость с открытым исходным кодом PHP 5.5 ORM

Примечание : Версия 2 Propel все еще находится в разработке.Пожалуйста, посетите
http://propelorm.org/Propel/, если вы хотите использовать стабильную версию.

Полное руководство по установке см. В документации по установке. Следующие параметры позволяют загрузить код и документацию Propel.

Композитор

Вы можете загрузить Propel с помощью Composer. Сначала загрузите файл composer.phar , используя одну из следующих команд в зависимости от вашей системы:

  $ curl -sS https://getcomposer.org/installer | php
# Альтернативно
$ wget http: // getcomposer.org / composer.phar
  

Затем коснитесь файла composer.json со следующим содержимым

  {
    "требовать": {
        "propel / propel": "~2.0@dev"
    }
}
  

Затем просто запустите php composer.phar install , чтобы получить Propel и его зависимости.

Git

Клонировать:

  $ git clone git: //github.com/propelorm/Propel2.git
  

Или добавьте его как подмодуль:

  $ git submodule add git: // github.com / propelorm / Propel2.git / путь / к / propel
  

Subversion Checkout / Внешний вид

  $ svn co http://github.com/propelorm/Propel2
  

Предупреждение
SVN больше не используется по умолчанию для управления исходным кодом с 2011 года.

Полный комплект ходовой части

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

Другие выпуски доступны для загрузки на files.propelorm.org.

Лицензия

Copyright (c) С 2005 года Ханс Леллелид, Давид Зуэльке, Франсуа Занинотто, Уильям
Дюран, Марк Дж. Шмидт

Настоящим предоставляется бесплатное разрешение любому лицу, получившему копию
этого программного обеспечения и связанных файлов документации («Программное обеспечение») для работы с
в Программном обеспечении без ограничений, включая, помимо прочего, права
использовать, копировать, изменять, объединять, публиковать, распространять, сублицензировать и / или продавать
копий Программного обеспечения и разрешить лицам, которым Программное обеспечение
предоставлено для этого, при соблюдении следующих условий:

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

ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНЫХ ИЛИ
ПОДРАЗУМЕВАЕТСЯ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИИ КОММЕРЧЕСКОЙ ЦЕННОСТИ,
ПРИГОДНОСТЬ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ И ЗАЩИТА ОТ ПРАВ. НИ В КОЕМ СЛУЧАЕ
АВТОРЫ ИЛИ ДЕРЖАТЕЛИ АВТОРСКИХ ПРАВ НЕСУТ ОТВЕТСТВЕННОСТЬ ЗА ЛЮБЫЕ ПРЕТЕНЗИИ, УБЫТКИ ИЛИ ДРУГИЕ
ОТВЕТСТВЕННОСТЬ, ВЫЯВЛЯЮЩАЯСЯ ЛИ В РЕЗУЛЬТАТЕ ДОГОВОРА, ПРАКТИКИ ИЛИ ИНЫМ ОБРАЗОМ,
ВНЕЗАПНО ИЛИ В СВЯЗИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ИЛИ ДРУГИМИ ДЕЯМИ
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ.

Доктрина

: проект с открытым исходным кодом PHP

Doctrine — это набор проектов, созданных для PHP.Каждый проект можно использовать отдельно и установить вместе с Composer.

Кэш

Библиотека

PHP Doctrine Cache — это популярная реализация кеширования, которая поддерживает множество различных драйверов, таких как redis, memcache, apc, mongodb и другие.

Стандарт кодирования

Doctrine Coding Standard — это набор правил PHPCS, применяемых ко всем проектам Doctrine.

Коллекции

Библиотека PHP Doctrine Collections, которая добавляет дополнительные функции поверх массивов PHP.

Обычный

PHP Doctrine Common project — это библиотека, которая предоставляет дополнительные функции, от которых зависят другие проекты Doctrine, такие как улучшенная поддержка отражения, прокси и многое другое.

Уровень абстракции базы данных

Мощный уровень абстракции базы данных PHP (DBAL) с множеством функций для самоанализа схемы базы данных и управления ею.

Менеджер мероприятий

Doctrine Event Manager — это простая система событий PHP, созданная для использования с различными проектами Doctrine.

Инфлектор

PHP Doctrine Inflector — это небольшая библиотека, которая может выполнять строковые манипуляции с заглавными / строчными буквами и формами единственного / множественного числа слов.

Инстанциатор

Небольшая легкая утилита для создания экземпляров объектов в PHP без вызова их конструкторов

Лексер

Библиотека парсера Doctrine Lexer PHP, которая может использоваться в парсерах с рекурсивным спуском сверху вниз.

Миграции

Проект

PHP Doctrine Migrations предлагает дополнительные функции поверх уровня абстракции базы данных (DBAL) для управления версиями вашей схемы базы данных и простого развертывания в ней изменений. Это очень простой в использовании и мощный инструмент.

Стойкость

Проект Doctrine Persistence — это набор общих интерфейсов и функциональных возможностей, которые разделяют разные средства отображения объектов Doctrine.

PHPCR ODM

PHP Doctrine Content Repository Object Document Mapper (ODM) обеспечивает прозрачное постоянство для объектов PHP.

Отражение

Проект Doctrine Reflection — это простая библиотека, используемая различными проектами Doctrine, которая добавляет некоторые дополнительные функции поверх функциональности отражения, поставляемой с PHP.Он позволяет статически получать информацию об отражении о классах, методах и свойствах.

Анализатор RST

Библиотека

PHP для анализа документов reStructuredText и создания документов HTML или LaTeX.

Составитель скелетов

Doctrine SkeletonMapper — это каркас объекта, отображающий объекты, в котором вы на 100% отвечаете за реализацию внутренних операций операций сохранения.Это означает, что вы пишете простой старый PHP-код для репозиториев данных, репозиториев объектов, гидраторов объектов и персистеров объектов.

Это проекты, которые интегрируют Doctrine с другими библиотеками и / или фреймворками и официально поддерживаются Doctrine.

Когда-то это были активные и поддерживаемые проекты. Если вы заинтересованы в поддержке любого проекта Doctrine, ознакомьтесь с открытыми проблемами на GitHub и отправьте запросы на вытягивание.

Эти проекты больше не поддерживаются без шансов на возрождение и были заархивированы.

Что такое ORM? | PHP.earth

ORM (объектно-реляционное отображение), также известное как O / RM, и отображение O / R — это программный подход для преобразования данных между несовместимыми системами типов.

Многие фреймворки полного стека предоставляют свои собственные подходы к абстракции баз данных или ORM.

Автономные уровни абстракции базы данных и ORM для проверки:

  • Aura SQL — Расширение для собственного PDO вместе с профилировщиком и локатором соединений.
  • DataMonkey — База данных ORM для PHP, построенная поверх Doctrine.
  • Doctrine — дом для нескольких библиотек PHP, в первую очередь ориентированных на хранение баз данных и отображение объектов. Основными проектами являются объектно-реляционный сопоставитель (ORM) и уровень абстракции базы данных (DBAL), на котором он построен.
  • Eloquent — компонент базы данных Illuminate, используемый во фреймворке Laravel, но также как отдельный компонент.
  • Medoo — Легкая структура базы данных PHP для ускорения разработки.
  • Propel — Гибкая настраиваемая и невероятно быстрая библиотека ORM.
  • ProxyManager — Библиотека, которая предоставляет абстракцию для создания различных типов прокси-классов.
  • RedBeanPHP — Простая в использовании ORM для PHP.
  • safemysql — настоящий безопасный и удобный способ обработки запросов MySQL.
  • Spot ORM — простой и эффективный DataMapper, построенный на уровне абстракции базы данных Doctrine.
  • Zend \ Db — компонент базы данных Zend.

Паттерны проектирования

В ORM используются в основном два основных шаблона проектирования — Active Record и Data Mapper.

Когда не использовать ORM?

Как указывалось в некоторых статьях (1, 2, 3), ORM — это антипаттерн, нарушающий принципы объектно-ориентированного программирования.

В качестве альтернативы ORM есть Pomm. Он не предлагает уровень абстракции и предназначен для Postgres, позволяющего разработчикам кодировать непосредственно на SQL для извлечения сущностей. Он сопоставляет объектный / реляционный импеданс с помощью реляционной операции проекции для гидратации гибких экземпляров. Он особенно подходит для создания внутренних приложений для транзакций или отчетов.

См. Также

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

Веб-разработка

— Какая библиотека PHP ORM самая лучшая?

веб-разработка — Какая библиотека PHP ORM лучшая? — Обмен стеками программной инженерии

Сеть обмена стеков

Сеть Stack Exchange состоит из 176 сообществ вопросов и ответов, включая Stack Overflow, крупнейшее и пользующееся наибольшим доверием онлайн-сообщество, где разработчики могут учиться, делиться своими знаниями и строить свою карьеру.

Посетить Stack Exchange

  1. 0

  2. +0

  3. Авторизоваться
    Зарегистрироваться

Software Engineering Stack Exchange — это сайт вопросов и ответов для профессионалов, ученых и студентов, работающих в рамках жизненного цикла разработки систем.Регистрация займет всего минуту.

Зарегистрируйтесь, чтобы присоединиться к этому сообществу

Кто угодно может задать вопрос

Кто угодно может ответить

Лучшие ответы голосуются и поднимаются наверх

Спросил

Просмотрено
8к раз

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

Закрыт 9 лет назад.

Я хочу создать веб-приложение PHP, но всегда сталкиваюсь с проблемой, связанной с тем, что мне нужно подключиться к базе данных и работать со связанными объектами.Итак, я попробовал codeigniter, и он использует специальный способ подключения к базе данных с именем Active Record, и я знал, что это метод ORM, и существует множество библиотек ORM.

Какие из них самые лучшие, самые простые и самые быстрые?

Яннис

38.2k4040 золотых знаков176176 серебряных знаков214214 бронзовых знаков

Создан 20 ноя.

Эмад ЭльсаидЭмад Эльсаид

27122 серебряных знака88 бронзовых знаков

1

RedBean — это то, что я использую для этой цели: http: // redbeanphp.com /

RedBean упрощает этап разработки за счет автоматического изменения схемы на лету. он очень хорошо работает с MySQL и SQLite, но и другие базы данных, поддерживаемые PDO, тоже должны работать.

Создан 20 ноя.

2

Doctrine и Propel — два популярных ORM.Лично у меня только опыт работы с Doctrine, и никаких претензий нет.

Вам также следует прочитать ответы на этот вопрос на StackOverflow.

Создан 20 ноя.

BenVBenV

811 золотой знак77 серебряных знаков1616 бронзовых знаков

1

Мне действительно нужно хвалить PHP.ActiveRecord. Это почти прямой клон Rails ActiveRecord ORM. Для меня это было просто потрясающе, и его относительно безболезненно интегрировать в современные фреймворки.

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

Это блестящий проект, и я очень рекомендую его, особенно если вы из опыта работы с Rails.

Создан 25 дек.

Machugamachuga

22111 серебряный знак33 бронзовых знака

2

язык-php

Software Engineering Stack Exchange лучше всего работает с включенным JavaScript

Ваша конфиденциальность

Нажимая «Принять все файлы cookie», вы соглашаетесь с тем, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в ​​отношении файлов cookie.

Принимать все файлы cookie

Настроить параметры

Фреймворк базы данных Atlas

для PHP

Почему Атлас?

Atlas помогает разработчикам начать работу так же легко, как если бы они работали с Active
Рекорд для их модели сохраняемости и обеспечивает путь к рефакторингу Подробнее
легко перейти к более богатой модели domain по мере необходимости.

Что такое модель постоянства?

Модель персистентности — это модель вашей базы данных, а не вашей
бизнес-домен. В частности, это объектно-ориентированный
представление таблиц и строк в базе данных.

Очень часто у разработчика нет хорошей чистой модели предметной области.
работать, особенно в начале проекта.Но есть
почти всегда какая-то база данных. Модели Атласа, которые
структура базы данных, чтобы вам было проще использовать ее в PHP-коде.

Зачем нужна модель постоянства?

Сама по себе модель персистентности должна заставить ваше приложение долго работать.
Кстати, особенно в начале проекта. Строка, Запись,
и объекты RecordSet в Атласе отключены от базы данных, что
должен сделать процесс рефакторинга и интеграции много
чище, чем с Active Record.

Поскольку Atlas работает со схемой базы данных как есть,
и не так, как ORM думает, Atlas — очень хороший
подходит для проектов с уже существующими базами данных. (Действительно, Атлас
поддерживает составные первичные ключи и
составные внешние ключи — для некоторых устаревших
системы, составные ключи абсолютно необходимы.)

Как работает Атлас?

На высоком уровне Atlas — это мини-фреймворк, построенный из набора
пакеты, где любой «младший» пакет может использоваться независимо
из тех, что «над» этим.Это означает, что вы можете выбрать точное
уровень функциональности, который вам нужен прямо сейчас, и расширьте его до
следующий больший набор функций — только по мере необходимости.

Иерархия пакетов снизу вверх выглядит так:

  • Atlas.Pdo предоставляет объект Connection базы данных и ConnectionLocator. Если все, что вам нужно, это удобная оболочка вокруг PDO с методами fetch и yield, этот пакет для вас.

  • Atlas.Query — это построитель запросов, который обертывает соединение Atlas.Pdo. Если вы просто хотите создавать и выполнять SQL-запросы с использованием объектно-ориентированного подхода, объекты запросов Atlas могут справиться с этим.

  • Atlas.Table — это реализация шлюза табличных данных, которая использует Atlas.Query под капотом. Если вам не нужна полная система отображения данных, и вы хотите взаимодействовать только с отдельными таблицами и их объектами строк, это поможет.

  • Atlas.Mapper — это реализация преобразователя данных, которая моделирует отношения между таблицами. Он позволяет вам создавать объекты Record и RecordSet, чьи объекты Row естественным образом сопоставляются с объектами Table; вы можете записать их обратно в базу данных по одному или сохранить весь граф записи обратно в базу данных за один раз.

  • Atlas.Orm — всеобъемлющий пакет ORM; он предоставляет удобную оболочку для системы Mapper, а также несколько стратегий для управления транзакциями.

Таким образом, Atlas использует шлюз табличных данных для нижележащих строк таблицы, а затем составляет
эти строки в Records и RecordSets через преобразователь данных; соединение PDO и запрос
система перемещает данные между PHP и базой данных.

От постоянства к домену

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

Затем, по мере роста модели предметной области в вашем приложении,
Мехди Халили
показывает, что процесс рефакторинга может идти по одному из двух путей:

  • «Модель предметной области, состоящая из модели устойчивости».То есть объекты домена
    может использовать модель сохраняемости Атласа Записывать объекты внутри, но не раскрывать
    их. Объекты домена могут манипулировать объектами модели сохраняемости.
    внутренне столько, сколько они хотят. Например, объект домена может иметь
    getAddress (), который читает из внутренней записи.
  • «DDD поверх ORM». Здесь репозитории сопоставляют объекты модели сохраняемости с
    и из доменных объектов.Это обеспечивает полную развязку модели предметной области.
    от модели персистентности, но требует больше времени для разработки.

Прочие соображения

Вот еще некоторые соображения относительно Атласа:

  • Автозаполнение IDE PHPStorm. Когда вы используете
    ресурс phpstorm.meta.php, включенный в соответствующий
    пакеты, PHPStorm будет автоматически заполнять методы и свойства
    из вашего Mapper, Record, RecordSet и др.классы.
  • Без аннотаций. Код должен быть в коде, а не
    в комментариях.
  • Нет ленивой загрузки. Ленивая загрузка соблазнительна,
    но в конечном итоге это больше проблем, чем оно того стоит. Атлас
    не делает его доступным вообще, поэтому его нельзя вызвать
    случайно.
  • Нет абстракций типов данных. Поначалу абстракция типов данных кажется отличной, но
    это тоже заканчивается тем, что не стоит усилий. Таким образом, фактический базовый
    типы баз данных раскрыты и доступны в максимально возможной степени.

Противопоказания

Возможно, вы не найдете Atlas подходящим для ваших нужд по следующим причинам: