Laravel has and orHas not working with where - php

I need get categories with products, only where products exists on category, I have code:
$categories = Category::with(['children.products', 'products'])->has('children.products')->orHas('products')->whereNull('parent_id')->whereId($category->id)->paginate(15);
But whereId = $category->id not working.. Why? I get category with other categories.. but I need get only certain category, where id = categoryId
Model category:
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
public function parent()
{
return $this->belongsTo(self::class, 'parent_id')->withoutGlobalScope('active');
}
public function products()
{
return $this->hasMany(Product::class);
}

You should combine has and orHas within enclosed function, something similar to below:
$query->where(function($query) {
$query->has('children.products');
$query->orHas('products');
});
Additionally, to above, I would recommend using "join" because "has" is a lot slower.

Related

Laravel return model with if statement

I'm trying to create offers and assign them to parent categories, to be more specific i have an Offer model and inside the offer model i have this many to many relationship
public function category() {
return $this->belongsToMany(Category::class);
}
I want the above function to return ONLY the categories which have NULL parent_category which mean they are the parent categories. Is it possible with the above code?
Without knowing the entire scope of your project, I'd suggest one of the following: either change the name of the relation (A) or keep the relation as is and query it when you need it (B).
Option A -
public function childCategory() {
return $this->belongsToMany(Category::class)->whereNull('parent_category');
}
Option B -
public function category() {
return $this->belongsToMany(Category::class);
}
$offer = Offer::with('category')
->whereHas('category' function ($query) {
$query->whereNull('parent_category');
});
public function category() {
return $this->belongsToMany(Category::class)->where('parent_category', null);
}

Laravel scope on collection

I'm in Pain because of this problem.
Problem
I have categories table which contains id, slug and parent_id.
lessons table which contains category_id (the child of a Category)
I want by Eloquent scope get all lessons posted by Category parent id
example:
parent category of id=1 have children categories of ids 3, 4 and 5.
Then retrieve Lessons under the parent category of id=1, so this must return the lessons of all of the childrens.
Categories table
public function parent()
{
return $this->belongsTo(self::class, 'parent_id');
}
public function lessons()
{
return $this->hasManyThrough(
\App\Lesson::class, \App\Category::class,
'parent_id', 'category_id', 'id'
);
}
//Pointless try
// public function scopeGetParent($query, $slug)
// {
// $query->where('slug', $slug)->first()->lessons;
// }
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
Lessons.php
return Lesson::recentLessons()
->byParentCategory($args['category'])
->simplePaginate($page)
->shuffle();
how can I construct scopeByParentCategory() function??
sorry for the fuzzy question! Spent 3 hours trying :(
update: I got this idea right after posting the question but still wanna know what do you think about it and if this the best way to handle it.
public function scopeByParentCategory($query, $slug)
{
$ids = [];
foreach (Category::where('slug', $slug)->first()->children as $value)
{
$ids[] = $value->id;
}
return $query->whereIn('category_id', $ids);
}
First put this code inside of your Category model:
public function scopeOfSlug($query, $slug)
{
$query->where('slug', $slug);
}
Then in your controller
return Category::ofSlug($args['category'])
->lessons
->simplePaginate($page)
->shuffle();

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.

Laravel has many and grouping

I can't seem to get the syntax right for this query.
Basically, I have a product that is listed, where an offer is made by a user:
So in Offer.php
public function user()
{
return $this->belongsTo('App\User', 'buyer_id');
}
public function product(){
return $this->belongsTo('App\Product');
}
And in User.php
public function offers()
{
return $this->hasMany('App\Offer', 'buyer_id');
}
Then in Product.php
public function offer()
{
return $this->hasMany('App\Offer');
}
I need to group offers by the user that has made them, and then group that again by the category of the product the offer is against.
Does anyone have ideas where I can start to group these correctly?
Try with Query Builder. Like this ( I don't know your tables`s structure):
$offers = DB::table('offers')
->joinLeft('users','users.id','=','offers.buyer_id')
->joinLeft('products','products.id','=','offers.product_id')
->groupBY('users.id','products.category_id')
->get();

Laravel: Ordering data at a query level when using pivot tables?

In my routes/web.php I have a route like this...
Route::get('/tags/{tag}', 'TagsController#show');
Then, inside TagsController because I have a post_tag pivot table that has been defined as a many-to-many relationship.
Tag.php...
public function posts(){
return $this->belongsToMany(Post::class);
}
public function getRouteKeyName(){
return 'name';
}
Post.php...
public function tags(){
return $this->belongsToMany(Tag::class);
}
I get the posts for a certain tag like this...
public function show(Tag $tag){
$posts = $tag->posts;
return view('posts.index', compact('posts','tag'));
}
Then, to sort the posts into newest first I can do this in index.blade.php...
#foreach ($posts->sortByDesc('created_at') as $post)
#include('posts.post')
#endforeach
This works fine, but I'm doing the re-ordering at collection level when I'd prefer to do it at query level.
From Eloquent: Relationships I can see that I can do something like this, which also works...
$user = App\User::find(1);
foreach ($user->roles as $role) {
//
}
But, something like this does not seem to work...
public function show($tag){
$posts = \App\Tag::find($tag);
return view('posts.index', compact('posts'));
}
My question is, how can I filter/order the data at a query level when using pivot tables?
To order your collection you must change
public function tags(){
return $this->belongsToMany(Tag::class);
}
to
public function tags(){
return $this->belongsToMany(Tag::class)->orderBy('created_at');
}
Extending #leli. 1337 answer
To order content without changing the relation created.
First, keep the original relation
class User
{
public function tags
{
return $this->belongsToMany(Tag::class);
}
}
Second, during query building do the following
//say you are doing query building
$users = User::with([
'tags' => function($query) {
$query->orderBy('tags.created_at','desc');
}
])->get();
With this, you can order the content of tags data and in query level also if needed you can add more where clauses to the tags table query builder.

Categories