Версия фреймворка:
5.4 4.2
Прогресс перевода
Перевод немного отстаёт от оригинала. Коммитов не переведено: 1

Eloquent ORM

Введение

Система объектно-реляционного отображения ORM Eloquent - красивая и простая реализация ActiveRecord в Laravel для работы с базами данных. Каждая таблица имеет соответствующий класс-модель, который используется для работы с этой таблицей.

Прежде чем начать настройте ваше соединение с БД в файле app/config/database.php.

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

Для начала создадим модель Eloquent. Модели обычно располагаются в папке app/models, но вы можете поместить в любое место, в котором работает автозагрузчик в соответствии с вашим файлом composer.json.

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

class User extends Eloquent {}

Заметьте, что мы не указали, какую таблицу Eloquent должен привязать к нашей модели. Если это имя не указано явно, то будет использовано имя класса в нижнем регистре и во множественном числе. В нашем случае Eloquent предположит, что модель User хранит свои данные в таблице users. Вы можете указать произвольную таблицу, определив свойство table в классе модели:

class User extends Eloquent {

	protected $table = 'my_users';

}
Примечание: Eloquent также предполагает, что каждая таблица имеет первичный ключ с именем id. Вы можете определить свойство primaryKey для изменения этого имени. Аналогичным образом, вы можете определить свойство connection для задания имени подключения к БД, которое должно использоваться при работе с данной моделью.

Как только модель определена у вас всё готово для того, чтобы можно было выбирать и создавать записи. Обратите внимание, что вам нужно создать в этой таблице поля updated_at и created_at. Если вы не хотите, чтобы они были автоматически используемы, установите свойство timestamps класса модели в false.

Получение всех моделей (записей)

$users = User::all();

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

$user = User::find(1);

var_dump($user->name);
Примечание: Все методы, доступные в конструкторе запросов, также доступны при работе с моделями Eloquent.

Получение модели по первичному ключу с возбуждением исключения

Иногда вам нужно возбудить исключение, если определённая модель не была найдена, что позволит вам его отловить в обработчике App::error и вывести страницу 404 ("Не найдено").

$model = User::findOrFail(1);

$model = User::where('votes', '>', 100)->firstOrFail();

Для регистрации обработчика ошибки подпишитесь на событие ModelNotFoundException

use Illuminate\Database\Eloquent\ModelNotFoundException;

App::error(function(ModelNotFoundException $e)
{
	return Response::make('Not Found', 404);
});

Построение запросов в моделях Eloquent

$users = User::where('votes', '>', 100)->take(10)->get();

foreach ($users as $user)
{
	var_dump($user->name);
}

Аггрегатные функции в Eloquent

Конечно, вам также доступны аггрегатные функции.

$count = User::where('votes', '>', 100)->count();

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

$users = User::whereRaw('age > ? and votes = 100', array(25))->get();

Обработка результата по частям

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

User::chunk(200, function($users)
{
	foreach ($users as $user)
	{
		//
	}
});

Данный код вынимает данные порциями по 200 (первый аргумент) записей. Обработка записи производится в функции-замыкании, которая передается вторым аргументом.

Указание имени соединения с БД

Иногда вам нужно указать, какое подключение должно быть использовано при выполнении запроса Eloquent - просто используйте метод on:

$user = User::on('имя-соединения')->find(1);

Массовое заполнение

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

Для начала определите в классе модели свойство fillable или guarded.

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

Указание доступных к заполнению атрибутов

class User extends Eloquent {

	protected $fillable = array('first_name', 'last_name', 'email');

}

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

Противоположность fillable - свойство guarded, которое содержит список запрещённых к заполнению полей.

Указание охраняемых (guarded) атрибутов модели

class User extends Eloquent {

	protected $guarded = array('id', 'password');

}

В примере выше атрибуты id и password не могут быть присвоены через массовое заполнение. Все остальные атрибуты - могут. Вы также можете запретить все атрибуты для заполнения специальным значением.

Примечание: Даже если вы используете guarded, по возможности избегайте массового присваивания Input::get() модели.

Защита всех атрибутов от массового заполнения

protected $guarded = array('*');

Вставка, обновление, удаление

Для создания новой записи в БД просто создайте экземпляр модели и вызовите метод save.

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

$user = new User;

$user->name = 'Джон';

$user->save();
Внимание: обычно ваши модели Eloquent содержат автоматические числовые ключи (autoincrementing). Однако если вы хотите использовать собственные ключи, установите свойство incrementing класса модели в значение false.

Вы также можете использовать метод create для создания и сохранения модели одной строкой. Метод вернёт добавленную модель. Однако перед этим вам нужно определить либо свойство fillable, либо guarded в классе модели, так как изначально все модели Eloquent защищены от массового заполнения.

Установка охранных свойств модели

class User extends Eloquent {

	protected $guarded = array('id', 'account_id');

}

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

$user = User::create(array('name' => 'Джон'));

Для обновления модели вам нужно получить её, изменить атрибут и вызвать метод save:

Обновление полученной модели

$user = User::find(1);

$user->email = 'john@foo.com';

$user->save();

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

Сохранение модели и её отношений

$user->push();

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

$affectedRows = User::where('votes', '>', 100)->update(array('status' => 2));

Для удаления модели вызовите метод delete на её объекте.

Удаление существующей модели

$user = User::find(1);

$user->delete();

Удаление модели по ключу

User::destroy(1);

User::destroy(array(1, 2, 3));

User::destroy(1, 2, 3);

Конечно, вы также можете выполнять удаление на наборе моделей:

$affectedRows = User::where('votes', '>', 100)->delete();

Если вам нужно просто обновить время изменения записи - используйте метод touch:

Обновление времени изменения модели

$user->touch();

Мягкое удаление

Когда вы "мягко" удаляете модель, она на самом деле остаётся в базе данных, однако устанавливается её поле deleted_at. Для включения мягких удалений на модели определите свойство её softDelete:

class User extends Eloquent {

	protected $softDelete = true;

}

Для добавления поля deleted_at к таблице можно использовать метод softDeletes из миграции:

$table->softDeletes();

Теперь когда вы вызовите метод delete, поле deleted_at будет установлено в значение текущего времени. При запросе моделей, используюих мягкое удаление, "удалённые" модели не будут включены в результат запроса. Для отображения всех моделей, в том числе удалённых, используйте метод withTrashed.

Включение удалённых моделей в результат выборки

$users = User::withTrashed()->where('account_id', 1)->get();

Если вы хотите получить только удалённые модели, вызовите метод onlyTrashed:

$users = User::onlyTrashed()->where('account_id', 1)->get();

Для восстановления мягко удалённой модели в активное состояние используется метод restore:

$user->restore();

Вы также можете использовать его в запросе:

User::withTrashed()->where('account_id', 1)->restore();

Метод restore можно использовать и в отношениях:

$user->posts()->restore();

Если вы хотите полностью удалить модель из БД, используйте метод forceDelete:

$user->forceDelete();

Он также работает с отношениями:

$user->posts()->forceDelete();

Для того, чтобы узнать, удалена ли модель, можно использовать метод trashed:

if ($user->trashed())
{
	//
}

Поля времени

По умолчанию Eloquent автоматически поддерживает поля created_at и updated_at . Просто добавьте эти timestamp-поля к таблице и Eloquent позаботится об остальном. Если вы не хотите, чтобы он поддерживал их, добавьте свойство timestamps к классу модели.

Отключение автоматических полей времени

class User extends Eloquent {

	protected $table = 'users';

	public $timestamps = false;

}

Для настройки форматов времени перекройте метод getDateFormat:

Использование собственного формата времени

class User extends Eloquent {

	protected function getDateFormat()
	{
		return 'U';
	}

}

Заготовки запросов

Заготовки позволяют вам повторно использовать логику запросов в моделях. Для создания заготовки просто начните имя метода со scope:

Создание заготовки запроса

class User extends Eloquent {

	public function scopePopular($query)
	{
		return $query->where('votes', '>', 100);
	}
	
	public function scopeWomen($query)
	{
		return $query->whereGender('W');
	}

}

Использование заготовки

$users = User::popular()->women()->orderBy('created_at')->get();

Динамические заготовки

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

class User extends Eloquent {

