【问题标题】:Merging input filters in Zend Framework 2在 Zend Framework 2 中合并输入过滤器
【发布时间】:2014-07-15 13:55:13
【问题描述】:

我有许多字段集,我想为每个字段集创建一个输入过滤器类。然后的想法是,对于我的每个表单,我可以创建一个由其他输入过滤器组成的输入过滤器类。例如,当通过注册表单创建帐户时,我想为我的Account 实体使用基本的Account 输入过滤器,并将其用于可以修改输入或添加其他输入的新输入过滤器类.如下所示。

class Register extends InputFilter
{
    public function __construct(ObjectRepository $accountRepository, Account $accountFilter)
    {
        /***** Add inputs from input filters *****/
        $this->inputs = $accountFilter->getInputs();

        /***** Add additional validation rules *****/
        // Username
        $usernameAvailability = new NoObjectExists(array(
            'object_repository' => $accountRepository,
            'fields' => array('username'),
        ));

        $username = $this->get('username');
        $username->getValidatorChain()
            ->attach($usernameAvailability, true);

        // E-mail
        $emailAvailability = new NoObjectExists(array(
            'object_repository' => $accountRepository,
            'fields' => array('email'),
        ));

        $email = $this->get('email');
        $email->getValidatorChain()
            ->attach($emailAvailability, true);
    }
}

我将一个输入过滤器传递给构造函数,我想将此过滤器的输入添加到我的Register 过滤器并修改输入。

我遇到的问题是我的一些输入似乎按预期进行验证,我似乎无法弄清楚原因。当我提交表单时,只有一些输入按预期进行验证:

有趣的是,在填写数据库中已存在的电子邮件时,电子邮件输入的行为与预期不同。结果应该是它已经存在的验证错误,但这不会发生。如果我调试并查看我的表单,我发现以下内容:

表单的过滤器具有正确的输入和正确的验证器,如上图所示,username 输入似乎验证正确。但是由于某种原因,这并没有在我的表单中直观地反映出来。

下面是我的代码。

字段集

class Profile extends Fieldset
{
    public function __construct(ObjectManager $objectManager)
    {
        parent::__construct('profile');

        $this->setHydrator(new DoctrineHydrator($objectManager))
            ->setObject(new ProfileEntity());

        // Elements go here

        $this->add(new AccountFieldset($objectManager));
    }
}



class Account extends Fieldset
{
    public function __construct()
    {
        parent::__construct('account');

        $username = new Element\Text('username');
        $username->setLabel('Username');

        $password = new Element\Password('password');
        $password->setLabel('Password');

        $repeatPassword = new Element\Password('repeatPassword');
        $repeatPassword->setLabel('Repeat password');

        $email = new Element\Email('email');
        $email->setLabel('E-mail address');

        $birthdate = new Element\DateSelect('birthdate');
        $birthdate->setLabel('Birth date');

        $gender = new Element\Select('gender');
        $gender->setLabel('Gender')
            ->setEmptyOption('Please choose')
            ->setValueOptions(array(
                1 => 'Male',
                2 => 'Female',
            ));

        $this->add($username);
        $this->add($password);
        $this->add($repeatPassword);
        $this->add($email);
        $this->add($birthdate);
        $this->add($gender);
        $this->add(new CityFieldset());
    }
}

表格

class Register extends Form
{
    public function __construct()
    {
        parent::__construct('register');

        // Terms and Conditions
        $terms = new Element\Checkbox('terms');
        $terms->setLabel('I accept the Terms and Conditions');
        $terms->setCheckedValue('yes');
        $terms->setUncheckedValue('');
        $terms->setAttribute('id', $terms->getName());

        // Submit button
        $submit = new Element\Submit('btnRegister');
        $submit->setValue('Register');

        $profileFieldset = new ProfileFieldset($objectManager);
        $profileFieldset->setUseAsBaseFieldset(true);

        // Add elements to form
        $this->add($terms);
        $this->add($profileFieldset);
        $this->add($submit);
    }
}

查看

$form->prepare();
echo $this->form()->openTag($form);
$profile = $form->get('profile');

$account = $profile->get('account');
echo $this->formRow($account->get('username'));
echo $this->formRow($account->get('password'));
echo $this->formRow($account->get('repeatPassword'));
echo $this->formRow($account->get('email'));
echo $this->formRow($account->get('birthdate'));
echo $this->formRow($account->get('gender'));

$city = $account->get('city');
echo $this->formRow($city->get('postalCode'));
echo $this->formRow($form->get('terms'));
echo $this->formSubmit($form->get('btnRegister'));
echo $this->form()->closeTag();

控制器

$form = new Form\Register();
$profile = new Profile();

