Получение всех объектов из hasMany отношения и paginate

В моем приложении Laravel у меня есть страница со списком категорий. Когда пользователь нажимает на определенную подкатегорию, я хотел бы перечислить все продукты и использовать разбиение на страницы этого результата. Я уже перечисляю все продукты, относящиеся к этой подкатегории, теперь, с помощью идентификатора подкатегории:

public function subcategoryListing($slug){
    $products = Subcategory::find($idofSubcat)->products;
    return view('pages.subcategorylisting')
        ->with(array(
            'products' => $products,
        ));
}

В этой структуре задействованы три класса: Категория, Подкатегория и Продукты. Они были объявлены следующим образом:

Категория

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use App\Subcategory;

class Category extends Model
{
    protected $table = 'category';

    public $timestamps = false;

    public function subCategory(){
        return $this->hasMany('App\Subcategory', 'category_id');
    }
}

категория

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Subcategory extends Model
{
    protected $table = 'subcategory';

    public $timestamps = false;

    public function products(){
        return $this->hasMany('App\Products');
    }
}

Продукция

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Products extends Model
{
    protected $table = 'products';
}

Для каждого класса модели у меня есть одна таблица с этой структурой:

Category
- id
- category_name

SubCategory
- id
- category_id
- subcategory_name

Products
- id
- subcategory_id
- product_title
- description
- price

Я хочу, чтобы разбивать результаты, полученные из запроса на моей странице. Есть ли лучший способ получить products, связанный с subcategory и разбивать на них страницы?

Ответ 1

В Eloquent (Laravel ORM), когда вы вызываете отношение как свойство ($subCategory->products), он возвращает связанный объект или коллекцию объектов в зависимости от типа отношения (принадлежит, имеет много,...). Вместо этого, если вы называете это функцией ($subCategory->products()), вы получаете экземпляр QueryBuilder.

Обратитесь к http://laravel.com/docs/5.1/eloquent-relationships#querying-relations в разделе Методы взаимодействия Vs. Динамические свойства для более подробной информации.

В любом случае, используя метод отношений, вы можете вызвать paginate() для своей коллекции. Затем, имея в виду, вы можете немного изменить свой код, чтобы получить то, что вы хотите:

public function subcategoryListing($slug) {

    // I'm supposing here that in somewhere before 
    // run the query, you set the value to $idofSubcat 
    // variable

    $products = Subcategory::find($idofSubcat)->products()->paginate();
    return view('pages.subcategorylisting')
        ->with(array(
            'products' => $products,
        ));
}

Ответ 2

Я думаю, что создать две таблицы категорий не так правильно, лучше будет использовать следующий:

категории таблицы

id    category_name   parent_id(nullable)  

и продукты

 id          category_id        product_title      description     price

Более полезно, вы можете удалить одну модель подкатегории и сделать все в категории.

namespace App;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    protected $table = 'category';

    public $timestamps = false;

    public function subCategory(){

        return $this->belongsToMany('App\Category', 'categories', 'id', 'parent_id');
    }

    public function products(){
        return $this->hasMany('App\Products');
    }
}

и модель продуктов

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Products extends Model
{
    protected $table = 'products';

    public function category() {
         return $this->belongsTo('App\Category')
    }


}

тогда вы можете получить результат запроса

public function subcategoryListing($slug){
        $products = Category::find($idofSubcat)->products;
        return view('pages.subcategorylisting')
            ->withProducts($products); // it a magic)) 
}

Но, существующая одна некрасивая вещь. Вы действительно уверены, что продукты будут только в одной категории?)

Ответ 3

Я не мог понять некоторые из ваших первоначальных функций:

// $slug is not being used anywhere within the function
public function subcategoryListing($slug){

    // $idOfSubcat isn't passed to this function so will throw an error
    $products = Subcategory::find($idofSubcat)->products;

    return view('pages.subcategorylisting')
        ->with(array(
            'products' => $products,
        ));
}

Если все, что вы пытаетесь сделать, это paginate Products, которые относятся к определенному subcategory_id, если у вас есть subcategory_id, тогда будет работать следующий код:

$products = Product::where('subcategory_id', $idofSubcat)->paginate();

Затем вы можете вернуть эту разбитую на страницу коллекцию к вашему представлению, как вы уже делаете:

return view('pages.subcategorylisting')
    ->with(compact('products'));