Call to undefined method App\Product::whereHas() in laravel - php

Hi try to get my products list in subcategory page but i'm getting this error
Call to undefined method App\Product::whereHas()
here is my function
// Subategory page included posts
public function productsubcategory($slug)
{
$products = Product::whereHas('subcategory.category', function($q) use($slug){
$q->where('slug',$slug);
})->paginate(6);
return view('frontend.subcategories', compact('products'));
}
this is my route:
Route::get('/category/{slug}/subcategory/{subslug}', ['as' => 'showbysub', 'uses' => 'IndexController#productsubcategory']);
my product model:
public function categories(){
return $this->belongsTo(Category::class);
}
public function subcategories(){
return $this->belongsTo(Subcategory::class);
}
category model:
public function products(){
return $this->hasMany(Product::class);
}
public function subcategories(){
return $this->hasMany(Subcategory::class);
}
subcategory model:
public function category(){
return $this->belongsTo(Category::class, 'category_id');
}
public function products(){
return $this->hasMany(Product::class);
}
any idea?
UPDATE:
I changed my function to:
public function productsubcategory($slug)
{
$subcategories = Subcategory::where('slug','=',$slug)->with('products')->paginate(6);
return view('frontend.subcategories', compact('subcategories'));
}
and now my page is loading but will not show any item (product).
UPDATE 2
I changed my function to this:
public function productsubcategory($slug)
{
$products = Product::with('subcategories')
->orderBy('id', 'desc')
->get();
return view('frontend.subcategories', compact('products'));
}
Now I can get products but the problem is all products will show even
if they're included other categories.
How to solve that?

I don't understand what do you mean in this lines
$products = Product::whereHas('subcategory.category', function($q) use($slug){
$q->where('slug',$slug);
})->paginate(6);
Refer to https://laravel.com/docs/5.4/eloquent-relationships. If you are trying to querying relationship, you can do like this:
$products = Product::whereHas('subcategories', function($q) use($slug){
$q->where('slug',$slug);
})->paginate(6);
or
$products = Product::whereHas('categories', function($q) use($slug){
$q->where('slug',$slug);
})->paginate(6);
The relationship name must the same with relationship method in your Product model

SOLVED
public function productsubcategory($slug, $subslug)
{
$products = Product::whereHas('subcategory', function($q) use($subslug){
$q->where('slug',$subslug);
})->get();
return view('frontend.subcategories', compact('products'));
}
and product model from subcategories change to subcategory

Related

Displaying latest news for each in Laravel

I want to display only 3 news in each category to display the last 3 news that were added.
Class category:
class category extends Model
{
use HasFactory;
public function articles(){
return $this->hasMany(Article::class)->limit(3)->orderBy('created_at', 'desc');
}
}
Class Article:
class Article extends Model
{
use HasFactory;
public function category(){
return $this->belongsTo(category::class);
}
}
$categories = category::with('articles')->limit(3)->get();
$articles = Article::orderBy('created_at', 'desc')->get();
return response()->view('news.index', compact('categories','articles'));
use whereHas
$categories = category::whereHas('articles', function($query){
return $query->orderBy('created_at', 'desc')->limit(3);
})->get();
return view('news.index', compact('categories'));
By using latest()
$categories = category::whereHas('articles', function($query){
return $query->latest()->take(3);
})->get();
return view('news.index', compact('categories'));

How to get Category info in detail page in laravel

I have a page where i show products under their subcategory url's and in top of my page i want to print the subcategory title and subcategory image, how can I do that?
here is my function:
public function productsubcategory($slug, $subslug)
{
$products = Product::whereHas('subcategory', function($q) use($subslug){
$q->where('slug',$subslug);
})->paginate(12);
return view('frontend.subcategories', compact('products'));
}
and I show my products with foreach like #foreach($products as $product) ....
The best way you doing is One to Many relationship. Use ORM for that. You will get details here: https://laravel.com/docs/5.0/eloquent
In your Category.php Model
public function subcategories()
{
return $this->hasMany('App\Subcategory', 'category_id');
}
In you Subcategory.php Model
public function category()
{
return $this->belongsTo('App\Category', 'category_id');
}
public function products()
{
return $this->hasMany('App\Product', 'subcategory_id');
}
And your Product.php Model
public function subcategory()
{
return $this->belongsTo('App\Subcategory', 'subcategory_id');
}
And you will get subcategory list
$subcategories = Category::find($id)->subcategories;
And You get products
foreach($subcategories as $subCat)
{
//your code
}
And here is another link for One to Many relationship. If you read details it will help you. https://laravel.com/docs/5.5/eloquent-relationships
SOLVED
I added another query in my function so totally become like this:
public function productsubcategory($slug, $subslug)
{
$products = Product::whereHas('subcategory', function($q) use($subslug){
$q->where('slug',$subslug);
})->paginate(12);
$productss = Product::whereHas('subcategory', function($q) use($subslug){
$q->where('slug',$subslug);
})->first();
return view('frontend.subcategories', compact('products', 'productss'));
}
And here is how i show my subcategory info in their pages.
{{$productss->Subcategory->title}}
Hope this help others.

Want to fetch data from three tables in laravel 5.2

