Getting all objects from hasMany relation and paginate - php

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?

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

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?)

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

Related

Laravel HasMany relationship not giving expected result

I have three table with following columns:
posts table
id
author
title
content
seen
post_img
post_category table
id
category_id
post_id
categories table
id
category
I created post_category table to store post catergories. I wanted to get posts that have specific category. And i created my PostModel associated with posts table like this:
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\AuthorModel;
use App\Models\PostCategoryModel;
use App\Models\CategoryModel;
class PostModel extends Model
{
use HasFactory;
protected $table = 'posts';
public function getAuthor(){
return $this->hasOne(AuthorModel::class, 'id', 'author');
}
public function getCategories(){
return $this->hasMany(PostCategoryModel::class, 'post_id', 'id');
}
}
After i got the PostCategoryModel from calling getCategories method, i created PostCategoryModel associated with post_category table like this:
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\CategoryModel;
use App\Models\PostModel;
class PostCategoryModel extends Model
{
use HasFactory;
protected $table = 'post_category';
public function getCategory(){
return $this->hasMany(CategoryModel::class, 'id', 'category_id');
}
public function getPosts(){
return $this->belongsToMany(PostModel::class, 'id', 'post_id');
}
}
But here is the problem, when i call PostModel::getCategories in my Controller method it gives me this error: Undefined constant App\Models\PostModel::getCategories. How can i get categories of a post in my case?
Laravel version: Laravel Framework 8.22.1
PHP version: PHP 8.0.1 (cli) (built: Jan 5 2021 23:43:33) ( NTS Visual C++ 2019 x64 )
As I know you can't call relation methods like static method cause it needs an instance to check its id and match with other table. You can use something like this:
$cats = PostModel::find(1)->getCategories();
But it's just an example and in real application you probably use route model binding or anything else.
I believe you have a many to many relation between post and category, If so then you don't need intermediate model for junction table post_category unless you have another specific reason to introduce model for this table.
For many to many relationship you need to adjust your post and category models as
class Post extends Model
{
//.. Other methods
public function categories(){
return $this->belongsToMany(Category::class, 'post_category', 'post_id', 'category_id');
}
}
class Category extends Model
{
//.. Other methods
public function posts(){
return $this->belongsToMany(Post::class, 'post_category', 'category_id','post_id');
}
}
I wanted to get posts that have specific category
Once you have proper relations in place you can get posts for specific category using whereHas()
$posts = Post::whereHas('categories', function (Builder $query) use($category_id) {
$query->where('id', $category_id);
})->get();
How can i get categories of a post in my case?
To get categories associated with posts you can eager load them as
$posts = Post::with('categories')
->whereHas('categories', function (Builder $query) use($category_id) {
$query->where('id', $category_id);
})->get();

how to get desired column from other table

there are two tables products and categories, that I created by PHPMyAdmin.
In the products table, it has a column name prd_category that has the foreign key of table categories named cat_id(primary key of categories table).
i am quite new in laravel
i want return all data from product table with category name(cat_name) from another table
//here is my controller
use App\Models\product;
class items extends Controller
{
public function sample(){
return product::all();
}
}
//route
Route::get('/',[items::class,'sample']);
//model for products table
class product extends Model
{
use HasFactory;
function category(){
return $this->hasOne('App\Models\category','cat_id','prd_id');
}
}
//model for category
class category extends Model
{
protected $table='categories';
use HasFactory;
}
pls help and thanks in advance..
you can use this code:
$products = product::whereHas('category',function($q)use($cat_name){
$q->where('name',$cat_name)
})->get();
or :
$categories = Category::where('name',$cat_name)->get()->pluck('id')->toArray()
$products = product::whereIn('category_id',$categories)->get();
Are you sure that one-to-many relation is correct? If a product can belong to many categories, you need to use many-to-many relations. Furthermore, if something else belongs to categories you should use many-to-many polymorphic relations. But let's go with one-to-many.
First, the relation function in Product.php looks incorrect. I think products should belong to a category.
function category(){
return $this->belongsTo('App\Models\Category','cust_name','name');
}
Then you need to define reverse relation in Category.php
function products(){
return $this->hasMany('App\Models\Product','cust_name','name');
}
When you define the relations properly, all you need yo do is to fetch data in controller:
use App\Models\Category
...
Category::with('products')->get();
you can use relationship with forign key like pro_id
function category(){
return $this->belongsTo('App\Models\Category','pro_id');
}
function products(){
return $this->hasMany('App\Models\Product','id');
}
$cat = Category::with('products')->all();
in Blade :
{{ $cat->products->cat_name; }}

