Eloquent ORM
Eloquent ORM — это встроенная объектно-реляционная проекция (ORM) для PHP-фреймворка Laravel, реализующая шаблон Active Record. Eloquent позволяет разработчикам взаимодействовать с базой данных с помощью объектно-ориентированного синтаксиса, автоматически сопоставляя таблицы базы данных с классами PHP (моделями) и строки таблиц — с экземплярами этих классов. Система является стандартным компонентом Laravel начиная с версии 4.0 (2013 год) и распространяется по лицензии MIT.
История
Проект Laravel был создан Тейлором Отвеллом (Taylor Otwell) в 2011 году как альтернатива более тяжеловесным фреймворкам, таким как Symfony и CodeIgniter. Первая версия (Laravel 1) не имела собственной ORM — для работы с базой данных использовалась встроенная библиотека PHP ActiveRecord. Однако уже в Laravel 3 (2012 год) была представлена собственная реализация Active Record, получившая название Eloquent. Название было выбрано как отсылка к красноречию (англ. eloquence) кода, который позволяет писать запросы к базе данных естественным языком.
В Laravel 4 (2013 год) Eloquent был полностью переработан: была добавлена поддержка «мягкого удаления» (soft deletes), временных меток (timestamps), а также улучшена система отношений. В версии 5.0 (2015 год) появились аксессоры и мутаторы (getters/setters), а в 5.4 — глобальные скоупы (global scopes). В Laravel 6 (2019 год) были добавлены ленивая загрузка (lazy loading) и улучшенная поддержка полиморфных отношений. В Laravel 8 (2020 год) появились фабрики моделей (Model Factories) с новым синтаксисом, а в Laravel 9 (2022 год) — поддержка типизированных свойств моделей. Актуальная версия (Laravel 11, 2024 год) продолжает развивать Eloquent, добавляя новые методы для работы с коллекциями и улучшенную интеграцию с Laravel Scout для полнотекстового поиска.
Архитектура и принципы работы
Eloquent основан на шаблоне Active Record, где каждый экземпляр модели представляет одну строку в таблице базы данных, а сам класс модели — таблицу. В отличие от Data Mapper (используемого, например, в Doctrine), Eloquent сочетает логику бизнес-правил и логику доступа к данным в одном объекте.
Модели
Модель — это PHP-класс, который наследуется от базового класса Illuminate\Database\Eloquent\Model. По соглашению, имя модели в единственном числе (например, User), а соответствующая таблица — во множественном (например, users). Если имя таблицы отличается от стандартного, его можно указать через свойство $table:
``php class Flight extends Model { protected $table = 'my_flights'; } ``
Каждая модель автоматически ожидает наличие первичного ключа с именем id (целочисленный, автоинкрементный). Если ключ называется иначе, это указывается через свойство $primaryKey. По умолчанию Eloquent предполагает, что в таблице есть поля created_at и updated_at (типа timestamp), которые автоматически заполняются при создании и обновлении записи. Отключить это поведение можно установкой public $timestamps = false.
Eloquent-запросы
Eloquent предоставляет fluent-интерфейс для построения запросов. Базовый метод — Model::query(), который возвращает экземпляр класса Illuminate\Database\Eloquent\Builder. Примеры:
User::all()— получить все записи.User::find(1)— найти запись по первичному ключу.User::where('active', 1)->get()— фильтрация.User::where('votes', '>', 100)->orderBy('name')->take(10)->get()— цепочка методов.
Важной особенностью является то, что Eloquent возвращает не массивы, а коллекции (Illuminate\Database\Eloquent\Collection), которые предоставляют дополнительные методы для работы с данными (например, filter, map, pluck).
Отношения (Relationships)
Eloquent поддерживает все основные типы реляционных связей:
- Один к одному (One-to-One):
hasOne()/belongsTo()— например, пользователь имеет один профиль. - Один ко многим (One-to-Many):
hasMany()/belongsTo()— пользователь имеет много постов. - Многие ко многим (Many-to-Many):
belongsToMany()— пользователи и роли, с промежуточной таблицей. - Полиморфные отношения (Polymorphic):
morphTo()/morphMany()— например, комментарии могут принадлежать как постам, так и видео. - Полиморфные многие ко многим (Many-to-Many Polymorphic):
morphToMany()/morphedByMany()— теги, прикрепляемые к различным типам контента.
Отношения определяются как методы модели, возвращающие соответствующий объект отношения. Например:
``php class Post extends Model { public function comments() { return $this->hasMany(Comment::class); } } ``
Затем можно обращаться к отношению как к свойству: $post->comments (ленивая загрузка) или использовать with('comments') для жадной загрузки.
Аксессоры и мутаторы
Аксессоры (getters) позволяют преобразовывать атрибуты модели при доступе к ним. Например, можно создать аксессор для поля first_name, который возвращает имя с заглавной буквы:
``php public function getFirstNameAttribute($value) { return ucfirst($value); } ``
Мутаторы (setters) выполняют обратное действие — преобразуют значение перед записью в базу:
``php public function setFirstNameAttribute($value) { $this->attributes['first_name'] = strtolower($value); } ``
Скоупы (Scopes)
Скоупы позволяют переиспользовать часто используемые условия запроса. Локальные скоупы определяются как методы с префиксом scope:
``php public function scopePopular($query) { return $query->where('votes', '>', 100); } ``
Использование: User::popular()->get(). Глобальные скоупы применяются ко всем запросам к модели автоматически (например, для фильтрации по признаку активности).
Критика и ограничения
Несмотря на популярность, Eloquent имеет ряд критических замечаний:
- Производительность: Active Record может приводить к проблеме N+1 запросов, если не использовать жадную загрузку. Хотя Laravel предоставляет инструменты для её решения, новички часто забывают о ней.
- Нарушение принципа единой ответственности: Модель Eloquent одновременно отвечает и за хранение данных, и за бизнес-логику, что может усложнить тестирование и поддержку крупных проектов.
- Сложность миграции: При переходе на другую СУБД или ORM (например, Doctrine) может потребоваться значительная переработка кода, так как Eloquent тесно связан с Laravel.
- Отсутствие строгой типизации: До Laravel 9 свойства модели не были типизированы, что могло приводить к ошибкам. В версии 9 появилась поддержка типизированных свойств, но она не является обязательной.
Применение
Eloquent является стандартным выбором для проектов на Laravel, включая веб-сайты, API, административные панели и SaaS-приложения. Он используется в таких крупных проектах, как October CMS, Koel (музыкальный стример) и Laravel Spark. По данным опроса Laravel Ecosystem Survey 2023 года, более 95% разработчиков Laravel используют Eloquent в своих проектах.
Интересные факты
- Название «Eloquent» было выбрано Тейлором Отвеллом из-за того, что код запросов выглядит «красноречивым» (eloquent) — например,
User::where('active', true)->get()читается как английское предложение. - Eloquent поддерживает «мягкое удаление» (soft delete): записи не удаляются из базы, а помечаются полем
deleted_at. Это позволяет восстанавливать данные. - В Laravel 5.5 появилась возможность автоматического обнаружения отношений (auto-discovery), что упростило конфигурацию.
- Eloquent использует паттерн «Repository» неявно: коллекции результатов предоставляют методы для работы с данными, не раскрывая детали SQL.
Источники
- Otwell, T. (2013). Laravel: From Apprentice to Artisan. Laravel LLC.
- Laravel Documentation. (2024). Eloquent ORM. Laravel LLC.
- Stauffer, M. (2019). Laravel: Up & Running: A Framework for Building Modern PHP Apps. O'Reilly Media.
- Laravel Ecosystem Survey 2023. (2023). Laravel News.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →