Symfony2: anulando un tipo de campo incorporado con un tipo de campo personalizado con el mismo nombre

Según este artículo sobre los documentos de Symfony, he creado un tipo de campo personalizado, lo configuré en services.yml y puedo usarlo con éxito.

Por ejemplo, creo un campo personalizado llamado customdate siguiente manera, que funciona perfectamente:

 # 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 } 

Sin embargo, si trato de nombrar mi campo personalizado como date (que es lo mismo que un tipo de campo de Symfony existente , ya que esto es lo que bash anular), como se muestra a continuación, Symfony ignora por completo mi campo personalizado, y se predetermina a el tipo de campo de date Symfony incorporado en su lugar:

 # 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 } 

Comprobé que mi función getName() devuelve el nombre correcto, coincidiendo con el alias que proporcioné en services.yml .

El código en el que hago uso de los servicios anteriores sigue a continuación.

Esto funciona:

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

Esto no funciona: (o mejor dicho, Symfony usa el tipo de campo incorporado en lugar del mío)

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

Debo señalar que si reemplazo la ‘fecha personalizada’ o ‘fecha’ con un objeto creado manualmente tal como una new Date() entonces funciona bien. El problema parece ser específicamente que Symfony prefiere sus tipos de campo integrados sobre los que se especifican en services.yml .

Mi pregunta: ¿hay alguna manera de anular los tipos de campo de Symfony incorporados con tipos de campos personalizados que tienen el mismo nombre? Claramente, por lo que describí anteriormente, Symfony parece ignorar cualquier campo personalizado que tenga un alias con el mismo nombre que un tipo de campo incorporado de Symfony. ¿Hay alguna forma de evitar esto?

Por lo que sé, no hay forma de anular verdaderamente los tipos de campo base, puede heredarlos y usar su propio nombre.

Sin embargo, si el tipo de campo que desea sobrescribir no proporciona la funcionalidad que usted considera que debería existir, es probable que exista un problema con ese tipo que deba informarse.

Para su caso, el tipo de fecha no toma la cadena de formato php date () típica. Al mirar la documentación aquí , vemos que el formato de fecha es analizado por la clase IntlDateFormatter. Para formatos válidos, revisa esta lista .

Para lograr el formato que desea date('d M Y') , debe usar:

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

Para responder a la primera pregunta, hay una manera de anular los tipos de formularios incorporados de Symfony. El código anterior es casi correcto. Solo necesita usar el mismo ID de servicio que se usa en Symfony. Vea la configuración del servicio de Symfony y use la misma identificación de servicio:

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

Lo he probado y parece funcionar bien. Acme\DemoBundle\Form\Type\DateType debería extender la clase Symfony\Component\Form\Extension\Core\Type\DateType con los cambios que sean necesarios. Esto se puede hacer con cualquier tipo de formulario Symfony.

Otro enfoque un poco más complicado pero más a prueba de futuro es usar un pase de comstackción para cambiar la clase de la definición del servicio, pero dejar el rest sin cambios. Parece que:

 //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'); } } 

luego el comstackdor se registra en la clase AcmeDemoBundle como;

 // 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()); } } 

Para obtener más información, consulte el servicio de documentos primarios y el documento de paso del comstackdor .