How to shorten eloquent query - laravel

Follow is my query which is working perfectly fine, it is giving me the expected result, but i am not happy with the way i have broken down the query in 3 pieces.
How can i combine this query like without breaking it down in pieces ?
$assignedMenusQuery = Branch::with(['menus' => function($query) {
$query->where('menus.status', true);
}])
->where('id', $branch->id)
->first();
if($assignedMenusQuery)
{
$assignedMenus = $assignedMenusQuery->menus->pluck('id')->toArray();
}
$assignedButSharedMenusQuery = Branch::with(['menus' => function($query) {
$query->where('menus.shared', true)
->where('menus.status', true);
}])
->whereNotIn('id', [$branch->id])
->first();
if($assignedButSharedMenusQuery)
{
$assignedButSharedMenus = $assignedButSharedMenusQuery->menus->pluck('id')->toArray();
}
$assignedButNotSharedMenusQuery = Branch::with(['menus' => function($query) {
$query->where('menus.shared', false)
->where('menus.status', true);
}])
->whereNotIn('id', [$branch->id])
->first();
if($assignedButNotSharedMenusQuery)
{
$assignedButNotSharedMenus = $assignedButNotSharedMenusQuery->menus->pluck('id')->toArray();
}
$menus = Menu::whereIn('id', array_merge($assignedMenus, $assignedButSharedMenus))->whereNotIn('id', $assignedButNotSharedMenus)->get();

Here what you can do this make a seperate function which accepts a parameter for shared & status. And other param for whereNotIn. And in that function you can use the when method and based on that you have to query in database.
Laravel Conditional Clauses

Here is how i did it, in case if someone needs it in future
$products = Product::whereNotIn('id', function($query) use($menu) {
$query->from('menu_product')
->select('menu_product.product_id');
})
->orWhereIn('id', function($query) {
$query->from('menu_product')
->select('menu_product.product_id')
->where('products.shared', true);
})
->orWhereIn('id', function($query) use($menu) {
$query->from('menu_product')
->select('menu_product.product_id')
->where('menu_product.menu_id', $menu->id);
})
->get();

Related

Eloquent query : Retrieve the list of offices where the user possess all the desks, not just one (nested whereHas)

I want to retrieve all the offices ( with the desks eager loaded) but I only want offices where the user possess all the desks in the office
I have the following models and relationships between them :
I came up with the following query which seems to almost work :
<?php
Office::query()
->whereHas('desks', function ($query) {
$query->whereHas('possessedDesks', function ($query) {
$query->where('user_id', auth()->id);
});
})
->with(['desks'])
->get();
The current query seems to return a result where if a user own a single desk in the office then the office is returned in the query. Am I missing something ? Is there a way to be more strict in the whereHas to have some kind of and instead of a or
Thanks in advance for your help ;)
Edit :
Thanks to Tim Lewis's comment I tried this with not more result :
<?php
Office::query()
->withCount('desks')
->whereHas('desks', function ($query) {
$query
->whereHas('possessedDesks', function ($query) {
$query->where('user_id', auth()->id);
})
->has('possessedDesks', '=', 'desks_count');
})
->with(['desks'])
->get();
Edit 2 :
I managed to get exactly what I need, outside of an Eloquent query. The problem is still persist since I need it to be in an Eloquent query because I need this for a query string request (Search engine).
<?php
$offices = Office::query()
->with(['desks'])
->get();
$possessedDeskIds = auth()->user->with('possessedDesks.desk')->possessedDesks()->get()->pluck('desk.id');
$fullyOwnedOffices = [];
foreach($offices as $office) {
$officeDeskIds = $office->desks()->pluck('id');
$atLeastOneDeskIsNotPossessed = false;
foreach($officeDeskIds as $officeDesk) {
if ($possessedDeskIds->doesntContain($officeDesk)) {
$atLeastOneAromaIsNotPossessed = true;
break;
}
}
if (!$atLeastOneDeskIsNotPossessed) {
$fullyOwnedOffices[] = $office;
}
}
Edit 3 :
Ok, With the previous edit and the need to have some kind of one line query (for the query string of a search engine) I simplified the request since the nested whereHas where hard to make sense of.
It's not the prettiest way to do it, It add more query for the process, but with the code from the Edit2 I can generate an array of Ids of the Office where all the Desk are possessed by the user. With that I can just say that when this option is required in the search engine, I just select the ones my algorithm above gave me and no more logic in the query.
If some genius manage to find a way to optimize this query to add the logic back inside of it, I'll take it but for now it works as expected.
Thanks Tim for your help
<?php
class SearchEngineController extends Controller
{
public function index(Request $request) {
$officesWithAllDesksPossessed = collect([]);
if ($request->has('with_possessed_desks') && $request->input('with_possessed_desks')) {
$publicOffices = Office::query()
->isPublic()
->with(['desks'])
->get();
$possessedDeskIds = currentUser()
->possessedDesks()
->with('desk')
->get()
->pluck('desk.id');
foreach($publicOffices as $office) {
$publicOfficesDeskIds = $office->desks()->pluck('id');
$atLeastOneDeskIsNotPossessed = false;
foreach($publicOfficesDeskIds as $officeDesk) {
if ($possessedDeskIds->doesntContain($officeDesk)) {
$atLeastOneDeskIsNotPossessed = true;
break;
}
}
if (!$atLeastOneDeskIsNotPossessed) {
$officesWithAllDesksPossessed->push($office);
}
}
$officesWithAllDesksPossessed = $officesWithAllDesksPossessed->pluck('id');
}
return Inertia::render('Discover', [
'offices'=> OfficeResource::collection(
Office::query()
->isPublic()
->with(['desks'])
->when($request->input('search'), function ($query, $search) {
$query->where('name', 'like', "%{$search}%");
})
->when($request->input('with_possessed_desks'), function ($query, $active) use($officesWithAllDesksPossessed) {
if ($active === 'true') {
$query->whereIn('id', $officesWithAllDesksPossessed);
}
})
->paginate(10)
->withQueryString()
),
'filters' => $request->only(['search', 'with_possessed_desks']),
]);
}
}

