3
votes

When working with other frameworks, or pure-PHP, I protect my model properties. I then create public getters and setters where required, and proxy to them using __get() and __set(). This helps me sleep at night.

Recently I started using Laravel and I am surprised at how 'unprotected' the Eloquent models are. I understand that I can use the $guarded and $fillable properties to control mass assignment, but that still leaves a lot of room for accidental access.

For example, my model has a status property. It has a default value set on model creation, and should only be modified when $model->activate() or $model->deactivate() is called. But by default, Laravel allows developers to modify it directly. As far as I can see, the only way to prevent this is to create a setter, and throw an exception if it is called.

Am I missing something? Perhaps I just need to relax? What's the best way to build Eloquent models that are secure by default?

3

3 Answers

1
votes

You can override __get and __set method. You need to define an array protectedProperties and a boolean variable protectedChecks so you can control the model fields.

protected $protectedChecks = true;

protected $protectedProperties = [ 'status' ];

protected $fillable = ['status'];

public function __get($key)
{
    return (in_array($key, $this->fillable) && !in_array($key, $this->protectedProperties)) ? $this->attributes[$key] : null;
}

public function __set($key, $value)
{
    if(!$this->protectedChecks || !in_array($key, $this->protectedProperties))
            return parent::__set($key, $value);
        trigger_error('Protected Field');
}

public function activate()
{
    $this->protectedChecks = false;
    $this->status = 1;
    $this->save(); // this is optional if you want to save the model immediately
    $this->protectedChecks = true;
}

If you want to use every model you should write something like above in BaseModel.

0
votes

You may try:

<?php

class User extends Eloquent {

     protected $hidden = array('password', 'token');

}
0
votes

For what i see you probabely coming from symfony or other system that uses Mapping as a base to deal with database layer. Forget what you have done there as Eloquent uses Active Records an is different. Best way is this: Eloquent: Accessors & Mutators Alo check in laracast there is explanation how to do it in old php fashion way using absolute properties.