Symfony 4.0.0服务参数连接错误

时间:2018-02-15 09:25:24

标签: php symfony dependency-injection symfony4

我正在制作一个基于FOSU​​serbundle的ProductBundle,但我在使用FormFactory和ProductManager类的服务参数自动装配时遇到了麻烦。

我一直收到错误:

  

无法自动装配服务“App \ Boa \ ProductBundle \ Form \ Factory \ FormFactory”:方法“__construct()”的参数“$ name”必须具有类型提示或明确赋予值。

FormFactory类:

namespace App\Boa\ProductBundle\Form\Factory;

use Symfony\Component\Form\FormFactoryInterface;

class FormFactory implements FactoryInterface
  {
/**
 * @var FormFactoryInterface
 */
private $formFactory;

/**
 * @var string
 */
private $name;

/**
 * @var string
 */
private $type;

/**
 * @var array
 */
private $validationGroups;

/**
 * FormFactory constructor.
 *
 * @param FormFactoryInterface $formFactory
 * @param string               $name
 * @param string               $type
 * @param array                $validationGroups
 */
public function __construct(FormFactoryInterface $formFactory, $name, 
$type, array $validationGroups = null)
{
    $this->formFactory = $formFactory;
    $this->name = $name;
    $this->type = $type;
    $this->validationGroups = $validationGroups;
}

/**
 * {@inheritdoc}
 */
public function createForm(array $options = array())
{
    $options = array_merge(array('validation_groups' => $this->validationGroups), $options);

    return $this->formFactory->createNamed($this->name, $this->type, null, $options);
}
}

create.xml(位于App \ Boa \ ProductBundle \ Resources \ config)

<?xml version="1.0" encoding="UTF-8" ?>

<container xmlns="http://symfony.com/schema/dic/services"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
    <service id="boa_product.create.form.factory" class="App\Boa\ProductBundle\Form\Factory\FormFactory" public="true">
        <argument type="service" id="form.factory" />
        <argument key="$name">%boa_product.create.form.name%</argument>
        <argument key="$type">%boa_product.create.form.type%</argument>
        <argument>%boa_product.create.form.validation_groups%</argument>
    </service>

    <service id="boa_product.create.form.type" class="App\Boa\ProductBundle\Form\Type\CreateFormType">
        <tag name="form.type" alias="boa_product_create" />
        <argument key="$class">%boa_product.model.product.class%</argument>
    </service>

    <service id="boa_product.create.controller" class="App\Boa\ProductBundle\Controller\CreateController" public="true">
        <argument type="service" id="boa_product.create.form.factory" />
        <argument type="service" id="boa_product.product_manager" />
    </service>
</services>

扩展名:

<?php

namespace App\Boa\ProductBundle\DependencyInjection;

use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

class BoaProductExtension extends Extension
{
/**
 * @var array
 */
private static $doctrineDrivers = array(
    'orm' => array(
        'registry' => 'doctrine',
        'tag' => 'doctrine.event_subscriber',
    )
);

public function load(array $configs, ContainerBuilder $container)
{
    $configuration = new Configuration();

    $config = $this->processConfiguration($configuration, $configs);

    $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
    //$Yamlloader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));

    $loader->load('services.xml');

    if ('custom' !== $config['db_driver']) {
        if (isset(self::$doctrineDrivers[$config['db_driver']])) {
            $loader->load('doctrine.xml');
            $container->setAlias('boa_product.doctrine_registry', new Alias(self::$doctrineDrivers[$config['db_driver']]['registry'], false));
        } else {
            $loader->load(sprintf('%s.xml', $config['db_driver']));
        }
        $container->setParameter($this->getAlias().'.backend_type_'.$config['db_driver'], true);
    }

    if (isset(self::$doctrineDrivers[$config['db_driver']])) {
        $definition = $container->getDefinition('boa_product.object_manager');
        $definition->setFactory(array(new Reference('boa_product.doctrine_registry'), 'getManager'));
    }
    $container->setAlias('boa_product.product_manager', new Alias($config['service']['product_manager'], true));
    $container->setAlias('App\Boa\ProductBundle\Model\ProductManagerInterface', new Alias('boa_product.product_manager', true));

    $this->remapParametersNamespaces($config, $container, array(
        '' => array(
            'db_driver' => 'boa_product.storage',
            'model_manager_name' => 'boa_product.model_manager_name',
            'product_class' => 'boa_product.model.product.class',
        ),
    ));

    $this->loadCreate($config['create'], $container, $loader);
}

/**
 * @param array            $config
 * @param ContainerBuilder $container
 * @param array            $namespaces
 */
protected function remapParametersNamespaces(array $config, ContainerBuilder $container, array $namespaces)
{
    foreach ($namespaces as $ns => $map) {
        if ($ns) {
            if (!array_key_exists($ns, $config)) {
                continue;
            }
            $namespaceConfig = $config[$ns];
        } else {
            $namespaceConfig = $config;
        }
        if (is_array($map)) {
            $this->remapParameters($namespaceConfig, $container, $map);
        } else {
            foreach ($namespaceConfig as $name => $value) {
                $container->setParameter(sprintf($map, $name), $value);
            }
        }
    }
}

/*
* @param array            $config
* @param ContainerBuilder $container
* @param array            $map
*/
protected function remapParameters(array $config, ContainerBuilder $container, array $map)
{
    foreach ($map as $name => $paramName) {
        if (array_key_exists($name, $config)) {
            $container->setParameter($paramName, $config[$name]);
        }
    }
}

/**
 * @param array            $config
 * @param ContainerBuilder $container
 * @param XmlFileLoader    $loader
 */
private function loadCreate(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
    $loader->load('create.xml');

    $this->remapParametersNamespaces($config, $container, array(
        'form' => 'boa_product.create.form.%s',
    ));
}
}

