This is my child controller:
class VolunteersController extends \BaseController
{
public function index()
{
$this->checkForRoles(['admin']);
//list some secret stuff for admin
}
}
In my base controller I did this:
class BaseController extends Controller
{
protected function checkForRoles($roles)
{
foreach ($roles as $role) {
if (!(Auth::user()->hasRole($role))) {
return Redirect::to('/');
}
}
}
}
Now what I expected was that the line return Redirect::to('/');
in BaseController would redirect the user to home page if his role is not admin.
But it does not happen. //list some secret stuff for admin
gets executed in any case.
Edit:
Some people may wonder, why am I not using filters. Well yeah, the desired functionality is of filters but apparently filters do not support array arguments in Laravel yet. And as you can see, I need to pass an array of roles to the function.
Please help.
The redirect will happen only if VolunteersController::index() will return a "Redirect". It does not do so in your code.
It would, if you had
class VolunteersController extends \BaseController
{
public function index()
{
if ($res = $this->checkForRoles(['admin'])) return $res;
//list some secret stuff for admin
}
}
I would move the logic to a filter, which will allow the Redirect
to function properly. This is the kind of thing filters were designed for.
If you need to pass multiple roles to the filter, instead of passing an array to the filter (which Laravel won't allow), use a delimiter like "+" and then explode
the parameter in the filter to simulate passing an array.
For example, your route would be:
Route::get('volunteer', array(
'before' => 'roles:admin+author',
'uses' => 'VolunteersController@index'
));
...and then your filter can easily convert the multiple roles into an array:
Route::filter('roles', function($route, $request, $roles)
{
$roles = explode('+', $roles);
// 'admin+author' becomes ['admin', 'author'];
// continue with your checkForRoles function from above:
foreach ($roles as $role) {
if (!(Auth::user()->hasRole($role))) {
return Redirect::to('/');
}
}
}
Then you can remove the logic from the BaseController.
Alternatively, you can pass multiple parameters to a filter as a comma-delimited list. So if you called your route with 'before' => 'roles:admin,author'
, you could access them in your filter using func_get_args()
:
Route::filter('roles', function($route, $request, $roles)
{
$roles = array_slice(func_get_args(), 2); // remove $route and $request
//...continue as above.