Laravel 5.4 collection sortByDesc not working - php

I have two queries with Eloquent which I collect and merge and after i do sortByDesc but it's not sorting collection.
$f_games = collect(Game::with('fUser', 'sUser')->where('first_user_id', Auth::user()->id)>get());
$s_games = collect(Game::with('fUser', 'sUser')->where('second_user_id', Auth::user()->id)->get());
$response = $f_games->merge($s_games)->sortByDesc('id');

You can use values() at the end of sorting, as discussed in documentation
$gameCollection = collect($game);
$sorted = $gameCollection->sortByDesc('date');
return $sorted->values()->all();
In you case it should be
$response = $f_games->merge($s_games)->sortByDesc('id')->values();

There is no need to wrap in collect(), $f_games and $s_games will be collection without additional wrapping:
$f_games = Game::with('fUser', 'sUser')->where('first_user_id', Auth::user()->id)>get();
$s_games = Game::with('fUser', 'sUser')->where('second_user_id', Auth::user()->id)->get();
$response = $f_games->merge($s_games)->sortByDesc('id');
But the best way is:
$user_id = Auth::user()->id;
$f_s_games = Game::with('fUser', 'sUser')
->where('first_user_id', $user_id)
->orWhere('second_user_id',$user_id)
->orderBy('id', 'desc')
->get();

The sortByDesc method sorts the collection by field that belongs to some eloquent relation in your model.
If you are trying to sort collection with sortByDesc for model itself ( your current object of model), please user orderBy rather than sortByDesc
Example:
For model itself
{$collection_list = $this->model_name->orderBy('field_name','DESC')->get();}
For relations that will be lazy loaded in views
{$collection_list = $this->model_name->get()->sortBy('table_name.field_name', SORT_REGULAR, true);}
Note: sortByDesc internally called sortBy() with descending order,
true means Descending Order and false means Ascending Order.

Related

how to make an eloquent result into an array Laravel

I want to combine two data search results into one array, I use array_merge but there is an array_merge() error:
Argument # 1 is not an array
How to turn $vendor's eloquent results into an array and combine it with $plucked?
$vendor = Vendor::find($id);
$vendor_detail = VendorDetail::where('vendor_id',$id)->get();
$plucked = $vendor_detail->pluck('vendor_profile_value','vendor_profile_name');
$coba = array_merge($vendor,$plucked);
$plucked already an array
I think the problem here is that $vendor is not yet an array
You could do it like this:
$vendor = Vendor::find($id);
$vendor_details = VendorDetail
::select('vendor_profile_value', 'vendor_profile_name')
->where('vendor_id', $id)
->get()
->toArray();
$coba = array_merge($vendor,$vendor_details);
The get() method execute the query returning a Collection instance, in which you can call the toArray() method.
Side note
As far as I can see, you could make use of relationships and eager loading.
If you have a one-to-many relationship defined like this in your Vendor model:
public function details()
{
return $this->hasMany(VendorDetails::class);
}
Then, you could eager load the relationship like this:
$vendor = Vendor::with('details')->find($id);
// ^^^^^^^^^^^^^^
You could even just load the wanted fields:
$vendor = Vendor::with('details:vendor_profile_value,vendor_profile_name')
->find($id);
Then, your object will have a new attribute called "details" containing the related objects (or a collection of the limited selected fields).
You can convert the $vendor to an Array like below.
$vendor = Vendor::find($id)->toArray();

Operetion on child collection

I have code like this
$tag = Tag::where('slug' = $slug)->first();
$posts = $tag->posts;
It works correctly but I want to use limit, orderBy, offset and other operation on posts. So it works
$posts = $tag->posts->where('accept', 1);
But it doesn't works
$posts-> $tag->posts->orderBy('created_at', 'desc');
//or
$posts-> $tag->posts
->offset($offset)
->limit($limit);
I must use offset and limit into query from var.
How I can do that?
When you set up your initial query Tag::where('slug' = $slug)->first(); you're using Query Builder and it's methods. But when Laravel returns the results, they're returned as a collction object -- those have very similar but slightly different methods available. https://laravel.com/docs/5.8/collections#available-methods
On a collection or its children, instead of orderBy() you would use sortBy() or sortByDesc(). Those will return an instance of the collection, sorted by your specified key. $results = $posts->sortBy($sorting);
The same idea with limit, in this case you can use the splice method. (Collections are basically php arrays on steroids) Splice accepts two parameters, a starting index and a limit. So, to get only the first 10 items, you could do this: $results = $posts->splice(0, 10);
And of course, you can also chain those togeather as $results = $tag->posts->sortBy('id')->splice(0, 10);
When you use child, Eloquent create another subquery, then result is added to parent, thats way its not sorting properly.
A solution could be join tables:
$tags = Tag::where('tags.slug' = $slug)
->join('tags', 'tag.post_id', '=', 'posts.id')
->orderBy('posts.created_at', 'desc')
->select('tags.*')
->get();

