【问题标题】:Symfony2: Overriding a built-in field type with a custom field type having the same nameSymfony2:使用具有相同名称的自定义字段类型覆盖内置字段类型
【发布时间】:2014-03-26 21:18:22
【问题描述】:

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

【问题讨论】:

  • 出于好奇,为什么要将它命名为相同的东西?为什么不使用自定义名称?
  • 如果无法覆盖现有字段类型,则可以使用自定义名称。我喜欢将其命名为相同的原因是,从逻辑上讲,它仍然表示与内置 date 字段相同类型的数据,因此不会增加认知负担记住自定义字段的名称。问题是内置的 date 字段类型在自定义日期格式方面有些限制,如 GitHub 上的此问题所述:github.com/symfony/symfony/issues/8345
  • 据我所知,格式问题已得到修复,您尝试使用什么格式却不让您使用?
  • 我需要的格式,例如,2014 年 1 月 1 日。基本上,如果使用 PHP date() 函数,则如下:date('d M Y')
  • 这将通过'format'=>'d MMM Y' 完成。由 IntlDateFormatter 类解析的日期。可以找到有效格式here

标签: php symfony symfony-forms


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 有趣的是,虽然你的建议解决了我的特殊要求,但格式选项似乎仍然存在限制,即仅限于 d、M 和 y 的组合,而不是全部范围您提供的链接中记录的符号(这与 Symfony 文档指向的引用相同)。尝试使用任何其他符号会导致引发 InvalidOptionsException。见:github.com/symfony/symfony/commit/…
  • 全部符号范围还包括时间,您可以使用datetime 表示。您还有其他不支持的具体示例吗?
  • 啊,是的,你是对的。其他符号确实有效。我提供的 GitHub 链接仅表明“d”、“M”和“y”是明确的最低要求符号。
【解决方案2】:

要回答第一个问题,有一种方法可以覆盖内置的 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 了解更多信息。

【讨论】:

    猜你喜欢
    • 2014-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-17
    • 1970-01-01
    • 2012-03-13
    相关资源
    最近更新 更多