Связи моделей в Eloquent — Настройка связей 'один ко многим' и 'многие ко многим' между категориями, товарами и заказами
Изучение реляционных связей в Laravel Eloquent ORM. Мы настроим взаимодействия между моделями Category, Product, Order и OrderItem, применяя методологию Direct Instruction для глубокого понимания архитектуры базы данных.
Добро пожаловать в одиннадцатый урок нашего курса по созданию интернет-магазина. Сегодня мы переходим к одной из самых мощных возможностей фреймворка Laravel — системе реляционных связей Eloquent ORM. В рамках методологии Direct Instruction мы последовательно разберем, как таблицы в базе данных общаются друг с другом через модели PHP. В реальном интернет-магазине данные никогда не существуют изолированно. Товар всегда принадлежит какой-то категории, а заказ состоит из множества товаров. Для реализации такой логики используются связи 'Один ко многим' (One-to-Many) и 'Многие ко многим' (Many-to-Many). Eloquent позволяет нам работать с этими связями как с обычными свойствами объектов, скрывая под капотом сложные SQL-запросы с операторами JOIN. Это значительно ускоряет разработку и делает код более читаемым. Важно понимать: прежде чем настраивать связи в моделях, ваши миграции должны быть корректно настроены с использованием внешних ключей (foreign keys), таких как category_id в таблице products.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Category extends Model
{
protected $fillable = ['name', 'slug'];
// Связь 'Один ко многим': Одна категория имеет много товаров
public function products(): HasMany
{
return $this->hasMany(Product::class);
}
}
В приведенном выше коде мы определили связь в модели Category. Метод products() возвращает объект отношения HasMany. Обратите внимание на типизацию возвращаемого значения — это хорошая практика в PHP 8. Теперь, если у нас есть объект категории, мы можем получить все её товары, просто обратившись к свойству: $category->products. Laravel автоматически выполнит SQL-запрос вида SELECT * FROM products WHERE category_id = ?. Типичная ошибка новичков — вызов метода со скобками $category->products() вместо свойства. Если вы используете скобки, вы получаете объект построителя запросов (Query Builder), к которому можно добавить дополнительные условия (например, $category->products()->where('price', '>', 100)->get()). Если же вы обращаетесь как к свойству, вы получаете готовую коллекцию (Collection) моделей Product.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Product extends Model
{
protected $fillable = ['category_id', 'name', 'description', 'price'];
// Обратная связь: Товар принадлежит одной категории
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
}
Для полноценной работы связи необходимо настроить её с обеих сторон. В модели Product мы используем метод belongsTo. Это означает, что в таблице products есть столбец category_id, который ссылается на id в таблице categories. Теперь мы можем сделать так: $product->category->name, чтобы вывести название категории конкретного товара. Применяя принцип Chunking, мы разбиваем сложную тему на части. Мы только что освоили 'Один ко многим'. Теперь поговорим о заказах. Заказ (Order) содержит множество товаров, но и один и тот же товар может быть в разных заказах. Это связь 'Многие ко многим' (Many-to-Many). Однако в e-commerce мы обычно используем промежуточную модель OrderItem (позиция заказа), которая хранит не только связи, но и цену на момент покупки, а также количество. Поэтому мы сводим это к двум связям 'Один ко многим': Order имеет много OrderItem, а OrderItem принадлежит Order и Product.
Какой метод Eloquent используется в модели Product для указания того, что товар принадлежит определенной категории?
Практическое задание: Настройка связей
В рамках нашего проекта (Project-Based Learning) реализуйте связи между моделями.
- Откройте файл app/Models/Category.php и добавьте метод products() с использованием hasMany.
- Откройте файл app/Models/Product.php и добавьте метод category() с использованием belongsTo.
- Создайте модель OrderItem (php artisan make:model OrderItem).
- В модели Order добавьте связь items(), возвращающую hasMany(OrderItem::class).