簡體   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