	public function scopeOfType($query, $type)
	{
		return $query->whereType($type);
	}

}

А затем передайте их при вызове метода заготовки:

$users = User::ofType('member')->get();

Отношения

Конечно, ваши таблицы скорее всего как-то связаны с другими таблицами БД. Например, статья в блоге может иметь много комментариев, а заказ может быть с связан с оставившим его пользователем. Eloquent упрощает работу и управление такими отношениями. Laravel поддерживает 4 типа связей:

Один к одному

Связь вида "один к одному" является очень простой. К примеру, модель User может иметь один Phone. Мы можем определить такое отношение в Eloquent.

Создание связи "один к одному"

class User extends Eloquent {

	public function phone()
	{
		return $this->hasOne('Phone');
	}

}

Первый параметр, передаваемый hasOne - имя связанной модели. Как только отношение установлено вы можете полчить к нему доступ через динамические свойства Eloquent:

$phone = User::find(1)->phone;

Сгенерированный SQL имеет такой вид:

select * from users where id = 1

select * from phones where user_id = 1

Заметьте, что Eloquent считает, что поле в таблице называется по имени модели плюс _id. В данном случае предполагается, что это user_id.Если вы хотите перекрыть стандартное имя передайте второй параметр методу hasOne:

return $this->hasOne('Phone', 'custom_key');

Для создания обратного отношения в модели Phone используйте метод belongsTo ("принадлежит к"):

Создание обратного отношения

class Phone extends Eloquent {

	public function user()
	{
		return $this->belongsTo('User');
	}

}

В примере выше Eloquent будет искать поле user_id в таблице phones. Если вы хотите назвать внешний ключ по другому, передайте это имя вторым параметром к методу belongsTo:

class Phone extends Eloquent {

	public function user()
	{
		return $this->belongsTo('User', 'custom_key');
	}

}

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

Примером отношения "один ко многим" является статья в блоге, которая имеет "много" комментариев. Вы можем смоделировать это отношение таким образом:

class Post extends Eloquent {

	public function comments()
	{
		return $this->hasMany('Comment');
	}

}

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

$comments = Post::find(1)->comments;

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

$comments = Post::find(1)->comments()->where('title', '=', 'foo')->first();

Как обычно, вы можете передать второй параметр к методу hasMany для перекрытия стандартного имени ключа:

return $this->hasMany('Comment', 'custom_key');

Для определения обратного отношения используйте метод belongsTo:

Определение обратного отношения

class Comment extends Eloquent {

	public function post()
	{
		return $this->belongsTo('Post');
	}

}

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

Отношения типа "многие ко многим" - более сложные, чем остальные виды отношений. Примером может служить пользователь, имеющий много ролей, где роли также относятся ко многим пользователям. Например, один пользователь может иметь роль "Admin". Нужны три таблицы для этой связи: users, roles и role_user. Название таблицы role_user происходит от упорядоченного по алфавиту имён связанных моделей и должна иметь поля user_id и role_id.

Вы можете определить отношение "многие ко многим" через метод belongsToMany:

class User extends Eloquent {

	public function roles()
	{
		return $this->belongsToMany('Role');
	}

}

Теперь мы можем получить роли через модель User:

$roles = User::find(1)->roles;

Вы можете передать второй параметр к методу belongsToMany с указанием имени связующей (pivot) таблицы вместо стандартной:

return $this->belongsToMany('Role', 'user_roles');

Вы также можете перекрыть имена ключей по умолчанию:

return $this->belongsToMany('Role', 'user_roles', 'user_id', 'foo_id');

Конечно, вы можете определить и обратное отношение на модели Role:

class Role extends Eloquent {

	public function users()
	{
		return $this->belongsToMany('User');
	}

}

Полиморфические отношения

Полиморфические отношения позволяют модели быть связанной с более, чем одной моделью. Например, может быть модель Photo, содержащая записи, принадлежащие к моделям Staff и Order. Мы можем создать такое отношение таким образом:

class Photo extends Eloquent {

	public function imageable()
	{
		return $this->morphTo();
	}

}

class Staff extends Eloquent {

	public function photos()
	{
		return $this->morphMany('Photo', 'imageable');
	}

}

