What is the meaning of Eloquent's Model::query()? - laravel

Can anyone please explain in detail what Eloquent's Model::query() means?

Any time you're querying a Model in Eloquent, you're using the Eloquent Query Builder. Eloquent models pass calls to the query builder using magic methods (__call, __callStatic). Model::query() returns an instance of this query builder.
Therefore, since where() and other query calls are passed to the query builder:
Model::where()->get();
Is the same as:
Model::query()->where()->get();
Where I've found myself using Model::query() in the past is when I need to instantiate a query and then build up conditions based on request variables.
$query = Model::query();
if ($request->color) {
$query->where('color', $request->color);
}

Related

Laravel different use of where clause

I want to ask about some feature in Laravel, I'm working with some old code written by someone else and I want to understand why it is written this way:
$users = Users::all();
$results = $users->where('age', '>','30')->get();
My question is how can 'where' clause be used with the '$users' variable? This works fine and no error is given and it returns the required results. But as far as i know, 'where' clause can be used like:
Classname::where()->get()
Does the User model implements some feature or use something to be able to call 'where' clause this way? When i try to do the same but with a new model i'm creating I get
"Type error: Too few arguments to function Illuminate\\Support\\Collection::get()
How can 'where' clause be used with the '$users' variable?
The where clause can be used because the all() method returns a Collection, and the where() and get() methods are available on the Collection class.
Does the User model implements some feature or use something to be able to call 'where' clause this way?
Each Eloquent model serves as a query builder which will make you able to add constraints and receive the results with the get() method afterwards.
// Collection::get() is diferent with QueryBuilder::get()
$builder = Users::query(); // you got QueryBuilder object
$builder->where('age', '>','30'); // you got QueryBuilder object
$list = $builder->get(); // you got Collection object
$list->where('age', '>','30'); // you got Collection object
// Collection object has 'get', but it require argument.
// QueryBuilder object has 'get' too, but do not require argument.

Why does groupBy() work but Count() does not in laravel eloquent model function?

I need to get counts of all the records based on belongsToMany relationship. normally I can use groupBy() in a function inside the model. but if I use count() or withCount() inside a model function, i get the error as followed:
function code:
public function TaskCount(){
return $this->belongsToMany(User::class)->count();
}
Error message:
Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function addEagerConstraints() on int in file /Users/dragonar/Dev/iyw/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php on line 560
If I do the following...
public function TaskCount(){
return $this->belongsToMany(User::class)->Count();
}
//expected record is 4(int)
//output is 4(array) user records.
...it gives me data but like 4 records of the user instead of a number 4. The user data is useless. The only thing needed is totalCount for those records.
Relationship methods have to return Relation type objects. You are returning the result of a query, count() returns a number not the Relation object / Builder. Remove the count from that statement you are returning. Renamed the relationship tasks here.
public function tasks()
{
return $this->belongsToMany(User::class);
// this returns a Relation type object a BelongsToMany object
}
Where you need to use that relationship you can then use count:
$something->tasks()->count();
Or you can load the count of the relationship using loadCount:
$something->loadCount('tasks');
$something->tasks_count;
Or via eager loading for a collection:
$results = Something::withCount('tasks')->get();
foreach ($results as $model) {
echo $model->tasks_count;
}
If you really wanted to you could create an accessor to get the count as well, you just may want to avoid the N+1 issue by preloading the relationship and using the dynamic property to access it in the accessor.
These relation objects are Builders. When you called groupBy on it previously that is returning the Builder, it isn't executing the query. You can add where conditions and order by statements because they are just building the query, not executing it, they return the builder you are calling the method on.
Laravel 6.x Docs - Eloquent - Relationships - Counting Related Models withCount loadCount
Why not use: Task::all()->count(); ?
you can use the withCount method while calling relation like this
User::withCount('images')->get();
You can add get the data and just count it.
public function TaskCount(){
return $this->belongsToMany(User::class)->get()->count();
}
You can call it like
$taskCount = $task->TaskCount();

Don't paginate the results

The following is the query I am using to get the results from the database. As you can see it has a chain paginate. I don't want my results to be paginated.
return DB::table('example')->where('status', '1')->orderBy('name', 'desc')->paginate(50);
When I remove the method paginate.
return DB::table('example')->where('status', '1')->orderBy('name', 'desc');
I get the following error message.
Object of class Illuminate\Database\Query\Builder could not be
converted to string
How can I do that?
Paginate is one of several methods that execute the query. When you remove it you still have an unexecuted query builder. To execute the query without paginating simply use get()
return DB::table('example')->where('status', '1')->orderBy('name', 'desc')->get();

Eloquent find() with joins and eager loading

I want to retrieve one record via the time-tested method of this URL:
public/api/laptop/1
hitting this route:
Route::get('laptop/{id}', 'LaptopController#getLaptop');
then this controller method:
$laptop = Laptop::find($id)->addJoins()->selectListCols()->with('earmarks', 'movements')->get();
return $laptop;
Problem is this doesn't work (it returns every record). To make it work I have to do this:
$laptop = Laptop::where('laptops.id', $id)->addJoins()->selectListCols()->with('earmarks', 'movements')->get();
return $laptop;
But I'm just wondering why find() doesn't work? earmarks and movements are Many-To-One models, by the way.
find() is just a shortcut for where()->first() so it will return an object and Query Builder methods will not work with it:
User::find(1); // Will return User object with ID = 1.
That's why you need to use where(), which returns Query Builder object, so you can use with() and other builder methods to build your query.

laravel query builder, optional search parameters

Laravel newbie looking for guidance. Can anyone please show me the best way to add optional posted search parameters to the following Eloquent query and return all related data and paginated? The optional search parameters are the foreign keys; country_id, season_id and parameter_id.
$dataitems = Dataitem::orderBy('name')->with('country')->with('season')->with('parameter')->paginate(10);
I am reading the docs and have seen the fluent query builder I'm just struggling to recreate this nicely paginated query.
Many thanks.
I am not sure if I understand what you want. But i would do something like this :
Create your base eloquent query :
$query = Dataitem::orderBy('name');
If you have a specific parameter, add the condition to you existant query.
You can repeat this if block for all your optional parameters.
if (Input::has('country_id'))
{
$query->whereHas('country', function($q){
$q->where('id', '=' ,Input::get('country_id'));
});
}
When you're done, paginate:
$query->paginate(10);

Resources