assign separate middleware to each method of a resource in laravel - php

I am using Zizaco/entrust laravel package as a ACL Manager for my project.
I know that for limit access to a route group via middlewares and assign a role (or permission) to it, I should do that like this:
Route::group(['prefix' => 'admin', 'middleware' => ['role:admin']], function() {
....
});
But I want to assign separate permission to different routes(methods) of a resource controller.
I know that how can so that for whole resource but I can not implement it for each controller method:
Route::group(['prefix' => 'admin', 'middleware' => ['role:admin']], function() {
Route::resource('/post', ['middleware' => ['permission:manage-posts'], 'uses' => 'PostController']);
});
I want to assing this permission to related method :
'post-create' => public function create ()
'post-edit' => public function edit()
and so on.

You can assign middlewares in your controller's constructor:
class Foo extends Conroller
{
public function __construct() {
$this->middleware('post-create', ['only' => ['create']]);
$this->middleware('post-edit', ['only' => ['edit']]);
}
}

Imagine you have apiResource units-of-measure. You can assign different middlewares to separate endpoints like this:
Route::middleware('role:seller|buyer')->group(function () {
Route::apiResource('units-of-measure', UnitOfMeasureController::class)->only('index');
});
Route::middleware('role:seller')->group(function () {
Route::apiResource('units-of-measure', UnitOfMeasureController::class)->except('index');
});
The index endpoint will be accessible for sellers as well as for buyers. The rest of endpoints are only for sellers.

you can chain the methods, using the only method.
here is an example:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
use Spatie\Permission\Models\Role;
class UserController extends Controller
{
public function __construct()
{
$this->middleware('permission:read-user')->only('index','show');
$this->middleware('permission:edit-user')->only('edit','update');
$this->middleware('permission:delete-user')->only('delete');
$this->middleware('permission:create-user')->only('create','store');
}

Related

Laravel : Overriding route for specific route in voyager

I am trying to override a route for creating a row. (posting, not viewing)
http://lsapp.dev/admin/cpu-speed/create
In web.php
I modified
Route::group(['prefix' => 'admin'], function () {
Voyager::routes();
Route::post('/cpu-speed',['uses' => 'Admin\Mobiles\CPUSpeedController#store', 'as' => 'store']);
});
Also I created Controller
namespace App\Http\Controllers\Admin\Mobiles;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class CPUSpeedController extends Controller
{
public function store(){
return 'hello';
}
public function create(){
return 'create';
}
}
But it throws the following error:
ErrorException (E_ERROR) Route [voyager.cpu-speed.store] not defined.
(View:
/var/www/html/lsapp/vendor/tcg/voyager/resources/views/bread/edit-add.blade.php)
It appears you are only naming it store here:
Route::post('/cpu-speed',['uses' => 'Admin\Mobiles\CPUSpeedController#store', 'as' => 'store']);
It should probably be:
Route::post('/cpu-speed',['uses' => 'Admin\Mobiles\CPUSpeedController#store', 'as' => 'voyager.cpu-speed.store']);
I'm not entirely sure this will work, since it may be interpreted and descend into the Voyager package, rather than just reading your web.php file, but I believe it will do what you like.

Define Laravel 5 route inside subfolder and display it via controller

I have Laravel 5.2.45 app.
I have controller structure like this:
App
Http
Controllers
Admin
AdminController.php
inside AdminController.php I have
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Requests;
class AdminController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('is.admin');
}
public function index()
{
return view('admin.home');
}
}
I have views folder structure like this:
views
admin
home.blade.php
And inside my routes.php I have
Route::get('/admin/home', 'Admin\AdminController#index');
So I'm trying to get that when I type .../admin/home browser displays home.blade.php inside admin folder.
My routes.php:
Route::auth();
Route::get('/', 'FrontController#index');
Route::get('/home', 'FrontController#index');
Route::get('/add_user', 'FrontController#user');
Route::group(['prefix', 'admin', 'namespace' => 'Admin'], function() {
Route::get('home', 'AdminController#index');
});
The prefix is missing in your route definition. Correct it to look like this:
<?php
Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function() {
Route::get('/home', 'AdminController#index');
});
Now, try base_url/admin/home in your browser and it should work.
You can use route groups with the namespace and prefix options.
Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function() {
Route::get('home', 'AdminController#index');
});
Here, the prefix allows you to specify the beginning of a URL that should always be in the routes inside the group. So any routes you put inside that group should start with admin.
The namespace lets you specifiy a folder/namespace for the controllers you reference. So all the controllers must be in the App\Http\Controllers\Admin namespace and the app/Http/Controllers/Admin folder.
You need to drop the leading forward slash so it becomes:
Route::get('admin/home', 'Admin\AdminController#index');

