Reset local scope - laravel

I am (trying) to use scopes to handle some "filtering" within my models.
I got two scopes on the model: verified and unverified. Unfortunately the verification is not a single field in the database, but a query like:
return $query->whereHas('profile', function ($q) {
$q->whereHas('invitations', function ($i) {
...
});
Now I got the following issue: If I scope like this
$verified_members = $members->verified();
and work with $verified_members everything works fine:
$verified_members->whereHas('car', function ($q) {
$q->where('stolen', true);
})->count();
but if I do something like:
$verified_members = $members->verified();
$unverified_members = $members->unverified();
$verified_members->whereHas('car', function ($q) {
$q->where('stolen', true);
})->count();
$unverified_members->whereHas('car', function ($q) {
$q->where('stolen', true);
})->count();
I get 0 as result for $unverified_members, as it seems like the scopes are being chained. If I remove $verified_members again, I am getting results for $unverified_members.

Related

Laravel, eloquent, query: problem with retriving right data from DB

I'm trying to get the right data from the database, I'm retriving a model with a media relation via eloquent, but I want to return a photo that contains the 'main' tag stored in JSON, if this tag is missing, then I would like to return the first photo assigned to this model.
how i assign tags to media
I had 3 ideas:
Use orWhere() method, but i want more likely 'xor' than 'or'
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main')->orWhere();
}]);
return $models->paginate(self::PER_PAGE);
Raw SQL, but i don't really know how to do this i tried something with JSON_EXTRACT and IF/ELSE statement, but it was to hard for me and it was a disaster
Last idea was to make 2 queries and just add media from second query if there is no tag 'main'
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main');
}]);
$models_all_media = Model:: with(['media']);
return $models->paginate(self::PER_PAGE);
but i tried something like
for($i=0; $i<count($models); $i++) {
$models->media = $models_all_media
}
but i can't do this without get() method, beacuse i don't know how to change this to LengthAwarePaginator class after using get()
try using whereHas https://laravel.com/docs/9.x/eloquent-relationships
Model::with('media')
->whereHas('media',fn($media)=>$media->whereJsonContains('custom_properties->tags', 'main'))
->paginate(self::PER_PAGE);
as per your comment you can use
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main');
}])
->leftJoin('media', function ($join) {
$join->on('models.id', '=', 'media.model_id')
->whereNull('media.custom_properties->tags->main');
})
->groupBy('models.id')
->paginate(self::PER_PAGE);
return $models;

In Laravel hasMany relationship How to use with and where?

