Return keyword in query callback - laravel

Is it necessary to write return keyword while using whereHas in laravel.
For eg. return $query->where('status', 1);
$posts = App\Post::whereHas('comments', function ($query) {
$query->whereHas('content', function ($query){
$query->where('status', 1);
});
})->get();
Do we need to write return in every query callback?

No, you're modifying the query builder instance passed to your closure by calling $query->where('status', 1);. Since objects are passed by reference and where() mutates this instance, there's no need to return anything.

There is no need. Also you can use whereHas with nested relationship.
Example:
$posts = App\Post::whereHas('comments.content', function ($query) {
$query->where('status', 1);
})->get();

No. Because you have the same object (and modify it) inside every function. No need to return.

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;

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

Replace Laravel query callback with function

I have the following base query I use for retrieving collections with their relations, scopes, sorting, filtering,... This base query is used on almost all my models by extending the class this base query is in.
return $this->runSortQuery(
$query->when($request->has('filter'),
function($query) use ($request) {
return $query->search($request->filter);
}
)->when($request->has('with'),
function($query) use ($request) {
return $query->with(
explode(',', $request->with)
);
}
)->when($request->has('scopes'),
function($query) use ($request) {
return $query->scopes(
json_decode($request->scopes, true)
);
}
) /* and so on... */, $request
)->paginate((isset($request->paginate)) ? $request->paginate : 15);
Is it possible to replace the callback in every when with a custom function call? The reason I want this is because this base function is getting really long and I would like the method in the callback in it's own function, for readability and to keep this maintainable.
I tried this, but this obviously does not work.
$query->when($request->has('filter'), $this->filter($query, $request->filter))
->when($request/* and so on... */);
Can this be done in another way or what would be a good pattern or method to do this?
Yes, you can use the callables like so:
$query->when($request->has('filter'), [$this, 'someMethodNameInClass'])
->...
Check out this SO thread to learn more

laravel - send a selected field to with function

how can i use "airpot_id" in with function?
City::select([
"cities.id",
"airports.id As airport_id"
])
->RightJoin('airports', function ($join)
{
$join->on('cities.id', '=', 'airports.city_id');
})
->with(["airports" => function ($q)
{
$q->where("id",airport_id) //I want to use here.
}])
->paginate(env("PER_PAGE", 10))->toArray();
Why are you using joints like this? Use the eloquent query builder. Maybe you should post you modal, relations and your objective. In general, if we need to pass value inside function we use use($variable). Something like this
$airport_id = 1;
$data = City::with(["airports" => function ($q) use($airport_id){ //Like this we pass data
$q->where("id",airport_id)
}])->get();
I don't think this will work in your case

laravel: odd behavior when query is empty

I have a model
I call it this way:
Sight::filter(['type'=>'menu']);
and in model:
public function scopeFilter($query,$params)
{
return $query
->wherePublish(1)
->whereIn_special(1)
->latest()
->first();
}
when there is one or more records, it works normally.
but when database is empty I get an odd behavior:
with dd(Sight::filter(['type'=>'menu']))
or
$query
->wherePublish(1)
->whereIn_special(1)
->latest()
->first();
dd($query);
I got this result:
But with
dd(
$query
->wherePublish(1)
->whereIn_special(1)
->latest()
->first();
)
I got Null so it is right!
how can I return Null? what is my wrong?
You shouldn't be calling first() inside of a scope - you are only meant to adjust the query by constraining it. You should call first() in your chain after applying the filter() scope. If you want to use the same syntax rather than chaining like that you would be best to define a custom static method.
public static function filter($params)
{
return self::wherePublish(1)
->whereIn_special(1)
->latest()
->first();
]
Also note that in your example your scope accepts an argument (and you pass it one) but it isn't actually used in your code.

Resources