use keyBy method inside with method in eloquent - laravel-4

I want use keyBy method inside of with method in Eloquent. like this:
$settings = $settings->with(
array('languages' => function($query)
{
$query->get()->keyBy('languages_language_id');
})
)->get()->keyBy('setting_key');
How can i do that? thanks.

You can't do it directly in the with Clause, instead you can override the collection with the keyBy version:
foreach ($settings as $keySetting => $setting)
{
$settings[$keySettings]->languages = $settings[$keySettings]->languages->keyBy('languages_language_id');
}
As you can se you still have to iterate over the results and reorder one by one. This is just a cleaner version using keyBy of what you are doing already.

Finally i use this:
$settings = $settings->with('languages')->get()->keyBy('setting_key')->toArray();
foreach ($settings as $keySetting => $setting)
{
$languages = $setting['languages'];
$settings[$keySetting]['languages'] = array();
foreach ($languages as $lang)
{
$settings[$keySetting]['languages'][$lang['languages_language_id']] = $lang;
}
}

Related

How to add object to existing Laravel Query?

What I want to do is add an object to the existing query.
This is my work in progress right now:
$users = ModelUser::where('date_created', $date)->get();
foreach($users as $user){
$obj = ['test1'=> 'val1','test2' => 'val2','test3'=> 'val3',];
$users['items'] = $obj;
}
return $users;
what I'm hoping is a result is like this.
{"username":'Username1', "Fname":'fname1', "items":['test1' = 'val1','test3' = 'val3','test3' = 'val3']
"username":'Username2', "Fname":'fname2', "items":['test1' = 'val1','test3' = 'val3','test3' = 'val3']
"username":'Username3', "Fname":'fname3', "items":['test1' = 'val1','test3' = 'val3','test3' = 'val3']
"username":'Username4', "Fname":'fname4', "items":['test1' = 'val1','test3' = 'val3','test3' = 'val3']
}
Where the items are like in a sub object.
Convert it into a collection and push into it
https://laravel.com/docs/9.x/collections#method-push
Just to understand a bit more, does the "items" element you want to add to the user object have any relationship at the database level?
If so, it would be better to define a relationship within the ModelUser https://laravel.com/docs/9.x/eloquent-relationships#defining-relationships
In case not, I see you're using a $user as an array, but actually $user is a ModelUser element.
So a trick, definitely not recommended, would be:
$user->items = $obj;
You can use laravel map as
$users = ModelUser::where('date_created', $date)->get();
will return a collection. So your expected code will be something like the following
$users = $users
->map(function ($user) use ($obj) {
return $user->items = $obj;
})
);

Laravel Collection paginate does not exist

I'm trying to implement basic pagination when retrieving notifications, but I get the following error.
Method
Illuminate\Notifications\DatabaseNotificationCollection::paginate does
not exist.
public function index()
{
$messages = collect();
$notifications = auth()->user()->unreadNotifications->paginate(5);
foreach ($notifications as $notification) {
$message = NotificationToMessageFactory::make($notification->type)
->toMessage($notification->data);
$messages->push($message);
}
}
You've to call paginate() on query builder instance not on a collection.
Correct syntax will be :
$notifications = auth()->user()->unreadNotifications()->paginate(5);
You should paginate before looping through the collection, otherwise you will be retrieving all records matching the query, when you only need 5. Like this:
$messages = collect();
$notifications = auth()->user()->unreadNotifications()->paginate(5);
foreach($notifications as $notification) {
$message = NotificationToMessageFactory::make($notification->type)->toMessage($notification->data);
$messages->push($message);
}

Sorting collections in Laravel

