问题
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