retrieve simple products and product_variation with corcel

In larvel I'm using corcel and with the help of this comment I'm trying to retrieve only simple products and variations of variable products.
$type = array('product_variation','product');
$status = 'publish';
$posts =
\Corcel\Model\Post::
type($type)->
whereHas('taxonomies', function($q) {
$q->where('taxonomy', 'product_type')
->whereHas('term', function($q) {
$q->where('slug', 'simple');
})
// since variations have no product_type taxonomy, then
->orwhere('taxonomy','<>', 'product_type');
})->
status($status)->
latest()->
limit(500)->
get();
return $posts;
but it only returns product_variation(s), and no simple product. can some one please explain my wrong doing?
i had the same problem, i realized that i can use doesntHave
$posts = \Corcel\Model\Post::status('publish')
->whereIn('post_type', ['product_variation','product'] )
->doesntHave('taxonomies')
->orWhereHas('taxonomies', function ($query) {
$query->whereIn('taxonomy',['product_type'])
->whereHas('term', function($q) {
$q->where('slug', 'simple');
});
})
->latest()
->limit(50)
->get();
return $posts;

OrderByRaw in Laravel

I am making an app that filters products
I want to add this query chunk to my $products = $products-> newQuery();
I'm using $products = $products-> newQuery(); Because I am querying with filters. Example:
$products = $products->newQuery();
if ($request->has('brand') && !empty($brand)) {
$products->where('brand', '=', $brand);
}
if ($request->has('size') && !empty($size)) {
$products->whereHas('stocks', function($query) use ($size) {
$query->where('size', '=', $size);
});
}
I want to add this query
$best_sellers = OrderItem::select('product_id')->groupBy('product_id')->orderByRaw('SUM(quantity) DESC')->limit(2)->get();
I have previously used it in another method and it works but I don't know how to integrate it
I tried:
$products->whereHas('order_items', function($query) {
$query->select('product_id')->groupBy('product_id')->orderByRaw('SUM(quantity) DESC');
});
But it hasn't worked
Any idea? thanks
Updated with Error:
you need to use with() to add relationship data whereHas() it just for filter it does not add new key
example
$products->with(['order_items'=> function ($q) {
$q->select('product_id')->groupBy('product_id')->orderByRaw('SUM(quantity) DESC')->limit(2)->get();
}]);

Laravel eloquent order by subquery

I have a problem with ordering by columns in subquery (lastname, firstname).
I already tried this code as suggested by other posts:
->with(['customer' => function ($query) {
$query->orderBy("lastname", "asc")
->orderBy("firstname", "asc");
}])
Here my full code, but it doesn't work.
return Membership::forCompany($companyId)
->whereIn('state', ['ATTIVA', 'IN ATTESA DI ESITO', 'DA INVIARE'])
->where(function ($query) {
$query->where('end_date', '>=', Carbon::now()->toDateString())
->orWhereNull('end_date');
})
->with('federation')
->with(['customer' => function ($query) {
$query->orderBy("lastname", "asc")
->orderBy("firstname", "asc");
}]);
Here the relationships:
In customer model I have:
public function memberships() {
return $this->hasMany('App\Models\Membership');
}
In Membership model I have:
public function customer() {
return $this->belongsTo("App\Models\Customer");
}
Try orderBy() with join() like:
$memberships = \DB::table("memberships")
->where("company_id", $companyId)
->where(function ($query) {
$query->where('end_date', '>=', Carbon::now()->toDateString())
->orWhereNull('end_date');
})
->join("customers", "memberships.customer_id", "customers.id")
->select("customers.*", "memberships.*")
->orderBy("customers.lastname", "asc")
->get();
dd($memberships);
Let me know if you are still having the issue. Note, code not tested! so you may need to verify by yourself once.

Laravel whereHas when connecting foreign key is not null then apply where

This is my query using eloquent with and whereHas functions.
$list = $list->with([
'site' => function($query) {
$query->select('site_id', 'name')->where('status', 1);
},
'certification' => function($query) {
$query->select('certification_id', 'name')->where('status', 1);
},
])->whereHas('site', function($query) {
$query->where('status', 1);
})
->whereHas('certification', function($query) {
$query->where('status', 1);
});
->where('status', '1')
Certification and site have Many to One relation with list table.
However, the above code would work fine till all the items in list table has a certification_id. But at times certification_id can be Null.
How do I write this query so as to implement whereHas only when certification_id is not null. So as to give all the results where certification_id is Null + give all the results where certification_id is not null and certifications.status = 1
Relation in list table is as
public function certification()
{
return $this->belongsTo('App\Certification', 'certification_id', 'certification_id');
}
Wasted 4 hours and it clicked as I posted this question. I nested the whereHas or certification_id is null in a where block and tada!
$list = $list->with([
'site' => function($query) {
$query->select('site_id', 'name')->where('status', 1);
},
'certification' => function($query) {
$query->select('certification_id', 'name')->where('status', 1);
}
])->whereHas('site', function($query) {
$query->where('status', 1);
})
->where(function($query) {
$query->whereHas('certification', function($query) {
$query->where('status', 1);
})->orWhereNull('certification_id');
})

Resources