假设我有一个实体类和一个与实体
对应的泛型FormTypeclass Entry {
protected $start_time;
protected $end_time;
protected $confirmed; // Boolean
// ... Other fields and getters and setters
}
在此实体的CRUD上,如果实体已被确认,我不希望允许对start_time
或end_time
进行任何修改,或者$confirmed === true
{} p>
在twig文件中,我禁用了我想要限制的字段,如下所示:
{% if entity.approved == true %}
{{ form_row(entity.start_time), { 'attr' : { 'disabled' : 'disabled' } }) }}
{% endif %}
{# Sameway for another field #}
现在的问题是,这是一个前端分辨率,现在可以使用Web浏览器中的Web开发人员工具轻松篡改。但无论我想要实现什么,一旦确认实体,就不会改变这两个字段。
所以,我试过的一种方法是在提交表单之后,我检查实体是否已经确认,如果是,我获取实体的早期状态并设置新实体的值(即将到来)坚持使用旧的价值观。
在控制器上:
$confirmed = $entity->getConfirmed();
$form->handleRequest($request);
if($form->isSubmitted() && $editForm->isValid()) {
// The form was submitted
if($confirmed === true) { // if the entity was confirmed previously
$oldEntity = $em->getRepository('...')->find($entity->getId());
$entity->setStartTime($oldEntity->getStartTime());
$entity->setEndTime($oldEntity->getEndTime());
}
$em->persist($entity);
$em->flush();
}
此处的问题是$oldEntity
与$entity
完全相同。我的猜测是学说它已经有了被要求的实体并且刚刚给我回复了相同的对象。无论如何,我解决这个问题的尝试失败了。
知道如何限制/恢复所选属性的更改,同时允许更改实体的其余属性吗?
更新
修改表单类型以禁用该字段不是一个选项,因为我只希望它们只有在确认实体时才是只读/禁用,剩下的时间我希望表单不变。
答案 0 :(得分:1)
您必须在表单构建器中添加属性'disabled' => true
,而不仅仅是在树枝中。
如果您不希望用户修改字段的值,可以将disabled选项设置为true。任何提交的值都将被忽略。
参考:http://symfony.com/doc/current/reference/forms/types/form.html#disabled
如果您希望动态修改,请使用表单事件,例如:
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$entity = $event->getData();
// if confirmed, disable start_time field
if ($entity->getConfirmed()) {
$config = $form->get('start_time')->getConfig();
$options = $config->getOptions();
// set disabled option to true
$options['disabled'] = true;
// replace origin field
$form->add(
'start_time',
$config->getType()->getName(),
$options
);
}
});
答案 1 :(得分:0)
我想我现在理解你的问题@Starx,我一开始并没有仔细阅读,你的更新也有所帮助。
也许您需要分离您的实体?
查看此链接(会话中的实体)[http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/cookbook/entities-in-session.html]。也许将实体存储在会话中会起作用。作为单独的实体分离可能会起作用,并将分离的实体与更新的实体进行比较。
答案 2 :(得分:0)
我找到了两种方法来解决这个问题:
您可以检索实体的原始数据。它返回一个数组,其中包含一个实体的旧数据,可用于重置数据。
if($form->isSubmitted() && $editForm->isValid()) {
// The form was submitted
if($confirmed === true) { // if the entity was confirmed previously
$oldData = $em->getUnitOfWork()->getOriginalEntityData($entity);
$entity->setStartTime($oldData['start_time']);
$entity->setEndTime($oldData['end_time']);
}
$em->persist($entity);
$em->flush();
}
使用表单事件
以下是Symfony 3解决方案,请尝试使用maximkou的answer进行Symfony 2。
class EntityType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// ....
// ....
// Your form fields
$builder->addEventListener(FormEvents::POST_SET_DATA, array($this, 'onPreSetData'));
}
public function onPreSetData(FormEvent $event) {
/** @var YourEntity $entity */
$entity = $event->getData();
$form = $event->getForm();
if($entity instanceof YourEntity) {
if ($entity->getTimesheetEntry()->getTimeApproved() === true) {
$config = $form->get('start_time')->getConfig();
$options = $config->getOptions();
$options['disabled'] = true;
$form->add('start_time', get_class($config->getType()->getInnerType()), $options);
$config = $form->get('end_time')->getConfig();
$options = $config->getOptions();
$options['disabled'] = true;
$form->add('end_time', get_class($config->getType()->getInnerType()), $options);
}
}
}
}