webiny/service-manager

Webiny 服务管理组件

v1.6.1 2017-09-29 08:12 UTC

README

安装组件

安装组件的最佳方式是使用 Composer。

composer require webiny/service-manager

要查看该软件包的其他版本,请访问Packagist 页面

用法

可用的服务配置参数包括

  • Arguments (对象 & ObjectArguments
  • 抽象
  • 调用
  • 作用域

对于工厂服务,额外的参数是

  • Factory - 类或服务
  • Static (可选)- 默认为 TRUE,表示在 Factory 对象上以静态方式调用 Method
  • Method - 在 Factory 对象上调用的方法
  • MethodArguments (可选)- Method 的参数

有两种可能的作用域类型

  • container (默认)- 只创建一个服务实例,并在每次服务请求时重复使用
  • prototype - 每次请求服务时创建一个新的服务实例

服务定义

要注册服务,您需要创建一个服务配置对象(使用 ConfigObject 类)并将其传递给 ServiceManager

您可以在 YAML 中创建配置文件,或者使用纯 PHP 直接构建数组。如果使用 PHP,请调用 new ConfigObject($configArray) 来构建适当的配置对象。如果使用 YAML,请调用 $config = Config::getInstance()->yaml($pathToYourConfigFile);

基本服务定义仅包含 Class 参数

$config = [
    'Class' => '\My\Service\Class'
];

ServiceManager::getInstance()->registerService('MyService', new ConfigObject($config));

// Now get your service
$myService = ServiceManager::getInstance()->getService('MyService');

您可以通过创建服务定义数组并将其注册为组来逻辑上分组您的服务

$config = [
    'MyLogger' => [
        'Class' => '\My\Service\Class'
    ],
    'MyMailer' => [
        'Class' => '\My\Mailer\Class'
    ]
];

ServiceManager::getInstance()->registerServices('MyServiceGroup', new ConfigObject($config));

// Now get your specific service
$myMailer = ServiceManager::getInstance()->getService('MyServiceGroup.MyMailer');

构造函数参数

您可以通过使用 Arguments 参数向您的服务类提供构造函数参数。参数可以是任何值,包括类名(它将被实例化并作为 PHP 对象传递给构造函数)以及对另一个服务的引用(使用 @ 字符输入服务引用)

$config = [
    'Class' => '\My\Service\Class'
    'Arguments' => ['FirstArgument', [1,2,3], '\This\Class\Will\Be\Instantiated', '@someOtherService']
];

如果您需要向您的参数类或服务提供构造函数参数,您将需要使用扩展参数语法(以下是一个 YAML 编写的配置示例)

Class: \My\Service\Class
Arguments:
    name: FirstArgument
    ids: [1,2,3]
    some_instance:
        Object: \This\Class\Will\Be\Instantiated
        ObjectArguments: [Name, Y-m-d]
    some_service:
        Object: @some.other.service
        ObjectArguments: [Name]

从 YAML 配置文件创建服务

要从您的 YAML 文件创建 ConfigObject 并注册新的服务,只需调用

$config = Config::getInstance()->yaml($pathToYourConfigFile);
ServiceManager::getInstance()->registerService('MyNewService', $config);

服务对象方法调用

如果您需要在您的服务实例上调用某些方法,您可以使用 Calls 参数指定它们

Class: \My\Service\Class
Arguments: [FirstArgument, [1,2,3], \This\Class\Will\Be\Instantiated, @some.other.service]
Calls:
    - [yourMethod]
    - [yourMethodWithArguments, [Arg1, 123]]
    - [yourMethodWithClassArgument, [\Some\Class\That\Will\Be\Instantiated]]
    - [yourMethodWithServiceArgument, [@some_service]]

抽象服务和参数

服务管理器还支持抽象服务。当您有两个或更多具有类似功能的服务时,您可以提取共同的内容到一个抽象服务中。在下面的示例中,我们还使用了 Parameters。参数就像变量一样,定义一次,需要时重复使用。

参数配置文件

# Definition of parameters
logger.class: \Webiny\Component\Logger\Logger
logger.driver.class: \Webiny\Component\Logger\Drivers\Webiny
logger.handler.udp.class: \Webiny\Component\Logger\Drivers\Webiny\Handlers\UDPHandler

注意:目前,参数不能在 ObjectArguments 中使用。

服务配置文件(这也可以定义为纯 PHP 数组)

UdpHandler:
    Class: %logger.handler.udp.class%
TrayLoggerAbstract:
    Abstract: true
    Class: %logger.class%
    Calls:
      - [addHandler, [@UdpHandler]]
WebinySystem:
    Parent: @TrayLoggerAbstract
    Arguments: [System, %logger.driver.class%]
WebinyEcommerce:
    Parent: @TrayLoggerAbstract
    Arguments: [Ecommerce, %logger.driver.class%]

现在我们需要使用 ServiceManager 注册参数和服务

// Registering multiple parameters at once
$parameters = Config::getInstance()->yaml($pathToYourParametersConfigFile);
ServiceManager::getInstance()->registerParameters($parameters);

// Registering one parameter
ServiceManager::getInstance()->registerParameter('someClassName', '\Webiny\Some\Class\Name');

// Registering your services
$servicesConfig = Config::getInstance()->yaml($pathToYourServicesConfigFile);
ServiceManager::getInstance()->registerServices('Logger', new ConfigObject($servicesConfig));

在这个例子中,我们定义了一个抽象服务 TrayLoggerAbstract 和两个扩展该抽象服务的真实日志器,WebinySystemWebinyEcommerce。这两个日志器具有相同的类和方法调用,但构造函数参数不同。

您还可以在抽象类中指定参数,然后在实际类中覆盖它们。此外,您还可以从子服务中添加更多方法调用。

# Services
UdpHandler:
    Class: %logger.handler.udp.class%
TrayLoggerAbstract:
    Abstract: true
    Class: %logger.class%
    Arguments: [Default, %logger.driver.class%]
    Calls:
      - [addHandler, [@UdpHandler]]
WebinySystem:
    Parent: @TrayLoggerAbstract
    Calls:
    - [setSomething, [someParameter]]
WebinyEcommerce:
    Parent: @TrayLoggerAbstract
    Arguments: [Ecommerce, %logger.driver.class%]

在这个最后一个例子中,WebinySystem 服务将使用父服务的参数进行构建,并且还会添加一个额外的方法调用。WebinyEcommerce 将为其父构造函数提供自己的参数,并将继承父的 Calls

如果您需要替换 Calls 参数中的方法,请在调用定义中使用索引指定第三个参数,以替换方法。在以下示例中,子方法 setSomething 将替换索引为 0 的父方法,即 addHandler

UdpHandler:
    Class: %logger.handler.udp.class%
TrayLoggerAbstract:
    Abstract: true
    Class: %logger.class%
    Arguments: [Default, %logger.driver.class%]
    Calls:
      - [addHandler, [@UdpHandler]]
WebinySystem:
    Parent: @TrayLoggerAbstract
    Calls:
    - [setSomething, [someParameter], 0]

如果您想替换所有父 Calls,请在 Calls 键前加上感叹号,使其看起来像这样 - !Calls

UdpHandler:
    Class: %logger.handler.udp.class%
TrayLoggerAbstract:
    Abstract: true
    Class: %logger.class%
    Arguments: [Default, %logger.driver.class%]
    Calls:
      - [addHandler, [@UdpHandler]]
WebinySystem:
    Parent: @TrayLoggerAbstract
    !Calls:
    - [setSomething, [someParameter]]

在这种情况下,子服务的 Calls 将完全替换父 Calls

通过 PHP 访问服务

要在您的代码中使用 ServiceManager,最简单的方法是简单地使用 ServiceManagerTrait。这将使您能够访问 $this->service()

class YourClass{
    use ServiceManagerTrait;
    
    public function yourMethod(){
        $service = $this->service('YourServiceName');
    }
}

如果您确实需要直接访问 ServiceManager 类,请按照以下方式使用它

ServiceManager::getInstance()->getService('YourServiceName')

通过标签访问服务

您可以使用标签对服务进行分组,并使用单个调用加载所有相关服务。要实现这一点,您需要将 tags 键添加到服务配置中。

WebinySystem:
    Parent: @TrayLoggerAbstract
    !Calls:
    - [setSomething, [someParameter]]
    Tags: [logger]
WebinyCustom:
    Parent: @TrayLoggerAbstract
    Tags: [logger, custom_logger]

现在执行以下代码。结果将是一个包含两个服务(WebinySystemWebinyCustom)的数组。

class YourClass{
    use ServiceManagerTrait;
    
    public function yourMethod(){
        $services = $this->servicesByTag('logger');
    }
}

您还可以告诉 ServiceManager 使用给定的接口或类名过滤服务。它首先检索包含请求标签的所有服务,然后使用给定的类或接口名称过滤它们,最后将最终结果集返回给您。这样,您可以确保只获取所需的内容,而无需自己进行检查,从而产生更简洁的代码。

class YourClass{
    use ServiceManagerTrait;
    
    public function yourMethod(){
        $services = $this->servicesByTag('cms_plugin', '\Your\Expected\Class\Or\Interface');
    }
}

资源

要运行单元测试,您需要使用以下命令

$ cd path/to/Webiny/Component/ServiceManager/
$ composer.phar install
$ phpunit