[英]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.