I've got a little problem with my Laravel controller and sorting it:
public function index()
{
$achievements = Achievement::all();
$news = News::all();
$livingspaces = Livingspace::all();
$therapies = Therapy::all();
$events = Event::all();
$collection = collect();
foreach ($achievements as $achievement) {
$collection->push($achievement);
}
foreach ($news as $new) {
$collection->push($new);
}
foreach ($livingspaces as $livingspace) {
$collection->push($livingspace);
}
foreach ($events as $event) {
$collection->push($event);
}
foreach ($therapies as $therapy) {
$collection->push($therapy);
}
$sortedData = $collection->sortBy('category')->sortByDesc('created_at');
return response()->json([
'sortedData' => $sortedData
], 200);
}
It's not sorting at all. It should sort if after the data in the created_at timestamp which comes out of the box when creating a new migration for a Laravel controller. But I can't sort the data. I think it has something to do with pushing the data from the DB directly into the collection and it's not looking for "created_at" at all. It's not giving any errors or anything its just not doing anything. The same goes for sortBy.
sortByDesc method has the same signature as the sortBy method, but will sort the collection in the opposite order. By default sortBy to do the ascending operation. If you want to sort by decending:
$sortedData = $collection->sortBy('category', true);

Filter model with HasMany relationship

Let's say I have two models: Park and Items. Each Park can have a number of Items, through a HasMany relationship.
In Items table there's a park_id field and a type flag: an Item can be a fountain, or a basketball court, or whatever.
What I need to do is to filter the parks to obtain only those who has ALL of the item types passed in an array. This is what I have:
$parks = Park::whereHas('items', function($q) use ($request) {
$q->where('type', json_decode($request->type_list));
})->get();
But it's not working properly. Any ideas?
Thanks a lot, and happy new year to all!
Edit: I've found a working though really ugly solution:
$types_array = json_decode($request->type_list, true);
$results = [];
// A collection of parks for each item type
foreach($types_array as $type) {
$results[] = Park::whereHas('items', function($q) use ($type) {
$q->where('type', $type);
})->get();
}
// Intersect all collections
$parks = $results[0];
array_shift($results);
foreach ($results as $collection) {
$parks = $collection->intersect($parks);
}
return $parks;
You can use a foreach in whereHas method. It should be something like this:
$array = json_decode($request->type_list, true)
$parks = Park::whereHas('items', function($q) use ($array) {
foreach ($array as $key => $type) {
$q->where('type', $type);
}
})->get();
I think using where clause to match all item's type for the same row will result nothing, it's like doing where id = 1 and id = 2 and this is impossible because id can take only one value, what you should do is to use whereIn to get all items that match at least one type and then use groupBy to group result by park_id, then in the having clause you can check if the group count equal the type_list count:
$types = json_decode($request->type_list, true);
$parks = Park::whereHas('items', function($q) use ($types) {
$q->select('park_id', DB::raw('COUNT(park_id)'))
->whereIn('type', $types)
->groupBy('park_id')
->havingRaw('COUNT(park_id) = ?', [ count($types) ]);
})->get();
You can add multiple whereHas() constraint to one query:
$types_array = json_decode($request->type_list, true);
$query = Park::query();
foreach($types_array as $type) {
$query->whereHas('items', function($q) use($type) {
$q->where('type', $type);
});
}
$parks = $query->get();

Laravel controller method for router with an optional parameter

I'd like to have a controller handling url like .../item/list and .../item/list/5.
First one would be to display all items, second one would display items whose author has an ID = 5.
public function getList($userid) {
$items = \DB::table('items')->get();
if ($userid) $items = \DB::table('items')->where('user_id', '=', $userid)->get();
foreach ($items as $item) {
// ...
}
}
URL like .../item has an argument missing.
Is there option to solve this?
I think your route looks like this:
Route::get('item/{userid}', 'MyController#getList');
But what should happen if there is no id?
Let's change your logic like this:
If there is a userId in the url then display the user's items. If there is no id display all.
So change your route:
Route::get('item/{userid?}', 'MyController#getList');
And also your function:
public function getList($userid = null) {
$items = \DB::table('items')->get();
if ($userid) $items = \DB::table('items')->where('user_id', '=', $userid)->get();
foreach ($items as $item) {
// ...
}
}
Create a route with an optional parameter
Route::get('item/list/{userid}', 'MyController#getList');
Then change userid in your function to have a default argument value
public function getList($userid = '') {
$query = \DB::table('items');
if ($userid) {
$query->where('user_id', '=', $userid);
}
$items = $query->get();
foreach ($items as $item) {
// ...
}
}

Resources