Laravel 5 Model orderBy? - php

I see you can call my MyModel::all() and then call "where" "groupBy" .. etc
I cant seem to find orderBy as this Q & A suggest..
Has this been removed in Laravel 5?
I've tried looking through the docs for a reference in Collection and Model but I'm assuming these are actually just modifiers for the collection returned and not actually modifying the query statement..
The only way I know of using order by is
\DB::table($table)->where($column)->orderBy($column);
Is that the only way to order your database select when executing a query?

You can actually just use it like where and groupBy:
$result = MyModel::orderBy('name', 'desc')->get();
Note that by calling MyModel::all() you're already executing the query.
In general you can pretty much use every method from the query builder documented here with Eloquent models. The reason for this is that the model proxies method calls (that it doesn't know) to a query builder instance:
public function __call($method, $parameters)
{
// irrelevant code omitted
$query = $this->newQuery();
return call_user_func_array(array($query, $method), $parameters);
}
$this->newQuery() creates an instance of the query builder which then is used to actually run the query. Then when the result is retrieved the model/collection is hydrated with the values from the database.
More info
Eloquent - Laravel 5 Docs
Illuminate\Database\Eloquent\Builder - API docs
And also the regular query builder (since quite a few calls get passed from the eloquent builder)
Illuminate\Database\Query\Builder - API docs

You can achieve this with the following solution:
$result = ModelName::orderBy('id', 'desc')->get();

You can do it by using sort keys
Model::all()->sortKeys()
(or)
Model::all()->sortKeysDesc()

Related

Why is it not possible to use groupBy() in an eager loading query - Laravel

ErrorException:
stripos() expects parameter 1 to be string, object given
For the groupBy() call in the with() method
$user = User::with([
'pricelists' => function($query) {
$query->groupBy(function($var) {
return Carbon::parse($var->pivot->created_at)->format('m');
});
}
])->where('id', $id)->get();
I already saw a few posts talking about how to manage this problem and that it shall not be possible to use groupBy() in eloquent but I do not really understand why...
To be clear:
User and Pricelist model got a many-to-many relationship with the default timestamps() method. I am trying to get the downloaded pricelists grouped by their months they were downloaded from the current user.
After a few attempts I just deleted the above shown => function($query... statement from the with() method and just left the with(['pricelist']) to fetch all datasets and tried this:
$user->pricelists = $user->pricelists->groupBy(function($var) {
return Carbon::parse($var->pivot->created_at)->format('m');
});
return $user->pricelists;
And it works fine and returns an array with multiple arrays for each month... But returning it like this:
return $user;
returns just 1 array with all entries... I do not really get the sense behind it right now...
The two groupBy() method that you are using in the two code you provide are totally different methods.
The first groupBy() where you use it in the callback is actually being called by $query which is a query builder object. The groupBy() here is used to add SQL GROUP BY Statement into the query. And as per the documentation, it only take string variables as parameter.
The groupBy() in your second code is being called by $user->pricelists which is a laravel eloquent collection. The groupBy() method here is actually from the base collection class and is used to group the items inside the collection into multiple collections under the different key defined by the parameter passed to the function. Please read the documentation here.
For your case, the second groupBy() is the one you should be using since you plan to use a callback and will allow you to use more complicated logic.

Laravel blade method latest doesn´t exist on user model

In my user model (App\User.php), I declare following relationship:
public function actionables() {
return $this->hasMany(Actionable::class, 'owner_id', 'id');
}
In my migration scheme for the actionables table, I specify following foreign key:
$table->foreign('owner_id')->references('id')->on('users')->onDelete('cascade');
When I call
{{ auth()->user()->actionables->where('act_type', 'order')->latest()->content }}
In a blade view, I get following error message:
Method Illuminate\Database\Eloquent\Collection::latest does not exist.
I´ve tried using ->get() and using other way´s of accessing the user model (Auth::user), but nothing has solved the problem so far.
The distinction that the other answers are glossing over is using the query builder vs using a collection. When you call the relationship using a property Eloquent will fetch all the results then return a collection (which is basically just a beefed up array). So when you do
auth()->user()->actionables
Laravel executes the SQL Query then returns all the results as a collection.
SELECT * FROM actionables WHERE owner_id = ?
The collection class has a where method that functions similarly to the query builder method, but it's important to realize that it's performing the search in PHP not SQL because the query has already been executed and can't be changed anymore. latest() exists on the query builder, but not the collection which is where your error is coming from.
To leverage the relationship in the query builder you need to call the relationship as a function. user()->actionables()
auth()->user()->actionables()->where('act_type', 'order')->latest()->first()
The above will execute the SQL query then return just the record you're looking for.
SELECT * FROM actionables WHERE act_type = order AND WHERE owner_id = ? ORDER BY created_at DESC LIMIT 1
latest not exist not within Collection methods.
to get the last element of your database query you should apply this query:
*Note that you should have created_at within the Actionable table.
auth()->user()->actionables()->where('act_type', 'order')->orderBy('created_at', 'desc')->first()->content
You should use the query builder actionables() not the collection actionables, i.e:
{{ auth()->user()->actionables()->where('act_type', 'order')->latest()->first()->content }}
It must be ->last() not ->latest()
{{ auth()->user()->actionables->where('act_type', 'order')->last()->content ?? ""}}
Collection does not have the latest method, it's the query builder that has that method.
Try last instead.
Ref: https://laravel.com/docs/5.8/collections#available-methods

When not or should use get() in Laravel 5

I need to understand when/not to use get(); in Laravel 5.
PHP warning: Missing argument 1 for Illuminate\Support\Collection::get()
Google shows me answers to their issue but no one really explains when you should/not use it.
Example:
App\User::first()->timesheets->where('is_completed', true)->get(); // error
App\Timesheet::where('is_completed', true)->get(); // no error
Fix:
App\User::first()->timesheets()->where('is_completed', true)->get(); // no error
Noticed the timesheets() and not timesheets? Could I have a detail explanation for what is going on, please?
I'm coming from a Ruby background and my code is failing as I do not know when to use () or not.
I'll try to describe this as best I can, this () notation after a property returns an instance of a builder, let's take an example on relationships,
Say you have a User model that has a one-to-many relationship with Posts,
If you did it like this:
$user = App\User::first();
$user->posts();
This here will return a relationship instance because you appended the (), now when should you append the ()? you should do it whenever you want to chain other methods on it, for example:
$user->posts()->where('some query here')->first();
Now I will have a the one item I wanted.
And if I needed say all posts I can do this:
$user->posts;
or this
$user->posts()->latest()->get();
$user->posts()->all()->get();
So the key thing here is, whenever you want to chain methods onto an eloquent query use the (), if you just want to retrieve records or access properties directly on those records then do it like this:
$user->posts->title;
Well, ->timesheet returns a collection, where ->timesheet() returns a builder.
On a Collection you can use ->where(), and ->get('fieldname'), but no ->get().
The ->get() method can be used on a builder though, but this will return a collection based on the builder.
Hope this helps.
The 'problem' you are facing is due to the feature of being able to query relations
When accessing a relation like a property, ->timesheets, the query defined in the relationship is executed and the result (in the form of a Collection) is returned to you.
When accessing it like a method, ->timesheets(), the query builder is returned instead of the resulting collection, allowing you to modify the query if you desire. Since it is then a Builder object, you need to call get() to get the actual result, which is not needed in the first case.
When you use ->timesheets you are accessing a variable, which returns the value of it (in this case an instance of Collection).
When you use ->timesheets() you are invoking whatever is assigned to the variable, which in this case returns an instance of Builder.
whilst pascalvgemert's answer does answer your problem regarding Laravel, it does not explain the difference between accessing or invoking a variable.
In simple term
$user = App\User::get();
is used to fetch multiple data from database
rather
$user = App\User::first();
is used to fetch single record from database

Laravel 5 where method not working

I'm trying to query records using a parameter from a route, but it's not working properly.
This is my route:
Route::get('reports/{id}', 'ReportsController#show');
This is my controller method:
public function show($id) {
return Reports::all()->where('user_id', $id);
}
When accessing the route 'reports/1', it returns nothing. However, if I hardcode in the id to use in the method, it does work:
public function show($id) {
return Reports::all()->where('user_id', 1);
}
I don't know what is wrong with my code, please help.
Your issue is that you're calling where() on a Laravel Collection, not on a Laravel Query Builder.
Reports::all() will run a query that will get every single report from the database and put it into a Collection. You're then running the where() method on that Collection.
The difference is that the where() method on a Collection loops through the items in the collection, and does a strict comparison (===), whereas the query builder adds a parameterized where clause to the SQL, which doesn't care about the variable type.
What you're running into is that when using the variable, you're running where('user_id', '1'), which is doing a strict comparison (===) of the user_id field to the string '1'. Since all the user ids are integers, you won't get any results.
What you really want to do is add your where conditions to the SQL statement. Instead of your current logic, you want:
public function show($id) {
return Reports::where('user_id', $id)->get();
}
This will fix your issue, as well as only return those records that match your where clause, which may severely boost your performance. If you have a million reports, you don't want to build a collection of a million objects, and then iterate through them.

Eloquent ORM returning collection with single item

Using Laravel 4.2 and eloquent ORM, I know that all multi-result sets returned by a query will return a Collection object, as documented here (http://laravel.com/docs/eloquent#collections).
I am running a query that returns a single object:
$faq = ProductFaq::where($where)->with('products')->get();
However, I'm being returned a collection.
In order to use the result do I need to chain ->first() to the end of my statement? I'm just confused if the docs are saying that every call that uses get() will return a collection, or only get() calls that have multiple results.
Get returns a Collection instance, you should call first instead of the get method
$faq = ProductFaq::where($where)->with('products')->first();

Categories