0

I have two issues involving Zend\Form\Annotation\AnnotationBuilder.

First, I want to tell the AnnotationBuilder to create a Zend\Form\Fieldset rather than a Zend\Form\Form (because the docs say it's good practice to use fieldsets for your entities). So my entity class says @Annotation\Type("Fieldset"), and a Fieldset gets instantiated when I invoke createForm() on the AnnotationBuilder -- so far so good. But I have not been able to do get the validators to run against the fieldset elements. As an experiment, I have a controller action doing this:

$em = $this->serviceManager->get('entity-manager');
$builder = new  \Zend\Form\Annotation\AnnotationBuilder($em);
$form = new \Zend\Form\Form('person-form');
$hydrator = new \DoctrineModule\Stdlib\Hydrator\DoctrineObject($em);
$form->setHydrator($hydrator);

$fieldset = $builder->createForm(\Application\Entity\Person::class);
$fieldset->setHydrator($hydrator)
    ->setObject(new \Application\Entity\Person())
    ->setUseAsBaseFieldset(true);
// more about this later....
$element = new \DoctrineModule\Form\Element\ObjectSelect('hat',
    [
        'object_manager' => $em,
        'target_class' => 'Application\Entity\Hat',
        'property' => 'name',
        'label' => 'hat',
        'display_empty_item' => true,        
    ]);
$fieldset->add($element);
$form->add($fieldset);

$filter = $form->getInputFilter();
$filter->add([
        'person' => [
            'name' => 'hat',
            'validators' =>[
                [
                    'name' => 'Zend\Validator\NotEmpty',
                    'options' => [
                        'messages' => [
                            'isEmpty' => 'the "hat" is required'
                        ],
                    ],
                ],
            ],
        ],
    ]);
// so anyway...         
$viewModel = new ViewModel(['form' => $form]);
$request = $this->getRequest();
if ($request->isPost()) { 
    $data = $request->getPost();
    $person = new \Application\Entity\Person();
    $form->bind($person);
    $form->setData($data);
    if (! $form->isValid()) {
            echo "not valid ...messages? ";
            \Zend\Debug\Debug::dump($fieldset->getMessages());
            return $viewModel;
        }
        $em->persist($person);
        $em->flush();
        $this->flashMessenger()->addMessage("congratulations! you inserted an entity.");
        return $this->redirect()->toRoute('home');
    }
    return $viewModel;

}

and what happens when I submit the form is that ìsValid() returns false, I get the generic "value is required and can't be empty" for the "hat" element that I added after the fact, and none of the validators seem to run against the other fields (error messages array is otherwise empty). So, I would like to know the proper way to create a Fieldset as opposed to a Form via annotations and the AnnotationBuilder. Note that when I do all of this with an annotation-created Form rather than Fieldset, it all works fine.

Second, I would like to be able to mix and match elements (and filters and validators) created via annotations with others added on the fly. Why? Well, the idea of having a max length validator for a string living right alongside the Doctrine annotation that specifies the column width makes good sense to me, plus all the other benefits of these annotations -- I know not everyone is crazy about them. So, the "Hat" element in the example below is such an element, i.e., one I want to add after the form has been instantiated and otherwise initialized. And again, that does work with a Form as opposed to a Fieldset. (Actually, I would be glad to add the element via annotation but it doesn't seem possible to do that with exotic form elements whose constructors have dependencies -- question for another day.)

For the record, here is the Entity class in pertinent part

namespace Application\Entity;

use Doctrine\ORM\Mapping as ORM;
use Zend\Form\Annotation;
* @Annotation\Name("person")
* @Annotation\Type("Fieldset")
* //Annotation\Type("Form")
* @ORM\Entity  @ORM\Table(name="people",uniqueConstraints={@ORM\UniqueConstraint(name="hat_email_idx",columns={"email","hat_id"})})
* @ORM\InheritanceType("JOINED")
*
* @ORM\DiscriminatorColumn(name="discr", type="string")
* @ORM\DiscriminatorMap({"person" = "Person", "interpreter"="Interpreter", "judge"="Judge"})
*/



class Person
{
    /**
     * entity id
     * @Annotation\Exclude()
     * @ORM\Id @ORM\GeneratedValue @ORM\Column(type="smallint",options={"unsigned":true})
     */
    protected $id;

    /**
    * the Person's email address.
    * 
    * @ORM\Column(type="string",length=50,nullable=true)
    *
    * @var string
    */
    protected $email;

    /**
    * the Person's last name.
    * 
    * @Annotation\Options({"label":"last name"})
    * @Annotation\Filter({"name":"StringTrim"})
    * @Annotation\Validator({"name":"NotEmpty",
    *  "break_chain_on_failure": true,
    *  "options":{"messages":{"isEmpty":"last name is required"}
    *  }}) 
    * @Annotation\Validator({
    *  "break_chain_on_failure": true,
    *  "name":"Application\Form\Validator\ProperName",
    *  "options" : {"type":"last"}
    * })
    * @Annotation\Validator({"name":"StringLength", "options":{"min":2, "max":50,
    *  "messages":{"stringLengthTooShort":"name must be at least 2 characters long",
    *   "stringLengthTooLong":"name exceeds maximum length of 50 characters"}}})
    * 
    * @ORM\Column(type="string",length=50,nullable=false)
    * @var string
    */
    protected $lastname;

 /**
  *  Everyone must where a hat in this life.
  *  
  *  @ORM\ManyToOne(targetEntity="Hat",fetch="EAGER")
  *  @ORM\JoinColumn(nullable=false)
  *  
  *  @var Hat
  */
    protected $hat;

  // etc etc omitted 

}

Many thanks in advance.

David
  • 815
  • 8
  • 18
  • were you able to solve this? – Dennis Mar 15 '17 at 15:10
  • the first issue: no. the second issue: pretty much. I have a factory that instantiates the form via the annotation builder, then dresses it up with everything else that it needs. Something like this: https://github.com/davidmintz/court-interpreters-office/blob/master/module/InterpretersOffice/src/Form/Factory/AnnotatedEntityFormFactory.php#L67 what I don't like about the solution is that it's convoluted. what I do like is that it works :-) also, I recall seeing somewhere that you can add things like Doctrine object-repository select thingies via annotations, but I forget where/how. – David Mar 15 '17 at 20:39

0 Answers0