PrestaShop 1.7:如何优雅重写Symfony表单约束以将商品名称字段长度扩展至300字符
优雅修改PrestaShop商品名称字符长度限制的方案
需求与当前临时处理
我需要把商品名称的字段长度上限从默认的128字符提升到300字符。目前已经通过直接修改核心文件实现了功能:在src/PrestaShopBundle/Form/Admin/Product/ProductInformation.php里,找到商品名称的表单定义,把Assert\Length约束的max值从128改成300。
原代码片段:
->add('name', TranslateType::class, [ 'type' => FormType\TextType::class, 'options' => [ 'constraints' => [ new Assert\Regex([ 'pattern' => '/[<>=#{}]/', 'match' => false, ]), new Assert\NotBlank(), new Assert\Length(['min' => 3, 'max' => 128]), ], ], ])
修改后代码:
->add('name', TranslateType::class, [ 'type' => FormType\TextType::class, 'options' => [ 'constraints' => [ new Assert\Regex([ 'pattern' => '/[<>=#{}]/', 'match' => false, ]), new Assert\NotBlank(), new Assert\Length(['min' => 3, 'max' => 300]), ], ], ])
功能是正常的,但问题很明显——直接改核心文件的话,下次PrestaShop版本更新时,这个修改肯定会被覆盖,所以得找个不用碰核心代码的优雅办法。另外我已经在官方仓库提交了PR,现在等着官方回复呢。
两种优雅的替代方案
方案1:用表单事件监听器动态修改约束
这种方式是通过订阅表单事件,在表单构建的时候动态调整字段的约束条件,完全不用修改核心文件:
- 先在你的自定义模块里创建一个事件订阅者类,比如
src/YourModule/EventListener/ProductFormModifierListener.php:
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Validator\Constraints\Length; class ProductFormModifierListener implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ FormEvents::PRE_SET_DATA => 'preSetData', ]; } public function preSetData(FormEvent $event) { $form = $event->getForm(); $nameField = $form->get('name'); if (!$nameField) { return; } // 获取字段当前的约束配置 $constraints = $nameField->getConfig()->getOption('constraints'); // 遍历找到Length约束,修改max值 foreach ($constraints as &$constraint) { if ($constraint instanceof Length) { $constraint->max = 300; } } // 更新字段的约束选项 $nameField->setOption('constraints', $constraints); } }
- 然后在模块的
services.yml里注册这个订阅者:
services: your_module.product_form_modifier: class: YourModule\EventListener\ProductFormModifierListener tags: - { name: kernel.event_subscriber }
方案2:重写商品信息表单类型
利用PrestaShop的服务重写机制,创建一个自定义的表单类型来覆盖核心的ProductInformationType:
- 在模块里创建
src/YourModule/Form/Admin/Product/ProductInformationType.php:
use PrestaShopBundle\Form\Admin\Product\ProductInformationType as BaseProductInformationType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\Length; class ProductInformationType extends BaseProductInformationType { public function buildForm(FormBuilderInterface $builder, array $options) { // 先调用父类方法构建原始表单 parent::buildForm($builder, $options); // 获取name字段的配置信息 $nameFieldConfig = $builder->get('name')->getConfig(); $fieldOptions = $nameFieldConfig->getOptions(); // 找到Length约束并修改max值 foreach ($fieldOptions['constraints'] as &$constraint) { if ($constraint instanceof Length) { $constraint->max = 300; } } // 重新添加name字段,应用修改后的配置 $builder->add('name', get_class($nameFieldConfig->getType()->getInnerType()), $fieldOptions); } }
- 在模块的
config/services.yml里配置服务重写:
services: prestashop.form.admin.product.information: class: YourModule\Form\Admin\Product\ProductInformationType parent: prestashop.form.admin.product.information public: true tags: - { name: form.type }
这两种方案都是基于自定义模块实现的,完全独立于核心代码,PrestaShop版本更新的时候根本不会影响到你的修改,完美解决了被覆盖的问题。
内容的提问来源于stack exchange,提问作者Louis Bertin
相关产品推荐
相关产品推荐

