Laravel 5 where method not working - php

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.

Related

Why query result suddenly changed after called from other medthod in Laravel

I have problem here with query result from Eloquent, I tried to query from DB and put in variable $contractList in my mount() method and the result as expected. But when I tried to retrieve specific data from $contractList with $contractList->find($id), the result not same as in mount() method.
Here is query from mount():
public function mount(){
$contractList = Kontrak::select(['id', 'mou_id'])->with(['order:id,kontrak_id', 'order.worklist:id', 'order.worklist.khs:id,mou_id,worklist_id,khs', 'amdNilai:id,kontrak_id,tgl_surat'])->withCount('amdNilai')->get()
}
Here the result:
But when I tried to find specific data from $contractList, properties that shown not same as in mount:
public function itemSelected($id)
{
//amd_nilai_count not showing
$kontrak = $this->contractList->find($id);
if ($kontrak->amd_nilai_count == 1) {
$this->nilai_amd = $this->calculateNilai($id);
}
}
Here is the result called from itemSelected():
I have tried use get() but the result still problem, how to get same properties same as in mount().By the way im use laravel & livewire.
As i read your comments you seem to mix up ActiveRecords ORM with an Data Mapper ORM. Laravel uses active records.
Laravel will always fetch models on every data operation.
Kontrak::select('name')->find(1); // select name from kontraks where id = 1;
Kontrak::find(1); // select * from kontraks where id = 1;
This will always execute two SQL calls no matter what and the objects on the heap will not be the same. If you worked with Doctrine or similar, this would be different.
To combat this you would often put your logic in services or similar.
class KontrakService
{
public function find(int $id) {
return Kontrak::select(['id', 'mou_id'])->find($id);
}
}
Whenever you want the same logic, use that service.
resolve(KontrakService::class)->find(1);
However, many relationship operations is hard to do with this and then it is fine to just fetch the model with all the attributes.

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.

How to filter laravel collection

I am trying to make a filter in laravel. This following filter works
$posts= Post::where('category',$request->category)->orderBy('id','desc')->paginate(10);
But when I try to do something like this
public function index(Request $request)
{
$posts= Post::where('category',$request->category)->get();
$posts->latest()->paginate(10);
dd($posts);
It doesn't work. Can someone explain why is this and provide me the code that works. My project have multiple filter.
Error
Because $posts = Post::all(); already execute a query.
Post::where('category',$request->category)->latest()->paginate(10)->get();
would be what you want.
A note:latest requires the created_at column
You should go
$posts = Post::where('category',$request->category)->latest()->paginate(10);
the get request is unnecessary as the paginate will execute the query.
The first one makes the query by pagination i.e fetch 10 records per constructed page
For the second one, based on observation, you most likely have encountered at least 2 errors:
The first, on the line that used the get method because that method requires at least one parameter.
Type error: Too few arguments to function Illuminate\Support\Collection::get()
The other since its a collection, and since there is nothing like paginate or latest method on collection therefore throws other errors. You should check Collection's Available methods to have a glimpse of the methods allowed on collection.
One of the best solutions is to simply order the result when making the query:
Blog::where('category',$request->category)
->orderBy('created_at', 'desc') //you may use also 'updated_at' also depends on your need
->paginate(10);
This way you have the latest coming first int the pagination and also having not worrying about paginating a collection

GroupBy and OrderBy Laravel Eloquent

Building a chat application with a dashboard and am trying to get a notification of the last message the that other user sent.
Here is my Model relationships:
public function messages() {
return $this->hasMany('App\Message', 'author_id');
}
public function lastMessage() {
return $this->hasMany('App\Message', 'recipient_id')->orderBy('created_at', 'DESC')->groupBy('author_id');
}
On thing I cant figure out is instead of returning the last message as it should be sorted by using orderBY, it returns the first record of that group that exists in the database.
Looked around online but cant seem to find any info on this. The only thing I found is a post by someone who said that orderBy and groupBy in laravel don't play well together.
Any help is appreciated!
Instead of redefining the relationship in lastMessage, you might try calling messages from it and then running your query from that.
Without seeing more of your model schema (ie: where are these relationships defined??), this might not be perfect, but it's a start:
public function lastMessage()
{
return $this->messages() // <-- Notice the ()...this creates a query instead of immediately returning the relationship
->where('recipient_id', $this->id) // Not sure if this is correct, might need to adjust according to how you have defined the tables
->orderBy('created_at', 'desc')
->first();
}
It will query the messages relationship with the chained constraints that are listed. And by returning first() it returns only one record as opposed to a collection.

Laravel 5 Model orderBy?

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()

Categories