Laravel: how to invalidate an update if an unknown field is passed

Viewed 713

I have a custom validator:

    $validator = Validator::make($request->all(), [
        'name' => 'sometimes|unique:stock.containers|max:255',
    ]);

I would like to throw an error if I do:

 PUT:localhost/my/model?description=foobar

Because I only want to accept name in this case. Then I would ensure that my $validator->valid() only contain accepted fields.

Here is my Controller:

class ContainerController extends Controller
{
    public function update($id, Request $request) {
        $container = Container::find($id);

        $rules = ['name' => 'max:255'];

        $validator = Validator::make($request->all(), $rules);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);  //i'm not getting any
        }

        $container->update($validator->valid());
    }
}

And with the above request, I reach the $container->update. I would like to restrict the field to those mentioned in my rules.

3 Answers

What you can do is make a type of Request which filters out the parameters that you do not want, so you can pass it into your controller like: private function myfunction(MyCustomRequest $request), so by the time it reaches your validator, the invalid parameters have already been removed.

In your MyCustomRequest you can have a list of valid parameters, like so:

 $validParameters = ["name"]; // add as many as you need

So you want to now check what is in the request, which you can see using $request->all(). You can iterate through your valid parameters and only pass back the request values that match your custom list.

 $requestData = $request->all();

 $goodRequestData = [];

 foreach ($validParameters as $validParameter) {
      if (array_key_exists($validParameter, $requestData) {
           $goodRequestData[] = $requestData[$validParameter];
      }
 }

 return $goodRequestData;

You can read more about custom requests in the Laravel docs here: https://laravel.com/docs/5.8/validation#creating-form-requests

You can use the built-in validate method of the controller instead of making a new instance of Validator.

public function update($id, Request $request) {
    $valid = $this->validate($request, [
        'name' => 'max:255',
    ]);

    dd($valid);
}

So even if someone submits other params that are not included in the rules, it will not be included.

In our case, if you do the curl request as mentioned, $valid would return an empty array.

And then you could check if the array is empty or not:

if (empty($valid)) {
    // Do what you want
}

Side Note

I noticed you are using Container::find($id); but you could also use the built-in model binding in your routes file:

Route::put('your-path/{container}', 'ContainerController@update');

Instead of

Route::put('your-path/{id}', 'ContainerController@update');

Which would then allow this in your controller:

public function update(Container $container, Request $request)
{
    // $container would be the Container instance already
}

Update

If you still want to make a new Validator instance, you can do it like this:

$validator = \Validator::make($request->all(), $rules);


if ($validator->fails()) {
    // ...
}

if (! $valid = $validator->validated()) {
    // Nothing has been validated
}

Basically you should use $validator->validated() instead of $validator->valid() to retrieve the fields only from your rules.

You can simply use the ->only() method:

class ContainerController extends Controller
{
    public function update($id, Request $request) {
        $container = Container::find($id);

        $rules = ['name' => 'max:255'];

        $validator = Validator::make($request->all(), $rules);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);  //i'm not getting any
        }

        $container->update($request->only(['name']));
    }
}

From the docs:

The only method returns all of the key / value pairs that you request; however, it will not return key / value pairs that are not present on the request.

Related