title: How to create form inputs/elements in ZF2
body: <p>EDIT : My main question has now become 'How do I get the ServiceManager with the doctrine entity manager into the hands of my form, element, and input classes in some clean way?' Read on to see the full post.</p>
  
  <p>I'm going to try and ask by example here so bear with me. Let me know where I'm going wrong/right or where I could improve</p>
  
  <p>I'm trying to create a registration form. I could use ZfcUser module but I want to do this on my own. I'm using ZF2 with Doctrine2 as well so that leads me away from that module a bit. </p>
  
  <p>My strategy was this, </p>
  
  <ol>
  <li><p>Create a form class called registration form</p></li>
  <li><p>Create separate 'element' classes for each element where each element will have an input specification</p></li>
  <li><p>Since each element is a separate class from the form I can unit test each one separately.</p></li>
  </ol>
  
  <p>All seemed fine until I wanted to add a validator to my username element that would check that the username is NOT is use yet. </p>
  
  <p>Here is the code thus far</p>
  
  <pre><code>namepsace My\Form;
  
  use Zend\Form\Form,
      Zend\Form\Element,
      Zend\InputFilter\Input,
      Zend\InputFilter\InputFilter,
  
  /**
   * Class name : Registration
   */
  class Registration
      extends Form
  {
  
      const USERNAME     = 'username';
      const EMAIL        = 'email';
      const PASSWORD     = 'password';
      const PASS_CONFIRM = 'passwordConfirm';
      const GENDER       = 'gender';
      const CAPTCHA      = 'captcha';
      const CSRF         = 'csrf';
      const SUBMIT       = 'submit';
  
      private $captcha = 'dumb';
  
      public function prepareForm()
      {
          $this-&gt;setName( 'registration' );
  
          $this-&gt;setAttributes( array(
              'method' =&gt; 'post'
          ) );
  
          $this-&gt;add( array(
              'name'       =&gt; self::USERNAME,
              'type'       =&gt; '\My\Form\Element\UsernameElement',
              'attributes' =&gt; array(
                  'label'     =&gt; 'Username',
                  'autofocus' =&gt; 'autofocus'
              )
              )
          );
  
          $this-&gt;add( array(
              'name'       =&gt; self::SUBMIT,
              'type'       =&gt; '\Zend\Form\Element\Submit',
              'attributes' =&gt; array(
                  'value' =&gt; 'Submit'
              )
          ) );
  
      }
  
  }
  </code></pre>
  
  <p>I removed a lot that I think isn't necessary. Here is my username element below.</p>
  
  <pre><code>namespace My\Form\Registration;
  
  use My\Validator\UsernameNotInUse;
  use Zend\Form\Element\Text,
      Zend\InputFilter\InputProviderInterface,
      Zend\Validator\StringLength,
      Zend\Validator\NotEmpty,
      Zend\I18n\Validator\Alnum;
  
  /**
   *
   */
  class UsernameElement
      extends Text
      implements InputProviderInterface
  {
  
      private $minLength = 3;
      private $maxLength = 128;
  
      public function getInputSpecification()
      {
          return array(
              'name'     =&gt; $this-&gt;getName(),
              'required' =&gt; true,
              'filters'  =&gt; array(
                  array( 'name'       =&gt; 'StringTrim' )
              ),
              'validators' =&gt;
              array(
                  new NotEmpty(
                      array( 'mesages' =&gt;
                          array(
                              NotEmpty::IS_EMPTY =&gt; 'The username you provided is blank.'
                          )
                      )
                  ),
                  new AlNum( array(
                      'messages' =&gt; array( Alnum::STRING_EMPTY =&gt; 'The username can only contain letters and numbers.' )
                      )
                  ),
                  new StringLength(
                      array(
                          'min'      =&gt; $this-&gt;getMinLength(),
                          'max'      =&gt; $this-&gt;getMaxLength(),
                          'messages' =&gt;
                          array(
                              StringLength::TOO_LONG  =&gt; 'The username is too long. It cannot be longer than ' . $this-&gt;getMaxLength() . ' characters.',
                              StringLength::TOO_SHORT =&gt; 'The username is too short. It cannot be shorter than ' . $this-&gt;getMinLength() . ' characters.',
                              StringLength::INVALID   =&gt; 'The username is not valid.. It has to be between ' . $this-&gt;getMinLength() . ' and ' . $this-&gt;getMaxLength() . ' characters long.',
                          )
                      )
                  ),
                  array(
                      'name'    =&gt; '\My\Validator\UsernameNotInUse',
                      'options' =&gt; array(
                          'messages' =&gt; array(
                              UsernameNotInUse::ERROR_USERNAME_IN_USE =&gt; 'The usarname %value% is already being used by another user.'
                          )
                      )
                  )
              )
          );
      }    
  }
  </code></pre>
  
  <p>Now here is my validator</p>
  
  <pre><code>namespace My\Validator;
  
  use My\Entity\Helper\User as UserHelper,
      My\EntityRepository\User as UserRepository;
  use Zend\Validator\AbstractValidator,
      Zend\ServiceManager\ServiceManagerAwareInterface,
      Zend\ServiceManager\ServiceLocatorAwareInterface,
      Zend\ServiceManager\ServiceManager;
  
  /**
   *
   */
  class UsernameNotInUse
      extends AbstractValidator
      implements ServiceManagerAwareInterface
  {
  
      const ERROR_USERNAME_IN_USE = 'usernameUsed';
  
      private $serviceManager;
  
      /**
       *
       * @var UserHelper
       */
      private $userHelper;
      protected $messageTemplates = array(
          UsernameNotInUse::ERROR_USERNAME_IN_USE =&gt; 'The username you specified is being used already.'
      );
  
      public function isValid( $value )
      {
          $inUse = $this-&gt;getUserHelper()-&gt;isUsernameInUse( $value );
          if( $inUse )
          {
              $this-&gt;error( UsernameNotInUse::ERROR_USERNAME_IN_USE, $value );
          }
  
          return !$inUse;
      }
  
      public function setUserHelper( UserHelper $mapper )
      {
          $this-&gt;userHelper = $mapper;
          return $this;
      }
  
      /**
       * @return My\EntityRepository\User
       */
      public function getUserHelper()
      {
          if( $this-&gt;userHelper == null )
          {
              $this-&gt;setUserHelper( $this-&gt;getServiceManager()-&gt;get( 'doctrine.entitymanager.orm_default' )-&gt;getObjectRepository( 'My\Entity\User') );
          }
          return $this-&gt;userHelper;
      }
  
      public function setServiceManager( ServiceManager $serviceManager )
      {
          echo get_class( $serviceManager );
          echo var_dump( $serviceManager );
          $this-&gt;serviceManager = $serviceManager;
          return $this;
      }
  
      /**
       *
       * @return ServiceManager
       */
      public function getServiceManager( )
      {
          return $this-&gt;serviceManager;
      }
  
  }
  </code></pre>
  
  <p>Why did this seem like a good idea to me? </p>
  
  <ol>
  <li><p>It seemed like a good testability/re-use choice to make since I could re-use the elements separately across my application if need be. </p></li>
  <li><p>I could unit test each Input generated by each element to make sure it correctly accepts/rejects input. </p></li>
  </ol>
  
  <p>This is the example of my unit test for the element</p>
  
  <pre><code>public function testFactoryCreation()
  {
      $fac = new Factory();
  
      $element = $fac-&gt;createElement( array(
          'type' =&gt; '\My\Form\Registration\UsernameElement'
          ) );
      /* @var $element \My\Form\Registration\UsernameElement  */
  
      $this-&gt;assertInstanceOf( '\My\Form\Registration\UsernameElement',
                               $element );
  
      $input      = $fac-&gt;getInputFilterFactory()-&gt;createInput( $element-&gt;getInputSpecification() );
      $validators = $input-&gt;getValidatorChain()-&gt;getValidators();
      /* @var $validators \Zend\Validator\ValidatorChain */
  
      $expectedValidators = array(
          'Zend\Validator\StringLength',
          'Zend\Validator\NotEmpty',
          'Zend\I18n\Validator\Alnum',
          'My\Validator\UsernameNotInUse'
      );
  
      foreach( $validators as $validator )
      {
          $actualClass = get_class( $validator['instance'] );
          $this-&gt;assertContains( $actualClass, $expectedValidators );
  
          switch( $actualClass )
          {
              case 'My\Validator\UsernameNotInUse':
                  $helper = $validator['instance']-&gt;getUserHelper();
                  //HAVING A PROBLEM HERE
                  $this-&gt;assertNotNull( $helper );
                  break;
  
              default:
  
                  break;
          }
      }
  
  }
  </code></pre>
  
  <p>The problem I'm having is that the validator can't fetch the UserHelper properly, which is really a UserRepository from doctrine. The reason this is happening is because the validators only get access to the ValidatorPluginManager as a ServiceManager rather than having access to the application wide ServiceManager.</p>
  
  <p>I get this error for the Validator portion, although if I call the same get method on the general service manager it works with no problems. </p>
  
  <pre><code>1) Test\My\Form\Registration\UsernameElementTest::testFactoryCreation
  Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for doctrine.entitymanager.orm_default
  </code></pre>
  
  <p>The var_dump( $serviceManager ) in validator shows me it is of the class ValidatorPluginManager.</p>
  
  <p>I tried putting a factory in the service_manager entry like so </p>
  
  <pre><code>'service_manager' =&gt; array(
                  'factories' =&gt; array(
                      'My\Validator\UsernameNotInUse' =&gt; function( $sm )
                      {
                          $validator = new \My\Validator\UsernameNotInUse();
                          $em        = $serviceManager-&gt;get( 'doctrine.entitymanager.orm_default' );
                          /* @var $em \Doctrine\ORM\EntityManager */
                          $validator-&gt;setUserHelper( $em-&gt;getRepository( '\My\Entity\User' ) );
  
                          return $validator;
                      }
                  )
  </code></pre>
  
  <p>but that didn't work because it's not consulting the application level service manager.</p>
  
  <p>So, overall, here are my questions : </p>
  
  <ol>
  <li><p>Is this strategy of separating the form and elements a good one? Should I keep going this way? What are alternatives? ( I'm for breaking stuff up for the sake of testability ) I was going to test ONLY the form itself originally with a combination of ALL the inputs but it seemed like I'd be trying to do too much.</p></li>
  <li><p>How do I resolve the issue I have above?</p></li>
  <li><p>Should I be using the Form/Element/Input parts of Zend in some other way that I'm not seeing? </p></li>
  </ol>