How to make doctrine and ZF2 form annotations work together

doctrine-orm, php, zend-framework2

Solution

Solved it!

It's necessary to register autoload namespace, since Doctrine uses its own autoload mechanism. I needed to make use of AnnnotationRegistry and its registerAutoloadNamespace method. It accepts the namespace containing annotations (Zend\Form\Annotation) and the base directory of the root namespace (in my case C:\Program Files\Zend\Apache2\htdocs\CommunicationApp\vendor\ZF2\library), as its parameters. More information here: Doctrine Annotations

My Entity now looks like this (and works with both Doctrine and Zend Form annotations):

namespace Users\Entity;

use Doctrine\ORM\Mapping as ORM;
use Zend\Form\Annotation;

use Doctrine\Common\Annotations\AnnotationRegistry;
$pathToZF2Library = __DIR__.'/../../../../../vendor/ZF2/library/';
AnnotationRegistry::registerAutoloadNamespace('Zend\Form\Annotation', $pathToZF2Library);

/** 
* @ORM\Entity
* @ORM\Table(name="users")
* @Annotation\Name("Users") 
*/
class User {

    /** 
    * @ORM\Id @ORM\Column(type="integer")
    * @ORM\GeneratedValue
    * @Annotation\Type("Zend\Form\Element\Hidden")
    */
    protected $id;

    /** 
    * @ORM\Column(type="string")
    * @Annotation\Type("Zend\Form\Element\Text")
    * @Annotation\Filter({"name":"StripTags"})
    * @Annotation\Filter({"name":"StringTrim"})
    * @Annotation\Validator({"name":"Alnum", "options": {"allowWhiteSpace":"true"}})
    * @Annotation\Validator({"name":"StringLength", "options": {"min":"2", "max":"25"}})
    * @Annotation\Options({"label":"Username: "})
    */
    protected $username;

    /** 
    * @ORM\Column(type="string")
    * @Annotation\Type("Zend\Form\Element\Email")
    * @Annotation\Filter({"name":"StripTags"})
    * @Annotation\Filter({"name":"StringTrim"})
    * @Annotation\Validator({"name":"EmailAddress", "options": {"domain":"true"}})
    * @Annotation\Options({"label":"Email: "})
    */
    protected $email;

    /** 
    * @ORM\Column(type="string")
    * @Annotation\Type("Zend\Form\Element\Password")
    * @Annotation\Filter({"name":"StripTags"})
    * @Annotation\Filter({"name":"StringTrim"})
    * @Annotation\Options({"label":"Password: "})
    */
    protected $password;

    public function __construct() {
    }

    public function setId($id) {
        $this->id = $id;
    }

    public function getId() {
        return $this->id;
    }

    public function setUsername($username) {
        $this->username = $username;
    }

    public function getUsername() {
        return $this->username;
    }

    public function setEmail($email) {
        $this->email = $email;
    }

    public function getEmail() {
        return $this->email;
    }

    public function setPassword($password) {
        $this->password = $password;
    }

    public function getPassword() {
        return $this->password;
    }
}

Problem

I am trying to make Doctrine annotations work together with ZF2 Form annotations. My controller looks like this: ``` namespace Users\Controller; use Zend\Mvc\Controller\AbstractActionController; use Zend\View\Model\ViewModel; //Doctrine Stuff use Doctrine\ORM\Tools\Setup; use Doctrine\ORM\EntityManager; use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator; use DoctrineORMModule\Form\Annotation\AnnotationBuilder; class IndexController extends AbstractActionController { private $entityManager; public function getEntityManager() { if (!$this->entityManager) { $paths = array ( realpath ( dirname ( __FILE__ ) . '/../Entity' ) ); $isDevMode = true; // the connection configuration $dbParams = array ( 'driver' => 'pdo_mysql', 'user' => 'root', 'password' => 'my_password', 'dbname' => 'commapp' ); $config = Setup::createAnnotationMetadataConfiguration ( $paths, $isDevMode, null, null, false ); $this->entityManager = EntityManager::create ( $dbParams, $config ); } return $this->entityManager; } public function updateAction() { $entityManager = $this->getEntityManager (); $repository = $entityManager->getRepository ( 'Users\Entity\User' ); $id = $this->params ()->fromRoute ( 'id' ); $user = $repository->findOneBy (array('id' => $id)); $builder = new AnnotationBuilder ( $entityManager ); $form = $builder->createForm ( $user ); $form->setHydrator ( new DoctrineHydrator ( $entityManager, 'Users\Entity\User' ) ); $form->bind ( $user ); $send = new Element ( 'send' ); $send->setValue ( 'Create' ); // submit $send->setAttributes ( array ('type' => 'submit' ) ); $form->add ( $send ); $view = new ViewModel (); $view->setVariable ( 'form', $form ); $view->setVariable ( 'id', $id ); return $view; } } ``` and the Entity looks like this: ``` namespace Users\Entity; use Doctrine\ORM\Mapping as ORM; use Zend\Form\Annotation as Form; /** * @ORM\Entity * @ORM\Table(name="users") * @Form\Name("user") * @Form\Hydrator("Zend\Stdlib\Hydrator\ObjectProperty") */ class User { /** * @var int * @ORM\Id @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue * @Form\Exclude() */ protected $id; /** * @var string * @ORM\Column(name="user_name", type="string", length=255, nullable=false) * @Form\Filter({"name":"StringTrim"}) * @Form\Validator({"name":"StringLength", "options":{"min":1, "max":25}}) * @Form\Validator({"name":"Regex", "options":{"pattern":"/^[a-zA-Z][a-zA-Z0-9_-]{0,24}$/"}}) * @Form\Attributes({"type":"text"}) * @Form\Options({"label":"Username:"}) */ protected $username; /** * @var string * @ORM\Column(name="email", type="string", length=255, unique=true) * @Form\Type("Zend\Form\Element\Email") * @Form\Options({"label":"Your email address:"}) */ protected $email; } ``` When I enter the URL commapp/users/index/update/1, I should get the form displayed for the user of ID=1. Instead I get the `Doctrine\Common\Annotations\AnnotationException`, with message: `[Semantical Error] The annotation "@Zend\Form\Annotation\Name" in class Users\Entity\User does not exist, or could not be auto-loaded.` I can't see what I'm doing wrong...?

Original source