How to get flat array of eager loading in laravel 5.5? - laravel

this my eloquent query:
$data = Disciplines::where('type', '<>', 'Initiator')
->with(['discipline_boxes.assign.box' => function($query) {
$query->select('id');
}])
->get();
return $data;
i want return only array of id's of box relation
e.g:[2,3,4,5]

Solved!!
this worked for me!
$disciplines = new Disciplines();
$results = $disciplines->getAllBox_ID()->toArray();
dd(array_flatten(array_pluck($results,'discipline_boxes.*.assign.box.id')));

Potentially if you have the inverse for this chain of relationships you could get this information from the Box end (making name assumptions here):
Box::whereHas('assign.discipline_box.discipline', function ($q) {
$q->where('type', '<>', 'Initiator');
})->pluck('id');

Related

Laravel eloquent with and with condition

I'm trying to get category and selected items from category. Here is my code:
$reqItems = $request->items; //array - selected item
$categories = Category::where('type_id', 1)
->whereHas('items', function ($query) use ($reqItems){
$query->whereIn('id', $reqItems);
})
->with('items');
->get();
But this will return all the items, even not in selected item.
And i tried with foreach, its return null
$reqItems = $request->items; //array - selected item
$categories = Category::where('type_id', 1)->with('items');
foreach($reqItems as $reqItem) {
$categories = $categories->whereHas('items', function ($query) use ($reqItem){
$query->where('id', '=', $reqItem);
});
}
$categories = $categories->get();
How to return only selected items?
As suggested by #lagbox, here the working code:
$reqItems = $request->items;
$categories = Category::where('type_id', 1)
->with(['items' => function ($query) use ($reqItems){
$query->whereIn('id', $reqItems);
}])->get();
when you wish to eager load a relationship and specify additional query conditions for the eager loading query. You can accomplish this by passing an array of relationships to the with method where the array key is a relationship name and the array value is a closure that adds additional constraints to the eager loading query:
$categories = Category::where('type_id', 1)
->whereHas('items', function ($query) use ($reqItems){
$query->whereIn('id', $reqItems);
})
->with(['items'=>function ($query) use ($reqItems){
$query->whereIn('id', $reqItems);
}])
->get();

Laravel - Filter collection with closure on relationship

Wondering if there is a way to use closure on a relationship in order to filter the whole line if there isn't a value which corresponds?
Example code:
foreach ($paiementMethods as $value) {
$giftCards = GiftCard::with(['userEntered', 'userEmployee', 'client', 'payement', 'payement.payementMethods' => function($query) use ($value)
{
$query->where('id', $value);
}])
->where('date','>=', $dateStart)
->where('date','<=', $dateEnd)
->orderBy('updated_at', 'desc')->get();
$giftCardsCollection = $giftCardsCollection->merge($giftCards);
}
}
In this example, if $query->where doesn't find a row for the payement.payementMethods which matches the $value, I want the giftCard to return null. The result I get is the giftCard with only the relation on payement.payementMethods being empty.
My other solution would be to query the giftCard and after that checking the $value to see if I have to include the giftCard in the collection or not.
Best regards
I think using whereHas, it can be solved
$giftCards = GiftCard::with(['userEntered', 'userEmployee', 'client', 'payement', 'payement.payementMethods'])
->whereHas( 'payement.payementMethods', function($query) use ($paiementMethods) {
$query->whereIn('id', $paiementMethods);
})
->where('date','>=', $dateStart)
->where('date','<=', $dateEnd)
->orderBy('updated_at', 'desc')
->get();

Best way to return the sum aggregation of a relations property

I have a simple structure where a post has many votes. A vote has an "value" property which is either 1 or -1
When reading all posts I'd love to select this sum for each post into a custom property on post level. Currently i do this
$posts = Post::where('published_at', '<=', $date)
->orderBy('published_at', 'desc')
->simplePaginate(20);
$posts->each(function($post) {
$post->overallRating = $post->getRating();
});
This is fully working, however I think it's not that good to make like 20 queries to the database to read the ratings. Is there a way to simplify this in the actual fetch of the posts?
public function getRating()
{
return $this->votes->sum('value');
}
If you want to keep the votes included in the in the pagination results then I would suggest adding with('votes') so they're at least eager loaded i.e.
$posts = Post::with('votes')
->where('published_at', '<=', $date)
->orderBy('published_at', 'desc')
->simplePaginate(20);
However, if you don't want/aren't bothered about having the votes and you just want the ratings for each post you could add the following scope to your Post model:
public function scopeWithRating(Builder $query)
{
if (is_null($query->getQuery()->columns)) {
$query->select([$query->getQuery()->from . '.*']);
}
$query->selectSub(
$this->votes()->getRelationExistenceQuery(
$this->votes()->getRelated()->newQuery(), $query, new Expression('sum(value)')
)->toBase(),
'rating'
);
}
Then:
$posts = Post::withRating()
->where('published_at', '<=', $date)
->orderBy('published_at', 'desc')
->simplePaginate(20);
Hope this helps!
Try this:
$posts = Post::where('published_at', '<=', $date)
->orderBy('published_at', 'desc')
->with(['votes' => function($query) {
$query->sum('value');
}])->simplePaginate(20);

Getting a relationship with a condition?

I have category and article tables, they are in a many to many relationship. i have the relationships set up on the models.
How can I get all articles where a category id is = 1?
I've tried:
Article::whereHas('category', function ($query) use ($id) {
$query->where('category_id', $id);
})->get();
The above works, but seems clunky, is there a more efficient way in eloquent to do this?
You can use eager loading technique.
Article::with(['category', function ($query) use ($id) {
$query->where('category_id', $id);
}])->get();
The following groupBy code is assuming that Category::find($id)->articles is not an option for whatever reason.
What about groupBy?
Article::groupBy('category')
->having('category', $id)
->get();
whereHas will return articles that match that condition, but won’t filter articles then fetched by the same conditions. You could therefore create an anonymous function that contains the constraints, and pass it to both the whereHas and with methods:
$filter = function ($query) use ($categoryId) {
$query->where('category_id', '=', $categoryId);
};
Article::whereHas('category', $filter)
->with(['category' => $filter])
->get();

Laravel 4 Eager Loading constraints

I want to get all Items (topics) WITH their comments, if comments user_id = $id. I try something like this, but it isn't working. So if Item hasn't got any comment with user_id = $id, then I don't need this Item.
In DiscussionsItem model I have methode:
public function discussionsComments() {
return $this->hasMany('DiscussionsComment', 'discussionsitem_id');
}
My query in controller is like this:
$items = DiscussionsItem::whereBrandId($brand_id)
->whereBrandCountryId($country_id)
->with(['discussionsComments' => function($query) use ($id) {
$query->where('user_id', '=', $id);
}])
->whereHas('discussionsComments', function($query) use ($id) {
$query->where('user_id', '=', $id);
})
->with(['views' => function($query) use ($id) {
$query->where('user_id', $id)->count();
}])
->orderBy('created_at', 'DESC')->get();
My problem is that I get items with comments, where comments user_id != $id.
P.S. I need to take 5 comments, but I cant imagine how to do that, because ->take(5) in my eager load is not working.
You can do a custom scope, or just limit the amount returned by your relation:
public function discussionsComments() {
return $this->hasMany('DiscussionsComment', 'discussionsitem_id')
->latest()
->take(5);
}

Resources