dream752614590 2016-03-19 16:42
浏览 58

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

I work with Symfony 2.8.3

I've read these resources:
- How to Create a Custom Form Field Type
- Symfony2: Overriding a built-in field type with a custom field type having the same name
and some other ones wich were mentioned in them.

It's necessary to create such 'date' field type wich would satisfy the customer in many parameters including format. And this field type (created by me) must be used everywhere in the project even in other bundles.

I create a class:

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

Register it in services:

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

and use it in a form:

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

However this code throws an exception:

The field type "Symfony\Component\Form\Extension\Core\Type\DateType" is not registered with the service container.

What does it mean, 'not registered'?!! Ah, yeah, not registered )). That’s because I registered my field type instead of the built-in one.

One of the resources that I've shown above has an advice regarding how to register customer’s type forcedly.

Ok, let’s do it.

I create a self compiler:

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

Use it while building the main bundle:

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

But it’s still unsuccessful. That code throws an exception again but this time it was different:

The type name specified for the service "form.type.date" does not match the actual name. Expected "Symfony\Component\Form\Extension\Core\Type\DateType", given "Application\Symfony\Component\Form\Extension\Core\Type\DateType"

After researching the code I find out that the Sonata Project throws the exception from its different bundles. In my projetct I use Sonata Admin and Sonata Blocks. These bundles can't create custom date type field in their forms. Because they recieve differentt names of classes.

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

And now tell me please what I do wrong.

Thank you very much.

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥120 计算机网络的新校区组网设计
    • ¥20 完全没有学习过GAN,看了CSDN的一篇文章,里面有代码但是完全不知道如何操作
    • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
    • ¥20 海浪数据 南海地区海况数据,波浪数据
    • ¥20 软件测试决策法疑问求解答
    • ¥15 win11 23H2删除推荐的项目,支持注册表等
    • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
    • ¥15 qt6.6.3 基于百度云的语音识别 不会改
    • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
    • ¥15 神经网络怎么把隐含层变量融合到损失函数中?