Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do query scopes work in Laravel?

Tags:

I'm watching the Laracasts: Laravel 5.4 from Scratch series, and have come across the concept of query scopes.

In the video, we set up a class like this:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{

    public function scopeIncomplete($query)
    {

        return $query->where('completed', 0);

    }
}

My first question:

Why is a method like: public function scopeIncomplete($query) called like this: App\Task::incomplete() with the :: operator?

Isn't that a non-static method being called statically?

My second question:

Where does $query come from?

From what I can understand this is the "existing" query, but it is called like this: App\Task::incomplete()->where('id', '>', 1)->get();

So I'm not really sure where this variable is coming from.

Maybe it's explained more in depth later but I can't wrap my head around how this works.

like image 369
Timothy Fisher Avatar asked Dec 27 '17 01:12

Timothy Fisher


People also ask

What are query scopes in Laravel?

You can use Laravel scopes to DRY up the code. The scope is just a method that you can use in your model to encapsulate the syntax used to execute a query such as above. Scopes are defined by prefixing the name of a method with scope, as below.

How does Laravel query builder work?

In Laravel the database query builder provides an easy interface to create and run database queries. It can be used to perform all the database operations in your application, from basic DB Connection, CRUD, Aggregates, etc. and it works on all supported database systems like a champ.

What is local and global scope in Laravel?

Global Scope is a very important concept of laravel 6. using Global Scope you can reuse same eloquent condition in laravel application. i also written tutorial of how to create local scope in laravel 6. Local scope it only for single model. But you define global scope then you can use with all model.

What are global scopes in Laravel?

Laravel global scopes allow us to add constraints to all queries for a given model. You know that Laravel's own soft delete functionality utilizes global scopes to only pull "non-deleted" models from the database.


1 Answers

This is pretty broad since it is covering two large topics on Eloquent.


The first refers to Eloquent's use of the facade pattern to pass static calls to non-static methods.

The facade pattern utilizes the IoC container to pass a method call to a bound, or new, instance of a class.

The facade pattern makes use of overloading and the magic method __callStatic.


The second question refers to Eloquent's overloading that passes the unregistered method calls to a query builder object (specifically \Illuminate\Database\Eloquent\Builder). This is what allows for where() and various other Query Builder methods to be called on the Eloquent model itself. Inside the Model class, you can see:

/**
 * Handle dynamic method calls into the model.
 *
 * @param  string  $method
 * @param  array  $parameters
 * @return mixed
 */
public function __call($method, $parameters)
{
    if (in_array($method, ['increment', 'decrement'])) {
        return $this->$method(...$parameters);
    }

    return $this->newQuery()->$method(...$parameters);
}

Since where() or incomplete() are not defined in Model, they'll be passed to the Builder class, which is returned by Model::newQuery().

Inside the Builder __call method, you have:

    if (method_exists($this->model, $scope = 'scope'.ucfirst($method))) {
        return $this->callScope([$this->model, $scope], $parameters);
    }

So this is checking for the scopes defined inside the model and passing the $parameters which includes this Builder instance.

So in summary, the call for Model::incomplete() will go:

Model __call() -> Builder __call() -> Model scopeIncomplete(Builder $builder)

like image 73
Devon Avatar answered Sep 21 '22 13:09

Devon