The naming convention of controllers favors pluralization of the last
word in the controller’s name, although it is not strictly required
(e.g. ApplicationController
). For example, ClientsController
is
preferable to ClientController
, SiteAdminsController
is
preferable to SiteAdminController
or SitesAdminsController
, and
so on.
NOTE: The controller naming convention differs from the naming convention of models, which are expected to be named in singular form.
With strong parameters, request input parameters can be prevented from being used in Model mass assignments until they have been permitted. This means that you can make a conscious decision about which attributes to permit for mass update. This is a security measure to help prevent accidentally allowing users to update sensitive model attributes, and is an alternative/supplement to guarded attributes, which can sometimes be annoying to deal with in backend, non-user-based coding.
In addition, parameters can be marked as required and will flow through a predefined exception flow that will result in a 400 Bad Request being returned if not all required parameters are passed in.
class PeopleController extends Controller
/**
* This will pass with flying colors as long as there's a person key
* in the parameters, otherwise it'll raise an exception, which will get
* caught by the framework and turned into a 400 Bad Request error.
*/
public function update() {
$person = People::find(request('id'));
$person->updateOrFail($this->personParams());
return redirect()->path($person);
}
private function personParams() {
/**
* Using a private method to encapsulate the permissible parameters
* is just a good pattern since you'll be able to reuse the same
* permit list between store and update. Also, you can specialize
* this method with per-user checking of permissible attributes.
*/
return $this->params()->require('person')->permit(['name', 'age']);
}
}
Calling permit
like:
$params->permit('id');
permits the specified key (id
) for inclusion if it appears in $params
and
it has a permitted scalar value associated. Otherwise, the key is going
to be filtered out, so arrays/hashes, or any other objects cannot be
injected.
The permitted scalar types are string
, int
, float
, bool
,
UploadedFile
, and null
.
To declare that the value in $params
must be an array of permitted
scalar values, map the key to an empty array:
$params->permit(['id' => []]);
Sometimes it is not possible or convenient to declare the valid keys of
a hash parameter or its internal structure. Just map to an instance of AnyStructure
:
$params->permit(['preferences' => new AnyStructure()]);
but be careful because this opens the door to arbitrary input. In this
case, permit
ensures values in the returned structure are permitted
scalars and filters out anything else.
You can also use permit
on nested parameters, like:
$params->permit([
'name',
'emails' => [],
'friends' => [
[
'name',
'family' => ['name'],
'hobbies' => []
]
]
])
This declaration permits the name
, emails
, and friends
attributes. It is expected that emails
will be an array of permitted
scalar values, and that friends
will be an array of resources with
specific attributes: they should have a name
attribute (any
permitted scalar values allowed), a hobbies
attribute as an array of
permitted scalar values, and a family
attribute which is restricted
to having a name
(any permitted scalar values allowed here, too).
You may want to also use the permitted attributes in your create
action. This raises the problem that you can’t use require
on the
root key because, normally, it does not exist when calling create
:
/**
* using `fetch` you can supply a default and use
* the Strong Parameters API from there.
*/
$params->fetch('blog', [])->permit('title', 'author');
The model class trait NestedAttributes
allows you to update and destroy
associated records. This is based on the id
and _destroy
parameters:
// permit id and _destroy
$params->require('author')
->permit(['name', 'books_attributes' => [['title', 'id', '_destroy']]]);
Imagine a scenario where you have parameters representing a product name, and a hash of arbitrary data associated with that product, and you want to permit the product name attribute and also the whole data hash:
private function productParams()
$this->params()->require('product')->permit(['name', 'data': new AnyStructure]);
end
The strong parameter API was designed with the most common use cases in mind. It is not meant as a silver bullet to handle all of your parameter filtering problems. However, you can easily mix the API with your own code to adapt to your situation.