You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Sulu管理前端实体持久化后禁用类别Key表单字段?

在Sulu CMS中实现类别Key持久化后不可修改的方案

要实现Sulu后台中类别Key在实体创建后不可修改,有两种可靠的方案,兼顾前端表单禁用和后端校验:

方案一:通过表单事件动态禁用字段

利用Sulu的表单事件系统,在表单加载时根据实体状态(是否已持久化)动态设置字段禁用属性:

  1. 创建表单事件订阅者
<?php

namespace App\Form\Subscriber;

use Sulu\Bundle\CategoryBundle\Entity\CategoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class CategoryFormSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            FormEvents::PRE_SET_DATA => 'onPreSetData',
        ];
    }

    public function onPreSetData(FormEvent $event): void
    {
        $category = $event->getData();
        $form = $event->getForm();

        // 仅当实体已持久化(存在ID)时禁用key字段
        if ($category instanceof CategoryInterface && null !== $category->getId()) {
            $keyField = $form->get('key');
            if ($keyField) {
                $keyField->setDisabled(true);
            }
        }
    }
}
  1. 注册订阅者
    在services.yaml中配置:
App\Form\Subscriber\CategoryFormSubscriber:
    tags:
        - { name: kernel.event_subscriber }

方案二:自定义字段类型(更灵活的全局控制)

如果需要在多个场景复用这个逻辑,可以自定义字段类型:

  1. 创建自定义Key字段类型
<?php

namespace App\Form\Type;

use Sulu\Bundle\CategoryBundle\Entity\CategoryInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CategoryKeyType extends TextType
{
    public function buildView(FormView $view, FormInterface $form, array $options): void
    {
        parent::buildView($view, $form, $options);

        $data = $form->getParent()->getData();
        // 判断实体是否已持久化,设置禁用状态
        if ($data instanceof CategoryInterface && null !== $data->getId()) {
            $view->vars['disabled'] = true;
        }
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        parent::configureOptions($resolver);
        $resolver->setDefaults([
            'disabled' => false,
        ]);
    }
}
  1. 在类别表单配置中替换原字段类型
    找到Sulu类别表单的配置文件(通常是config/packages/sulu_category.yaml或自定义表单配置),将key字段的类型替换为自定义的CategoryKeyType:
sulu_category:
    forms:
        category:
            fields:
                key:
                    type: App\Form\Type\CategoryKeyType
                    options:
                        label: 'sulu_category.key'
                        required: true

关键补充:后端校验防止非法修改

前端禁用只是界面层面的限制,必须配合后端校验防止通过API或其他方式修改:

在类别实体的preUpdate事件中添加校验:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Sulu\Bundle\CategoryBundle\Entity\Category as BaseCategory;

#[ORM\Entity]
#[ORM\Table(name: 'category')]
class Category extends BaseCategory
{
    #[ORM\PreUpdate]
    public function preUpdate(): void
    {
        // 禁止修改已持久化实体的key字段
        if ($this->getId() && $this->getKey() !== $this->getOriginalKey()) {
            throw new \RuntimeException('Category key cannot be modified after creation.');
        }
    }

    // 获取原始key值
    private function getOriginalKey(): string
    {
        $uow = $this->getEntityManager()->getUnitOfWork();
        $originalData = $uow->getOriginalEntityData($this);
        
        return $originalData['key'] ?? $this->getKey();
    }
}

内容的提问来源于stack exchange,提问作者stollr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 22:20:29