Связь один ко многим
Давайте теперь изучим связь один ко многим. Такая связь образуется, когда запись одной таблицы соответствует многим записям из другой таблицы.
Давайте посмотрим на примере. Пусть у нас есть следующая таблица с категориями:
category
id
name
Пусть также у нас есть следующая таблица с постами:
posts
id
title
category_id
Заюзаем в модели с категориями модель с постами:
app/Models/Category.php<?php
use App\Models\Post;
class Category extends Model
{
}
Каждая категория имеет много постов, которые ссылаются на нее. Давайте в модели с категориями сделаем метод для получения постов:
app/Models/Category.php<?php
use App\Models\Post;
class Category extends Model
{
public function posts()
{
}
}
Пропишем в этом методе связь через отношение hasMany
:
app/Models/Category.php<?php
class Category extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
Получение данных
Выше мы связали категории и их посты отношением hasMany
. Давайте теперь в контроллере получим какую-нибудь категорию:
app/Http/Controllers/CategoryController.php<?php
class CategoryController extends Controller
{
public function show()
{
$category = Category::find(1);
dump($category);
}
}
Вместе с категорией мы автоматически получим коллекцию постов:
app/Http/Controllers/CategoryController.php<?php
class CategoryController extends Controller
{
public function show()
{
$category = Category::find(1);
dump($category->posts); // коллекция постов
}
}
Давайте переберем коллекцию с постами через цикл:
app/Http/Controllers/CategoryController.php<?php
class CategoryController extends Controller
{
public function show()
{
$category = Category::find(1);
foreach ($category->posts as $post) {
dump($post->title);
}
}
}
Давайте теперь получим коллекцию категорий. Переберем ее циклом, для каждой категории получим коллекцию постов и также переберем ее циклом:
app/Http/Controllers/CategoryController.php<?php
class CategoryController extends Controller
{
public function show()
{
$categories = Category::all();
foreach ($categories as $category) {
dump($category->name);
foreach ($category->posts as $post) {
dump($post->title);
}
}
}
}
Условия
Можно добавлять дополнительные условия при получении связанных данных. Давайте посмотрим, как это делается. Пусть у нашей таблицы с постами будет также и поле likes
, содержащее количество лайков:
posts
id
title
likes
category_id
Давайте для начала получим категорию вместе с коллекцией ее постов:
app/Http/Controllers/CategoryController.php<?php
class CategoryController extends Controller
{
public function show()
{
$posts = Category::find(1)->posts;
dump($posts);
}
}
Теперь заменим свойство posts
на метод posts()
. В этом случае метод своим результатом вернет построитель запросов:
app/Http/Controllers/CategoryController.php<?php
class CategoryController extends Controller
{
public function show()
{
$qb = Category::find(1)->posts();
dump($qb);
}
}
Так как возвращается построитель запросов, то мы можем дальше продолжить цепочку, к примеру, наложив некоторое условие на получаемые посты:
app/Http/Controllers/CategoryController.php<?php
class CategoryController extends Controller
{
public function show()
{
$posts = Category::find(1)
->posts()
->where('likes', '>', 10)
->get();
dump($posts);
}
}
Обратная связь
Пусть у нас опять есть таблица с категориями и таблица с постами. Выше мы говорили, что каждая категория имеет много постов. Но это зависит от точки зрения.
Если посмотреть со стороны поста, то каждый пост принадлежит одной категории. Это значит что пост можно связать с категорией отношением belongsTo
:
app/Models/Post.php<?php
class Post extends Model
{
public function category()
{
return $this->belongsTo(Category::class);
}
}
Получим теперь пост вместе с его категорией:
app/Http/Controllers/PostController.php<?php
class PostController extends Controller
{
public function show()
{
$post = Post::find(1);
dump($post);
dump($post->category);
}
}
Получим все посты, переберем их циклом и выведем их вместе с их категориями:
app/Http/Controllers/PostController.php<?php
class PostController extends Controller
{
public function show()
{
$posts = Post::all();
foreach ($posts as $post) {
dump($post);
dump($post->category);
}
}
}
Несколько обратных связей
Может такое быть, что одна таблица имеет несколько связей. Давайте посмотрим, как действовать в таком случае.
Пусть у нас есть таблица с постами:
posts
id
title
Таблица с юзерами:
users
id
name
Пусть у нас есть таблица с комментами, в который каждый коммент связан со своим постом и со своим юзером:
comments
id
text
post_id
user_id
Давайте пропишем эту связь в модели для комментов:
app/Models/Comment.php<?php
class Comment extends Model
{
public function post()
{
return $this->belongsTo(Post::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
Теперь при получении коммента мы можем получить его пост и его юзера:
app/Http/Controllers/CommentController.php<?php
class CommentController extends Controller
{
public function show()
{
$comment = Comment::find(1);
dump($comment);
dump($comment->post);
dump($comment->user);
}
}