mnapoli / fluent-symfony
Requires
- php: >=7.0
- symfony/config: ^3.2
- symfony/dependency-injection: ^3.2
Requires (Dev)
- phpunit/phpunit: ^6.0
- symfony/symfony: ^3.2
README
此包为Symfony容器提供了一种替代配置语法,灵感来源于PHP-DI的配置。
为什么?
主要目标是利用PHP引擎和IDEs进行更严格的分析。如果您感兴趣,也可以阅读为什么YAML在PHP-DI 5中被类似语法取代。
与现有格式的比较
目前,在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]