class Order extends Eloquent {

	public function photos()
	{
		return $this->morphMany('Photo', 'imageable');
	}

}

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

Чтение полиморфической связи

$staff = Staff::find(1);

foreach ($staff->photos as $photo)
{
	//
}

Однако истинная "магия" полиморфизма происходит при чтении связи на модели Photo:

Чтение связи на владельце полиморфического отношения

$photo = Photo::find(1);

$imageable = $photo->imageable;

Отношение imageable модели Photo вернёт либо объект Staff либо объект Orderв зависимости от типа модели, к которой принадлежит фотография.

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

Структура таблиц полиморфической связи

staff
	id - integer
	name - string

orders
	id - integer
	price - integer

photos
	id - integer
	path - string
	imageable_id - integer
	imageable_type - string

Главные поля, на которые нужно обратить внимание: imageable_id и imageable_type в таблице photos. Первое содержит ID владельца, в нашем случае - заказа или персонала, а второе - имя класса-модели владельца. Это позволяет ORM определить, какой класс модели должен быть возвращёт при использовании отношения imageable.

Запросы к отношениям

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

Проверка связей при выборке

$posts = Post::has('comments')->get();

Вы также можете указать оператор и число:

$posts = Post::has('comments', '>=', 3)->get();

Динамические свойства

Eloquent позволяет вам читать отношения через динамические свойства. Eloquent автоматически определит используемую связь и даже вызовет get для связей "один ко многим" и first - для связей "один к одному". К примеру, для следующей модели $phone:

class Phone extends Eloquent {

	public function user()
	{
		return $this->belongsTo('User');
	}

}

$phone = Phone::find(1);

Вместо того, чтобы получить e-mail пользователя так:

echo $phone->user()->first()->email;

...вызов может быть сокращён до такого:

echo $phone->user->email;

Активная загрузка

Активная загрузка (eager loading) призвана устранить проблему запросов N + 1. Например, представьте, что у нас есть модель Book со связью к модели Author. Отношение определено как:

class Book extends Eloquent {

	public function author()
	{
		return $this->belongsTo('Author');
	}

}

Теперь, у нас есть такой код:

foreach (Book::all() as $book)
{
	echo $book->author->name;
}

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

К счастью, мы можем использовать активную загрузку для кардинального уменьшения числа запросов. Отношение будет активно загружено, если оно было указано при вызове метода with:

foreach (Book::with('author')->get() as $book)
{
	echo $book->author->name;
}

В цикле выше будут выполнены всего два запроса:

select * from books

select * from authors where id in (1, 2, 3, 4, 5, ...)

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

Конечно, вы можете загрузить несколько отношений одновременно:

$books = Book::with('author', 'publisher')->get();

Вы даже можете загрузить вложенные отношения:

$books = Book::with('author.contacts')->get();

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

Ограничения активной загрузки

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

$users = User::with(array('posts' => function($query)
{
	$query->where('title', 'like', '%первое%');
}))->get();

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

Ленивая активная загрузка

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

$books = Book::all();

$books->load('author', 'publisher');

Вставка связанных моделей

Часто вам нужно будет добавить связанную модель. Например, вы можете создать новый комментарий к сообщению. Вместо явного указания значения для поля post_id вы можете вставить модель через её владельца - модели Post:

Создание связанной модели

$comment = new Comment(array('message' => 'Новый комментарий.'));

$post = Post::find(1);

$comment = $post->comments()->save($comment);

В этом примере поле post_id вставленного комментария автоматически получит значение ID своей статьи.

Связывание моделей (Belongs To)

При обновлении связей belongsTo ("принадлежит к") вы можете использовать метод associate. Он установит внешний ключ на связанной модели:

$account = Account::find(10);

$user->account()->associate($account);

$user->save();

Связывание моделей (многие ко многим)

Вы также можете вставлять связанные модели при работе с отношениями многие ко многим. Продолжим использовать наши модели User и Role в качестве примеров. Вы можем легко привязать новые роли к пользователю методом attach.

Связывание моделей "многие ко мнгим"

$user = User::find(1);

$user->roles()->attach(1);

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

$user->roles()->attach(1, array('expires' => $expires));

