Ambient Technologies

Implementing custom validation rules for model

by Janis Volbergs, June 28h, 2012

Recently, I came across nice article about implementing max-length validation for fields in Models, written by Romans. In his article, he provides nice introduction to creation of new interfaces, implementing them, creating new Field type. However, similar functionallity can be achieved in a bit different way. I will show you how you can do the same stuff using custom controller. Let's see how hard can it be.

Adding controller to the model

Already in my previous article where I published migration notes, I talked about extending your models with extra Controllers. Today, we will look at specific case - adding validation rules for your model fields. I will not extends Field object for that, but rather create a validation controller, which, when attached to model, will add extra functionallity in terms of adding new validation rules. This is just an example to show how flexible the Agile Toolkit is. Obviously, it's up to you to decide which method is more convenient in your case, but having more examples is always good.

Okay, so here is what we will do:

  1. Let's create Controller_Validator
  2. Let's create dummy Model C and attach our Controller_Validator to it
  3. Let's define a sample validation rule

Controller_Validator

Our new controller will allow it's owner to add validation rules for fields, identified by names. Further, we will hook on beforeSave method, and when when that hook is exectued, we will validate fields, against rules as required. Our Validator contorller will be smart. It will allow to have common validators in itself and it will allow custom validators to be present in Models as required.

<?php

class Controller_Validator extends AbstractController {
    private 
$rules = array();
    function 
init(){
        
parent::init();
        
$this->owner->addHook("beforeSave", array($this"validate"));
        
$this->owner->addMethod("addRule", array($this"addRule"));
        
$this->owner->addMethod("raiseError", array($this"raiseError"));
    }
    function 
addRule($obj$field$method$params){
        
$this->rules[$field][] = array($method$params);
    }
    function 
validate($ptr){
        foreach (
$this->rules as $field => $rules){
            foreach (
$rules as $rule){
                list(
$method$params) = $rule;
                
$method "validate" $method;
                if (
method_exists($this->owner$method)){
                    
$ptr $this->owner
                } else if (
method_exists($this$method)){
                    
$ptr $this;
                } else {
                    throw 
$this->exception("Method $method not defined""ValidityCheck");
                }
                
call_user_func_array(
                    array(
$ptr$method),
                    
array_merge(array($field$ptr->get($field)), $params)
                );
            }
        }
        
/* magic */
    
}
    function 
raiseError($obj$field$error){
        throw 
$this->exception($error"ValidityCheck")->setField($field);
    }
}

Now, let's consider Model_C, and let's say we want to limit the length of the name between 5 & 10 chars:

<?php

class Model_C extends Model_Table {
    public 
$table "cc";
    function 
init(){
        
parent::init();
        
$this->add("Controller_Validator");
        
$this->addField("name");
        
$this->addRule("name""Len", array(510));
    }
    function 
validateLen($field$val$min$max){
        
$len mb_strlen($val);
        if (
$len $min || $len $max){
            
$this->raiseError($field"Current len: $len. Should be between $min and $max");
        }
    }
}

As you can see, a few interesting things just happened:
1. $this->dd("Controller_Validator"); this line enhances our Model
2. $this->addRule("name", "Len", array(5, 10)); now, we can define Model-based validation rules
3. function validateLen($field, $val, $min, $max){ we actually implement the validation rule

Obviously, "validateLen" could and should be brought to the Controller_Validator, however, this is just to demonstrate that you can now easily add your own validation rules as required

Final demo

Now, some hands on application. Let's create a basic page

<?php

class page_c extends Page {
    function 
init(){
        
parent::init();
        
$this->add("CRUD")->setModel("C");
    }
}   

which looks like this, when new record is being added:

Conclusion

Agile Toolkit allows you to control your models and behavior in very many ways. You have full power of fields, models, and their behaviour. Of course, hooks and method registration is a bit advanced topic, but it enables you to control every aspect of data and ensure that it corresponds to all the conditions. Always.

I hope this example made you say at least a little "wow" and that it will inspire you to get more involved with this great framework!

As usually, good luck, and drop me a line, if you need more explanation.

P.s. Follow @AmbientTech_lv to get updates about new blog entries about Agile Toolkit

 

home | contact us

© since 2010