How to create array with key => values from object{key, value}?

I solver this by this code
$service_list = Service::all();
$services = [];
foreach ($service_list as $item){
$services[$item['id']] = $item['name'];
}
but how to do that using php_array functions?
its for dropdown select
Not sure why you have to use PHPs built in array methods but we have pluck on the Query Builder and Collection class.
$services = Service::pluck('name', 'id');
// $services->all(); // for the actual array contained
This will only select the name and id in the query and give you a Collection keyed by the id only containing the name field.
$services = Service::all();
$services_array = $services->pluck('name', 'id')->all();
If you already have your collection of models (code above has queried for every field and hydrated models with the result) you can use pluck on the Collection to achieve the same result (though less efficient as it had to query for all fields, hydrate models, then pull those 2 fields from them)
Laravel 5.5 Docs - Query Builder - Retrieving Results
Laravel 5.5 Docs - Collections - pluck method
Use toArray() to convert the collection to an array, then use array_combine() to create an associative array from that.
$service_list = Service::all()->toArray();
$services = array_combine(array_column($service_list, 'id'), array_column($service_list, 'name'));
$service_list = Service::all()->toArray();
all() will return a collection. The collection supports a toArray() method

Laravel 5.2: Is it possible to use where clause condition in eloquent object

Fetched the initial data by joining the other table
$results = Model::join('joining other table')
->where('initial condition')
->limit(100)->get();
Now, i need to filter the data by some additional condition.
$new = $results->where('column',value); // Additional Condition
I had tried this but it returns empty collection, even though persist in the $results collection. Is it possible to use the where condition in later part ?.
You can use model relationships, which is very powerful. If you define your relationships between the different models you can call:
User::with(['posts' => function($builder){
$builder->where('published', true) // this is on the relationship (posts)
}])->get();
You can also do the following:
Post::whereHas(['user' => function($builder){
$builder->where('confirmed', true);
}])->get();
That will only return the posts where the associated user is confirmed...
Have you tried:
Model::join('joining other table')
->where('initial condition')
->where('column',value)
->limit(100)->get();

How to count and fetch data query in laravel?

How to merge this two queries ?
$data = DB::table('category_to_news')
->where('category_to_news.name', ucwords($category))
->remember(1440)
->count();
and
$data = DB::table('category_to_news')
->where('category_to_news.name', ucwords($category))
->remember(1440)
->get();
So, as far as I understand from your comment, you simply want to get all records from the table category_to_news and you want to know how many records are in there, right?
MySQL's count is an aggregate functions, which means: It takes a set of values, performs a calculation and returns a single value. If you put it into your names-query, you get the same value in each record. I'm not sure if that has anything to do with 'optimization'.
As already said, you simply run your query as usual:
$data = DB::table('category_to_news')
->where('name', ucwords($category))
->remember(1440)
->get(['title']);
$data is now of type Illuminate\Support\Collection which provides handy functions for collections, and one them is count() (not to be confused with the above mentioned aggregate function - you're back in PHP again, not MySQL).
So $data->count() gives you the number of items in the collection (which pretty much is an array on steroids) without even hitting the database.
Hi DB class dont return collection object it give error "call member function on array" but eloquent return collection object. for above code we can use collect helper function to make it collection instance then use count and other collection methods https://laravel.com/docs/5.1/collections#available-methods .
$data = DB::table('category_to_news')
->where('name', ucwords($category))
->remember(1440)
->get();
$data = collect($data);
$data->count();
You my get it using:
$data = DB::table('category_to_news')
->where('name', ucwords($category))
->remember(1440)
->get();
To get the count, try this:
$data->count();
Why you are using DB::table(...), instead you may use Eloquent model like this, create the model in your models directory:
class CategoryToNews extends Eloquent {
protected $table = 'category_to_news';
protected $primaryKey = 'id'; // if different than id then change it here
}
Now, you may easily use:
$data = CategoryToNews::whereName(ucwords($category))->get();
To get the count, use:
$data->count();

Categories