I have a little query in which I need your help, Please have a look below.
I want to fetch all the data from the products table with some conditions like city, price, Type, category.
I can fetch all the data but I can't fetch the category data from the product model with all other conditions.
Below is my tables and Eloquent relations. I am using Laravel 5.2.
products ->foreign_key('subcategory_id')
subcategories ->foreign_key('category_id')
category
users: ->foreign_key('product_id')
users table columns: ->city, price, product_id
Relations:
User Model:
public function product(){
return $this->hasMany('App\Product');
}
Product Model:
public function subcategory(){
return $this->belongsTo('App\Subcategory', 'subcategory_id');
}
Subcategory Model:
public function product(){
return $this->hasMany('App\Product', 'subcategory_id');
}
public function category(){
return $this->belongsTo('App\Category');
}
Category Model:
public function subCategory(){
return $this->hasMany('App\Subcategory');
}
public function product(){
return $this->hasManyThrough('App\Product', 'App\Subcategory');
}
Here is my query(in ProductsController.php).
$city_id, $category_id, $min_price, $max_price : demo data passed
//fetching city data
$products = Product::whereHas('user', function($query) use($city_id) {
$query->where('city_id', $city_id);
});
//fetching category data (I am not sure about this part)
$products = $products->whereHas('category', function($query) use($category_id) {
$query->where('id', $category_id);
});
//fetching price data
$products = $products->where('price', '>=', $min_price)->where('price', '<=', $max_price);
//sub category filtering
$products = $products->where('subcategory_id', 1);
$products = $products->get()->toArray();
return $products;
Any help would be appreciated. Thanks in Advance.
I think you can use with() method:
Product Model:Add the following method
public function subcategory($category_id){
return $this->belongsTo('App\Subcategory', 'subcategory_id')->with(`category`)->where('category_id',$category_id);
}
Now in Controller, you can check if the product belongs to that category,
$products = $products->subcategory($category_id);
This will get you category data also.

Passing array in many to many relationship to the controller- laravel

I have a many to many relationship between Category and posts tables like this:
Category class:
class Category extends Model {
public function posts()
{
//return $this->hasMany('App\Posts','category_id');
return $this->belongsToMany('App\Posts', 'categories_post', 'category_id', 'post_id')
->withTimestamps();
}
}
Posts class:
class Posts extends Model {
public function category()
{
//return $this->belongsTo('App\Category','category_id');
return $this->belongsToMany('App\Category', 'categories_post', 'post_id', 'category_id')
->withTimestamps();
}
}
When I need to access only one category's posts I do this in my controller:
public function cat($category_id)
{
$posts= $category_id->posts()->paginate(7);
return view('cat')->with('posts',$posts);
}
Edit
to make this work, I added this in "RouteServiceProvider.php" file:
public function boot(Router $router)
{
parent::boot($router);
$router->model('categories','App\Category');
}
and this works perfectly. The problem is, I have another controller which should get the posts for multiple categories :
public function index()
{
$title = 'news';
$categories= [1, 2, 10, 11];
// Here is the problem:
$posts= $categories->posts()->paginate(7);
return view('news')->with('posts',$posts)->with('title',$title);
}
This gives me this error: Call to a member function posts() on a non-object
I know there is something wrong with calling the array, but I don't know how to solve it. Can any one help me please :)
The solution
after what Thomas Van der Veen said in his answer , I came up with this controller which is working perfectly:
public function index()
{
$title = 'news';
$category_ids = [1, 2, 10, 11];
$posts = Posts::whereHas('category', function($query) use ($category_ids) {
$query->whereIn('id', $category_ids);
})->get();
return view('news')->with('posts',$posts)->with('title',$title);
}
You could do something like:
$category_ids = [1, 2, 10, 11];
$posts = Post::whereHas('categories', function($query) use ($category_ids) {
$query->whereIn('id', $category_ids);
});
See this.

Laravel 4.1 eager loading

I'm having trouble on the eager loading.
Let's say I have models of Members, TrainingCategory, TrainingCategoryResult and Registration
Member Model:
public function registration() {
return $this->hasMany('Registration', 'member_id');
}
public function trainingResults(){
return $this->hasMany('trainingResult', 'member_id');
}
public function trainingCategoryResults() {
return $this->hasMany('TrainingCategoryResult', 'member_id');
}
TrainingCategory Model:
public function trainings() {
return $this->hasMany('Training', 'id');
}
public function trainingCategoryResults() {
return $this->hasMany('trainingCategoryResult', 'category_id');
}
TraningCategoryResult Model:
public function category() {
return $this->belongsTo('TrainingCategory', 'id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
Registration Model:
public function course() {
return $this->belongsTo('Course', 'course_id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
I am trying to eager load all the registration info and its related info including the TraningCategoryResult info but I not sure how to get that TraningCategoryResult which required two foreign keys (category_id and member_id), is there any way to do that?
Here is my code atm:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
});
$members= $members
->with('registration.course',
'registration.course.traningCategories',
->get(['member.id']);
Thank you.
This will not work Member::with('categoryResult')->with('registration')->get()
You can make a new relation in Member Model
public function categoryResult()
{
return $this->belongsTo('Category')->with('Registration');
}
//and then call
Member::with('categoryResult')->get();
You could use a few options to achieve that:
OPTION 1: create a variable relationship
Change your relation in the Member model
public function trainingCategoryResults($category_id = null) {
if(empty($category_id))
return $this->hasMany('TrainingCategoryResult', 'member_id');
else
return $this->hasMany('TrainingCategoryResult', 'member_id')
->where('category_id', $category_id);
}
The code above might have limitations and it doesn't take advantage of many laravel features, but it will work.
OPTION 2: Access from relationship
You can keep everything as is, and load as follow:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
})
->where('id', $member_id) // set the id of the memeber
->with(array(
'traningCategoryResults' => function($q)use($category_id){
$q->where('category_id', $category_id); // This makes sure you get only desired results
}
))
In this way you will have only what you need, assuming you know the $category_id

Categories