Sorting a many to many relation with Laravel Eloquent - sorting

I do have swatches table, a colors table and a swatch_color pivot table.
Relations are set as:
public function colors()
{
return $this->belongsToMany('Color');
}
public function swatches()
{
return $this->belongsToMany('Swatch');
}
I have no problem to retrieve the swatches with the color relations
$swatches = Swatch::with('colors')->get();
return dd($swatches);
Colors is always an array of 5 color objects with hue, R, G, and B attributes.
Now I would like to sort the swatches by the R value of the first related color.

This is all you need to sort $swatches collection:
$swatches->sortBy(function ($swatch) {
return ($color = $swatch->colors->first())
? $color->r
: null;
});
Another way would be manual joining the tables.
You can use sortByDesc for descending order.

Best Solution
$collection = collect($arr);
$sorted = $collection->sortBy(function($vv, $kk) {
return [$vv['isFriend'],$vv['isCoworker'],$vv['icecount']];
});
$finalArr = $sorted->values()->all();

Related

Laravel get result from query in side query by Eloquent in one object

I have two tables:
main_presentations
so here i have "id" and "isEnabled";
child_presentations
And here i have "id" , "isEnabled" and "idParent";
I want to select in one object this is my code:
public function MainSlider(MainPresentation $MainPresentations, ChildPresentation $ChildPresentations)
{
$MainPresentations = MainPresentation::where('isEnabled', true)->get();
foreach ($MainPresentations as $MainPresentation) {
$AnArray[] = ChildPresentation::where([
['idParent', $MainPresentation['id']],
['isEnabled', true]
])->get();
}
return $AnArray;
}
but this is the result:
enter image description here
What you are doing is executing a query per result, which can be ineffective when it starts getting bigger.
You can:
Use querybuilder
As it follows, you just build a query starting on ChildPresentation, set a relation to MainPresentation table by id and get the collection
public function MainSlider()
{
$childPresentations = ChildPresentation::join('main_presentations','main_presentations.id','child_presentations.idParent')
->where('child_presentations.isEnabled', true)->where('main_presentations.isEnabled', true)->get();
return $childPresentations;
}
If you want all the MainPresentations with their respective ChildPresentations, only the enables ones.
You can take advantage of Laravel relationships and eager loading.
https://laravel.com/docs/5.6/eloquent-relationships
First, set the relationships in your MainPresentation model
In MainPresentation.php
public function childPresentation {
return $this->hasMany('App\ChildPresentation', 'idParent', 'id');
}
Your MainSlider function would be:
(Btw, no idea why you're receiving two arguments if you're overriding them but doesn't matter)
public function MainSlider() {
$mainPresentations = MainPresentation::with(['childPresentations' => function ($advancedWith) {
child_presentation.isEnabled is true
$advancedWith->where('isEnabled', true);
}])
->where('isEnabled', true)->get()->toArray();
return $mainPresentations;
}
This will return an array of MainPresentations that contain an array of child_presentations, with all their childs.
This translates to two queries:
Select * from main_presentations where isEnabled = true;
Select * from child_presentations where isEnabled= true and id in (in the first query);
Laravel then does background work to create the structure you desire when you write ->toArray()
Note: If you have a $visible array in your MainPresentation model, be sure to add: 'childPresentation' to it, otherwise the toArray will not agregage the childs to the parent.
Second note: I advise following some standards whenever you're writing code, usually functions are named camelCase and variables are camelCase.

Laravel count collections within a collection (with a filter)

Two realted questions here...
Say I have two models Owner and Dog, an owner can have many dogs. The dogs also have a field 'color'.
I get all owners with dogs,
$owners = Owner::with('dogs')->get();
1. How to get the total number of dogs?
With the $owners collecton I want to return the total number of dogs.
I could add a count property to the owners model and sum that, but is there another way?
2. How to get the total number of black dogs?
I would also like to get the total number of dogs with a color of black.
Thanks
There is a special function on the Eloquent query builder available called withCount($relation), which basically does the same as $model->relation()->count(). The difference is that it eager loads the count for all models in the collection, which yields better performance.
$owners = Owner::withCount([
'dogs as dog_count',
'dogs as black_dog_count' => function($query) {
$query->where('color', 'black')
},
])->get();
Eager loading the relation counts will not load the relation itself. So of course you can chain with('dogs') to the function as well.
Also you can add class appends 'dog_count','black_dog_count',
class Owner extends Model
{
protected $appends = [
'dog_count',
'black_dog_count',
];
public function getDogCountAttribute()
{
return $this->dogs->count();
}
public function getBlackDogCountAttribute()
{
return $this->dogs->where('color', 'black')->count();
}
}
And usage
$owners = Owner::with('dogs')->get();
$allDogsCount = $owners->sum('dog_count');
$allBlackDogsCount = $owners->sum('black_dog_count');
or
$allDogsCount = $owners->sum(function ($owner) {
return $owner->dogs->count();
});
$allBlackDogsCount = $owners->sum(function ($owner) {
return $owner->dogs->where('color', 'black')->count();
});

filtering making subqueries

I'm on a Laravel project and I'm trying to do a filter:
I have the following tables: pubs, tapps, pub_tapps(pub_id, tapp_id)
I would like to filter an item (pubs, in this case) by some characteristics that are stored in a separate table (tapps, in this case), and both are related by pub_tapps.
An array of chosen tapps id's is given to me, then I want to query on pub_tapps to know the pub_id's that satisfy the conditions.
For example, I'm trying to filter by WIFI (tapp_id=5) and CreditCard (tapp_id=16). If we're strict the result must be pub_id=57 (tapp_id=5,8), if not pub_id=57 and pub_id=16 (tapp_id=5,7,8).
Any ideas to do something like this?Note that I'm triying to filter with different values of a sema field :S
Thanks a lot for your attention.
as long you An array of chosen tapps $ids
choose tapps that satisfy your conditions
$tapIds = Tapps::whereIn('id',$ids)->where('condition',true)->pluck('id')->toArray();
then get The Ids of the pubs in the connected Table
$pubIds = PubTapps::whereIn('tapp_id',$tapIds)->pluck('pub_id')->toArray();
then get the pubs
$Pubs = Pubs::whereIn('id',$pubIds)->get();
Many to Many
class Pubbs extends Model
{
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tapps()
{
//All but the first argument here are optional so long as you follow Laravel naming conventions
return $this->belongsToMany(Tapps::class, 'pub_tapps', 'pub_id', 'tapp_id', 'id', 'id');
}
}
whereHas
$tappIds = [5, 16];
$strictMode = true;
$pubs = app(App\Models\Pubbs::class)->whereHas('tapps', function (Illuminate\Database\Eloquent\Builder $query) use ($tappIds, $strictMode) {
$tappKey = $query->getModel()->getKeyName();
if (!$strictMode) {
return $query->whereIn($tappKey, $tappIds);
}
foreach ($tappIds as $tappId) {
$query->where($tappKey, $tappId)
}
})->get();

Laravel Relationship with WHERE clause returns nothing

I have areas. Each area have N curses
So, each curse belongsTo only one area.
My class
class Area extends Model
{
public function curses()
{
return $this->hasMany('App\Curse');
}
}
My Controller
public function getCursesByAreaId()
{
$areaId = Input::get('areaId'); //ID of selected Area
//area_id is a field of table CURSE. A FK to Area.
$areas = Area::with('curses')->where('area_id', $areaId)->get();
foreach($areas as $area)
{
var_dump($areas);
}
}
Curse Model
class Curseextends Model
{
protected $fillable =
[
'description',
'area_id'
];
}
Using the laravel's debugbar, I see that the query being executed is this:
select * from "areas" where "area_id" = '2'
Isn't it supose to run the relational query ? (with the joins)
Already checked if I'm receiving the right id and it's ok.
the problem is that it's bringing no data at all.
You need something like the following:
$areas = Area::whereHas('curses', function($query) use ($areaId) {
$query->where('area_id', $areaId);
})
->with('curses')
->get();
The whereHas is required only if you want to get the areas that has matching curses.
But, I think you can do it like this way if you only need the related curses because one curse only belong to a single area so, if have the area then you'll get all the curses attached to it:
$area = Area::with('curses')->find($areaId); // Single area
// Access the curses
$curses = $area->curses; // collection of curses
I think you are using relational area_id which is present in curse table, try retrieving the ID of area by id not by area_id, something like this:
$areas = Area::where('id', $areaId)->with('curses')->get();
Hope you get the solution.
Try this :
$areas = Area::whereHas('curses', function($area_query) use ($area_id) {
$area_query->where('area_id', $area_id)
})
->with('curses')
->get();

Laravel Collection filter into Parent Data

I have created map table for relation between Products & Product Categories. I want to get Product object from collection using below code.
return $collection->products->product_categories()->get()->filter(function($item) use ($itemIds)
{
if(isset($item->pivot->parent->id))
{
return $item->pivot->parent;
}
});
If I dump and die parent then I can see Product object but when I try to return Product it shows Category data.
You're almost there. You just need to return the product data from the categories. Assuming your code works, you just have to map the collection to return the parent from the pivot.
return $collection->products->product_categories()->get()->filter(function($item) use ($itemIds)
{
if(isset($item->pivot->parent->id))
{
return $item->pivot->parent;
}
})->map(function($item){
return $item->pivot->parent;
});

Resources