Laravel Collection returns only 11 values - php

I'm building timeline for my app and got this issue, that my collection returns me only 11 values.
I have tried to change merged data and it always returns me 11 values that makes me very confused, bc their is no limits in my code.
public function timeline($company_id)
{
// USER COMPANY
$company = auth()->user()->companies()->findOrFail($company_id);
//GETTING DATA TO MERGE COLLECTION
$equities = Share::where('company_id', $company_id)->get();
$equityGrants = EquityGrant::whereIn('share_id', $equities->pluck('id')->toArray())->get();
$warrants = Warrant::where('company_id', $company_id)->orderBy('created_at', 'DESC')->get();
$warrantGtrants = WarrantGrant::whereIn('warrant_id', $warrants->pluck('id')->toArray())->get();
$convertibles = Convertible::where('company_id', $company_id)->get();
// CREATING COLLECTION
$operations = $equities->merge($equityGrants)->merge($warrants)->merge($warrantGtrants)->merge($convertibles);
$operations = $operations->sortByDesc('created_at');
// RETURNS ME ONLY 11 VALUES
return $operations->values()->all();
}
I tried to merge() less instances, like $operations = $equities->merge($equityGrants)->merge($warrants)->merge($warrantGtrants) but always maximum 11 values. I need to return all data for my timeline.
HELP ME Please! :)
Cheers, love :)
SOLUTION:
function concat() instead of merge() fixed the problem.

Using merge() on collections in Laravel will cause overiding all elements with the same ids comming from Eloquent query.
I believe that is why you are getting only 11 elements because this is the count off all elements having distinct ids.

According to the documentation of merge, when a key matches, it will be overwritten by the last item with that key (the collection you are merging in).
A solution to your problem would be the keyBy method (documentation). If you use keyBy('created_at'), it will give you an array where the keys are the created_at timestamps.
Although it sounds like they would be unique, there is a great change that some of the linked resources (like warrant and warrentGrants) are created at the exact same moment. If that is the case, you should try to find another key or something that is unique across all resources.

SOLUTION: function concat() instead of merge() fixed the problem.

Related

Laravel 8 Dynamic relationships

I'm using Laravel 8. I have relationships strings but I don't how to load the relationships inside a loop. I'd like to explode() my relationships on the dot and load each relationship to get the column
$userPostTitle = 'post.title';
$userAvatarFilename = 'profil.avatar.filename';
The idea is to use explode() on the dot explode('.', $userPostTitle) and add bracket object dynamically for each relationship :
// for the userPostTitle we need two level
$postTitle = $user->{explode[0]}->{explode[1]};
// for the userAvatarFilename we need three level
$avatarFilename = $user->{explode[0]}->{explode[1]}->{explode[2]};
How it's possible to add dynamically the exploded relationship ? {rel1}->{rel2}->{rel3} etc... Maybe there is a better solution than using explode()
You have to keep in mind that your solution possibly does a lot of queries if you haven't preloaded the relations beforehand. However I think you can use the Laravel helper object_get() for your problem:
$relation = 'profile.avatar.filename';
$avatarFilename = object_get($user, $relation);
// Which roughly translates to calling `$user->profile->avatar->filename`
It also accepts a third parameter which is a default value if the property turns out to be null.

How to replace collection in query result Mongo

I queried to get info from a table with a manytomany relationship like this
$userList = UserListing::where('user_id', $user->id)->with("objects")->paginate(10);
Now, i want to limit the amount of results in the "Objects" table, but at the same time i want to know how many objects are in total.
$userList = UserListing::where('user_id', $user->id)->with(["objects"=> function($query) {
$query->take(2);
}])->paginate(10);
But by doing this, i can't get the total of objects since i limited it to 2, then i tried to process the info like this
$userList = UserListing::where('user_id', $user->id)->with("objects")->paginate(10);
foreach ($userList as $key => $value) {
$l = count($value["objects"]);
$value["objects"] = $value["objects"]->take(2);
$value["number_objects"] = $l;
}
But apparently this did not replace the collection value["objects"], since it still returned 3 objects, despite supposedly being reduced with $value["objects"] = $value["objects"]->take(2);. How can i replace the collection with the reduced one?
So, i kept investigating, and noted that userList was a LengthAwarePaginator object, which by property apparently is inmutable in its original fields(Meaning you can add new ones, but not delete/modify the already existent). Knowing this, i searched a little more and found this answer:
https://stackoverflow.com/a/49133519/7228093
Which basically creates a new LenghtAwarePaginator from the original one, allowing you to modify the fields. If someone finds in this situation, this may be a good option(The transform method of collections did not work by the way, only this one).