因此,在阅读symfony的文档时,由于标量类型无法自动装配,因此获得此异常消息是正常的,但是当我拥有(我认为是)正确的xml文件并且手动连接服务时,我仍然会收到消息它们。

当我更改create.xml文件中的一个键时,例如将键“$ name”更改为“$ example”我收到以下消息:

  

无效服务“boa_product.create.form.factory”:方法“App \ Boa \ ProductBundle \ Form \ Factory \ FormFactory :: __ construct()”没有名为“$ example”的参数。检查您的服务定义。

所以我猜他们必须连接?然后,使用所有参数删除整个服务只会给我相同的旧异常

  

无法自动装配服务“App \ Boa \ ProductBundle \ Form \ Factory \ FormFactory”:方法“__construct()”的参数“$ name”必须具有类型提示或明确赋予值。

所以看起来我的xml根本没有做太多。

我昨天花了整整一天时间尝试一些东西并查找文档,但没有成功。非常感谢您的帮助。

如果您需要更多代码,我很乐意提供代码。

再次感谢!

4 个答案:

答案 0 :(得分:0)

您是否尝试过执行错误消息所说的内容?

  

参数&#34; $ name&#34;方法&#34; __ construct()&#34;必须有一个类型提示或   明确给出一个值

$name$type都没有方法签名中的类型提示。尝试将方法签名更改为:

public function __construct(FormFactoryInterface $formFactory, string $name, string $type, array $validationGroups = null)

修改

另一种可能性是在定义此参数之前,您尝试在服务定义中使用%boa_product.create.form.name% param。

答案 1 :(得分:0)

如果您使用接口,则需要覆盖该接口别名或添加FormFactory的显式定义。

退房:

Working with Interfaces

答案 2 :(得分:0)

boa_product.create.controller 作为服务的定义中,您缺少参数的键属性。尝试:

<service id="boa_product.create.controller" class="App\Boa\ProductBundle\Controller\CreateController" public="true">
    <argument key="$formFactory" type="service" id="boa_product.create.form.factory" />
    <argument key="$productManager" type="service" id="boa_product.product_manager" />
</service>

$ formFactory $ productManager CreateController 构造函数中的参数。

在您的扩展程序中,为 App \ Boa \ ProductBundle \ Model \ ProductManagerInterface 定义别名

$container->setAlias('App\Boa\ProductBundle\Model\ProductManagerInterface', new Alias('boa_product.product_manager', true));

所以我想,你可以删除:

<argument key="$productManager" type="service" id="boa_product.product_manager" />

因为这将是自动装配的。

或者,您可以自动装配,a.k.a。也为 boa_product.create.form.factory 定义 App \ Boa \ ProductBundle \ Form \ Factory \ FactoryInterface 的别名。 how to aurowire services

添加:

<service id="App\Boa\ProductBundle\Form\Factory\FormFactory" alias="boa_product.create.form.factory" />

答案 3 :(得分:0)

我的问题最终得到了解决。我认为这是由于我试验了服务文件,但在测试结果之前没有清除缓存。因此我认为我的服务没有加载(因为结果显然没有改变)。

我最终把我的Bundle放在一个单独的存储库中,并通过composer将它包含在项目中。我还用YAML而不是XML重写了配置文件,因为我觉得它更容易阅读。

这样我就可以更好地控制它的调试,最终我摆脱了错误。

使用服务时最重要的是每次进行更改时都要运行php bin/console cache:clear

感谢您的帮助