if ($this->request->isPost()) {
    $form->bind($profile);

    $form->setData($this->request->getPost());
    $form->setInputFilter($this->serviceLocator->get('Profile\Form\Filter\Register'));

    if ($form->isValid()) {
        // Do stuff
    }
}

return new ViewModel(array('form' => $form));

我在这里误解了什么吗?有没有更好的方法来做到这一点,同时仍然有多个输入过滤器类?我真的更愿意像这样保持我的代码可维护,而不是为不同的表单复制验证规则。很抱歉发了这么长的帖子——这个问题真的很难解释!

【问题讨论】:

    标签: php zend-framework2


    【解决方案1】:

    好吧,看来我想通了。显然我的第一种方法是完全错误的。我找到了一种为我的每个字段集设置一个输入过滤器类的方法,然后为我的表单重用这些输入过滤器,同时为某些表单元素(来自我的字段集)添加额外的验证规则。这样,我可以在每个字段集的标准输入过滤器类中定义我的通用验证规则,并针对不同的上下文(即表单)修改它们。下面是代码。这些类与问题有点不同,因为这稍微简化了。

    主输入过滤器

    // This input filter aggregates the "fieldset input filters" and adds additional validation rules
    class Register extends InputFilter
    {
        public function __construct(ObjectRepository $accountRepository, InputFilter $profileFilter)
        {
            /***** ADD ADDITIONAL VALIDATION RULES *****/
            // Username
            $usernameAvailability = new NoObjectExists(array(
                'object_repository' => $accountRepository,
                'fields' => array('username'),
            ));
    
            $emailInput = $profileFilter->get('account')->get('username');
            $emailInput->getValidatorChain()->attach($usernameAvailability, true);
    
            // E-mail
            $emailAvailability = new NoObjectExists(array(
                'object_repository' => $accountRepository,
                'fields' => array('email'),
            ));
    
            $emailInput = $profileFilter->get('account')->get('email');
            $emailInput->getValidatorChain()->attach($emailAvailability, true);
    
    
            /***** ADD FIELDSET INPUT FILTERS *****/
            $this->add($profileFilter, 'profile');
        }
    }
    

    配置文件输入过滤器

    class Profile extends InputFilter
    {
        public function __construct(InputFilter $accountFilter)
        {
            $this->add($accountFilter, 'account');
    
            // Add generic validation rules (inputs) for the profile fieldset here
        }
    }
    

    上面代码中提到的Account输入过滤器是一个完全正常的输入过滤器类,它扩展了Zend\InputFilter\InputFilter并添加了输入。没什么特别的。

    我的字段集保持不变,并且与问题中的字段集相同,表单类和控制器也是如此。使用setInputFilter 方法将Register 输入过滤器添加到表单中,就是这样!

    使用这种方法,每个输入过滤器实例都被添加到一个字段集中——这是我的第一种方法没有做到的。我希望这可以帮助有类似问题的人!

    【讨论】:

      【解决方案2】:

      我有一个 User 实体,其中指定了一些验证器。

      但我想扩展该验证器列表,以便根据服务调用添加一个以检查用户电子邮件是否尚未使用。

      问题是我需要在验证器中注入一个实体管理器来调用服务。而且我不能(或者更确切地说不知道如何也不想:-) 将实体管理器注入到实体中。

      我还想保留实体上的现有验证,因为它更靠近存储库并且可能在我的控制器之外使用。所以我无法将所有验证器移出这个实体,移到我的新自定义过滤器中。

      因此,我的新自定义过滤器将按原样重用实体的现有验证器。

      新的自定义过滤器称为UserFormFilter,它在其控制器中接收现有的实体过滤器,在其上循环,将每个传入的验证器添加到自身:

      class UserFormFilter extends InputFilter
      {
      
          public function __construct(EntityManager $em, $identity, InputFilter $userDefaultInputFilter)
          {
              // Add the validators specified in the user entity
              foreach ($userDefaultInputFilter->inputs as $inputFilter) {
                  $this->add($inputFilter);
              }
      
              $this->add(array(
                  'name' => 'email',
                  'required' => true,
                  'filters' => array(),
                  'validators' => array(
                      array('name' => 'EmailAddress'),
                      array(
                          'name' => 'Application\Validator\User',
                          'options' => array('manager' => $em, 'identity' => $identity)
                      )
                  ),
              ));
          }
      
      }
      

      我现在可以在我的 UserController 中实例化一个自定义 UserFormFilter:

      $formFilter = new \Application\Form\UserFormFilter($em, $user->getInputFilter());
      $form->setInputFilter($formFilter);
      

      您可以在上面的代码中看到自定义UserFormFilter 采用了我的User 实体getInputFilter 方法中指定的默认过滤器。附带说明一下,它还通过启用自定义过滤器的实体管理器来执行服务调用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多