LARAVEL: I am only getting one item from my table when there are multiple items. How would I get all of them and output them?

I am using a session to create a basic cart. In the session there are multiple IDs ranging from 1-3.
When I output the data using foreach it only outputs the first item from the table. I would like all the related items to appear. How would I go about doing that?
Here is my index function from my controller:
public function index()
{
session_start();
$cartData = implode(',', $_SESSION['cart']);
$cartProducts = Product::where('id',$cartData)->get();
return view('basket',['cartProducts'=>$cartProducts ],['cartData' =>$cartData] );
}
This is my output on the cart page:
#foreach($cartProducts as $cartProduct)
<p>{{$cartProduct->name}}</p>
<p>{{$cartProduct->size}}</p>
<p>{{$cartProduct->price}}</p>
#endforeach
And for testing purposes this is my dump and die of the $cartData:
"1,1,3"
And finally this out the actual output:
Original
small
8
You have two issues:
You're passing in a string of IDs instead of an array
where only looks for a single value.
So the query is actually becoming where id = '1,1,3', which may only match the id of 1. To fix it, pass in the actual array, and use whereIn:
Product::whereIn('id', $_SESSION['cart'])->get();
This changes the query to where id IN (1,1,3).
You are just using where, which is not helpful on what you are trying to achieve.
You should rather be using whereIn (equivalent to wherein() in sql) without imploding (use array directly).
->whereIn('id', $cartData)
This should solve your problem.

Laravel - filter collection and then ->toJson, having a minor issue

I have a Laravel controller which takes a search parameter, looks through all the records in a certain time range, uses the laravel collection ->filter method, and then on the results of that filter method, returns the json ->json
$logs = RequestLog::orderBy('created_at', 'DESC')->whereBetween('created_at', [$start, $end])->get();
$logs = $logs->filter(function($log) { /* my own logic in here */ });
return response()->json($logs->toJson());
Now this seems to work just fine. It normally returns an array of the matching records, [{"id":1},{"id":2},{"id":3}]
But if the ->filter function leaves one result, let's say the 25th record in the array, the response now comes out like this: {25: {"id": 25}}. It ruins the normal array structure and returns a JSON object with a single key.
Is this expected? What's up with this? How do I deal with this?
Note: my filter function cannot be done via sql means, it has to be done in PHP.
[edit] it's actually returning an Object JSON anytime the filter results are anything other than the first items in the original Query results.
Normally after applying methods that modifies (especially removes an item from) a collection, the indexes may not come ordered. This is why you need ->values() on the collection.
So you'd have:
return response()->json($logs->values()->toJson());
values() Resets the keys on the underlying array.

Append a Laravel collection with another collection

I am trying to append an Eloquent collection with another Eloquent collection in Laravel 5.3.
This is what I've done so far:
$entries = Entry::all();
$posts = Post::all();
$entries->merge($posts);
I tried to use merge() as shown in the code above, but it seems that I'm stuck with this kind of problem (since some of them have the same id with the same value):
Collection merge eating up some rows
Any ideas?
For versions < 5.4 you can merge the two eloquent collections by resetting keys with toBase like this:
$mergedCollection = $entries->toBase()->merge($posts);
For versions >= 5.4 you can use concat as suggested by Jason.
I believe you may be looking for concat(). This will append one container to the end of another container, regardless of the keys of either.
$mergedCollection = $entries->concat($posts);
Here's the link: laravel7.X
$collection = collect(['Desk', 'Chair']);
$merged = $collection->merge(['Bookcase', 'Door']);
$merged->all();
if you need to merge big_products and small_products:
$products = $bigProducts->values()->merge($smallProducts->values());
The merge method merges the given array or collection with the original collection. If a string key in the given items matches a string key in the original collection, the given items's value will overwrite the value in the original collection.
But
If the given items's keys are numeric, the values will be appended to the end of the collection:
Thus, all you need is to get rid of keys and you can do it with ->values() function.
Tested on Laravel-6
The merge() method receives an array, so you have to do something like
$entries->merge($posts->toArray());
Laravel Collections: merge() method

Categories