How to choose a Controller in the routes

In Laravel 4.2, I have the following route:
Route::group(array('before' => 'auth'), function() {
Route::post('/account/edit', array(
'as' => 'account-edit',
'uses' => 'UserController#accEdit'
));
});
I have a ClientController and an AdminController for common user and admin, respectively.
Assuming that I know the user type (Auth::getUser()->getType()), how can I replace the UserController with the correct controller without adding extra logic to routes class? Can this be done with filters?
I'm trying to avoid an extra controller between the routes and the final controller.
Actually, it is not necessary to create two user controller. Just use middleware to limit the access rights of clients. By this way, you can keep the original UserController.
You can add IsAdmin.php in the middleware.
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\RedirectResponse;
use Illuminate\Contracts\Auth\Guard;
class IsAdmin {
public function handle($request, Closure $next)
{
if (Auth::getUser()->getType() === 'admin')
{
return $next($request);
}
return new RedirectResponse(url('/'));
}
}
In kernel.php, you need declare your middleware.
protected $routeMiddleware = [
// some other middlewares
'admin' => 'App\Http\Middleware\IsAdmin',
];
Then, add the following statements in public function __construct of the UserController.php
$this->middleware('admin', ['only' => ['OnlyForAdmin1','OnlyForAdmin2']]);
Thus, clients will have no access to the function OnlyForAdmin1 and function OnlyForAdmin2.

Custom urls same controller

Suppose I had a controller that look like this:
AController.php
<?php namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class AController extends Controller {
public function doThis(){...}
public function doThat(){...}
public function doThing(){...}
}
routes.php
Route::get('/doThis', [
'as' => 'acontroller.dothis', 'uses' => 'AController#doThis'
]);
Route::get('/doThis', [
'as' => 'acontroller.dothat', 'uses' => 'AController#doThat'
]);
Route::get('/doThis', [
'as' => 'acontroller.dothing', 'uses' => 'AController#doThing'
]);
Is there a better way than using Route::get()? I want my route to be automatically ControllerName.methodName and the url to be /methodName without having to explicitly use Route::get()
You're looking for an "implicit controller" (docs here).
If you define your route like:
Route::controller('/', 'AController');
All of the routes underneath the specified prefix (first parameter) will get routed to that controller. Laravel then expects the method names to be defined as a combination of the HTTP verb and the route.
So, your controller would be:
class AController extends Controller {
public function getDoThis(){...} // GET to /doThis
public function postDoThat(){...} // POST to /doThat
public function anyDoThing(){...} // any verb to /doThing
}

Laravel Add a filter to resourceful route

I'm using Laravel 4.2
I have a ressourceful route like this:
Route::resource('customers', 'CustomersController');
How can I add a filter, let's say 'auth' filter to all corresponding routes and how to target only some of them, let's say I want only to filter access to the named route 'customers.create'.
You can define a filter in your Controller's constructor:
public function __construct()
{
$this->beforeFilter('auth', ['only' => ['update', 'store']]);
}
If you have many resources you can use route groups:
Route::group(['before'=>'auth'], function () {
Route::resource('customers', 'CustomersController');
// ... another resource ...
});
...and specify beforeFilter in each Controller's constructor.
OR:
Use a simple if statement in routes.php:
if (Auth::check()) {
Route::resource('customers', 'CustomersController');
} else {
Route::resource('customers', 'CustomersController', ['except' => ['update', 'store']]);
}
Create a base controller for resources that use the same filter and extend it:
class AuthorizedController extends BaseController {
// ... constructor with beforeFilter definition ...
}
class CustomersController extends AuthorizedController { ... }

Categories