[英]How can I update mapped fields only when a condition is satisfied?
In my Symfony2 application I created a custom form to edit objects of a User
class. 在我的Symfony2应用程序中,我创建了一个自定义表单来编辑User
类的对象。 Users have a password
property which contains a hash of the user's password. 用户具有password
属性,其中包含用户密码的哈希值。 For obvious reasons, I do not want to echo this property's value into a field. 出于明显的原因,我不想将此属性的值回显到字段中。 However, I want a password field on my form so that when editing a user it is possible to change the user's password. 但是,我希望表单上有一个密码字段,以便在编辑用户时可以更改用户的密码。
This password field should behave as follows: 该密码字段的行为应如下:
********
.********
。 I thought of implementing this with a custom data transformer. 我想到了使用自定义数据转换器实现这一点。 However, the data transformer does not provide me with a way to skip updating the user's password
property when the password field is posted empty. 但是,当密码字段发布为空时,数据转换器无法为我提供一种跳过更新用户password
属性的方法。
Where do I need to extend the framework to add custom logic deciding which fields should be updated? 我需要在哪里扩展框架以添加自定义逻辑来决定应更新哪些字段?
This is the legacy code I am trying to replace: 这是我要替换的旧代码:
/* 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);
}
I can live with removing the string length checks. 我可以忍受删除字符串长度检查。 All I want to check is whether something has been entered. 我要检查的是是否已输入内容。
As you can see, I can not simply move this code to a data transformer as it needs to access the $user
which is the user we are currently editing. 如您所见,我不能简单地将此代码移至数据转换器,因为它需要访问$user
(我们当前正在编辑的用户)。 I don't think it is a good idea to create a service providing this value. 我认为创建提供这种价值的服务不是一个好主意。
Just insert a control directly into your entity method and use data transformer (as you have insight) 只需将控件直接插入到您的实体方法中并使用数据转换器(您便会了解)
So your entity will be 所以你的实体将是
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
}
}
If you want to take advantage only of DataTransformers, you could still do what you need that way 如果您只想利用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();
}
}
}
Of course you need to inject service_container
service into you data transformer (or better, you should inject it into your form type's selector and pass to DataTransformer constructor as follows: 当然,您需要将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 }
For the form part, you should take a look a this widget. 对于表单部分,您应该看一下此小部件。
http://symfony.com/doc/current/reference/forms/types/repeated.html http://symfony.com/doc/current/reference/forms/types/repeated.html
It provides an easy way to ask and treat confirmation on a field (it also hide values with stars when you set type to password). 它提供了一种在字段上进行询问和确认的简便方法(当您将类型设置为密码时,它也会用星号隐藏值)。
$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')));
It will check first and second options to be equal. 它将检查第一个和第二个选项是否相等。 If that's the case then your form will be considered as valid. 如果是这种情况,那么您的表格将被视为有效。 Otherwise, invalid_message will be displayed and first field will set to the content typed by user while confirmation field (second option) will be emptied. 否则,将显示invalid_message,并且第一个字段将设置为用户键入的内容,而清空确认字段(第二个选项)。
You can add some logic afterwards like hashing the password to finally persist your entity. 之后,您可以添加一些逻辑,例如对密码进行哈希处理以最终保留您的实体。 (Extracting it in a form handler would be a good practice). (在表单处理程序中提取它是一个好习惯)。
Here is what I came up with for now but I am not happy with the solution as it involves custom form processing in the controller. 这是我现在想到的,但是我对解决方案不满意,因为它涉及控制器中的自定义表单处理。 However, so far this is the only way I have found to make it work. 但是,到目前为止,这是我发现使其起作用的唯一方法。
My form class adds an unmapped field for the user's password: 我的表单类为用户的密码添加了一个未映射的字段:
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';
}
}
This field is then processed manually in my controller class: 然后,在我的控制器类中手动处理此字段:
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.