Zend_Db_Table
is good and all, but if you want a real-life model you need to work from scratch.Which is how it should be, really.
The model is the base for your application. It should have all the so called "business rules", and this includes, of course, validation. Now, ZF has some pretty neat validation classes that you can use. The problem is how to write the code only once for the model and for the forms (view).
I've asked this question and got one answer, and while it was a good option it didn't exactly suit my needs, so I'm proposing another solution here.
When you create a Zend_Form, you have a couple of ways of adding elements to it. One of them is to call, from the form's
init
method, the addElement
method, and pass it an array of options that contain everything about the element, like this:$username = $this->addElement('text', 'username', array(
'validators' => array(
'Alpha',
array('StringLength', false, array(3, 20)),
),
'label' => 'Username',
));
This is all good, but how can you share those validators with your User model? Well, the idea is to create an Entity class from which almost all the model inherits, which works like this:
abstract class Entity
{
protected $_data = array();
protected static $_validators = array();
public function __set($name, $value)
{
// process validators, if any
if (array_key_exists($name, self::$_validators))
{
foreach (self::$_validators[$name] as $v)
{
if (is_string($v))
$v = array($v, NULL, NULL);
if (!Zend_Validate::is($value, $v[0], $v[2]))
throw new Exception('Invalid input');
}
}
$this->_data[$name] = $value;
}
public function __get($name)
{
return $this->_data[$name];
}
}
You can see we've overriden the
__set
and __get
methods so we can access the $_data
array directly. This allows for very clean code later, instead of writing a bunch of setters and getters which is tedious and boring. So, the User class would be something like this:class User extends Entity
{
protected $_data = array('id', 'username');
protected static $_validators = array(
'username' => array(
'Alpha',
array('StringLength', false, array(3, 20)),
),
);
}
This way, when you have a
$user
object, you can simply set its attributes and validation will happen magically. So, what about the form? You can easily get the validators array with a public function in Entity
:abstract class Entity
{
...
public function getValidators($name)
{
return array_key_exists($name, self::$_validators)
? self::$_validators
: array();
}
}
And, finally, in your form's init function:
$username = $this->addElement('text', 'username', array(
'validators' => User::getValidators('username'),
'label' => 'Username',
));
Now you can change the validators in one place, and your code looks clean and is maintainable.
Of course, you can apply the same idea to Zend Filters, using the
Zend_Filter::filterStatic
function. Filtering would happen before validation, of course, using a similar foreach
loop.
thank you very much, i mean!
ReplyDelete