Связи в Eloquent ORM: Отношения между моделями
Студент настроит связи «один ко многим» и «многие ко многим» между категориями, товарами и заказами, используя возможности Eloquent.
Введение в связи базы данных и Eloquent ORM
В предыдущих уроках мы создали миграции и базовые модели для нашего интернет-магазина. Однако реальная сила реляционных баз данных (таких как MySQL) и ORM (Object-Relational Mapping) заключается в их способности связывать данные между собой. В архитектуре MVC модель отвечает за структуру данных, и именно в моделях мы описываем эти связи. Eloquent ORM — это реализация паттерна ActiveRecord в Laravel, позволяющая работать с таблицами базы данных как с объектами классов.
Представьте интернет-магазин: у нас есть Категории (Categories) и Товары (Products). Одна категория может содержать множество товаров — это классическая связь «Один ко многим» (One-to-Many). Eloquent позволяет нам описать эту связь всего одной строчкой кода, после чего мы сможем получать все товары категории простым обращением к свойству: $category->products. В этом уроке мы подробно разберем, как настраивать такие связи, как они работают под капотом и как избежать типичных ошибок новичков, таких как проблема N+1.
Реализация связи «Один ко многим»
Чтобы связать модели Category и Product, нам нужно определить методы внутри самих классов моделей. В Laravel для связи «Один ко многим» используются методы hasMany() (имеет много) и belongsTo() (принадлежит к). Важно понимать логику: таблица, которая содержит внешний ключ (в нашем случае это category_id в таблице products), всегда использует метод belongsTo. Таблица, на которую ссылаются, использует hasMany.
Типичная ошибка новичков: путаница в том, где какой метод применять. Запомните простое правило: если в миграции таблицы есть поле с суффиксом _id (например, category_id), то соответствующая модель ДОЛЖНА иметь метод с belongsTo. Давайте посмотрим, как это выглядит в коде на практике.
// App\Models\Category.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model {
// Категория имеет много товаров
public function products() {
return $this->hasMany(Product::class);
}
}
// App\Models\Product.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
// Товар принадлежит одной категории
public function category() {
return $this->belongsTo(Category::class);
}
}
Как Eloquent строит SQL-запросы
Когда вы вызываете $product->category, Laravel под капотом делает следующее: он берет значение поля category_id у текущего товара и выполняет SQL-запрос вида: SELECT * FROM categories WHERE id = ? LIMIT 1. Это происходит автоматически, благодаря строгим соглашениям Laravel (Conventions). Фреймворк сам догадывается, что внешний ключ называется category_id, потому что метод называется category, а первичный ключ в таблице категорий — id.
Если вы отступаете от стандартов именования (например, ваш внешний ключ называется cat_id), вы можете передать его вторым аргументом: $this->belongsTo(Category::class, 'cat_id'). Однако следование стандартам (Scaffolding) значительно ускоряет разработку и делает код чище. В нашем курсе мы строго следуем PSR-12 и соглашениям Laravel.
Какой метод Eloquent ORM нужно использовать в модели Product, если таблица products содержит поле category_id?
Связь «Многие ко многим» и сводные таблицы
Теперь рассмотрим более сложный случай: Заказы (Orders) и Товары (Products). Один заказ может содержать множество разных товаров, а один и тот же товар может присутствовать в сотнях разных заказов. Это классическая связь «Многие ко многим» (Many-to-Many). Реляционные базы данных не поддерживают такую связь напрямую. Для ее реализации требуется третья, промежуточная таблица, называемая сводной (pivot table).
В нашем архиве проекта указано, что мы используем таблицу order_items. Эта таблица содержит как минимум два поля: order_id и product_id, а также дополнительные данные, такие как quantity (количество) и price (цена на момент покупки). В Eloquent для такой связи используется метод belongsToMany(). Чтобы получить доступ к дополнительным полям сводной таблицы (например, количеству), необходимо использовать метод withPivot('quantity', 'price') при описании связи.
Как называется паттерн, который реализует Eloquent ORM, позволяя работать с таблицами БД как с объектами классов?
Настройка связей в проекте
Примените полученные знания для настройки моделей вашего интернет-магазина. Это критически важный шаг перед разработкой контроллеров.
- Откройте модель App\Models\Category и добавьте метод products() с использованием hasMany.
- Откройте модель App\Models\Product и добавьте метод category() с использованием belongsTo.
- Убедитесь, что миграция таблицы products содержит поле category_id (как было указано в архивных упражнениях).
- Запустите php artisan tinker и проверьте работу связей, создав тестовую категорию и товар.