Конечно, существует противоположность attach - detach:

$user->roles()->detach(1);

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

Использование Sync для привязки моделей "многие ко многим"

$user->roles()->sync(array(1, 2, 3));

Вы также можете связать другие связующие таблицы с нужными ID.

Добавление данных для связующий таблицы при синхронизации

$user->roles()->sync(array(1 => array('expires' => true)));

Иногда вам может быть нужно создать новую связанную модель и добавить её одной командой. Для этого вы можете использовать метод save:

$role = new Role(array('name' => 'Editor'));

User::find(1)->roles()->save($role);

В этом примере новая модель Role будет сохранена и привязана к модели User. Вы можете также передать массив атрибутов для помещения в связующую таблицу:

User::find(1)->roles()->save($role, array('expires' => $expires));

Обновление времени владельца

Когда модель принадлежит к другой посредством belongsTo - например, Comment, принадлежащий Post- иногда нужно обновить время изменения владельца при обновлении связанной модели. Например, при изменении модели Comment вы можете обновлять поле updated_at её модели Post. Eloquent делает этот процесс простым - просто добавьте свойство touches, содержащее имена всех отношений с моделями-потомками.

class Comment extends Eloquent {

	protected $touches = array('post');

	public function post()
	{
		return $this->belongsTo('Post');
	}

}

Теперь при обновлении Comment владелец Post также обновит своё поле updated_at:

$comment = Comment::find(1);

$comment->text = 'Изменение этого комментария.';

$comment->save();

Работа со связующими таблицами

Как вы уже узнали, работа отношения многие ко многим требует наличия промежуточной таблицы. Например, предположим, что наш объект User имеет множество связанных объектов Role. После чтения отношения мы можем прочитать таблицу pivot на обоих моделях:

$user = User::find(1);

foreach ($user->roles as $role)
{
	echo $role->pivot->created_at;
}

Заметьте, что каждая модель Role автоматически получила атрибут pivot. Этот атрибут содержит модель, представляющую промежуточную таблицу и она может быть использована как любая другая модель Eloquent.

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

return $this->belongsToMany('Role')->withPivot('foo', 'bar');

Теперь атрибуты foo и bar будут также доступны на объекте pivot модели Role.

Если вы хотите автоматически поддерживать поля created_at и updated_at актуальными, используйте метод withTimestamps при создании отношения:

return $this->belongsToMany('Role')->withTimestamps();

Для удаления всех записей в связующей таблице можно использовать метод detach:

Удаление всех связующих записей

User::find(1)->roles()->detach();

Заметьте, что эта операция не удаляет записи из таблицы roles, а только из связующей таблицы.

Коллекции

Все методы Eloquent, возвращающие набор моделей - либо через get, либо через отношения - возвращают объект-коллекцию. Этот объект реализует стандартный интерфейс PHP IteratorAggregate, что позволяет ему быть использованным в циклах наподобие массива. Однако этот объект также имеет набор других полезных методов для работы с результатом запроса.

Например, мы можем выяснить, содержит ли результат запись с определённым первичным ключом методом contains.

Проверка на существование ключа в коллекции

$roles = User::find(1)->roles;

if ($roles->contains(2))
{
	//
}

Коллекции также могут быть преобразованы в массив или строку JSON:

$roles = User::find(1)->roles->toArray();

$roles = User::find(1)->roles->toJson();

Если коллекция преобразуется в строку результатом будет JSON-выражение:

$roles = (string) User::find(1)->roles;

Коллекции Eloquent имеют несколько полезных методов для прохода и фильтрации содержащихся в них элементов.

Проход и фильтрация элементов коллекции

$roles = $user->roles->each(function($role)
{

});

$roles = $user->roles->filter(function($role)
{

});

Применение функции обратного вызова

$roles = User::find(1)->roles;

$roles->each(function($role)
{
	//
});

Сохранение коллекции по значению

$roles = $roles->sortBy(function($role)
{
	return $role->created_at;
});

Иногда вам может быть нужно получить собственный объект Collection со своими методами. Вы можете указать его при определении модели Eloquent, перекрыв метод newCollection.

Использование произвольного класса коллекции

class User extends Eloquent {

