Symfony2:使用具有相同名称的自定义字段类型覆盖内置字段类型

时间:2014-03-26 21:18:23

标签: php symfony symfony-forms

根据Symfony文档中的this article,我已经创建了一个自定义字段类型,在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(与an existing Symfony field type相同,因为这是我试图覆盖的内容),如下所示,那么Symfony完全忽略我的自定义字段,默认为内置的Symfony date字段类型:

# 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字段类型别名相同的自定义字段。有没有办法解决这个问题?

2 个答案:

答案 0 :(得分:1)

据我所知,无法真正覆盖基本字段类型,您可以继承它们并使用自己的名称。

但是,如果您要覆盖的字段类型未提供您认为应该报告的类型的功能,那么应该报告该类型的问题。

对于您的情况,日期类型不采用典型的php date()格式字符串。通过查看文档 here ,我们看到日期格式由IntlDateFormatter类解析。有效格式请查看 this list

要完成您想要使用的格式date('d M Y')

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

答案 1 :(得分:0)

要回答第一个问题,有一种方法可以覆盖内置的symfony表单类型。上面的代码几乎是正确的。它只需要使用与symfony中使用的相同的服务ID。请参阅Symfony service config并使用相同的服务ID:

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

然后编译器传递在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());
    }
}

有关详细信息,请参阅overriding services doccompiler pass doc