Servage Magazine

Information about YOUR hosting company – where we give you a clear picture of what we think and do!

Model-based validation with Eloquent

Friday, November 14th, 2014 by Servage

ImageIn some opinions the lack of model-based validation is one of the major deficits with Eloquent models in the Laravel PHP framework. One side argues that it pollutes the core model code by implementing lots of rarely used functionality – which the other side counters with the opposite argument: It’s needed in the core model, because it is commonly used functionality. However, even if agreeing on making validation model-based, the next discussion would be about the implementation. It would therefore be great for the Laravel community to overcome this discussion, and implement a widely accepted model-based validation principle. In the meantime you can be inspired by the implementation below – of not only validation through a base model, but also validation scenarios, to deal with different situations in which a model can be living.

Base Model

Normally you extend the Eloquent class directly, but instead we are going to use an intermediary model to hold the functionality we want to extend Eloquent with. All subsequent models are then going to extend the BaseModel class instead of the Eloquent class.

BaseModel extends Eloquent { ... }
SomeOtherModel extends BaseModel { ... }

Defining validation rules

Since Laravel already provides good validation functions, we are going to reuse the Laravel Validator class to build the model validation. Therefore we need to define the model-rules for each model in the respective model’s class. The rules will be organized in an associative array, where the keys are the scenario names – so you can declare multiple sets of rules, to be used in different scenarios.

protected $rules = array( ... );

Creating a model with a scenario

On top of instantiating a new model instance, you also need to set the current scenario to be used for the validation.

$model = new SomeOtherModel();
$model->setScenario( 'signup' );

Validating and saving the model

You can interact with the model like you normally do when setting and getting attributes. Nothing is validated until the BaseModel’s validate method is fired. You should do that, before you save the model – if you want a validation check. That’s up to your script’s logic.

$model->name = 'John';
if ( $model->validate() ) {
  $model->save();
}

Full BaseModel class

Here is the full example implementation of the BaseModel class, from which the other models can inherit:

class BaseModel extends Eloquent {
    
    protected $rules;
    
    public function getScenarios()
    {
        return array_keys($this->scenarios);
    }

    public function getScenario()
    {
        return $this->scenario;
    }

    public function getScenarioSettings($scenario = null)
    {
        if (is_null($scenario))
        {
            $scenario = $this->scenario;
        }

        if (array_key_exists($scenario, $this->scenarios))
        {
            return $this->scenarios[$scenario];
        }
    }
    
    public function setScenario($name)
    {
        if (array_key_exists($name, $this->scenarios))
        {
            $this->scenario = $name;
        }
    }
    
    public function validate($data = null, $scenario = null)
    {
        if (!is_array($data))
        {
            $data = $this->getAttributes();
        }

        if ($scenario !== false)
        {
            $settings = $this->getScenarioSettings($scenario);
            if (isset($settings['rules']))
            {
                $rules = $settings['rules'];
            }
        }
        else
        {
            $rules = $this->rules;
        }

        if (empty($rules))
        {
            return true;
        }

        $validator = Validator::make($data, $rules);

        if ($validator->fails())
        {
            $this->messages = $validator->messages();
            $this->failed = $validator->failed();
            return false;
        }

        return true;
    }
    
    public function failed()
    {
        return $this->failedRules;
    }

    public function messages()
    {
        return $this->messages;
    }

}

Example Model class

Here is an example declaration of scenario-based rules in a child model:

class SomeOtherModel extends BaseModel {
    
    $rules = array(
    
        'signup' => array( ... ),
        'edit' => array( ... ),
        
    );
    
}

You could take this implementation even further, and introduce more advanced functionality if needed. Some more improvements could include:

  • Setting the scenario via the class constructor on instantiation.
  • Throwing an exception when setting invalid scenarios.
  • Auto-validating on save.

References & more reading

Model-based validation with Eloquent, 4.7 out of 5 based on 3 ratings
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

No comments yet (leave a comment)

You are welcome to initiate a conversation about this blog entry.

Leave a comment

You must be logged in to post a comment.