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.
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:
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(5, 10));
}
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
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:
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.
© since 2010