Rey*_*rPM 5 php dependency-injection symfony symfony-3.3 symfony3.x
我正在将Symfony 3.2项目移植到Symfony 3.3,我想使用DI新功能.我已经阅读了文档,但到目前为止我可以使这个工作.请参阅以下类定义:
use Http\Adapter\Guzzle6\Client;
use Http\Message\MessageFactory;
abstract class AParent
{
protected $message;
protected $client;
protected $api_count_url;
public function __construct(MessageFactory $message, Client $client, string $api_count_url)
{
$this->message = $message;
$this->client = $client;
$this->api_count_url = $api_count_url;
}
public function getCount(string $source, string $object, MessageFactory $messageFactory, Client $client): ?array
{
// .....
}
abstract public function execute(string $source, string $object, int $qty, int $company_id): array;
abstract protected function processDataFromApi(array $entities, int $company_id): array;
abstract protected function executeResponse(array $rows = [], int $company_id): array;
}
class AChildren extends AParent
{
protected $qty;
public function execute(string $source, string $object, int $qty, int $company_id): array
{
$url = $this->api_count_url . "src={$source}&obj={$object}";
$request = $this->message->createRequest('GET', $url);
$response = $this->client->sendRequest($request);
}
protected function processDataFromApi(array $entities, int $company_id): array
{
// ....
}
protected function executeResponse(array $rows = [], int $company_id): array
{
// ....
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的app/config/services.yml
文件的样子:
parameters:
serv_api_base_url: 'https://url.com/api/'
services:
_defaults:
autowire: true
autoconfigure: true
public: false
CommonBundle\:
resource: '../../src/CommonBundle/*'
exclude: '../../src/CommonBundle/{Entity,Repository}'
CommonBundle\Controller\:
resource: '../../src/CommonBundle/Controller'
public: true
tags: ['controller.service_arguments']
# Services that need manually wiring: API related
CommonBundle\API\AParent:
arguments:
$api_count_url: '%serv_api_base_url%'
Run Code Online (Sandbox Code Playgroud)
但是我收到以下错误:
AutowiringFailedException无法自动装配服务"CommonBundle\API\AChildren":方法"__construct()"的参数"$ api_count_url"必须具有类型提示或显式赋予值.
当然我在这里遗漏了一些东西,或者仅仅这是不可能的,这导致我接下来的问题:这是一个糟糕的OOP设计还是Symfony 3.3 DI功能缺少的功能?
当然我不想让AParent
类成为接口,因为我不想重新定义实现这种接口的类的方法.
此外,我不想重复自己,并在孩子们身上复制/粘贴相同的功能.
想法?线索?建议吗?这可能吗?
UPDATE
阅读" 如何使用父服务管理常见依赖关系 "后,我在我的方案中尝试了以下内容:
CommonBundle\API\AParent:
abstract: true
arguments:
$api_count_url: '%serv_api_base_url%'
CommonBundle\API\AChildren:
parent: CommonBundle\API\AParent
arguments:
$base_url: '%serv_api_base_url%'
$base_response_url: '%serv_api_base_response_url%'
Run Code Online (Sandbox Code Playgroud)
但错误变成:
当设置"父"时,服务"CommonBundle\API\AChildren"上的属性"autowire"不能从"_defaults"继承.将您的子定义移动到单独的文件或在/var/www/html/oneview_symfony/app/config/services.yml中显式定义此属性(从"/ var/www/html/oneview_symfony/app/config /导入" config.yml").
但是,我可以使用以下设置:
CommonBundle\API\AParent:
arguments:
$api_count_url: '%serv_api_base_url%'
CommonBundle\API\AChildren:
arguments:
$api_count_url: '%serv_api_base_url%'
$base_url: '%serv_api_base_url%'
$base_response_url: '%serv_api_base_response_url%'
Run Code Online (Sandbox Code Playgroud)
这是正确的方法吗?这有道理吗?
更新#2
按照@Cerad说明我做了几个mod(参见上面的代码,看下面的定义),现在对象来了NULL
吗?任何想法为什么会这样?
// services.yml
services:
CommonBundle\EventListener\EntitySuscriber:
tags:
- { name: doctrine.event_subscriber, connection: default}
CommonBundle\API\AParent:
abstract: true
arguments:
- '@httplug.message_factory'
- '@httplug.client.myclient'
- '%ser_api_base_url%'
// services_api.yml
services:
CommonBundle\API\AChildren:
parent: CommonBundle\API\AParent
arguments:
$base_url: '%serv_api_base_url%'
$base_response_url: '%serv_api_base_response_url%'
// config.yml
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: services.yml }
- { resource: services_api.yml }
Run Code Online (Sandbox Code Playgroud)
为什么对象NULL
在子类中?
有趣的。看来您希望自动装配了解 AChild 扩展 AParent,然后使用 AParent 服务定义。我不知道这种行为是否被故意忽略或不受设计支持。autowire 仍处于起步阶段并正在大力开发中。
我建议前往 di github 存储库,检查问题,然后打开一个(如果适用)。开发人员会让您知道这是否是设计使然。
同时,如果您将子定义移至不同的服务文件,则可以使用父服务功能。它会起作用,因为 _defaults 内容仅适用于当前服务文件。
# services.yml
AppBundle\Service\AParent:
abstract: true
arguments:
$api_count_url: '%serv_api_base_url%'
# services2.yml NOTE: different file, add to config.yml
AppBundle\Service\AChild:
parent: AppBundle\Service\AParent
arguments:
$base_url: 'base url'
Run Code Online (Sandbox Code Playgroud)
最后一个稍微离题的注释:没有必要 public: false 除非你胡闹自动配置的东西。默认情况下,所有服务都被定义为私有的,除非您明确声明它们是公共的。
更新 - 评论提到了有关对象为空的一些内容。不太确定这意味着什么,但我去向我的测试类添加了一个记录器。所以:
use Psr\Log\LoggerInterface;
abstract class AParent
{
protected $api_count_url;
public function __construct(
LoggerInterface $logger,
string $api_count_url)
{
$this->api_count_url = $api_count_url;
}
}
class AChild extends AParent
{
public function __construct(LoggerInterface $logger,
string $api_count_url, string $base_url)
{
parent::__construct($logger,$api_count_url);
}
Run Code Online (Sandbox Code Playgroud)
由于只有一种 psr7 记录器实现,因此记录器会自动装配和注入,而无需更改服务定义。
更新 2 我更新到 S3.3.8 并开始获得:
[Symfony\Component\DependencyInjection\Exception\RuntimeException]
Invalid constructor argument 2 for service "AppBundle\Service\AParent": argument 1 must be defined before. Check your service definition.
Run Code Online (Sandbox Code Playgroud)
Autowire 仍在大力开发中。此时不会花精力去找出原因。与参数的顺序有关。LTS 版本发布后我会再次访问。
归档时间: |
|
查看次数: |
2933 次 |
最近记录: |