Symfony2: переопределение встроенного типа поля с настраиваемым типом поля с тем же именем

В соответствии с этой статьей в документах Symfony я создал настраиваемый тип поля, настроил его в services.yml , и я могу использовать его успешно.

Например, я создаю собственное поле с именем customdate следующим образом, которое отлично работает:

 # src/Acme/DemoBundle/Resources/config/services.yml services: acme_demo.form.type.date: class: Acme\DemoBundle\Form\Type\DateType tags: - { name: form.type, alias: customdate } 

Однако, если я попытаюсь назвать свое настраиваемое поле как date (это то же самое, что и существующий тип поля Symfony , так как это то, что я пытаюсь переопределить), как показано ниже, тогда Symfony полностью игнорирует мое настраиваемое поле и по умолчанию вместо этого используется встроенный тип поля date Symfony:

 # src/Acme/DemoBundle/Resources/config/services.yml services: acme_demo.form.type.date: class: Acme\DemoBundle\Form\Type\DateType tags: - { name: form.type, alias: date } 

Я проверил, что моя getName() возвращает правильное имя, совпадающее с псевдонимом, который я предоставил в services.yml .

Ниже приведен код, в котором я использую вышеуказанные услуги.

Это работает:

 public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('date', 'customdate'))); } 

Это не работает: (или, скорее, Symfony использует встроенный тип поля вместо моего)

 public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('date', 'date'))); } 

Я должен отметить, что если я заменил «customdate» или «date» на созданный вручную объект, такой как new Date() тогда он отлично работает. Проблема заключается в том, что Symfony предпочитает свои встроенные типы полей над теми, которые указаны в services.yml .

Мой вопрос: есть ли способ переопределить встроенные типы полей Symfony с настраиваемыми типами полей, которые имеют одинаковое имя? Очевидно, что из того, что я описал выше, Symfony, похоже, игнорирует любые настраиваемые поля, которые сглажены с тем же именем, что и встроенный тип поля Symfony. Есть ли способ обойти это?

Насколько я знаю, нет способа действительно переопределить типы базового поля, вы можете наследовать их и использовать свое собственное имя.

Однако, если тип поля, который вы хотите переопределить, не обеспечивает функциональность, которая, по вашему мнению, должна быть проблемой с этим типом, о котором следует сообщить.

Для вашего случая тип даты не принимает типичную строку формата php date (). Изучая документацию, мы видим, что формат даты анализируется классом IntlDateFormatter. Для правильных форматов ознакомьтесь с этим списком .

Чтобы выполнить формат, который вам нужен, date('d M Y') вы должны использовать:

 $builder->add('my_date_field', 'date', array( 'format'=>'d MMM Y' )); 

Чтобы ответить на первый вопрос, есть способ переопределить встроенные типы форм symfony. Вышеприведенный код почти правильный. Просто нужно использовать тот же идентификатор службы, что и в symfony. См. Конфигурацию службы Symfony и используйте один и тот же служебный идентификатор:

 # src/Acme/DemoBundle/Resources/config/services.yml services: form.type.date: class: Acme\DemoBundle\Form\Type\DateType tags: - { name: form.type, alias: date } 

Я протестировал это и, похоже, работает нормально. Acme\DemoBundle\Form\Type\DateType должен расширять класс Symfony\Component\Form\Extension\Core\Type\DateType с любыми изменениями. Это можно сделать с помощью любого типа формы Symfony.

Другой подход несколько более сложный, но более надежное будущее – это использование прошивки для изменения класса определения службы, но остальное без изменений. Это выглядит как:

 //src/Acme/DemoBundle/DependencyInjection/Compiler/OverrideServiceCompilerPass.php namespace Acme\DemoBundle\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; class OverrideServiceCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { $definition = $container->getDefinition('form.type.date'); $definition->setClass('Acme\DemoBundle\Form\Type\DateType'); } } как //src/Acme/DemoBundle/DependencyInjection/Compiler/OverrideServiceCompilerPass.php namespace Acme\DemoBundle\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; class OverrideServiceCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { $definition = $container->getDefinition('form.type.date'); $definition->setClass('Acme\DemoBundle\Form\Type\DateType'); } } 

то пропуск компилятора зарегистрирован в классе AcmeDemoBundle, например;

 // src/Acme/DemoBundle/AcmeDemoBundle.php namespace Acme\DemoBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; use Acme\DemoBundle\DependencyInjection\Compiler\OverrideServiceCompilerPass; class AcmeDemoBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass(new OverrideServiceCompilerPass()); } } 

Дополнительную информацию см. В разделе « Предоставление дополнительных документов doc и компилятора» .