Один пользователь может содержать множество телефонов. Тогда следует использовать связь hasMany(). Другими примерами данного отношения «один ко многим» является статья в блоге, которая имеет «много» комментариев или мама, имеющая детей. Мы можем смоделировать это отношение таким образом:
class User extends Model{ public function phones() { return $this->hasMany('Phone'); } }
Теперь мы можем получить все телефоны пользователя с помощью динамического свойства:
$phones = User::find(1)->phones;
В этом случае, мы получили массив телефонов, и для просмотра всех телефонов, нужно пройтись по элементам массива.
foreach($phones as $one){ echo $one->body; echo '\n'; }
Если нужно добавить ограничения на получаемые телефоны, можно вызвать метод phones() и продолжить добавлять условия:
$phone = User::find(1)->phones()->where('title', '=', 'foo')->first();
Теперь мы получили один телефон, который сразу можно вывести на экран:
$phone->body
Рассмотрим еще один пример, который выявит недостатки связи hasMany. Предположим, у нас есть модель Book и модель Author. Book принадлежит (связь belongsTo) Author. И наоборот, Author содержит (связь hasMany) множество Book.
Определение связи в модели Book:
class Book extends Model { public function author() { return $this->belongsTo('Author'); } }
Получить все названия книг можно следующим образом:
foreach (Book::all() as $book) { echo $book->name; }
Мы обошлись всего одним заросом. Даже если будет 100 книг, это всё-равно один запрос:
SELECT * FROM books
Однако, если к выводу названия книги добавим автора:
foreach (Book::all() as $book) { echo $book->name; echo $book->author->name; }
То, получаем 101 запрос. Первым запросом получаем все книги, а потом в цикле делаем запрос на получение автора книги.
SELECT * FROM books; SELECT * FROM authors WHERE id = 1; SELECT * FROM authors WHERE id = 2; SELECT * FROM authors WHERE id = 3; ...
Это очень не рационально. И чтобы сократить нагрузку на сервер бызы данных, можно воспользоваться активной загрузкой.
Активная загрузка
Акнивная загрузка подразумевает подключение связующей модели с помощью метода with
.
foreach (Book::with('author')->get() as $book) { echo $book->author->name; }
Таким образом будут выполнены всего два запроса:
SELECT * FROM books; SELECT * FROM authors WHERE id IN(1,2,3);
Конечно, вы можете загрузить несколько отношений одновременно:
$books = Book::with('author', 'publisher')->get();
Разумное использование активной загрузки поможет сильно повысить производительность приложения.
Практика