2008年8月14日星期四

Re: [fw-mvc] Forms rant - Zend_Form critique. Was: Model Validation

-- Adam Jensen <jazzslider@gmail.com> wrote
(on Thursday, 14 August 2008, 03:41 PM -0500):
> On Thu, Aug 14, 2008 at 3:20 PM, Matthew Weier O'Phinney
> <matthew@zend.com> wrote:
> <snip>
> > There's absolutely nothing preventing you from creating elements called
> > "email" or "search". Zend_Form allows this. This is also in fact why
> > decorators are available -- so that you can choose the final
> > representation to suit your given application needs. Model an element
> > however you want, filter and validate and render it however you want --
> > that is the design.
> >
> > As for being able to validate the data without the form object, this is
> > possible -- you can use other strategies, such as creating your own
> > validation chain with Zend_Validate, or using Zend_Filter_Input.
>
> Personally I've always found Zend_Form very convenient; it's a little
> tricky trying to fit it into just a single part of the MVC pattern,
> but it's not a perfect world :)
>
> My original question, though, was about how to take advantage of
> Zend_Form's validation skills without having to duplicate the more
> fine-tuned semantic validation rules already defined in an existing
> domain model. Especially when the domain model has access to things
> that the form class doesn't (and/or shouldn't).
>
> You had mentioned that you were experimenting with attaching your
> Zend_Forms to your models to assist in the model's internal validation
> procedures...how did you go about this? Is the attached Zend_Form
> object publicly accessible or mutatable from outside of the model? If
> so, what happens when you call setValue() on one of its elements? Is
> the associated model property simultaneously modified? Or do you use
> the form as the model's internal data storage? If so, how do you keep
> yourself from just using the form as the domain model (which I assume
> would be just as problematic as using a database row as a domain
> model)?

I use it as the input filter for my data, and also have an accessor for
retrieving it. So, as an example:

class Paste
{
protected $_form;

protected $_table;

public function add(array $data)
{
$form = $this->getForm();

$belongTo = $form->getElementsBelongTo();
if (!empty($belongTo) && array_key_exists($belongTo, $data)) {
$data = $data[$belongTo];
}

if (!$form->isValid($data)) {
return false;
}

$values = $form->getValues();
if (!empty($belongTo)) {
$values = $values[$belongTo];
}

return $this->_getTable()->insert($values);
}

public function getForm()
{
if (null === $this->_form) {
require_once dirname(__FILE__) . '/Paste/Form.php';
$this->_form = new Paste_Form();
}
return $this->_form;
}

protected function _getTable()
{
if (null === $this->_table) {
$this->_table = new Paste_Table();
}
return $this->_table;
}

// ...
}

So, the idea is basically that within the model, the "form" acts as an
input filter -- you pass data through it, and it checks to see if it's
valid (and performs some filtering/sanitization of it via the filter
chains). In my controller, I can then fetch the form from the model, and
manipulate the decorators and/or metadata before rendering:

$form = $model->getForm();
$form->setAction('/paste/save')
->setMethod('post')
->setDecorators(array( // only if you need to...
// ...
));

And instead of validating the form in the controller, you try and save
the data on the model:

if (false === ($id = $model->add($request->getPost()))) {
// failed validation; errors with insertion result in exception
}

The criticism I've heard from some about this technique is that they
feel this creates too much overhead -- a lot of unused objects are
created for each element with this approach (decorators, basically).
However, this is not true anymore; if you are using the plugin system to
define your decorators, then the actual decorators are not instantiated
until rendering time (they are now lazy-loaded) -- which never happens
with successful validation.

--
Matthew Weier O'Phinney
Software Architect | matthew@zend.com
Zend Framework | http://framework.zend.com/

没有评论: