假设我有一个实体类和一个对应于实体的通用FormType
class Entry {
protected $start_time;
protected $end_time;
protected $confirmed; // Boolean
// ... Other fields and getters and setters
}
在这个实体的CRUD上,如果实体已经被确认,或者在上述情况下,当$confirmed === true
时,我不想允许对start_time
或end_time
进行任何修改
在trick文件上,我禁用了要限制的字段,如下所示:
{% 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
完全相同。我的猜测是,学说认为它已经拥有了被要求的实体,并刚刚给我返回了相同的对象。无论如何,我解决这个问题的尝试失败了。
知道如何限制/恢复对选定属性的更改,同时允许对实体的其余属性进行更改吗?
更新:
修改表单类型以禁用字段不是一个选项,因为我只希望它们是只读的/只有在实体被确认时才被禁用,其余时间我希望表单保持原样。
您必须在表单生成器中添加属性'disabled' => true
,而不仅仅是在trick中。
如果不希望用户修改字段的值,可以将禁用选项设置为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
);
}
});
我想我现在明白你的问题了@Starx,一开始我没有仔细阅读,你的更新很有帮助。
也许你需要分离你的实体?
检查有关(会话中的实体)的此链接[http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/cookbook/entities-in-session.html]。也许将实体存储在会话中会起作用。作为一个单独的实体分离可能会起作用,并将分离的实体与更新的实体进行比较。
我找到了两种方法来解决这个问题:
-
您可以检索实体的原始数据。它返回一个数组,其中包含可用于重置数据的实体的旧数据。
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对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); } } } }
源