Как получить много ко многим элементам отношений в laravel
есть структура данных для интернет-магазина:
Series -> (many to many) -> categories -> (many to many) -> products
например, серия "на открытом воздухе серия", категории" футболка", продукты " футболка а, футболка Б, ЕТК... "
и вот контроллер, который перечисляет продукты в один категория
public function view($series = 0, $cat = 0, $page = 1) {
$category = Category::find($cat);
$totalItems = count($category->product);
$itemsPerPage = 30;
$currentPage = $page;
$urlPattern = "/ums/product/view/$series/$cat/(:num)";
$this->data['product_list'] = $category->product()->orderBy('created_at', 'desc')->skip(($page - 1) * $itemsPerPage)->take($itemsPerPage)->get();
$this->data['paginator'] = new Paginator($totalItems, $itemsPerPage, $currentPage, $urlPattern);
$this->data['category'] = $category;
$this->data['page'] = $page;
return view('product/list')->with($this->data);
}
теперь проблема в том, что я хотел бы переписать код так, чтобы вместо показа одной категории я хотел бы показать одну серию.
это означает, что если $ series = 0, то он показывает продукты в одной категории, если $cat = 0, то он показывает продукты в multi категория
в laravel как получить продукты в multi категории? попробуйте $series - >category - >product (), но не повезло, а также как переписать эту функцию для поддержки показа серии?
Спасибо большое.
4 ответов
предполагая классы модели Laravel-серия, категория и продукт
для класса модели серии создайте функцию
public function categories()
{
return $this->belongsToMany('App\Category');
}
для класса модели категории создайте функцию
public function products()
{
return $this->belongsToMany('App\products');
}
теперь для данной серии, вы можете легко получить все связанные категории с помощью простой вызов функции
$categories = $series->categories();
наконец, подходит к основной проблеме показа продуктов под несколькими категориями.
for($categories as $category)
{
$productsOfThisCategory = $categories->products();
//save into some other data structure, say an array $allProducts
}
$allProducts будет имейте продукты multi-категории для специфической серии.
относятся : стандартные красноречивые отношения-многие ко многим
вы можете использовать этот ответ для сортировки.
как Сортировать по полю сводной таблицы отношений "многие ко многим" в красноречивом ORM
Если я правильно вас понимаю, то ваши модели выглядят как ниже
class Series extends Model
{
// other code
public function categories() {
return $this->belongsToMany('App\Category');
}
// other code
}
class Category extends Model
{
// other code
public function series() {
return $this->belongsToMany('App\Series');
}
public function products() {
return $this->belongsToMany('App\Product');
}
// other code
}
class Product extends Model
{
// other code
public function categories() {
return $this->belongsToMany('App\Category');
}
// other code
}
далее, чтобы получить все продукты определенной серии, вам нужно сделать это
public function view($series = 0, $cat = 0, $page = 1)
{
if (!empty($series)) {
$seria = Series::with(['categories' => function($query) {
$query->with('products');
})->find($series);
// or may be this will work, don't know
// Series::with('categories.products')->find($series);
// get all caegories from seria or certain one
if (empty($cat)) {
$categories = $seria->categories;
}
else {
$categories = $seria->categories()->where('id', $cat)->get;
}
// retrieve produts form each category and making from them collection
$products = $categories->map(function($category) {
return $category->products;
})->flatten();
// or use this approach if above not working
/*$products = collect([]);
foreach ($categories as $category) {
$produts = $products->merge($category->products);
}*/
// do your magic
}
else {
// not exactly understand what you want to do when $series is not set
}
// do your magic
}
мой подход состоял бы в том, чтобы создать что-то вроде пользовательского отношения в Serie
модель:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Serie extends Model
{
public function categories() {
return $this->belongsToMany('App\Category');
}
public function products()
{
return Product::whereIn('id', function($query){
$query->select('product_id')
->from('category_product as cp')
->join('category_serie as cs', 'cs.category_id', '=', 'cp.category_id')
->where('cs.serie_id', $this->id)
;
});
}
}
The products()
метод возвратит Builder
экземпляра. И вы можете использовать его в своем контроллере, например:
$serie = Serie::find($series);
$products = $serie->products()->get();
это выполнит только два запроса:
select * from `series` where `series`.`id` = ? limit 1
select *
from `products`
where `id` in (
select `product_id`
from `category_product` as `cp`
inner join `category_serie` as `cs`
on `cs`.`category_id` = `cp`.`category_id`
where `cs`.`serie_id` = ?
)
это также должно быть возможным:
$products = $serie->products()
->orderBy('created_at', 'desc')
->skip(($page - 1) * $itemsPerPage)
->take($itemsPerPage)
->get()
;