We're having issues using a global scope with a dynamic query parameter. The global scope is based on the manager ID, but $model is empty, and $this refers to the manager scope not the model so $this->id is an undefined property. Is there a way to do something like this:
public function apply(Builder $builder, Model $model)
{
return $builder->where('manager', $model->id); // $this->id
}
I'm assuming that $model
is supposed to be the manager model, but since it is empty and I can't find any documentation on it I'm not entirely sure (if anyone can tell me in a comment I'd appreciate it). This is our global scope method in the Manager model:
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ManagerScope);
}
Since global scopes don't require an explicit method to be applied I thought maybe adding something to the boot might allow for an extra parameter something like:
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ManagerScope($this->id);
}
But this isn't allowed in a static method, which makes sense after I saw the error.
Naturally global scopes are applied automatically and there are no way to pass parameters to them directly.
Therefore you can either stick with a dynamic local scope, which IMO makes more sense,
public function scopeForManager($query, $manager)
{
return $query->where('manager', $manager->id);
}
Document::forManager($manager)->all();
or if the a manager info is available in some kind of global state (i.e. session) you can create some sort of ManagerResolver class
class ManagerScope
{
protected $resolver;
public function __construct(ManagerResolver $resolver)
{
$this->resolver = $resolver
}
public function apply(Builder $builder, Model $model)
{
return $builder->where('manager', $this->resolver->getManagerId());
}
}
and pass an instance of it into your scope
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ManagerScope(new ManagerResolver());
}
Update for Laravel 8.x
You can create a static function inside your model and then use it in a created scope. For example, let's say that you want to create a global search for all tables without creating a search function for each model.
In your scope class do the following:
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class SearchScope implements Scope
{
/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function apply(Builder $builder, Model $model)
{
if(!empty($keyword = \request()->query('q')))
$builder->where($model::searchField(), 'LIKE', '%' . $keyword . '%');
}
}
Then create searchField() function in every model like this:
<?php
namespace Modules\Api\Models;
use Illuminate\Database\Eloquent\Model;
use App\Scopes\SearchScope;
class Product extends Model
{
protected static function searchField(){
return "products.name"; // Name of field to be used in WHERE clause while searching using LIKE operator
}
protected static function booted()
{
static::addGlobalScope(new SearchScope);
}
}
Bravo! Now you can use a dynamic variable in Laravel scope!!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With