如何导入配置Files/Resources

3.4 版本
维护中的版本

在本节,服务的配置文件被称作resources(资源)。这是为了强调一个事实,尽管多数配置资源都是文件形式(如YAML、XML、PHP),Symofny仍然保持极度灵活,配置信息是可以从任何地方加载的(比如从数据库中,甚至从一个外部web service)。

服务容器在构建时要使用一个配置资源(默认是app/config/config.yml)。所有其他服务配置(包括Symfony核心和第三方bundle的配置),必须从这个文件中被导入进来。这给了你绝对的灵活性来搞定你程序中的服务。

外部服务配置在导入时可以有两种方式。第一种方法,通常用于导入其他资源(译注:一般是把service/routing等配置加载到主配置文件中),通过imports指令。第二种方法,是使用dependency injection extensions(译注:SF根本核心之DI扩展,直接语义化配置,这部分配置交由用户完成,再经由扩展被bundle取得,程序才能按需运行。此部分非常难,是SF灵魂层面,必须精通容器用法),用于第三方bundle加载配置。继续阅读以了解这两种方法。

使用imports导入配置 

现在,你已经替换了你的app.mailer服务容器定义,直接在服务配置文件中完成(如app/config/services.yml)。如果你的程序有很多服务,这个文件会非常大且难于维护。为了避免这种情况,你可以分离出你的服务配置到多个服务文件中:

1
2
3
4
5
6
7
8
# app/config/services/mailer.yml
parameters:
    app.mailer.transport: sendmail

services:
    app.mailer:
        class:        AppBundle\Mailer
        arguments:    ['%app.mailer.transport%']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- app/config/services/mailer.xml -->
<?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">
 
    <parameters>
        <parameter key="app.mailer.transport">sendmail</parameter>
    </parameters>
 
    <services>
        <service id="app.mailer" class="AppBundle\Mailer">
            <argument>%app.mailer.transport%</argument>
        </service>
    </services>
</container>
1
2
3
4
5
6
7
8
9
// app/config/services/mailer.php
use Symfony\Component\DependencyInjection\Definition;
 
$container->setParameter('app.mailer.transport', 'sendmail');
 
$container->setDefinition('app.mailer', new Definition(
    'AppBundle\Mailer',
    array('%app.mailer.transport%')
));

定义本身并未改变,只是它的位置发生改变。为了让容器在这个资源的位置来加载定义,在已经加载了资源中使用imports根键(如app/config/services.ymlapp/config/config.yml):

1
2
3
# app/config/services.yml
imports:
    - { resource: services/mailer.yml }
1
2
3
4
5
6
7
8
9
10
11
<!-- app/config/services.xml -->
<?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">
 
    <imports>
        <import resource="services/mailer.xml"/>
    </imports>
</container>
1
2
// app/config/services.php
$loader->import('services/mailer.php');

resource键对应的位置,对于文件来说,既可以是相对于当前文件的路径,也可以是绝对路径。

因为parameter参数的解析方式,你不能使用它们来构建“动态导入”路径。这意味着像下面这种配置将不会工作:

1
2
3
# app/config/config.yml
imports:
    - { resource: '%kernel.root_dir%/parameters.yml' }
1
2
3
4
5
6
7
8
9
10
11
<!-- app/config/config.xml -->
<?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">
 
    <imports>
        <import resource="%kernel.root_dir%/parameters.yml" />
    </imports>
</container>
1
2
// app/config/config.php
$loader->import('%kernel.root_dir%/parameters.yml');

通过容器扩展(Container Extension)导入配置 

第三方bundle的容器配置,包括Symfony核心服务,在加载时通常使用另外一种方法,更加灵活,也更加容易在程序中进行配置。

在内部,每个bundle就像你看到的那样来定义它们的服务。但是,这些文件并不使用imports指令进行导入。这些bundles,使用的是 dependency injection extension 来加载文件。扩展还支持bundle让配置信息能够“动态加载服务”。

看看FrameworkBundle - 这是Symfony框架的核心bundle - 以它为例。在你的程序配置中,有下面这种代码,调用的就是FrameworkBundle的容器扩展:

1
2
3
4
5
# app/config/config.yml
framework:
    secret: xxxxxxxxxx
    form:   true
    # ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
>
 
    <framework:config secret="xxxxxxxxxx">
        <framework:form />
 
        <!-- ... -->
    </framework>
</container>
1
2
3
4
5
6
7
// app/config/config.php
$container->loadFromExtension('framework', array(
    'secret' => 'xxxxxxxxxx',
    'form'   => array(),
 
    // ...
));

当资源被解析时,容器要寻找一个负责处理framework指令的扩展。这种扩展,是存放在FrameworkBundle里面,该扩展将被调用,同时FrameworkBundle的相关服务配置也会被加载进来。

framework指令下面的设置(如form: true),用于指示扩展应该加载全部与“表单组件”相关的服务。如果表单被禁用,这些服务将不再被加载,表单整合将不可用。

当安装或配置一个bundle时,要参考bunlde文档以明确该bunlde所需之相关服务应如何安装和配置。例程中的核心bundle的配置选项可以在Refernce Guide(参考文档)中找到。

如果你希望在自己的共享bundles中使用dependency injection extension(译注:Symfony的DI扩展,简称Extension。bundle分发时必须要用到),并且提供给用户以友好的配置,看一下 如何在Bundle内加载服务配置这篇文章。

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)