In laravel's eloquent ORM, is there a way to define a model's allowed attributes?
By default I can put any attributes into the model's constructor - but then I only get notified about the erroneous attribute names when I actually try to save the model to database.
Example code:
// this works although there is a typo in "lastname"
$user = new \App\User(['firstname' => 'foo', 'lastnam' => 'bar']);
// this errors out with an SQL error
$user->save();
So, is there a way to let Laravel automatically check if there are invalid keys in the request's input data?
If you would like to prevent not only filling not allowed attributes using fill()
method but also directly setting them, like $model->foo = 'bar'
, then you got to override Model::setAttribute()
method.
Best to do it in a custom base Model that extends Eloquent. So in app/Model.php
:
namespace App;
use Exception;
use Illuminate\Database\Eloquent\Model as Eloquent;
class Model extends Eloquent
{
// this should be actually defined in each sub-model
protected $allowed = ['firstname', 'lastname'];
public function setAttribute($key, $value)
{
// this way we can allow some attributes by default
$allowed = array_merge($this->allowed, ['id']);
if (! in_array($key, $allowed)) {
throw new Exception("Not allowed attribute '$key'.");
}
return parent::setAttribute($key, $value);
}
}
Then in the models that should not allow invalid attributes you can extend this base model:
use App\Model;
class User extends Model
I don't believe this can be done natively. I think Laravel is intentionally permissive in that sense, and I personally don't mind having a SQL error instead of an Eloquent one if I make a mistake setting attributes somewhere.
That being said, it's not hard to customize your Models to fail when non-existing attributes are set:
// User.php
protected $fillable = [
'firstname',
'lastname',
];
public function fill(array $attributes)
{
foreach ($attributes as $key => $value) {
if (!in_array($key, $this->getFillable())) {
throw new \Exception("Attribute [{$key}] is not fillable.");
}
}
return parent::fill($attributes);
}
When you're adding attributes like this, Laravel uses the fill()
method which is part of mass assignment feature:
if ($this->isFillable($key)) {
$this->setAttribute($key, $value);
} elseif ($totallyGuarded) {
throw new MassAssignmentException($key);
}
So, to make it work add all allowed values you want to be saved to $fillable
array :
$fillable = ['firstname', 'lastname'];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With