Why choose FormRequest authorization instead of Policies/Gates in Controller?

Viewed 214

My question is simple, yet I couldn't find any answer to this question.


I use Policies to authorize CRUD operations.

I use Gates to authorize other non-model related actions.

I perform these authorizations in the Controller files.

...

In the meanwhile, I validate form inputs inside the FormRequest files.


My question is. Why would anyone perform authorization in the FormRequest file? Isn't it better to have it all in the controllers?

BlogPostController code:

class BlogPostController extends Controller
{

    public function __construct(){
        $this->middleware('auth', ['except' => ['index', 'show']]);
    }

    public function index()
    {

        // Okay, I authorize by gate here

        if (\Gate::denies('example-gate-authorization')){
            return redirect()->route('index');
        }


        $posts = BlogPost::with('user')->latest()->paginate(5);
        return view('posts.index', compact("posts"));
    }


    public function create()
    {
        // Okay, I authorize by policy here

        $this->authorize("create", BlogPost::class);

        $post = new BlogPost();

        return view('posts.createOrEdit', compact('post'));
    }

    // etc...
}

BlogPostRequest code:

class BlogPostRequest extends FormRequest
{

    public function authorize()
    {
        
        // BUT why would anyone authorize anything in here ???

        return true;
    }


    public function rules()
    {

        // Yeah the rules are okay here ..

        return [
            'title' => 'required|max:255|unique:posts' . ($this->post ? (',title,' . $this->post->title . ',title') : ''),
            'body' => 'required'
        ];
    }
}

Is there any practical reason when a developer would choose FormRequest authorization over Controller/Policy,Gate authorization?

(Yes, I know one can use Gates in the FormRequest file too)

2 Answers

Encapsulation and reusability are two arguments. Your form request object manages the authorisation and validation in a single place (encapsulation) which can be reused in other places that require the same logic (DRY).

Should your authorisation logic change, you only need change it in a single location.

As an example; consider you have a web controller with methods that require validation and authorisation through gates and policies. Your validation is in a FormRequest and your authorisation is specified in each controller action. Then you decide to extend your app to provide this functionality via an API. You now need to copy the authorisation logic to your API controller methods and remember to keep them in sync if/when changes occur. You also need to test that the authorisation workflow is functioning correctly in multiple places.

If that logic is in a FormRequest, you have a single place for this logic so only one code file to maintain and test (in a perfect world).

Does this mean you must use FormRequest objects? No. Are they helpful? Yes.

There is no difference between this discussion and the discussion around validating in a form request class vs. in the controller. They are both viable approaches, and whatever works best for you in the best solution for you.

Related