mnapoli/fluent-symfony

0.1.6 2017-04-22 11:24 UTC

This package is auto-updated.

Last update: 2024-09-19 20:56:05 UTC


README

Build Status

此包为Symfony容器提供了一种替代配置语法,灵感来源于PHP-DI的配置

为什么?

主要目标是利用PHP引擎和IDEs进行更严格的分析。如果您感兴趣,也可以阅读为什么YAML在PHP-DI 5中被类似语法取代

  • 类或常量的自动补全

  • 编写配置时的自动补全

  • 在IDE中进行实时验证

  • 常量支持

  • 更好的重构支持

与现有格式的比较

目前,在Symfony中,您可以使用以下方式配置容器

  • YAML

    parameters:
        mailer.transport: sendmail
    
    services:
        mailer:
            class:     Mailer
            arguments: ['%mailer.transport%']
  • XML

    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="https://symfony.ac.cn/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://symfony.ac.cn/schema/dic/services https://symfony.ac.cn/schema/dic/services/services-1.0.xsd">
    
        <parameters>
            <parameter key="mailer.transport">sendmail</parameter>
        </parameters>
    
        <services>
            <service id="mailer" class="Mailer">
                <argument>%mailer.transport%</argument>
            </service>
        </services>
    </container>
  • PHP代码

    $container->setParameter('mailer.transport', 'sendmail');
    $container
        ->register('mailer', 'Mailer')
        ->addArgument('%mailer.transport%');

使用此包,您现在可以使用第四种选择

return [
    'mailer.transport' => 'sendmail',

    'mailer' => create(Mailer::class)
        ->arguments('%mailer.transport%'),
];

安装

composer require mnapoli/fluent-symfony

要在一个Symfony全栈应用中启用新格式,只需在app/AppKernel.php中导入EnableFluentConfig特质,例如

<?php

use Fluent\EnableFluentConfig;
use Symfony\Component\HttpKernel\Kernel;
// ...

class AppKernel extends Kernel
{
    use EnableFluentConfig;

    // ...
}

现在您可以

  • 用“fluent”语法编写所有配置,为此,将AppKernel更改为加载.php文件而不是.yml

    class AppKernel extends Kernel
    {
        use EnableFluentConfig;
    
        // ...
    
        public function registerContainerConfiguration(LoaderInterface $loader)
        {
            $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.php');
        }
    }
  • 或将PHP配置文件从YAML配置文件导入

    imports:
        - services.php
        
    # ...

请注意,传统的形式(请参阅文档)的PHP配置文件仍然受到支持,并且将继续工作。

语法

配置文件必须返回一个PHP数组。在这个数组中,参数、服务和导入都定义在一起

<?php
# app/config/config.php

return [
    // ...
];

参数

参数声明为简单值

return [
    'foo' => 'bar',
];

这等同于

parameters:
    foo: 'bar'

参数和服务可以混合在同一个数组中。

服务

可以使用create()辅助函数简单声明服务

use function Fluent\create;

return [
    'mailer' => create(Mailer::class),
];

当调用$container->get('mailer')时,将创建并返回Mailer类的实例。

这等同于

services:
    mailer:
        class: Mailer

使用类名作为条目ID

如果容器条目ID是类名,则在调用create()时可以省略它。

return [
    Mailer::class => create(),
];

自动注入

服务也可以使用autowire()辅助函数(代替create())进行自动注入

use function Fluent\autowire;
 
return [
    Mailer::class => autowire(),
];

这等同于

services:
    Mailer:
        class: Mailer
        autowire: true

构造函数参数

return [
    'mailer' => create(Mailer::class)
        ->arguments('smtp.google.com', 2525),
];

这等同于

services:
    mailer:
        class: Mailer
        arguments: ['smtp.google.com', 2525]

依赖项

参数可以使用'%foo%'语法注入

return [
    'mailer' => create(Mailer::class)
        ->arguments('%mailer.transport%'),
];

这等同于

services:
    mailer:
        class:     Mailer
        arguments: ['%mailer.transport%']

服务可以使用get()辅助函数注入

use function Fluent\get;

return [
    'newsletter_manager' => create(NewsletterManager::class)
        ->arguments(get('mailer')),
];

这等同于

services:
    newsletter_manager:
        class: NewsletterManager
        arguments: ['@mailer']

setter注入

return [
    'mailer' => create(Mailer::class)
        ->method('setHostAndPort', 'smtp.google.com', 2525),
];

这等同于

services:
    mailer:
        class: Mailer
        calls:
            - [setHostAndPort, ['smtp.google.com', 2525]]

属性注入

return [
    'mailer' => create(Mailer::class)
        ->property('host', 'smtp.google.com'),
];

这等同于

services:
    mailer:
        class: Mailer
        properties:
            host: smtp.google.com

可选服务引用

服务可以有可选依赖项,这样依赖项不是它工作的必要条件。

将缺失的依赖项设置为null
use function Fluent\create;
use function Fluent\get;

return [
    'newsletter_manager' => create(NewsletterManager::class)
        ->arguments(get('mailer')->nullIfMissing()),
];

这等同于

<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="https://symfony.ac.cn/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://symfony.ac.cn/schema/dic/services
        https://symfony.ac.cn/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="newsletter_manager" class="NewsletterManager">
            <argument type="service" id="mailer" on-invalid="null" />
        </service>
    </services>
