问题
This episode from Voice of the ElePHPant, starts talking about Zend_Form
and how Zend\Form
will be in Zend Framework 2 around 22:00.
Filtering and validation is attached to models rather than being bound to the form, which allow having business rules (validation and filtering) at model level.
I'm developing with Zend Framework 1.11 and my models are Doctrine 2.2 entities: how can i attach filters and validation chains to my entities?
I'd like validation of entities with @LifecycleCallbacks
or to attach filtering and validation to the entities themselves. That way, no matter from where data comes (either from a web form context or from a web service or even a command line context), I can validate my data before it is flushed to the database.
Any help and code example will be appreciated. Thank you!
回答1:
From what I understand of the ZF2 Forms RFC http://framework.zend.com/wiki/display/ZFDEV2/RFC+-+Forms you'll be able to annotate your models / Entities by declaring Filter / Validate annotations on your properties.
You'd then have to bind your model to your form object, and the form will read and apply any relative annotations to itself. One problem I see with this implementation is that there is still no real seperation of validation / filtering logic as these definitions are encapsulated within your form object.
What would be nicer (and i've no idea if this is in the pipeline or not) would be for the form object to call validation routines on your model. Of course It may be possibly to simulate what the Form component does within your model (by reading the annotations) and apply it locally (in ZF2). This component is in development at the moment so i'd definately be interested in having a play when its nearer completion.
Anyway, for ZF 1.11 (and i've used this implementation myself) you could define validation routines within your model and any error messages generated by $model->validate() can be injected into the Zend Form error stack.
// element
$form->getElement('my_element')->addErrors($model->getErrorMessages());
// form
$form->addErrors($model->getErrorMessages());
So you'd end up with an implementation along the lines of;
$form = new My_Form();
if ($this->_request->_isPost())
{
$data = $this->_request->getPost();
$model = new \Entities\MyModel();
$model->populate($data);
if (!$model->isValid())
{
$form->addErrors($model->getErrorMessages());
}
if ($form->isValid())
{
// continue to save the model etc...
}
}
回答2:
- My approach is as follows:
a) Have validation client side (web forms) and in the models so that if there is a failure at the web client side validation, or if additional client types are added.
b) Validation rules in the model can also be unit tested which is great for ensuring that the rules workvalidation Also the mode
I am not using Zend_Form, since I develop all the forms by hand and add client side validation using the JQuery validation plugin (http://bassistance.de/jquery-plugins/jquery-plugin-validation/)
All validation on the client side, I also implemented in the Doctrine 2 Models using lifecycle call backs to a preInsert and preUpdate method.
However I did not use the Zend_Validate classes as I found them too verbose, so I went for the Symfony Validation classes which could be configured using annotations like my Doctrine 2 model mappings. More details here http://ssmusoke.wordpress.com/2012/03/04/doctrine-2-day-2-model-validation-using-symfony-validator-service-in-zend-framework/
回答3:
This is tricky, but if you want to build something similar with Zend Framework 1.X you will probably have to extend Zend_Form
.
You could that way build a class that accepts the EntityManager
(or a generic Doctrine\Common\Persistence\ObjectManager
as a dependency along with an entity.
You could then either analyze the metadata associated with your entity or define a set of fields that have to be checked against that entity. Generally, what you do is interacting with Doctrine\Common\Persistence\Mapping\ClassMetadata
instances like following in your constructor:
// in class Your\Form\EntityDriven
// $this->em is the EntityManager passed in
// $this->entity is the Entity object passed to the constructor
$class = $this->em->getClassMetadata(get_class($this->entity));
foreach ($class->getFieldNames() as $fieldName) {
// Add fieldst to the form based by their eventual @Column(type="...")
// Eventually, you could use your own AnnotationDriver to get more
// constraints as Symfony 2 does
}
That should actually work. The validators will be attached to the form instance though.
To persist the form you could then just override the persistData
public method as following:
public function persistData()
{
$this->em->persist($this->entity);
$this->em->flush($this->entity);
}
I wouldn't put validation within lifecycle events like @postPersist
or @preUpdate
, as the only way to prevent persistence in those cases is to throw an exception (except if you use external listeners, but that's even more complex). You would end up with a closed EntityManager
.
If you are interested in the concepts applied in Zend Framework 2, the new Zend\Form (see diff) component uses hydrators to assign values to models, so it doesn't interact directly with them, but instead can use a logic to discover setters/getters or public properties (just as an example). Input filtering has been moved to Zend\InputFilter
as a new component, as it should be used also without forms (what you want to do). Validation was already decoupled, but generally, hydrator shouldn't be executed when data isn't valid. So now you should be able to write a EntityHydrator
and EntityValidator
. If you are willing to contribute, please do a Pull Request on DoctrineModule :)
回答4:
First, I want to thank you all for your answers, and I promise that I will give a try to your solutions and see what is fit for me. Second, I find this: http://www.spiffyjr.me/2011/07/15/more-doctrine-2-and-zend-framework-integration-goodies/ and ofcourse the acompany github from that article, https://github.com/SpiffyJr/Spiffy which looks like the solution to my question, but I don't know if it's stable for production or if it will be improve/developed further, but with next occasion I will try that also. And I guess another answer to my question may be using the symfony validator in zend framework 1.X with doctrine 2
来源:https://stackoverflow.com/questions/10195188/attache-zend-filters-and-validation-chains-to-models-doctrine-entities