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

时间:2016-03-19 16:42:12

标签: php forms symfony

我使用Symfony 2.8.3

我已阅读这些资源:
- How to Create a Custom Form Field Type
- Symfony2: Overriding a built-in field type with a custom field type having the same name
以及其中提到的其他一些。

有必要创建这样的“日期”字段类型,以满足客户的许多参数,包括格式。 这个字段类型(由我创建)必须在项目的任何地方使用,即使在其他包中也是如此。

我创建了一个类:

class DateType extends \Symfony\Component\Form\Extension\Core\Type\DateType {
    // Here I overload the necessary methods
}

在服务中注册:

services:
    #...
    form.type.date:
        class: Application\Symfony\Component\Form\Extension\Core\Type\DateType
        tags:
            - { name: form.type, alias: date }
    #...

并以表格形式使用:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('birthday', 'date', array(
            'widget' => 'single_text',
            'label' => 'form.label.birthday',
            'translation_domain' => $this->translation_domain,
            'required' => true,
            'invalid_message' => 'form.error.birthday',
            'attr' => array(
                'class' => 'datepicker without-error-text',
            ),
            'format' => 'dd-MM-yyyy',
        ));
}

但是这段代码抛出异常:

  

字段类型“Symfony \ Component \ Form \ Extension \ Core \ Type \ DateType”未在服务容器中注册。

这是什么意思,'没有注册'?!!啊,是的,没有注册))。 那是因为我注册了我的字段类型而不是内置类型。

我上面展示的资源之一就如何强制注册客户类型提出了建议。

好的,我们来做吧。

我创建了一个自编译器:

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

在构建主包时使用它:

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

但它仍然不成功。该代码再次引发异常,但这次是不同的:

  

为服务“form.type.date”指定的类型名称与实际名称不匹配。   预期“Symfony \ Component \ Form \ Extension \ Core \ Type \ DateType”,   给定“Application \ Symfony \ Component \ Form \ Extension \ Core \ Type \ DateType”

在研究代码后,我发现Sonata项目抛出了异常 它的不同捆绑。在我的项目中,我使用了Sonata Admin和Sonata Blocks。这些捆绑包无法创建自定义 表单中的日期类型字段。因为他们收到了不同类别的名字。

//vendor\sonata-project\core-bundle\Form\Extension\DependencyInjectionExtension.php
// this block: if ($name !== get_class($type) && (method_exists($type, 'getName') && $type->getName() !== $name)) {...}

/**
 * {@inheritdoc}
 */
public function getType($name)
{
    // resolve code to FQCN
    $name = self::findClass($this->mappingTypes, $name);

    if (!isset($this->typeServiceIds[$name])) {
        throw new InvalidArgumentException(sprintf('The field type "%s" is not registered with the service container.', $name));
    }

    $type = $this->container->get($this->typeServiceIds[$name]);

    if ($name !== get_class($type) && (method_exists($type, 'getName') && $type->getName() !== $name)) {
        throw new InvalidArgumentException(
            sprintf('The type name specified for the service "%s" does not match the actual name. Expected "%s", given "%s"',
                $this->typeServiceIds[$name],
                $name,
                get_class($type)
            ));
    }

    return $type;
}

现在告诉我,我做错了什么。

非常感谢。

0 个答案:

没有答案