Symfony2: Overriding a built-in field type with a custom field type having the same name

一曲冷凌霜 提交于 2020-01-24 15:19:09

问题


As per this article on the Symfony docs, I've created a custom field type, set it up in services.yml, and I am able to use it successfully.

For example, I create a custom field named customdate as follows, which works perfectly:

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

However, if I try to name my custom field as date (which is the same as an existing Symfony field type, since this is what I am trying to override), as shown below, then Symfony completely ignores my custom field, and defaults to the built-in Symfony date field type instead:

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

I've checked that my getName() function returns the correct name, matching up with the alias I provided in services.yml.

The code in which I make use of the above services follows below.

This works:

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

This does not work: (or rather, Symfony uses the built-in field type instead of mine)

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

I should note that if I replace the 'customdate' or 'date' with a manually-created object such as new Date() then it works fine. The problem appears to be specifically that Symfony prefers its built-in field types over the ones that are specified in services.yml.

My question: is there any way to override built-in Symfony field types with custom field types that have the same name? Clearly, from what I described above, Symfony appears to ignore any custom fields that are aliased to the same name as a built-in Symfony field type. Is there any way around this?


回答1:


As far as i know there is no way to truly override the base field types, you can inherit them and use your own name.

However if the field type that you want to override is not providing the functionality you think it should there is likely an issue with that type that should be reported.

For your case the date type doesnt take typical php date() format string. From looking at the documentation here we see that the date format is parsed by the IntlDateFormatter class. For valid formats check out this list.

To accomplish the format you want date('d M Y') you would use:

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



回答2:


To answer the first question there is a way to override the built in symfony form types. The above code is almost correct. It just needs to use the same service id as used in symfony. See the Symfony service config and use the same service id:

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

I've tested this and seems to work fine. Acme\DemoBundle\Form\Type\DateType should extend the symfony class Symfony\Component\Form\Extension\Core\Type\DateType with whatever changes are needed. This can be done with any Symfony form type.

Another approach slightly more complicated but more future proof is using a complier pass to change the class of the service definition but leave the rest unchanged. It looks like:

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

then the compiler pass is registered in the AcmeDemoBundle class like;

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

See overriding services doc and compiler pass doc for more information.



来源:https://stackoverflow.com/questions/22673275/symfony2-overriding-a-built-in-field-type-with-a-custom-field-type-having-the-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!