Retrieve post by category id laravel

I want to retrieve all post with given category,
i am developing api, at input i will receive category name, and then i want to retrieve that category by its id in posts table,i want to do this because if some changed category name in the future i dont have to change that in my code
i have create like this
PostController.php
public function getPostsByCategory(Request $request)
{
$posts=Posts::where('category',$request->category)->get();
return response()->json(['posts'=>$posts]);
}
Post model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Posts extends Model
{
protected $fillable = [
'post_title','post_description', 'category', 'user_id',
];
Category Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Posts_Category extends Model
{
}
can you please help me with this, please suggest me any idea
i think you are looking for with eager load function
You must store category id not the name of the category..
class Posts extends Model
{
protected $fillable = [
'post_title','post_description', 'category_id', 'user_id',
];
public function category()
{
return $this->belongsTo(Posts_Category::class, 'category_id', 'id');
}
}
use as
$posts = Posts::where('category_id',$request->category)->with('category')->get();
If you really want to search by name
$posts = Posts::whereHas('category', function ($q) {
$q->where('category_name', 'like', "%{$request->category}%");
})->get();
You can fetch the category by its name first, and then filter posts by category id
public function getPostsByCategory(Request $request)
{
$category = Posts_Category::whereName($request->category)->firstOrFail();
$posts=Posts::where('category',$category->id)->get();
return response()->json(['posts'=>$posts]);
}
you're doing this the wrong way from the get go. best practice is to store category_id in posts table, of course this is only if you need a one-to-many relation between posts and categories table. plus I wouldn't recommend to break the convention of naming models unless you have no other way. I suggest you to read this section more thorough
https://laravel.com/docs/5.6/eloquent-relationships
Please i need a fix solution to this, i want to fetch all the latest post from a specific category in my laravel blog project
These are my models
Category model
public function posts()
{
return $this->belongsToMany('App\Post')->withTimestamps();
}
Post model
public function categories()
{
return $this->belongsToMany('App\Category')->withTimestamps();
}
What's they next thing to do?
please help
$posts = Posts::where('category_id', $category->id)->get();

Accessing Eloquent relationship attributes

I have three models all related by one-to-many. Category, Subcategory and Style. I have relationships working both ways - though I seem to have a problem accessing related attributes.
After my queries have ran, I'm left with this an instance of Style where 'relations' is an instance of Subcategory, and 'relations' in Subcategory is an instance of Category. Which is all correct.
The problem is that I now seem to not be able to access the related model instances. For example, if I call:
$style->subcategory->name;
I get 'Trying to get property of non-object'. So I tried calling just $style->subcategory and the result is '1'.
Why doesn't $style->subcategory return the instance of the subcategory model? Am I missing something or is my understanding incorrect?
--EDIT--
Models
Category
<?php
namespace Paragon\Products;
use Illuminate\Database\Eloquent\Model as Eloquent;
class Category extends Eloquent {
protected $table = 'product_categories';
protected $fillable = [
'name',
'slug',
'image'
];
public function subcategories() {
return $this->hasMany('Paragon\Products\Subcategory', 'category');
}
}
Subcategory
<?php
namespace Paragon\Products;
use Illuminate\Database\Eloquent\Model as Eloquent;
class Subcategory extends Eloquent {
protected $table = 'product_subcategories';
protected $fillable = [
'category',
'name',
'slug',
'image'
];
public function styles() {
return $this->hasMany('Paragon\Products\Style', 'subcategory');
}
public function category() {
return $this->belongsTo('Paragon\Products\Category', 'category');
}
}
Style
<?php
namespace Paragon\Products;
use Illuminate\Database\Eloquent\Model as Eloquent;
class Style extends Eloquent {
protected $table = 'product_styles';
protected $fillable = [
'subcategory',
'name',
'slug',
'image'
];
public function subcategory() {
return $this->belongsTo('Paragon\Products\Subcategory', 'subcategory');
}
}
Query
$style->where($id, $item)->with('subcategory.category')->first();
Tables
Paragon\Products\Category
ID ...
1
2
Paragon\Products\Subcategory
ID Category ...
1 2
2 2
Paragon\Products\Style
ID Subcategory ...
1 1
2 1
Since the subcategory method in the Style model should refer to a single instance of Subcategory and not a Collection of them, shouldn't I be able to just call attributes the way I am (or am trying to)?
Ok I think I see now what is going on. Your Eloquent model is called subcategory, but so is the foreign key. So when you call
$style->subcategory
That is returning the foreign key instead of the model. To fix this, I'd recommend changing the name of the foreign key id to subcategory_id. If you can't change the database, you could force it to use the model by chaining the method with something like this
$style->subcategory()->first()->name
Edit:
Another idea, you could change the name of the relationship to something like
public function subcategory_item()
{
return $this->belongsTo('Paragon\Products\Subcategory', 'subcategory');
}
Then you ought to be able to properly reference it with
$style->subcategory_item->name
I am taking a shot in the dark here. But I will try and explain how to work with collection and difference between first and get.
$users= $user-> with('images') -> first(); <-- this is first row in the table users, each user has many images.
$users-> username; //works;
$users-> images-> image_name; // wont work , model has many ,
you get error <-- Trying to get property of non-object.
// access the proprety image and loop through the collection of objects.
$images = $user-> images; //
foreach ($images as $image){
echo $image- >image_name;
}
on the other hand if the image did belong to one user and the user has one image. You can access image_name like this
$user -> image(() -> image_name;
in your case
$style -> subcategory() -> name;
to get a style by id with subcategoty
$style -> with('subcategry') -> where('id', $styleId) -> first();

Laravel relations

I am creating a basic forum just so I have something meaningful to do while learning Laravel.
So just like every forum is organized, on the main page i would like to have a list of categories and their subcategories, a total count of posts in every subcategory while also a link to latest post
So relationship is nested hasMany:
Category -> has Subcategories -> has Threads -> has Posts.
In controller method I have
$cat = Category::with('subcategory')->get();
return View::make('forum.index', compact('cat'));
and this works for basic list of categories and subcategories but I can't figure out the rest.
This sure doesnt work
Category::with('subcategory')->with('threads')->with('posts')->get();
since relation between them is not set. Looking at Laravel docs, there is hasManyThrough relation. Is that a solution?
class Category extends Eloquent {
public function subcategory() {
return $this->hasMany('Subcategory');
}
public function posts() { // not sure about this cause it doesnt work
return $this->hasManyThrough('Post', 'Thread');
}
}
And on top of that how do I get posts->count() for every subcategory? Is it possible to have it split? Chaining could get complicated..
EDIT
Table columns are
Categories
id | title
Subcategory
id | title | category_id
Threads
id | title | subcategory_id | user_id
Posts
id | title | body | thread_id | user_id
EDIT 2
What would be the code for grabing only latest post? This doesnt work
$data = Category::with('subcategories.threads')->with(array('posts' => function($query)
{
$query->take(1);
}))->get();
You have setup only one relation that works and that is:
class Category extends Eloquent {
public function subcategory() {
return $this->hasMany('Subcategory');
}
}
Declare other relationships in other models:
class Subcategory extends Eloquent {
public function threads() {
return $this->hasMany('Thread');
}
}
class Thread extends Eloquent {
public function posts() {
return $this->hasMany('Post');
}
}
Once you have declared relationships then you may use:
$categories = Category::with('subcategory.threads.posts')->get();
Since the one Category has many subcategories so use the plural name for subcategories instead of subcategory in your Category model, so for example, you may use:
class Category extends Eloquent {
public function subcategories() {
return $this->hasMany('Subcategory');
}
}
Then also:
$categories = Category::with('subcategories.threads.posts')->get();
All relationships will be retrieved as nested object collections. For example:
$categories->subcategories; // Will be a collection of Subcategory models
$categories->subcategories->threads // Will be a collection of Thread models
$categories->subcategories->threads->posts // Will be a collection of Post models
You may declare a hasManyThrough relationship between Subcategory and Post using something like this:
class Subcategory extends Eloquent {
public function threads() {
return $this->hasMany('Thread');
}
public function posts() {
return $this->hasManyThrough('Post', 'Thread');
}
}
Also, you may build a relationship between Category and Thread through Subcategory.
I have
QuestionCategory and Questions['category_id'] and ItemsOfQuestion['question_id']
This Code has Work for my I hope that is useful for you
$categories=ExamCategory::with(['question' => function ($query) use($exam){$query->where('exam_id','=',$exam->id)->with('Items');}])->get();

Categories