	public function newCollection(array $models = array())
	{
		return new CustomCollection($models);
	}

}

Читатели и преобразователи

Eloquent содержит мощный механизм для преобразования атрибутов модели при их чтении и записи. Просто объявите в её классе метод getFooAttribute. Помните, что имя метода должно следовать соглашению camelCase, даже если поля таблицы используют соглашение snake-case (он же - "стиль Си", с подчёркиваниями -прим. пер.).

Объявление читателя

class User extends Eloquent {

	public function getFirstNameAttribute($value)
	{
		return ucfirst($value);
	}

}

В примере выше поле first_name теперь имеет читателя (accessor). Заметьте, что оригинальное значение атрибута передаётся методу в виде параметра.

Преобразователи (mutators) объявляются подобным образом.

Объявление преобразователя

class User extends Eloquent {

	public function setFirstNameAttribute($value)
	{
		$this->attributes['first_name'] = strtolower($value);
	}

}

Преобразователи дат

По умолчанию Eloquent преобразует поля created_at, updated_at и deleted_at в объекты Carbon, которые предоставляют множество полезных методов, расширяя стандартный класс PHP DateTime.

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

public function getDates()
{
	return array('created_at');
}

Когда поле является датой, вы можете установить его в число-оттиск времени формата Unix (timestamp), строку даты формата(Y-m-d), строку даты-времени и, конечно, экземпляр объекта DateTime или Carbon.

Чтобы полностью отключить преобразование дат просто врените пустой массив из метода getDates.

public function getDates()
{
	return array();
}

События моделей

Модели Eloquent инициируют несколько событий, что позволяет вам добавить к ним свои обработчики с помощью следующих методов: creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored.

Когда первый раз сохраняется новая модель возникают события creating и created. Если модель уже существовала на момент вызова метода save, вызываются события updating и updated. В обоих случаях также возникнут события saving и saved.

Если обработчики creating, updating, saving или deletingвернут значение false, то действие будет отменено.

Отмена сохранения модели через события

User::creating(function($user)
{
	if ( ! $user->isValid()) return false;
});

Модели Eloquent также содержат статический метод boot, который может быть хорошим местом для регистрации ваших обработчиков событий.

Определение метода boot

class User extends Eloquent {

	public static function boot()
	{
		parent::boot();

		// Регистрация ваших обработчиков...
	}

}

Наблюдатели моделей

Для того, чтобы держать всех обработчиков событий моделей вместе вы можете зарегистрировать наблюдателя (observer). Объект-наблюдатель может содержать методы, соответствующие различным событиям моделей. Например, методы creating, updating и saving, а также любые другие методы, соответствующие именам событий.

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

class UserObserver {

	public function saving($model)
	{
		//
	}

	public function saved($model)
	{
		//
	}

}

Вы можете зарегистрировать его используя метод observe:

User::observe(new UserObserver);

Преобразование в массивы и JSON

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

Преобразование модели к массиву

$user = User::with('roles')->first();

return $user->toArray();

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

return User::all()->toArray();

Для преобразования модели к JSON, вы можете использовать метод toJson:

Преобразование модели к JSON

return User::find(1)->toJson();

Обратите внимание, что если модель преобразуется к строке, результатом также будет JSON - это значит, что вы можете возвращать объекты Eloquent напрямую из ваших маршрутов!

Возврат модели из маршрута

Route::get('users', function()
{
	return User::all();
});

Иногда вам может быть нужно ограничить список атрибутов, включённых в преобразованный массив или JSON-строку - например, скрыть пароли. Для этого определите в классе модели свойство hidden.

Скрытие атрибутов при преобразовании в массив или JSON

class User extends Eloquent {

	protected $hidden = array('password');

}

Вы также можете использовать атрибут visible для указания разрешённых полей:

protected $visible = array('first_name', 'last_name');

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

public function getIsAdminAttribute()
{
	return $this->attributes['admin'] == 'да';
}

Как только вы создали читателя добавьте его имя к свойству-массиву appends класса модели:

protected $appends = array('is_admin');

Как только атрибут был добавлен к списку appends, он будет включён в массивы и выражения JSON, образованные от этой модели.