【问题标题】:Symfony 4.0.0 Services argument wiring errorSymfony 4.0.0 服务参数接线错误
【发布时间】:2018-02-15 09:25:24
【问题描述】:

我正在制作基于 FOSUserbundle 的 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 并没有做太多事情。

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

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

再次感谢!

【问题讨论】:

  • 很确定您需要在服务定义文件中设置 _defaults 才能使自动装配工作。 symfony.com/doc/current/…我自己没试过所以可能是错的。

标签: php symfony dependency-injection symfony4


【解决方案1】:

您是否尝试按照错误消息中的说明进行操作?

方法“__construct()”的参数“$name”必须有类型提示或者是 明确给出一个值

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

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

编辑

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

【讨论】:

  • 您好,感谢您的建议,但是: - 更改构造方法参数只是绕过问题,并不能解决问题。那么你确实没有得到错误,但参数仍然没有传递给构造函数。 - 更改 create.xml 中的顺序不会导致更改。
  • @CharlesV 但是你在哪里定义%boa_product.create.form.name%?如果您将这个$name 参数替换为另一个字符串,例如MyName,它仍然是空的吗?
  • 此参数在扩展类“BoaProductExtension”中设置。即使使用硬编码的字符串,它也会给出相同的错误。
【解决方案2】:

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

退房:

Working with Interfaces

【讨论】:

    【解决方案3】:

    在将 boa_product.create.controller 定义为服务时,您的参数缺少 key 属性。试试:

    <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$productManagerCreateController 的构造函数中的参数。

    在您的扩展程序中,您为 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" />
    

    因为这将是自动装配的。

    或者,您可以自动装配,也就是为 App\Boa\ProductBundle\Form\Factory\FactoryInterface 定义一个别名,也可以为 boa_product.create.form.factoryhow to aurowire services

    添加这个:

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

    【讨论】:

      【解决方案4】:

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

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

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

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

      感谢您的帮助

      【讨论】:

        猜你喜欢
        • 2017-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多