In Job model :
public function jobApplications() {
return $this->hasMany(JobApplication::class, 'job_id');
}
In JobApplication Model
public function jobs()
{
return $this->belongsTo(Job::class, 'job_id');
}
In job_applications migration
$table->id();
$table->foreignId("job_id")->constrained("jobs");
$table->foreignId("user_id")->constrained("users");
$table->text('remarks')->nullable();
$table->unsignedInteger('status')->default(1);
I need to get all jobs and its job applications where job_applications.status = (user input status) and job_applications.user_id =authenticated users id. How can i get that?
Below is the syntax i tried, which returned undefined variable status
$jobs = Job::where('status',1);
$status =$request->status;
if($status){
$jobs = $jobs->whereHas('jobApplications', function($q){
$q->where('status',$status);
$q->where('user_id',Auth()->user()->id);
});
return $jobs->get();
Can any one sugest a solution?
If you use closer the variabl that is defined outside the closer is not accessible. so you should use it. Like this.
if($status){
$jobs = $jobs->whereHas('jobApplications', function($q) use($status){
$q->where('status',$status);
$q->where('user_id',Auth()->user()->id);
});
This will remove the error undefined veriable $status.
to use an external variable in closure method you need to pass that variable into method using "use" keyword like
if($status){
$jobs = $jobs->whereHas('jobApplications', function($q) use ($status) {
$q->where('status',$status);
$q->where('user_id',Auth()->user()->id);
});}
return $jobs->get();

how to use whereHas in laravel

I am new to laravel,
I need to create a query for the db,
$query = Deal::query();
I want to use the wherehas operator.
this is my code that is worked.
else if ($group_by == 'precedence') {
if($get_deals_for == 'noprecedence'){
$get_deals_for = 0;
}
$precedenceStatus = $get_deals_for;
$query-> where('precedence', '=', $precedenceStatus);
// \Log::info('The request precedence: '.$precedenceStatus);
}
I want to add this code also to the query
if($person) {
$query->whereHas('personnel', function ($subQuery) use ($person) {
$subQuery->where('id', '=', $person);
});
}
So I need to change the first code?
how I can convert the first code to wherehas?
the first code is from table called deal, the second section is from realtionship called personnel.
the second section worked in other places in the code, I just need to fix the first section and not understand what to write in the use
I try this and get error on the last }
else if ($group_by == 'precedence') {
if($get_deals_for == 'noprecedence'){
$get_deals_for = 0;
}
$precedenceStatus = $get_deals_for;
$query-> where('precedence', '=', $precedenceStatus)
-> when ($person, function($query) use($person) {
$query->whereHas('personnel', function ($query) use ($person) {
$query->where('id', '=', $person);
});
})
}
There is a method you can use called when(, so that you can have cleaner code. The first parameter if true will execute your conditional statement.
https://laravel.com/docs/9.x/queries#conditional-clauses
$result = $query
->where('precedence', '=', $precedenceStatus)
->when($person, function ($query) use ($person) {
$query->whereHas('personnel', fn ($q) => $q->where('id', '=', $person));
})
->get();
You should also be able to clean up your precedence code prior to that using when( to make the entire thing a bit cleaner.
Querying to DB is so easy in laravel you just need to what you want what query you want execute after that you just have to replace it with laravel helpers.Or you can write the raw query if you cant understand which function to use.
using,DB::raw('write your sql query').
Now Most of the time whereHad is used to filter the data of the particular model.
Prefer this link,[Laravel official doc for queries][1] like if you have 1 to m relation ship so u can retrive many object from one part or one part from many object.like i want to filter many comments done by a user,then i will right like this.
$comments = Comment::whereHas('user', function (Builder $query) {
$query->where('content', 'like', 'title%');
})->get();
$comments = Here will be the model which you want to retrive::whereHas('relationship name', function (Builder $query) {
$query->where('content', 'like', 'title%');
})->get();
you can also write whereHas inside whereHas.
[1]: https://laravel.com/docs/9.x/eloquent-relationships#querying-relationship-existence

Laravel Controller - how to get Model's query object directly?

The below Controller method changes the query based on the flags which are activated.
public function index(Request $request)
{
$q = new ProductModel();
if($request->has('flag1')) {
$q = $q->includeFlag1();
}
if($request->has('flag2')) {
$q = $q->doFlag2();
}
if($request->has('flag3')) {
$q = $q->doFlagthing3();
}
return $q->paginate();
}
Most example code I've seen will call a where() from the beginning instead of creating a new Model instance and looks something like this:
$q = ProductModel::where('available', true);
if($request->has('flag1')) {
$q->includeFlag1();
}
But in my case based on the table fields it isn't possible for me to start from a where like this so it seems I must do $q = $q every time in every case... It's not neat, neither would doing something hacky like attempting to use a where true clause.
How can I clean either get the query object neatly from the beginning and use that or otherwise avoid having to do $q = $q inside each if()?
You can use query() and when() methods :
public function index(Request $request)
{
$query = ProductModel::query()
->when($request->has('flag1'), function ($q) {
$q->includeFlag1();
})
->when($request->has('flag2'), function ($q) {
$q->doFlag2();
})
->when($request->has('flag3'), function ($q) {
$q->doFlagthing3();
})
->paginate();
}
The official documentation is here: https://laravel.com/docs/9.x/queries#conditional-clauses
Sometimes you may want certain query clauses to apply to a query based on another condition. (...) The when method only executes the given closure when the first argument is true. If the first argument is false, the closure will not be executed.
You have also a more concise alternative using arrow functions (thanks #miken32's comment):
public function index(Request $request)
{
$query = ProductModel::query()
->when($request->has('flag1'), fn ($q) => $q->includeFlag1())
->when($request->has('flag2'), fn ($q) => $q->doFlag2())
->when($request->has('flag3'), fn ($q) => $q->doFlagthing3())
->paginate();
}

Sort parents regarding child attribut using Eloquent

I have a model 'job' linked with the model 'job_translation' like that :
/**
* Get the translations for the job.
*/
public function translations()
{
return $this->hasMany('App\Models\JobTranslation');
}
I want to build a dynamic api route which can accept several parameters to filter ou sorter a query on the jobs. To do that I have this kind of controller (extract) :
public function index(Request $request)
{
$queryJob = Job::query();
// filter on the job short_name
if ($request->has('short_name')) {
$queryJob->where('short_name', 'ilike', '%'.$request->short_name.'%');
}
// filter on the translation
if ($request->has('translation')) {
$queryJob->whereHas('translations', function ($query) use ($request) {
$queryJob->where('internal_translation', 'ilike', '%'.$request->translation.'%');
});
}
// sort by the external translation
if ($request->has('order.external_translation')) {
// var_dump($request->input('order.external_translation'));
// var_dump($request->server('HTTP_ACCEPT_LANGUAGE'));
$queryJob->whereHas('translations', function ($query) use ($request) {
$query->where('language_id', $request->server('HTTP_ACCEPT_LANGUAGE'));
$query->orderBy('external_translation', 'asc');
});
/*
$queryJob->with(['translations' => function ($query) use ($request) {
$query->where('language_id', $request->server('HTTP_ACCEPT_LANGUAGE'));
$query->orderBy('external_translation', 'asc');
}]);
*/
}
// security for the qty of items per page
$qtyItemsPerPage = 15;
if ($request->has('qtyItemsPerPage')) {
if (is_numeric($request->qtyItemsPerPage) && $request->qtyItemsPerPage <= 50) {
$qtyItemsPerPage = $request->qtyItemsPerPage;
}
}
$jobs = $queryJob->paginate($qtyItemsPerPage);
return JobResource::collection($jobs);
My problem is for the sort condition (the others are OK). When I use this kind of url:
jobs?order[external_translation]=asc
I tried a lot of things without success (commented in the code), the result is never sorted like I want. I think my problem is in the relation between the two models.
So how to sort the parents regarding an attribute of their children, using Eloquent?
You cannot sort nested relationships with the query builder alone. Use the Collection's sortBy method instead.

Resources