Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Jawsh's avatar

Validation requests -- Finding controller parameters?

I am extending the Request class to pass in custom validation rules. My problem with this is, the Request class automatically runs a validation before the controller method is entered, and it doesn't share any arguments.

So lets say I have a method defined like this in my controller, which creates a post in the Board supplied by the router.

public function patchIndex(PostRequest $request, Board $board)

And PostRequest has a rules method like this.

public function rules()
{
    $rules = [
        "post" => "required|passes_word_filter",
    ];
    
    return $rules;
}

In this instance, we have a validation rule that stipulates a post must have no bad language in it. However, the problem rises when we want a SFW and a NSFW board. I can't set "passes_word_filter" if $board->sfw because $board doesn't exist in this context.

public function rules(Board $board)

This also doesn't work. $board is empty.

The ideal solution would be to have an attribute on PostRequest that had the arguments of the controller in it.

What's the best way to accomplish this?

0 likes
32 replies
absiddiqueLive's avatar

@Jawsh would you return true from authorize() function, by default it return false like blow.

public function authorize(){
    return false;
}

change like blow

public function authorize(){
    //you may use any condition if you have
    return true;
}
Jawsh's avatar

@absiddiqueLive I'm afraid that doesn't answer my question at all. I'm asking about how you pass controller parameters into a Request.

absiddiqueLive's avatar

@Jawsh Don,t worry sometime it's happen. Please, up you full code that you done i will try to solve that, if i can ! :)

Jawsh's avatar

@absiddiqueLive I don't know how to better phrase my question. This is the parts that matter.

Currently, I have:
Controller

public function patchIndex(Board $board)
{
    if (!$board->canView())
    {
        return abort(403);
    }
    
    return view("myform");
}

Now, I want:
Controller

public function patchIndex(PostRequest $request, Board $board)
{
    return view("myform");
}

Request

public function authorize(Board $board)
{
    return $board->canView();
}

$board does not exist in Request. I want $board from ::patchIndex into PostRequest $request so that I can use $board in ::authorize.

bestmomo's avatar

@Jawsh If you want Board in request you can create a constructor in your FormRequest and inject Board inside it and set a property to use it.

pmall's avatar

@Jawsh try this :

class PostFormRequest extends Request {

    private $board;

    public function __construct(Board $board)
    {
        $this->board = $board;
    }

    public function rules()
    {
        // $this->board
    }

}

But I thought you can inject it in rules. Strange.

Jawsh's avatar

Not working, unfortunately. It does create a Board but it does not have the attributes as the model supplied by the route.

pmall's avatar
pmall
Best Answer
Level 56

It does create a Board but it does not have the attributes as the model supplied by the route.

What ? I guess you use route - model binding. So use :

class PostFormRequest extends Request {

    public function rules()
    {
        $board = $this->board; // or $this->get('board') or $this->input('board');
    }

}
Jawsh's avatar

@pmall I'm afraid not.

Request

public function __construct(Board $board)
{
    dd($board);
}

