Closed
Description
- Laravel Version: 5.4.23
- PHP Version: 7.1
- Database Driver & Version: MariaDB 10.1.21
Description:
Let's say we have products which can be soft-deleted.
Normal users can manipulate only existing products, but users with elevated privileges can manipulate also deleted ones. Adding a global scope which removes SoftDeletingScope
under some condition does not work - the SoftDeletingScope
is removed but is also applied right after.
Steps To Reproduce:
Product:
class Product extends Model
{
use SoftDeletes;
protected static function boot()
{
static::addGlobalScope(function(Builder $query) {
if(true/* some condition here */) {
$query->withoutGlobalScope(SoftDeletingScope::class);
}
});
parent::boot();
}
}
In eg. a controller:
\DB::listen(function($query) {
dump($query->sql);
});
Product::get();
You'll see deleted_at is null
Possible fix:
Before applying a scope, check if it hasn't been removed from the list.
Illuminate\Database\Eloquent\Builder::applyScopes
public function applyScopes()
{
if (! $this->scopes) {
return $this;
}
$builder = clone $this;
foreach ($builder->scopes as $identifier => $scope) {
+ if(!isset($builder->scopes[$identifier])) {
+ continue;
+ }
$builder->callScope(function (Builder $builder) use ($scope) {
// If the scope is a Closure we will just go ahead and call the scope with the
// builder instance. The "callScope" method will properly group the clauses
// that are added to this query so "where" clauses maintain proper logic.
if ($scope instanceof Closure) {
$scope($builder);
}
// If the scope is a scope object, we will call the apply method on this scope
// passing in the builder and the model instance. After we run all of these
// scopes we will return back the builder instance to the outside caller.
if ($scope instanceof Scope) {
$scope->apply($builder, $this->getModel());
}
});
}
return $builder;
}
Metadata
Metadata
Assignees
Labels
No labels