如何在Sulu管理前端实体持久化后禁用类别Key表单字段?
在Sulu CMS中实现类别Key持久化后不可修改的方案
要实现Sulu后台中类别Key在实体创建后不可修改,有两种可靠的方案,兼顾前端表单禁用和后端校验:
方案一:通过表单事件动态禁用字段
利用Sulu的表单事件系统,在表单加载时根据实体状态(是否已持久化)动态设置字段禁用属性:
- 创建表单事件订阅者
<?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); } } } }
- 注册订阅者
在services.yaml中配置:
App\Form\Subscriber\CategoryFormSubscriber: tags: - { name: kernel.event_subscriber }
方案二:自定义字段类型(更灵活的全局控制)
如果需要在多个场景复用这个逻辑,可以自定义字段类型:
- 创建自定义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, ]); } }
- 在类别表单配置中替换原字段类型
找到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
相关产品推荐
相关产品推荐

