How to put where in relation to method? - php

Below is my Eloquent query.
$cat = Category::with('subcategory.items.products')
->where('id',$discates)->first();
I want to put a where on products with status = 1.
where('status',1)

You should spend some time reading Laravel docs. They are full of examples and a very good learning resource for the basics.
https://laravel.com/docs/8.x/eloquent-relationships#constraining-eager-loads
$cat = Category::with(['subcategory.items.products' => function($query){
$query->where('status', 1);
}])->where('id',$discates)->first();

Try this
$query = Category::query();
$query->whereHas('products', function ($q) {
$q->where('status', 1);
});
$cat = $query->with('subcategory.items.products')->find($discates);
or
$cat = $query->with('subcategory.items.products')>where('id',$discates)->first();

Related

Filter relations in laravel

I have Posts and Comments models with hasMany relation:
public function comments()
{
return $this->hasMany(Posts::class, 'posts_id', 'id');
}
In my controller I need to get all published posts (is_published = 1), with all published comments, that have at lease 1 published comment:
$dbRecords = Posts::all()->whereStrict('is_published', 1);
$posts = [];
foreach ($dbRecords as $post) {
if (count($post->comments()) === 0) {
continue;
}
foreach ($post->comments() as $comment) {
if ($comment->is_published === 1) {
$posts[] = $post;
continue(2); // to the next post
}
}
}
But, such solution is ugly. Also I will get all published post, wit published and not published comments, so I will forced to filter comments once again in Resource.
Another solution I've found - to use raw query:
$dbRecords = DB::select("SELECT posts.*
FROM posts
JOIN comments ON posts_id = posts.id
WHERE posts.is_published = 1
AND comments.is_published = 1
HAVING count(posts.id) > 0;");
$users = array_map(function($row) { return (new Posts)->forceFill($row); }, $dbRecords);
But it does not solves the problem with the need of filteration of unpublished comments in Resource.
Use Eager loading to remove n+1 query problem using with in Laravel eloquent.
Use has or whereHas function to querying relationship existence.
In your case it would be like this:
// Retrieve all posts that have at least one comment
$posts = Post::has('comments')->with('comments')->get();
// Retrieve posts with at least one comment and which are published
$callback = function($query) {
$query->where('is_published ', '=', '1');
}
$posts = Post::whereHas('comments', $callback)
->with(['comments' => $callback])
->where('is_published ', '=', '1')
->get();
What about this in eloquent
$posts = Post::query()->where('is_published', 1)->with(['comments' => function ($query) {
$query->where('is_published', 1);
}])->get();

Optimise Laravel Eloquent Query Result

I have a homework table in laravel-5.7 where 5000 records in the table also have some Relational records that are coming through HasMany() or HasOne() Relation. I tried many types of Eloquent Queries to get fast results. but Postman result time becomes 10200ms to 10700ms but when i direct dispaly this into postman then i am getting this into 500ms to 1100ms. i want to get it in near about 800ms after binding form Laravel Resource or Normal Array.
problem is, when i try to show the Eloquent result direct then it coming around 600ms to 1000ms. but when i bind into an Array and display in postman then its taking 6200ms why? i do not know?
$page = $req->page ?$req->page:1; // set starting value for look query limit.
$user = Auth::user()->student()->first();
$studentProfile = Auth::user()->student()->first();
// collecting all homework id that have assigned to student.
$studentHWList = StudentHomeWork::where("student_id",$studentProfile->id)
->select('home_work_id')
->get()->pluck('home_work_id');
// collecting page by page of homework id.
$hwLimitList = Homework::where('session_code', dnc($req->require('sid')))
->whereIn('id',$studentHWList )
->where('approved', '1')
->select('id')
->orderBy('updated_at','desc')
->get();
$hwIndexes = $hwLimitList->pluck('id')->forPage($page,$this->recordLimit);
$paginated = Homework::whereIn('id', $hwIndexes)
->with( "user:id,username,name",
'subject:id,subject_name,subject_code',
'approveByUser','publishBy')
->with(["likes"=>function($erw){
$erw->select('id','home_work_id','complete_status','likes')
->where("student_id", $studentProfile->id);
}])
->with(['comment'=>function($qur){
$qur->where('parent_id',0)
->where('user_id',$user->id);
}])
->orderBy('id','desc')
->get( );
if( count($paginated))
{
$paginationData = customPagination('getAllHW',$hwLimitList , $page , $this->recordLimit , $user, $studentProfile );
return response()->json(["error"=>0,"errmsg"=>"","paginationData"=>$paginationData ,
"response"=>['homework_list'=>$this->customResourceHWBinding($paginated , $req )],'auth'=>userType()]);
private function customResourceHWBinding($queryData , $request, $user, $studentProfile )
{
$document_list =[]; $is_seen=0; $resultData =[];
foreach ( $queryData as $query )
{
if( count($query->document) )
{
foreach($query->document as $document){
if( $document->changed_filename )
{
$file=""; $fileName ="";
$path =env('AWS_URL')."/uploads/".dnc($request->header('dbauth'))."/".$query->session_code."/homeWorks/";
if(is_s3FileExist( $path.$document->changed_filename ) )
{
$fileName =$document->changed_filename;
}
$document_list[] = [
'oname'=> $document->changed_filename,
'ext'=>$fileName?explode('.', $document->changed_filename):"",
'url'=>$file,
'file_url'=>$document->changed_filename?$path.$document->changed_filename:""
];
}
}
}
$resultData[] = [
'id'=>enc($query->id),
'ids'=>$query->id,
'pin_user_id'=>"",
'pin_enabled'=>0,
'created_by'=>$query->user->name,
'created_by_image'=>getUserImage($query->user,$query->user->privilege,$request),
'assignment_date'=>getDateFormat($query->assignment_date,0),
'assigment_date_edit'=>"",
'submission_date'=>getDateFormat($query->submission_date,1),
'submission_date_edit'=>"",
'class_code'=>$query->class_code,
'subject'=>$query->subject?$query->subject->subject_name:"",
'topic'=>$query->topic,
'is_student_seen'=> $this->studentHWSeen($query, $user, $studentProfile),
'updated_at'=> date('d-m-Y H:i:s' , strtotime($query->updated_at)),
'approved'=>$query->approved,
'approve_by'=> '',
'can_approve'=>0,
'comment_count'=>0,
'total_like'=>0,
'documents_count'=>count($document_list)?count($document_list):0,
'is_draft'=> $query->draft?$query->draft:0,
];
}
return $resultData;
}
private function studentHWSeen( $query , $user, $studentProfile)
{
if(count($query->studentSeen))
{
foreach($query->studentSeen as $seen){
if( user->privilege == 1 )
{
if($seen->student_id == $studentProfile->id )
return 1;
}
}
}
return 0;
}
I try to use Resource but it's also taking 3+seconds. I try too many others optimize a solution but not work in my case. someone told Use query builder instead of Eloquent to optimize queries. find here Optimising Laravel query . is it a good answer for me? I am not sure. please help me.
please check my image.
Eloquent Query Result
First of all, try to optimize this:
$paginated = Homework::whereIn('id', $hwIndexes)
->with( "user:id,username,name",'subject:id,subject_name,subject_code',
'approveByUser','publishBy')
->with(["likes"=>function($erw){
$erw->select('id','home_work_id','complete_status','likes')
->where("student_id",Auth::user()->student()->first()->id);
}])
->with(['comment'=>function($qur){
$qur->where('parent_id',0)
->where('user_id',Auth::id());
}])
->orderBy('id','desc')
->get( );
You run same code in nested query: Auth::user()->student()->first()->id.
Optimized version:
$studentId = Auth::user()->student()->first()->id;
$paginated = Homework::whereIn('id', $hwIndexes)
->with("user:id,username,name", 'subject:id,subject_name,subject_code', 'approveByUser', 'publishBy')
->with(["likes"=>function($erw) use ($studentId) {
$erw->select('id','home_work_id','complete_status','likes')
->where("student_id", $studentId);
}])
->with(['comment'=>function($qur) {
$qur->where('parent_id',0)
->where('user_id',Auth::id());
}])
->orderBy('id', 'desc')
->get();
Remember to add indexes to fields that you're using in where conditions.

Laravel Eloquent split large query in to chunk and reuse it

I am having really a very big query formation like below. i want to split this and need to re-use for many other ajax call's
$buildquery=Hotel::has('room');
$buildquery->whereHas('room', function($query) use ($request) {
// If amenities is there add it to query
if($request->filled('amenities')){
$amenities = $request->amenities;
$count = count($amenities);
$query->withCount(['amenities' => function($query) use ($amenities, $count){
$query->whereIn('amenities_id', $amenities);
}])
->having('amenities_count', $count);
}
/* filter based on guest */
if($request->filled('guestsCount')){
$memberCount = $request->guestsCount + $request->childCount;
$query->Where('capacity', '>=', $memberCount);
}else{
$query->Where('capacity', '>=', 1);
}
});
$buildquery->with(['room' => function ($query) use ($request) {
// If amenities is there add it to query
if($request->filled('amenities')){
$amenities = $request->amenities;
$count = count($amenities);
$query->withCount(['amenities' => function($query) use ($amenities, $count){
$query->whereIn('amenities_id', $amenities);
}])
->having('amenities_count', $count);
}
/* filter based on guest */
if($request->filled('guestsCount')){
$memberCount = $request->guestsCount + $request->childCount;
$query->Where('capacity', '>=', $memberCount);
}else{
$query->Where('capacity', '>=', 1);
}
$query->with('roomtype')->with('floorroomcount')->with('image')->with('amenities');
$query->OrderBy('price');
$query->Where('astatus', 1)->Where('status', 0);
}]);
/* client must be active */
$buildquery->whereHas('client', function($query) {
$query->Where('status', 1);
});
/* search based on rating */
if ($request->filled('rating')) {
if($request->rating > 0){
$rating = $request->rating;
$buildquery->where('star', $rating);
}
}
/* search based on hotel */
if ($request->filled('location_id')) {
$buildquery->Where('city', $request->location_id);
}
#include('roomlist.area');
$buildquery->Where('astatus', 1)->where('status', 0); //actually its hotel
$hotels = $buildquery->simplePaginate(20);
$hotels = $this->addRates($hotels, $request->checkin_date, $request->checkout_date);
$hotels = $this->addAvailableCount($hotels, $request->checkin_date, $request->checkout_date);
$hotels = $hotels->transform(function (Hotel $hotel){
$hotel->setRelation('room', $hotel->room->sortBy('price')->flatten());
return $hotel;
});
return view('roomlist.loadmore', compact('hotels'));
please see this line #include('roomlist.area'); in that roomlist/area.blade.php file i am having the following code
<?php
if($request->filled('type')){
if($request->type == "Area"){
//get the area first
$hotel = Hotel::select('area')->where('city', $request->location_id)->first();
if(isset($hotel)){
if($hotel->area != null){
$buildquery->where('area', $hotel->area);
}
}
}
}
?>
Is there any way that i can include this code from a blade or in any other manner.
Note: i need to re-use many things like this.
First thing you could do is break some of this functionality into scopes: https://laravel.com/docs/5.6/eloquent#query-scopes
For instance, you could change this:
/* search based on hotel */
if ($request->filled('location_id')) {
$buildquery->Where('city', $request->location_id);
}
Into this:
if ($request->filled('location_id')) {
$buildquery->inCity($request->location_id);
}
Or this:
/* client must be active */
$buildquery->whereHas('client', function($query) {
$query->Where('status', 1);
});
into this:
$buildquery->withActiveClient();
This is a small change but it allows you to use inCity in other places without re-writing as much, and for the other scopes it might be more code you can extract.
You could also make a Transformer class to change this:
$hotels = $hotels->transform(function (Hotel $hotel){
$hotel->setRelation('room', $hotel->room->sortBy('price')->flatten());
return $hotel;
});
To this:
$hotels = (new HotelRoomTransformer())->transform($hotels);
This type of extracting code could make this file much more readable, and that way if you need to reuse parts of it you have them in separate, reusable files.
Lastly, this type of functionality can all be extracted into a repository if you want to entirely remove Eloquent from your controllers. Here is a short guide on the repository pattern: https://medium.com/#connorleech/use-the-repository-design-pattern-in-a-laravel-application-13f0b46a3dce

Laravel: how to append to a query if not sure if the clause is needed

Im creating a filtering search system where people can choose which filters to add to their search. I want to be able to add a filter, depending on its EXISTENCE.
So, normally you do a query like this in Laravel:
$users = User::where('active', '=', 1)->orWhere('subscribed', '=', 1)->get();
But if you dont know whether youre gonna use the orWhere() clause. How do I do that?
You can use User::query() to fetch the query, then dynamically add clauses according to your app logic:
$query = User::query();
if(Request::get('active')){
$query = $query->whereActive();
}
if(Request::get('subscribed')){
$query = $query->orWhere('subscribed', 1);
}
return $query->get();
You can use where scope to append the where clause:
$users = User::where(function($query) use ($subscribed) {
$query->where('status', 1);
if ($subscribed)
$query->orWhere('subscribed', 1);
})->get();
Your question is not 100% clear to me but here is an approach:
$query = User::where('active', '=', 1);
if ($needSubscribers) {
$query = $query->orWhere('subscribed', '=', 1);
}
if ($needOtherCriteria) {
$query = $query->orWhere('filter', '=', 3);
}
$users = $query->get();
You can use when a method
$users = User::when(condition1, function ($query) {
$query->where('subscribed', '=', 1);
})->when(condition2, function ($query) {
$query->where('filter', '=', 3);
})->get();

Laravel eloquent give wrong result

I have this code:
public function inbox()
{
$id = Auth::user()->id;
$bids = Bid::where('user_id',$id)
->where('status','0')
->orWhere('status','4')
->latest()->get();
dd($bids);
return view('rooms.inbox', compact('bids'));
}
and this is my database:
But when I run it I get this result:
my Auth user id is 8 but I get wrong results? Why?
ALso when i try ;
$bids = Auth::user()->bids()->get(); then I get right results///
What is problem?
you are getting this unexpected error because of orWhere,you can do like this way
$bids = Bid::where('user_id',$id)
->where(function ($query) {
$query->where('status','0')
->orWhere('status','4');
})
->latest()->get();
You need to use Advanced Where Clauses
Your Query should like,
$bids = Bid::where('user_id',$id)
->where(function ($query) {
$query->where('status', '0')
->orWhere('status', '4');
})->latest()->get();

Categories