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

Php Symfony2:使用具有相同名称的自定义字段类型重写内置字段类型,php,symfony,symfony-forms,Php,Symfony,Symfony Forms,根据Symfony文档,我创建了一个自定义字段类型,在services.yml中进行了设置,我能够成功地使用它 例如,我创建了一个名为customdate的自定义字段,如下所示,该字段工作正常: # src/Acme/DemoBundle/Resources/config/services.yml services: acme_demo.form.type.date: class: Acme\DemoBundle\Form\Type\DateType ta

根据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
字段类型:

# 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使用内置字段类型而不是我的字段类型)

我应该注意,如果我用手动创建的对象(如
newdate()
)替换“customdate”或“date”,那么它就可以正常工作。问题似乎特别在于Symfony更喜欢其内置字段类型,而不是
services.yml
中指定的字段类型


我的问题:有没有办法用同名的自定义字段类型覆盖内置的Symfony字段类型?显然,从我上面描述的内容来看,Symfony似乎忽略了与内置Symfony字段类型同名的任何自定义字段。有没有办法解决这个问题?

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

但是,如果要覆盖的字段类型未提供您认为应该提供的功能,则该类型可能存在应报告的问题

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

要实现所需的格式
date('dmy')
,您可以使用:

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

要回答第一个问题,有一种方法可以覆盖内置的symfony表单类型。上面的代码几乎是正确的。它只需要使用与symfony中相同的服务id。请参阅并使用相同的服务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());
    }
}

有关更多信息,请参阅和。

出于好奇,为什么要将其命名为相同的名称?为什么使用自定义名称不是一个选项?如果无法覆盖现有字段类型,则使用自定义名称是一个可接受的选择。我之所以希望将其命名为相同的名称,是因为从逻辑上讲,它仍然表示与内置的
date
字段相同类型的数据,因此不需要记住自定义字段的名称,这不会增加认知负担。问题是内置的
date
字段类型在自定义日期格式方面有一定的局限性,正如GitHub上的本期文章所述:从我所知,格式问题已经解决,您尝试使用的格式是什么?举例来说,我需要的格式是2014年1月1日。基本上,如果使用PHP
date()
函数,以下操作:
date('dmy')
将通过
'format'=>'dmmy'
完成。IntlDateFormatter类解析的日期。有趣的是,可以找到有效的格式,尽管您的建议解决了我的特殊要求,但似乎格式选项中仍然存在限制,即仅限于d、M和y的组合,而不是您提供的链接中记录的全部符号范围(这与Symfony docs指向的参考相同)。尝试使用任何其他符号会导致引发InvalidoOptions异常。请参阅:完整的符号范围还包括时间,您将使用
datetime
来表示时间。您是否有另一个它不支持的特定示例?啊,是的,您是对的。其他符号确实有效。我提供的GitHub链接仅显示“d”、“d”M',和“y”是明确无误所需的最小符号。
// 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());
    }
}