sortBy not working (Nothings happen) in my case in laravel5.1 - sorting

I'm trying to use the sortBy() of laravel but it has no effect for my situation. I want to sort the question_number field in the question_numbers table. I'm using belongsToMany relationship here. Please see my code for reference:
$undeleted = function($query){
return $query->where('deleted', 0);
};
$quiz = Quiz::with([
'multiple_choices.question_numbers' => $undeleted
])->find($id);
$quiz_items = collect($quiz->multiple_choices);
$quiz_items->sortBy(function($quiz_item){
return $quiz_item['question_numbers.question_number'];
});
dd($quiz_items);
The result of the code above is just list of multiple choices without sorting.

Related

Laravel query on Many to Many relationship

I have an API to keep tracked photos and tags. Each photo can have N tags and one tag can be linked to N photos. That's done using 3 tables:
Photo's table.
Tag's table.
photo_tag relation table.
Now I'm working to get all photos tagged with a set of tags the idea is to make requests to my API with a list of tags and get a list of photos that has at least all the tags.
I've been trying with the whereIn operator.
This is my code (now it's all hardcoded):
$photos = Photo::whereHas('tags', function (Builder $query) {
$query->whereIn('tag', ['a5', 'mate', 'Brillante']);
})->get();
return response()->json($photos, 200);
When I execute it it return all that photos that match one tag and I need only photos that hast all the requested tags (in this example a5, mate).
I'm working on Laravel 9.
Edit:
As Tim Lewis suggested I've tried looping:
$tags = array("a5", "mate", "Brilante");
$photoQuery = Photo::query();
foreach($tags as $tag) {
\Log::debug($tag);
$photoQuery->whereHas('tags', function($query) use ($tag) {
return $query->where('tag', $tag);
});
}
$photos = $photoQuery->get();
Now it's returning an empty list I think because is looking for Photos that only have the 3 tags I hardcoded on the array.
Edit 2:
It seems that those changes were right, but for some reason Postman was not showing me any results of those changes are the solutions to my issue.
Since the whereIn() method matches against any of the values provided, and not all, you'll need to modify this. Specificying a number of whereHas() clauses, 1 for each Tag, should work:
$photoQuery = Photo::query();
foreach ($request->input('tags') as $tag) {
$photoQuery = $photoQuery->whereHas('tags', function ($query) use ($tag) {
return $query->where('tag', $tag);
});
}
$photos = $photoQuery->get();
Now, depending on the tags being sent to your API (assuming through the $request variable as a 'tags' => [] array), this query will include a whereHas() clause for each Tag, and only return Photo records that have all specified Tags.

Exclude empty or null column with Laravel Eloquent

How to exclude empty or null columns when getting collections with Laravel Eloquent ?
I tried this but unsuccessfully:
User::where('last_name', 'foo')->get()->filter()
In addition to #pr1nc3 answer, there is a method ->reject() for this specific purpose. It rejects/excludes the items that match the condition. For your case, use it like this:
User::where('last_name', 'foo')->get()->reject(function ($value) { return empty($value); });
All the values that meet the condition empty($value) i.e. the values that are null/empty will be rejected.
You can do the filter in 2 steps
$users = User::where('last_name', 'foo')->get(); //returns your collection
Then you can use filter for your collection like:
$myFilteredCollection = $users->filter(function ($value) { return !empty($value); });
If you still need it in one line then you can do:
Of course you can merge it into one, get() actually outputs the collections but looks a bit ugly i think. Keep your actions separate.
$users = User::where('last_name', 'foo')->get()->filter(function ($value) { return !empty($value); });

Query Builder filter for multi level deep relationship in Laravel

I have a selection of plots which each belong to a development by a hasManyThrough relationship through housetypes. I want to filter these by development on their overview page. Plots has a housetype_id column and housetypes has a development_id column.
public function plots()
{
return $this->hasManyThrough(Plot::class, Housetype::class);
}
When I use my filter it returns the developments ID number as $development, I then need this to only show plots which are linked to that development.
I have looked into using whereHas or Join methods but have been unable to figure this out. Current filter scope is below. Thanks
public function scopeFilterDevelopment($query)
{
$development = request()->input('filter_development');
if ($development == "") {
return;
}
if(!empty($development)){
$query->where('development_id', $development);
}
}
If I can understand it right you wish to assert a condition on other Model, HasMany will load all the objects to the related model once the query is completed. Eloquent then binds the related model objects to each.
Try joins from Laravel instead. I feel this is what you exactly want: https://laravel.com/docs/5.8/queries#joins
I would use whereHas to filter the relationship:
YourModel::whereHas('plots', function($query) {
$query->filterDevelopment();
})->get();
I would also edit the query scope not to rely on the request global function, but instead pass the development of value as a parameter.
you have make a leftjon and then use when, you dont have to use
if(!empty($development)){
$query->where('development_id', $development);
}
this any more, you can use
->when($development=="" ? false : true, function($query) use ($development){
return $query->where('development_id', $development);
})
this is a full example
$queryBuilder = DB::table('facturas')->
leftJoin('clientes','clientes.id','=','facturas.clientes_id')->
select('facturas.estados_id as estado','facturas.numero as
numero',DB::raw('concat(clientes.nombre," ",clientes.apellido) as cliente'))->
when($estados===null ? false: true,function($query) use ($estados){
return $query->whereIn('facturas.estados_id', $estados);
})
It was a whereHas that solved this in the end! (another developer at work walked me through this)
Relationship -
public function housetype()
{
return $this->belongsTo(Housetype::class);
}
Function -
public function scopeFilterDevelopment($query)
{
if (request()->input('filter_development') == "") {
return;
}else{
$query->whereHas('housetype', function($housetype){
$housetype->where('development_id', request()->input('filter_development'));
});
}
}
This then returns any plot where its housetype has a matching development_id for the filter_development from the request.
Thanks for everyone's input

How to filter collection rows while using .each() in laravel?

I want to filter this $authors collection.
$authors = Author::get();
In my view, I need to show how many books an author is related.
I use .each() to merge the count to $authors and return it to where it was called.
return $authors->each(function($author, $key){
$author->count = Author::findOrFail($author->id)->books()->count();
});
Question is "How can I remove/filter if an author have not wrriten any of a book(count <= 0)?"
I tried this is and it failed.
return $authors->each(function($author, $key){
$author->count = Author::findOrFail($author->id)->books()->count();
$author->filter(function($author, $key){
return $author->count <= 0;
})
});
You should use withCount() to avoid N+1 and performance problems:
$authors = Author::withCount('books')->get();
In a Blade view, you'll be able to do:
$author->books_count
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.
https://laravel.com/docs/5.4/eloquent-relationships#counting-related-models

A More Efficient Way to Query Relationships

I'm building a query on a table (product).
product has a foreign key, wrapper_id,
each wrapper, in turn, has a foreign key wrapper_classification_id.
This part of the query needs to modify the search based on an array of wrapper_classification_id's that may have been passed as input parameters.
This is what I'm doing:
// $query is already being built from above this line....
// wrapper_classification_id in input is an array
if (Input::get('wrapper_classification_id'))
{
$wrappers = Wrapper::whereIn('wrapper_classification_id', Input::get('wrapper_classification_id'))->get();
$wrapperArray = [];
foreach($wrappers as $wrapper) {
$wrapperArray[] = $wrapper->id;
}
$query->whereIn('wrapper_id', $wrapperArray );
}
Is there a more efficient way of approaching this scenario where you're querying against a value in a relationship?
Thanks in advance,
Rich
$query->whereIn(
'wrapper_id',
DB::raw(
Wrapper::whereIn(
'wrapper_classification_id',
Input::get('wrapper_classification_id')
)->toSql()
)
);
Or, try joins.
$query->join('wrapper AS w', 'w.wrapper_classification_id', 'IN', Input::get('wrapper_classification_id'))
->whereIn('product.wrapper_id', 'w.id');
Not sure if that exact code would work though.
Assuming the product model has a wrapper relationship:
if (Input::has('wrapper_classification_id'))
{
$query->whereHas('wrapper', function($q){
$q->whereIn('wrapper_classification_id', Input::get('wrapper_classification_id'));
});
}

Resources