12
votes

In my Laravel application, I have a category listing page. When the user clicks on a certain subcategory, I'd like to list all the products and use pagination on that result. I'm already listing all the products related to that subcategory, for now, with the help of a subcategory ID:

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

There are three classes involved in this structure: Category, Subcategory and Products. They were declared as follows:

Category

<?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');
    }
}

Subcategory

<?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');
    }
}

Products

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

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

For each model class I have one table, with this structure:

Category
- id
- category_name

SubCategory
- id
- category_id
- subcategory_name

Products
- id
- subcategory_id
- product_title
- description
- price

What I want is to paginate the results retrieved from the query in my page. Is there any better way to fetch the products associated to the subcategory and paginate them?

3
Hey @Sid, what is the content of your $slug variable? Also that $idofSubcat variable you're using when calling find method doesn't seem to have being initialized.Gustavo Straube
Hey! Have my answer below ever helped you? If so, please accept it as the correct one. Doing that you may help others seeking a solution for a similar problem.Gustavo Straube

3 Answers

6
votes

In Eloquent (Laravel's ORM) when you call a relation as a property ($subCategory->products), it returns the related object or a collection of objects depending on the relation type (belongs to, has many, ...). Instead, if you call it as a function ($subCategory->products()), you get a QueryBuilder instance.

Refer to http://laravel.com/docs/5.1/eloquent-relationships#querying-relations, under section Relationship Methods Vs. Dynamic Properties for more details on that.

Anyway, using the relationship method, you can call paginate() for your collection. Then, with that in mind, you can change your code slightly to get what you want:

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
votes

I think, that create two categories table not so correctly, it will be better to use next:

table categories

id    category_name   parent_id(nullable)  

and Products

 id          category_id        product_title      description     price

It's more usefull, you can remove one Subcategory model and do all in Category.

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');
    }
}

and products model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

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

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


}

then, you can get the query result

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

But, existing one not pretty thing. Do you really sure, that products will be only in one category?)

2
votes

I couldn't really understand some of your initial function:

// $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,
        ));
}

If all you're trying to do is paginate the Products that belong to a specific subcategory_id, given you have the subcategory_id then the following code will work:

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

Then you can return this paginated collection to your view as you're already doing:

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