如何在持久化时限制对实体选定属性的修改



假设我有一个实体类和一个对应于实体的通用FormType

class Entry {
protected $start_time;
protected $end_time;
protected $confirmed; // Boolean
// ... Other fields and getters and setters
}

在这个实体的CRUD上,如果实体已经被确认,或者在上述情况下,当$confirmed === true时,我不想允许对start_timeend_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]。也许将实体存储在会话中会起作用。作为一个单独的实体分离可能会起作用,并将分离的实体与更新的实体进行比较。

我找到了两种方法来解决这个问题:

  1. 您可以检索实体的原始数据。它返回一个数组,其中包含可用于重置数据的实体的旧数据。

    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();
    }
    
  2. 使用表单事件

    以下是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);
    }
    }
    }
    }
    

相关内容

  • 没有找到相关文章

最新更新