【问题标题】:how to make form ignore password fields if blank (symfony2 forms)如果为空,如何使表单忽略密码字段(symfony2 表单)
【发布时间】:2012-08-11 06:39:56
【问题描述】:

我的后端有一个简单的用户管理器,我希望能够在不设置新密码/每次都重复旧密码的情况下编辑用户。

现在如果我在编辑用户时将密码字段留空,symfony2 会抱怨必须输入密码,当然我在注册新用户时想要这个功能,但是当我编辑它们时,我想要如果未填写密码框,则忽略该表单。

这是如何实现的?

【问题讨论】:

    标签: php forms symfony


    【解决方案1】:

    Symfony 5 方法:

    在控制器类中:

    /**
     * @Route("/user/{id}/edit")
     */
    public function updateUser(
        $id, // See 'Route' annot., needed to `find()` User, adjust to your needs
        User $user,
        Request $request,
        UserPasswordEncoderInterface $passwordEncoder,
        UserRepository $userRepository
    ): Response {
        $form = $this->createForm(UserFormType::class, $user);
    
        // if password field is required by default, we have to `add()` it again
        // with `required` set to `false`
        $form->add( 
            'plainPassword',
            PasswordType::class,
            [
                // do not use Constraint NotBlank()
                'required' => false,
                'mapped' => false
            ]
        );
    
        $form->handleRequest($request);
    
        if ($form->isSubmitted() && $form->isValid()) {
            $entity = $userRepository->find($id); // as above, adjust to your needs
    
            if (!$entity) {
                throw $this->createNotFoundException('User does not exist!');
            }
    
            $originalPassword = $entity->getPassword();
    
            /** @var User $user */
            $user = $form->getData();
    
            // keep original password if new one isn't provided
            if (!empty($form['plainPassword']->getData())) {
                $user->setPassword(
                    $passwordEncoder->encodePassword(
                        $user,
                        $form['plainPassword']->getData()
                    )
                );
            } else {
                // set old password
                $user->setPassword($originalPassword);
            }
    
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);
            $em->flush();
    
            return new Response('User updated!');
        }
    
        return $this->render(
            'admin/user_edit.html.twig',
            [
                'requestForm' => $form->createView(),
            ]
        );
    }
    

    【讨论】:

      【解决方案2】:

      对于验证,使用 2 个不同的验证组,并通过可调用函数设置正确的一个。

      public function buildForm(FormBuilderInterface $builder, array $options)
      {
          $builder->add(
              'oldPassword',
              PasswordType::class,
              [
                  'constraints' => new UserPassword([
                      'groups' => 'profile_password',
                  ]),
                  'mapped' => false,
                  'required' => false,
              ]
          );
      
          $builder->add(
              'plainPassword',
              PasswordType::class,
              [
                  'constraints' => new NotBlank([
                      'groups' => 'profile_password',
                  ]),
                  'mapped' => false,
                  'required' => false,
              ]
          );
      }
      
      /**
       * {@inheritdoc}
       */
      public function configureOptions(OptionsResolver $resolver)
      {
          $resolver->setDefaults(
              [
                  'validation_groups' => function (FormInterface $form) {
                      $newPassword = $form->get('plainPassword')->getData();
                      $oldPassword = $form->get('oldPassword')->getData();
                      if ($oldPassword || $newPassword) {
                          return ['profile', 'profile_password'];
                      } else {
                          return ['profile'];
                      }
                  },
              ]
          );
      }
      

      【讨论】:

        【解决方案3】:

        我所做的是将UserType 保持原样,只删除控制器中的密码字段:

        /**
         * @Route("/users/edit/{username}", name="user_edit")
         */
        public function editAction(Request $request, User $user)
        {
            $form = $this->createForm(UserType::class, $user);
        
            // Remove the password field when editing the user
            // Otherwise it must be entered each time the user is edited
            // We can change the password via a special edit-user-password page
            $form->remove('password');
        
            $form->handleRequest($request);
        
            if ($form->isValid()) {
                // ...
            }
        }
        

        这样你就可以有一个单一的用户类型,可以在editAction和newAction中重复使用。

        请务必在$form->handleRequest($request); 之前添加行$form->remove('password');

        【讨论】:

        • 不错的一个!但是,您不能手动更新用户的密码(以防他/她忘记或出于任何原因。)
        • @NiketPathak,这就是为什么我说// We can change the password via a special edit-user-password page ;-)
        【解决方案4】:

        在你的实体设置器中设置密码属性,如下所示:

        /**
         * Set password
         *
         * @param string $password
         * @return User
         */
        public function setPassword($password)
        {
            if (!is_null($password)) {
                $this->password = $password;
            }
        
            return $this;
        }
        

        诀窍是检查传递的参数是否为空,如果不是则仅设置。

        【讨论】:

        • 但是如果用户输入空密码,那么创建表单呢?
        • @Riki137 imo,密码在 99,(99)% 的情况下不为空
        【解决方案5】:

        有一篇文章提供了许多选项来满足您的要求,来自 Symfony2 食谱,特别是下面的部分对我有用:

        Customizing your Form based on the underlying Data

        下面是实现:

        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            // ...
            $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
                $product = $event->getData();
                $form = $event->getForm();
        
                // check if the Product object is "new"
                // If no data is passed to the form, the data is "null".
                // This should be considered a new "Product"
                if (!$product || null === $product->getId()) {
                    $form->add('name', 'text');
                }
            });
        }
        

        【讨论】:

          【解决方案6】:

          如果您需要将 required 选项添加到 $options 数组。示例:

          public function buildForm(FormBuilder $builder, array $options)
          {   
          
              $builder
                  ->add('username', 'text', array('label' => 'Servernamn '))            
                  ->add('plainPassword', 'repeated', array(
                            'type' => 'password', 
                            'first_name' => 'password', 
                            'second_name' => 'repeat_password', 
                            'required' => false,
                      ));
          }
          

          【讨论】:

          • 没关系,我对我的大多数表单都没有验证,否则它不会允许复选框不被选中等等。
          【解决方案7】:

          为了别人的参考,我是这样设计的。

          我的表单类型:

          public function buildForm(FormBuilder $builder, array $options)
          {   
          
              $builder
                  ->add('username', 'text', array('label' => 'Servernamn '))            
                  ->add('plainPassword', 'repeated', array('type' => 'password', 'first_name' => 'Lösenord för server ', 'second_name' => 'Upprepa lösenord för server',));
          
              $builder-> addValidator(new CallbackValidator(function(FormInterface $form){
                $username = $form->get('username')->getData();
                  if (empty($username)) {
                    $form['username']->addError(new FormError("Du måste ange ett namn för servern"));
                  }
              }));
          
          }
          

          我的更新操作:

          public function updateServerAction($id)
          {
              $em = $this->getDoctrine()->getEntityManager();
          
              $entity = $em->getRepository('BizTVUserBundle:User')->find($id);
          
              if (!$entity) {
                  throw $this->createNotFoundException('Unable to find Container entity.');
              }
          
              $originalPassword = $entity->getPassword(); 
          
              $editForm   = $this->createForm(new editServerType(), $entity);
          
              $request = $this->getRequest();
          
              $editForm->bindRequest($request);
          
              if ($editForm->isValid()) {
          
                  $plainPassword = $editForm->get('plainPassword')->getData();
                  if (!empty($plainPassword))  {  
                      //encode the password   
                      $encoder = $this->container->get('security.encoder_factory')->getEncoder($entity); //get encoder for hashing pwd later
                      $tempPassword = $encoder->encodePassword($entity->getPassword(), $entity->getSalt()); 
                      $entity->setPassword($tempPassword);                
                  }
                  else {
                      $entity->setPassword($originalPassword);
                  }
          
                  $em->persist($entity);
                  $em->flush();
          
                  return $this->redirect($this->generateUrl('Server'));
              }
          

          因此更新我的用户密码应该设置,否则保留原始密码。

          【讨论】:

          • 完美的答案是想的一样,不知道怎么做
          • 完美且解释清楚的答案。谢谢。
          • 效果很好。我使用“密码”字段而不是plainPassword,让我免于修改实体:$plainPassword = $editForm->get('password')->getData();
          【解决方案8】:

          你可以用

          if (empty($password)) {
               //edit the password
          }
          

          尝试将其修复到表单的 PHP 中。

          【讨论】:

          • 这将在表单提交的任何时候解析为真,无论它是否在表单中设置,因为 $_POST['password']='' 将在 isset() 测试中解析为真。你的意思可能是if(empty($password)){...?
          • 再次,如果用户将密码设置为 000000,这将返回 true
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-26
          相关资源
          最近更新 更多