Global scopes: https://laravel.com/docs/5.4/eloquent#global-scopes
We often need to make a global scope for example status (0/1) and display items with only status = 1 on the site, and all (status 0/1) in the admin panel.
Unfortunately, now CRUD does not support the standard mechanism for disabling global scopes. It would be cool to add this functionality.
Whats the standard mechanism for disabling global scopes?
@OwenMelbz It is withoutGlobalScopes method. I can remove scopes for list in CRUD:
$this->crud->addClause('withoutGlobalScopes', [MyScope::class]);
But edit and another operation will not work. Because they use:
$this->model->findOrFail($id);
and the like. I can try to implement support for this. But first I want to hear your thoughts. ;)
I use to setup a global scope in the Model
php
use Illuminate\Database\Eloquent\Builder;
....
public static function boot() {
static::addGlobalScope('order', function (Builder $builder) {
$builder->orderBy('active', 'desc')->orderBy('name', 'asc')->orderBy('surname', 'asc');
});
}
And, if I need to exclude it, I can:
php
MyModel::withoutGlobalScope('order')->get();
As it works with the list method, or to populate a select2, never thought of the edit/delete... seems an useful adition, +1 for me
Hmm... Interesting. Haven't used withoutGlobalScopes() until now, thanks for letting me know.
Questions:
public function index()
{
$this->crud->addClause('withoutGlobalScopes', [MyScope::class]);
return parent::index();
}
Just want to understand the issue first.
Thanks, cheers!
I'm currently having the same issue. I have a review system, where reviews can be pending, approved or refused. The Review model has a global scope Approved. This scope makes sure that only the approved reviews are shown.
I have removed the global scope in the ReviewCrudController by putting this in the setup method:
$this->crud->addClause('withoutGlobalScopes', [Approved::class]);
The table view does now show all the reviews, including the pending and refused ones. The issue I'm having now, is that I can't execute the edit and delete actions.
I hope this helps.
Hi @jorenvanhee , thanks for the tip. What's the problem you're now having with the edit/delete actions? What error do they give or how does it not work?
Thanks, cheers!
Guys... just a thought. Can't withoutGlobalScopes() be applied on the crud model? Like... all the time? I think running this in your setup() method should do the trick:
$this->crud->model = $this->crud->model->withoutGlobalScopes();
// might also need this, not sure; it's the same solution as addClause, rephrased
$this->crud->query = $this->crud->query->withoutGlobalScopes();
@jorenvanhee , @votintsev , @MarcosBL , can any of you please confirm/deny that this works?
Just tested, @tabacitu
````php
$this->crud->setModel("App\Models\CRMEventos");
$this->crud->setRoute(config('backpack.base.route_prefix', 'admin')."/crm_eventos");
$this->crud->setEntityNameStrings('Evento', 'Eventos');
$this->crud->with('comercial');
$this->crud->with('accion');
$this->crud->query = $this->crud->query->withoutGlobalScopes();
````
In this example, I have a order by fecha desc global scope on the model

And after adding $this->crud->query = $this->crud->query->withoutGlobalScopes(); :

````php
$this->crud->setModel("App\Models\CRMEventos");
$this->crud->setRoute(config('backpack.base.route_prefix', 'admin')."/crm_eventos");
$this->crud->setEntityNameStrings('Evento', 'Eventos');
$this->crud->with('comercial');
$this->crud->with('accion');
$this->crud->model = $this->crud->model->withoutGlobalScopes();
````
The error:
php
BadMethodCallException in Builder.php line 2443:
Call to undefined method Illuminate\Database\Query\Builder::getKeyName()
Can confirm what @MarcosBL says.
The error is there because $this->crud->model->withoutGlobalScopes() returns an instance of the query builder, and not an eloquent model.
@jorenvanhee @MarcosBL - see https://laravel.com/api/5.4/Illuminate/Database/Eloquent/Builder.html#method_withoutGlobalScopes
@tabacitu - it seems that there are many and varied reasons for people peeking under the hood at the actual model itself; given that Laravel itself is a moving target, I'm wondering if an approved method of getting at the model should be made so that if people need to fiddle with it they can do so, but also should the way to get a model (or the models) need to be changed in Backpack/CRUD things don't break?
On the current CrudPanel it could be implemented like this (as a trait maybe - personally I think CrudPanel is a little trait happy):
/**
* Gets the model.
*
* @return Illuminate\Database\Eloquent\Model $model The model.
*/
public function getModel()
{
return $this->crud->model;
}
This is obviously doing the same thing as just $this->crud->model but just reaching (somewhat blindly) into an object (two actually, if one remembers that $this->crud is itself an object) seems to break data hiding/encapsulation.
Anyone found a solution for this?
I'm also in need of this. I have a site with products that can be enabled or disabled. I want the frontend to only show the enabled items, so the global scope is perfect for this. But I need to manage both enabled and disabled items in the backend, so a way to ignore the global scopes in Backpack would be awesome.
Guys, add this method to your model
public function clearGlobalScopes()
{
static::$globalScopes = [];
}
and then do following in your crud controller
$this->crud->query = $this->crud->query->withoutGlobalScopes();
$this->crud->model->clearGlobalScopes();
Hi guys,
@melihovv 's solution sounds to me like a simple way to solve this. Can you confirm it's working for you?
I'm totally open for Backpack to also offer native support for disabling global scopes (even though I personally have never used this), if someone who needs it submits a working PR. Sounds like using a getter like @lloy0076 suggested here, in combination with @melihovv 's solution should work. Right?
Cheers!
Just a thought here... would it be a problem to replace $this->model->findOrFail($id) with $this->model->newQueryWithoutScopes()->findOrFail($id) everywhere?
This will solve the edit, update, delete and reorder issues.
Besides, permissions are already checked whether you're allowed to edit/update/delete/reorder the entities anyway.
@FrittenKeeZ That would be a problem for the people who wants to use scopes in their query?
@tabacitu the solution provided by @melihovv is working for me, and we have been running live with it for a few months now.
@Frozire The change won't affect the list view, only the ability to retrieve entities without applying scopes. Anyway, it won't be a big problem to actually extract the applied scopes from the list query to the retrieval in edit/update/delete/reorder.
$this->model->withoutGlobalScopes($this->query->removedScopes())->findOrFail($id)
Alternative is to use the query directly $this->query->findOrFail($id).
If I have a global scope and it is applied, I don't want any framework just randomly removing them without me asking it to....
yeah, global scopes should only be disabled when users explicitly ask for it.
Let's see who screams if I close this.
Closing to see who screams 馃檴
Guys, add this method to your model
public function clearGlobalScopes() { static::$globalScopes = []; }and then do following in your crud controller
$this->crud->query = $this->crud->query->withoutGlobalScopes(); $this->crud->model->clearGlobalScopes();
Thank You, 泻褉邪褋邪胁褔懈泻!
Most helpful comment
Guys, add this method to your model
and then do following in your crud controller