</container>
忽略缺失的依赖项

在setter注入中使用时,可以使用ignoreIfMissing()来省略方法调用

use function Fluent\create;
use function Fluent\get;

return [
    'newsletter_manager' => create(NewsletterManager::class)
        ->method('setMailer', get('mailer')->ignoreIfMissing()),
];

这等同于

services:
    app.newsletter_manager:
        class:     AppBundle\Newsletter\NewsletterManager
        calls:
            - [setMailer, ['@?app.mailer']]

私有服务

return [
    Mailer::class => create()
        ->private(),
];

这等同于

services:
    mailer:
        class: Mailer
        public: false

装饰服务

服务可以使用decorate()方法进行装饰

return [
    'decorating_mailer' => create(MailerDecorator::class)
        ->decorate('mailer')
        ->argument(get('decorating_mailer.inner')),
];

这等同于

services:
    decorating_mailer:
        class: 'MailerDecorator'
        decorates: 'mailer'
        arguments: ['@decorating_mailer.inner']

如果您想对一个服务应用多个装饰器,您可以更改内部服务名称(即装饰过的服务)并配置装饰的优先级

return [
    'foo' => create(Foo::class),
    'bar' => create(Bar::class)
        ->decorate('foo', 'bar.foo', 5)
        ->arguments(get('bar.foo'))
    ,
    'baz': create(Baz::class)
        ->decorate('foo', 'baz.foo', 1),
        ->arguments(get('baz.foo'))
];

这等同于

foo:
    class: Foo

bar:
    class: Bar
    decorates: foo
    decoration_inner_name: 'bar.foo'
    decoration_priority: 5
    arguments: ['@bar.foo']

baz:
    class: Baz
    decorates: foo
    decoration_inner_name: 'baz.foo'
    decoration_priority: 1
    arguments: ['@baz.inner']

非共享服务

所有服务默认都是共享的。您可以通过使用 unshared() 函数辅助器强制容器始终创建一个新的实例

return [
    'app.phpmailer' => create(PhpMailer::class)
        ->unshared(),
];

这等同于

services:
    app.phpmailer:
        class: AppBundle\Mail\PhpMailer
        shared: false

合成服务

服务可以在运行时进行注入。您可以使用 synthetic() 函数辅助器注入一个类实例作为服务,而不是配置容器创建一个新的实例

return [
    'app.phpmailer' => create(PhpMailer::class)
        ->synthetic(),
];

这等同于

services:
    app.phpmailer:
        class: AppBundle\Mail\PhpMailer
        synthetic: true

工厂

可以使用 factory() 函数辅助器通过 工厂 创建服务。

use function Fluent\factory;

return [
    'newsletter_manager' => factory([NewsletterManager::class, 'create'], NewsletterManager::class)
        ->arguments('foo', 'bar'),
];

当调用 $container->get('newsletter_manager') 时,将返回 NewsletterManager::create('foo', 'bar') 的结果。

这等同于

services:
    newsletter_manager:
        factory: ['AppBundle\Email\NewsletterManager', 'create']
        class: 'AppBundle\Email\NewsletterManager'
        arguments: ['foo', 'bar']

当使用类名作为服务ID时,您不必明确指出服务的类名。

return [
    // you can write:
    NewsletterManager::class => factory([NewsletterManager::class, 'create']),
    // instead of:
    NewsletterManager::class => factory([NewsletterManager::class, 'create'], NewsletterManager::class),
];

别名

可以使用 alias() 函数辅助器对服务进行别名设置。

use function Fluent\create;
use function Fluent\alias;

return [
    'app.phpmailer' => create(PhpMailer::class),
    'app.mailer' => alias('app.phpmailer'),
];

当调用 $container->get('app.mailer') 时,将返回 app.phpmailer 的条目。

这等同于

services:
    app.phpmailer:
        class: AppBundle\Mail\PhpMailer
    app.mailer:
        alias: app.phpmailer

私有别名

return [
    'app.phpmailer' => create(PhpMailer::class),
    'app.mailer' => alias('app.phpmailer')
        ->private(),
];

这等同于

services:
    app.phpmailer:
        class: AppBundle\Mail\PhpMailer
    app.mailer:
        alias: app.phpmailer
        public: false

标签

服务可以进行标记

return [
    'mailer' => create(Mailer::class)
        ->tag('foo', ['fizz' => 'buzz', 'bar' => 'baz'])
        ->tag('bar'),
];

这等同于

services:
    mailer:
        class: Mailer
        tags:
            - {name: foo, fizz: buzz, bar: baz}
            - {name: bar}

导入

可以使用 import() 函数辅助器导入其他配置文件

use function Fluent\import;

return [
    import('services/mailer.php'),
];

您会注意到数组项不是按条目ID索引的。

这等同于

imports:
    - { resource: services/mailer.yml }

扩展

可以使用 extension() 函数辅助器配置扩展(例如,框架配置)

use function Fluent\extension;

return [
    extension('framework', [
        'http_method_override' => true,
        'trusted_proxies' => ['192.0.0.1', '10.0.0.0/8'],
    ]),
];

这等同于

framework:
    http_method_override: true
    trusted_proxies: [192.0.0.1, 10.0.0.0/8]