繁体   English   中英

仅在满足条件时如何更新映射的字段?

[英]How can I update mapped fields only when a condition is satisfied?

在我的Symfony2应用程序中,我创建了一个自定义表单来编辑User类的对象。 用户具有password属性,其中包含用户密码的哈希值。 出于明显的原因,我不想将此属性的值回显到字段中。 但是,我希望表单上有一个密码字段,以便在编辑用户时可以更改用户的密码。

该密码字段的行为应如下:

  • 如果用户设置了密码,则该字段应包含********
  • 如果用户未设置密码,则该字段应为空。
  • (事实证明,使用我当前的体系结构无法实现前两点,因此我打算这样做:)加载页面时,无论用户是否设置了密码,该字段都应该为空。
  • 如果该字段发布了内容,则应将用户密码设置为该字段的哈希值。
  • 如果将该字段发布为空,则不应更改用户密码,更重要的是,请勿清除该密码。

我想到了使用自定义数据转换器实现这一点。 但是,当密码字段发布为空时,数据转换器无法为我提供一种跳过更新用户password属性的方法。

我需要在哪里扩展框架以添加自定义逻辑来决定应更新哪些字段?

更新

这是我要替换的旧代码:

/* SomeController.php */

$pass = $request->get('password');
if (strlen($pass) >= 5 && strlen($pass) <= 16) {
    $factory = $this->get('security.encoder_factory');
    $encoder = $factory->getEncoder($user);
    $password = $encoder->encodePassword($pass, $user->getSalt());

    $user->setPassword($password);
}

我可以忍受删除字符串长度检查。 我要检查的是是否已输入内容。

如您所见,我不能简单地将此代码移至数据转换器,因为它需要访问$user (我们当前正在编辑的用户)。 我认为创建提供这种价值的服务不是一个好主意。

只需将控件直接插入到您的实体方法中并使用数据转换器(您便会了解)

所以你的实体将是

class User
{
  //some properties and methods here

  public function setPassword($pwd = null) {
    if (null !== $pwd) {
      $this->password = //do actions here like hash or whatever
    }
    //don't update the password
  }
}

如果您只想利用DataTransformers的优势,那么您仍然可以按照自己的方式做

use Symfony\Component\DependencyInjection\ContainerInterface;

class PasswordTransformer implements DataTransformerInterface
{
  private $ci;

  public function __construct(ContainerInterface $ci) {
    $this->ci = $ci;
  }
  //...
  public function reverseTransform($form_password) {
    if (!$form_password) {
      //return password already stored
      return $this->ci->get('security.context')
                      ->getToken()
                      ->getUser()
                      ->getPassword();
    }
  }
}

当然,您需要将service_container服务注入到数据转换器中(或者更好的是,应该将其注入到表单类型的选择器中,并按以下方式传递给DataTransformer构造函数:

services:
your.bundle.password_selector_type:
    class: Your\Bundle\Form\Type\PasswordSelectorType
    arguments: ["@security.context"]
    tags:
        - { name: form.type, alias: password_selector_type }

对于表单部分,您应该看一下此小部件。

http://symfony.com/doc/current/reference/forms/types/repeated.html

它提供了一种在字段上进行询问和确认的简便方法(当您将类型设置为密码时,它也会用星号隐藏值)。

$builder->add('password', 'repeated', array(
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'options' => array('attr' => array('class' => 'password-field')),
'required' => true,
'first_options'  => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password')));

它将检查第一个和第二个选项是否相等。 如果是这种情况,那么您的表格将被视为有效。 否则,将显示invalid_message,并且第一个字段将设置为用户键入的内容,而清空确认字段(第二个选项)。

之后,您可以添加一些逻辑,例如对密码进行哈希处理以最终保留您的实体。 (在表单处理程序中提取它是一个好习惯)。

这是我现在想到的,但是我对解决方案不满意,因为它涉及控制器中的自定义表单处理。 但是,到目前为止,这是我发现使其起作用的唯一方法。

我的表单类为用户的密码添加了一个未映射的字段:

class UserType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add('username')
            ->add('displayName')
            ->add('password', 'password', ['mapped' => false]);
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array('data_class' => 'MyCompany\MyBundle\Entity\User'));
    }

    public function getName() {
        return 'user';
    }
}

然后,在我的控制器类中手动处理此字段:

class UserAdminController extends Controller {
    public function editUserAction($userId, Request $request) {
        $user = $this->getDoctrine()->getRepository('MyCompanyMyBundle:User')->findOneById($userId);

        $form = $this->createForm('user', $user);

        $form->handleRequest($request);

        if ($form->isValid()) {
            $newPassword = $form['password']->getData();
            if ($newPassword !== "") {
                $factory = $this->get('security.encoder_factory');
                $encoder = $factory->getEncoder($user);
                $password = $encoder->encodePassword($newPassword, $user->getSalt());

                $user->setPassword($password);
            }
            $em = $this->getDoctrine()->getManager();
            $em->persist($user);
            $em->flush();
        }

        return $this->render(
            "MyCompanyMyBundle:Admin/Management/User:Edit.html.php",
            [
                "form"  => $form->createView()
            ]
        );
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM