Возвращает только последнюю категорию SlugCategory для всего дерева категорий (корневая и детская)
Это мое предложение:
В категории Модель:
public function slug() {
return $this->hasMany('App\CategorySlug', 'category_id', 'id')->latest();
}
- Вы устанавливаете отношение слагов как оно есть: один ко многим (категория имеет много слагов);
- Вы вызываете метод
latest()
, чтобы предоставить вам только последний слаг.
При таком подходе при вызове отношения slug()
он будет извлекать только самую последнюю запись CategorySlug.
В категории Модель:
public function children() {
return $this->hasMany('App\Category', 'parent_id', 'id')->
orderBy('order')->
with('children', 'slug');
}
Итак, этот вызов контроллера ...
$categories = Category::where('parent_id', null)->with('children', 'slug')->get();
... будет возвращать только последний слаг для основной категории (parent_id = null), а также для всех их детей.
ПРЕДУПРЕЖДЕНИЕ - бесконечная энергичная загрузка
После того, как я предоставил вам свое решение, я хотел бы поговорить о чем-то, что, как правило, многие разработчики Laravel / Eloquent не знают.
По сути, вы создаете бесконечную нетерпеливую загрузку. Позвольте мне объяснить вам:
Это модель вашей категории и их отношения:
Categories => Categories (children)
=> CategorySlug (slug)
А это ваша модель CategorySlug и их отношения:
CategorySlug => Category
Вы создали модель CategorySlug с методом, который возвращает модель Category.
В этом же методе вы вернули отношение категории с соответствующим слагом.
Из-за этого определения WITH в вашей модели CategorySlug фактически вы просто восстанавливаете ту же модель CategorySlug.
Это не имеет смысла, а также создает бесконечную нагрузку. Пример объяснения:
Category::find(1)->slug();
Что здесь произойдет:
category will load slug -> slug will load category -> category will load slug -> ...
Это бесконечная энергичная загрузка. Это приведет к исключению тайм-аута базы данных.
Чтобы избежать этого, просто удалите with
на своей модели CategorySlug.
Это не обязательно, с моей точки зрения.
Дайте мне знать, если ваши требования изменятся, и вам действительно нужны эти обратные отношения.
Трюки и дополнительные знания
- Старейшие и новейшие методы
Существует 2 метода, которые позволяют вам извлечь только самую старую или самую последнюю запись. Пример: * * тысяча семьдесят пять
$categories = Category::where('is_active', true); // we have many categories here
$last_created_category = $categories->latest(); // latest category created
$old_updated_category = $categories->oldest('updated_at'); // oldest category updated
Оба метода принимают строку в качестве параметров, чтобы определить, какое поле должно быть отсортировано.
По умолчанию created_at
.
- Использование стратегии области действия
Области являются отличным способом создания настраиваемой многократно используемой реализации.
Предполагая реализацию вашего контроллера, мы могли бы применить область действия в следующем случае:
В категории Модель -
class Category extends Model
{
...
public function scopeWithoutParent($query) {
return $query->whereNull('parent_id');
}
}
На контроллере -
$categories = Category::withoutParent()->with('children', 'slug')->get();
- Всегда стремимся загрузить ваши отношения
Это трюк, который, возможно, вы могли бы использовать в своем проекте.
По сути, вы можете заставить eloquent загружать отношения без явного вызова.
В категории Модель -
class Category extends Model
{
...
protected $with = [ 'children', 'slug' ];
public function children() {
return $this->hasMany('App\Category', 'parent_id', 'id')->orderBy('order');
}
public function slug() {
return $this->hasMany('App\CategorySlug', 'category_id', 'id')->latest();
}
На контроллере -
$categories = Category::withoutParent()->get();
Как видите, вам больше не нужно явно называть отношения.
Надеюсь, это будет полезно.
Хорошего дня.