Output (Empty #attributes)

Board {#375 ▼
  #table: "boards"
  #primaryKey: "board_uri"
  +incrementing: false
  #fillable: array:5 [▶]
  #settings: null
  #hidden: array:3 [▶]
  #connection: null
  #perPage: 15
  +timestamps: true
  #attributes: []
  #original: []
  #relations: []
  #visible: []
  #appends: []
  #guarded: array:1 [▶]
  #dates: []
  #casts: []
  #touches: []
  #observables: []
  #with: []
  #morphClass: null
  +exists: false
}

Controller

public function patchIndex(BoardConfigRequest $request, Board $board)
{
        dd($board);
}

Output (Set #attributes)

Board {#311 ▼
  #table: "boards"
  #primaryKey: "board_uri"
  +incrementing: false
  #fillable: array:5 [▶]
  #settings: null
  #hidden: array:3 [▶]
  #connection: null
  #perPage: 15
  +timestamps: true
  #attributes: array:8 [▶]
  #original: array:8 [▶]
  #relations: []
  #visible: []
  #appends: []
  #guarded: array:1 [▶]
  #dates: []
  #casts: []
  #touches: []
  #observables: []
  #with: []
  #morphClass: null
  +exists: true
}
pmall's avatar

@Jawsh re-read my post above carefully.

I noticed you can use $this->board in a form request because, as you have set up model binding, you can retrieve it directly as a request parameter.

This is what happen in you pathIndex action, the $board object is not injected, it comes from request parameter.

PS : I really hate route model binding. It just mess with everyone heads.

Jawsh's avatar

@pmall I should have specified I tried both.

public function rules()
{
    dd($this->board);
}
null
pmall's avatar

In your routes, how is named the board parameter ?

Jawsh's avatar

@pmall My routes are very complicated, but the pertinent part looks like this.

Route::group([
    'namespace' => 'Panel',
    'prefix'    => 'cp',
], function()
{
    Route::group([
        'namespace' => 'Boards',
        'prefix'    => 'board',
    ], function()
    {
        Route::controllers([
            '{board}' => 'ConfigController',
        ]);
    });
});

The URL looks like foo.bar/cp/boards/{board}. This opens the configuration panel for that board.

pmall's avatar

And so you use route model binding ? Have you tried with $this->get('board') or $this->input('board') ?

Jawsh's avatar

@pmall Oops, yes, I am.

$this->get('board') in the scope of the Controller returns the board, but $this->get('board') in the context of the Request does not.

Is there a way to just get the controller..?

pmall's avatar

dd($this->all()) in the form request rules method ?

Jawsh's avatar

@pmall

array:6 [▼
  "_method" => "PATCH"
  "_token" => "PAKkjqoqyb9TI97JN6HLTwegTXovrM8c1HPm0Co5"
  "postAttachmentsMax" => "3"
  "postMaxLength" => "2533"
  "postMinLength" => "5"
  "postsPerPage" => "15"
]
pmall's avatar

I've no idea.

What is 'postAttachmentsMax', etc ?

Jawsh's avatar

@pmall That's my config form being pushed to the request.

Do you have a document that would show what I'm trying to do? Maybe I can compare and figure out what's missing.

pmall's avatar

In fact I don't even know what your problem is anymore.

What are you trying to do and what doesn't work ?

Jawsh's avatar

@pmall

I have a URL that looks like this: foo.bar/cp/board/{board}

{board} is a slug that accesses a unique board. In the controller, I can very easily access the board like this:

public function getIndex(Board $board)
{
    dd($board);
}

This will have the model data that is associated with the board that is requested in the URL.

Now, I am building a config panel. These options are not directly related to the model, there is a many-to-many relationship between options and boards. The config form is very complicated, so I am building a FormRequest.

My problem is that the FormRequest has no idea what the Board is, unlike the controller. It also has no idea what the user is. It also has no idea what the controller is. It's like the Request object is completely and totally separated from the controller and there is nothing passed to it by default.

This is great for a complicated form with a fixed set of rules and expected input, but my form isn't that. A form will have different rules depending on what board it is associated to.and who is accessing it.

Because I do not have access to the user, the board, or the controller within my FormRequest, I cannot construct a fully dynamic set of rules as I require.

The only way I've found to get around this is to do this:

trait RequestAcceptsUserAndBoard {
    
    /**
     * Current Board set by controller.
     *
     * @var Board
     */
    protected $board;
    
    /**
     * Current Board set by controller.
     *
     * @var PermissionUser
     */
    protected $user;
    
    /**
     * Returns the request's current board.
     *
     * @return Board
     */
    public function getBoard()
    {
        return $this->board;
    }
    
    /**
     * Returns the request's current user.
     *
     * @return PermissionUser
     */
    public function getUser()
    {
        return $this->user;
    }
    
    /**
     * Sets the request's board.
     *
     * @param  Board  $board
     * @return void
     */
    public function setBoard(Board $board)
    {
        $this->board = $board;
    }
    
    /**
     * Returns the request's user.
     *
     * @param  PermissionUser  $user
     * @return void
     */
    public function setUser(PermissionUser $user)
    {
        $this->user = $user;
    }
    
}
class BoardConfigRequest extends Request {
    
    use RequestAcceptsUserAndBoard;
    
}

and then in my controller

public function patchIndex(BoardConfigRequest $request, Board $board)
{
    // Re-validate the request with new rules specific to the board.
    $request->setBoard($board);
    $request->setUser($this->user);
    $request->validate();
}       
pmall's avatar

Your board should be accessible in the form request. All url parameters are accessible in a form request.

Well, when you dd($this->board) do you have this :

/**
 * Current Board set by controller.
 *
 * @var Board
*/
protected $board;

?

1 like
Jawsh's avatar

@pmall Very nice catch.

Removing that populates $this->board correctly within ::rules. I still need to access the $controller->user though.

pmall's avatar

Removing that populates $this->board correctly within ::rules.

Yes because you got your attribute value (null) instead of firing the underlying form request magic getter.

I still need to access the $controller->user though.

I don't understand. What is $controller->user ?

Jawsh's avatar

@pmall Going out on a limb following your other advice,

public function __construct(ConfigController $controller)
{
    dd($controller);
}

This works.

You're a champion mate.

pmall's avatar

@Jawsh Why do you want to use a controller somewhere ? It is wrong, don't do this. Never instantiate a controller in your code.

What do you want to do here.

Jawsh's avatar

@pmall Every document on the site needs a $user. Even if the client is not signed in, they are given an Anonymous user that implements an interface used by both the User model and the Anonymous class.

If an administrator views the board config, for instance, they would be able to manipulate the slug given to the board.

If the board owner / lesser moderator views the board config, they can edit any other option except the slug.

So, the FormRequest needs the user, which is fetched in the controller, and is typically accessed with $this->user.

If there was some way to put $user in the global namespace or otherwise make it more accessible, this would be ideal.

pmall's avatar

which is fetched in the controller

This is wrong.

I mean, it is wrong to use the controller to fetch it somewhere else.

Use a service class (a bare php class) which encapsulate the logic to retrieve either the current user or the guest user. Then inject it in your controllers and your requests.

Jawsh's avatar

Is there a guide for this I can reference? I'm open to your idea.

Next

Please or to participate in this conversation.