Development

Documentation/zh_CN/book/1.0/05-Configuring-Symfony

You must first sign up to be able to contribute.

Version 3 (modified by Le.Jiang, 11 years ago)
updated translation

第 5 章 - 配置symfony

为了达到简单易用的目的,symfony定义了一些惯例,这些惯例能够满足大多数情况的需求。另一方面,使用一系列简单而强大的配置文件,我们可以定制这个框架及应用程序的几乎所有的地方。使用这些配置文件可以为程序增加一些特殊的参数。

这一章介绍配置系统怎么工作:

  • symfony配置信息保存在YAML格式的文件里,当然也可以换成其它格式
  • 配置文件分成项目、应用程序、模块这几个等级分别存放在项目目录里的对应目录里
  • 你可以定义几套不同的配置文件;symfony里面一套配置文件称之为环境
  • 配置文件里面定义的值可以在PHP代码里面取得
  • 另外,symfony认识YAML里面的PHP代码等,这使得配置系统更灵活

配置系统 The Configuration System

不论什么用途,大多数web应用程序都有一些共同的特征。例如,有些区域只允许一部分用户访问;很多页面共用一个布局;表单填写验证失败后自动把用户输入的内容放进表单。框架定义了一些实现这些特性的结构,开发者通过配置系统进一步的调整它们。这种策略可以节省大量开发时间,因为很多改变并不用改写代码,尽管实现这些改变需要很多代码。这种策略也更有效率,因为这些信息可以存放在容易找到的地方。

但是,这样的做法有两个严重缺点:

  • 开发者最后整天不停的写复杂的XML文件
  • 使用PHP处理每个请求花费的时间更多了

考虑到这些缺点,同时symfony又要充分利用配置文件的优点。事实上,symfony的配置系统的目标是:

  • 强大: 所有的可以配置的东西都可以用配置文件配置
  • 简单: 很多配置信息不会出现在普通的应用程序里,因为它们很少需要改变
  • 容易: 开发者可以很容易的阅读,建立,修改配置文件
  • 可定制: 默认的配置语言是YAML,但也可以换成INI、XML,或者是别的格式
  • 快速: 应用程序本身不用处理配置文件,由配置系统处理配置文件,把配置文件编译成能够快速执行的PHP代码

YAML与语法与symfony惯例 YAML Syntax and Symfony Conventions

symfony默认使用YAML格式存放配置信息,而不用传统的INI或者XML格式。YAML通过缩进表示结构而且写起来很快。它的特点与基本规则在第一章里面已经讲到了。不过,在写YAML的时候,你还需要记住几条规则。本节将介绍最常用的几个几个规则。想完整的了解YAML,请访问YAML网站(http://www.yaml.org/)。

首先,绝不要在YAML文件里使用制表符(tab),应该使用空格。YAML解析器不能解析制表符,所以请使用空格来缩进(在symfony里面使用两个空格缩进),如例5-1。

例 5-1 - YAML文件禁止制表符(tab)

# 绝不用制表符
all:
-> mail:
-> -> webmaster:  webmaster@example.com

# 应该使用空格
all:
  mail:
    webmaster: webmaster@example.com

如果你的参数是以空格开始或者结束的字符串,应使用单引号把它包起来。如果一个字符串参数包含特殊字符,也要用单引号包起来,如例5-2。

例 5-2 - 非标准的字符串要用单引号包起来

错误1: This field is compulsory
错误2: '  This field is compulsory  '
错误3: 'Don''t leave this field blank'   # 必须用两个单引号来表示字符串中的'

利用特殊字符头(> 与 |)与一个缩进,长的字符串可以跨行表示。如例5-3。

例 5-3 - 定义长的多行字符串

accomplishment: >           # 由>开头的折叠式
  Mark set a major league   # 每一个换行被折叠成一个空格
  home run record in 1998.  # 使得YAML可读性更强
stats: |                    # 由|开头的原始式
  65 Home Runs              # 所有的换行都被保留
  0.278 Batting Average     # 缩进不会在结果里出现

如果要定义数组,需要用方括号把元素括起来或者使用展开的减号语法,如例 5-4。

例 5-4 - YAML数组语法

# 数组语法的简写
players: [ Mark McGwire, Sammy Sosa, Ken Griffey ]

# 数组的展开语法
players:
  - Mark McGwire
  - Sammy Sosa
  - Ken Griffey

如果要定义联合数组或者说哈希,要用大括号把元素括起来,键与值key: value中间保留一个空格。也可以用展开语法,每一个新的建增加一个缩进与换行,如例5-5。

例 5-5 - YAML联合数组语法

# 错误的语法,冒号后缺少空格
mail: {webmaster:webmaster@example.com,contact:contact@example.com}

# 联合数组的正确简写
mail: { webmaster: webmaster@example.com, contact: contact@example.com }

# 联合数组的展开语法
mail:
  webmaster: webmaster@example.com
  contact:   contact@example.com

定义一个布尔值时,on1或者true代表肯定值,off0、或者false代表否定值。如例5-6。

例 5-6 - YAML 布尔值语法

true_values:   [ on, 1, true ]
false_values:  [ off, 0, false ]

请不要吝啬使用注释(以井号#开头)还有空格,这会使注释文件更易读,如例5-7。

例 5-7 - YAML 注释语法与值对齐

# 这是一个注释
mail:
  webmaster: webmaster@example.com
  contact:   contact@example.com
  admin:     admin@example.com   # 多的空格可以帮助对齐

在某些symfony配置文件里面,你会发现一些行以#开头(YAML解析器会忽略这些行),但这些行看上去像普通的设置行。这是一个symfony的惯例:默认设置,从symfony内核里其他的YAML文件里面继承的设置,这些会在你的应用程序配置文件里面出现并用#注释起来,给你参考。如果你想改变这些参数,只要把注释去掉就可以了。如例5-8。

例 5-8 - 注释里的默认配置

# 缓存的默认值是关闭
settings:
# cache: off

# 如果你想修改这个值,去掉注释
settings:
  cache: on

symfony有时会把一些参数定义分类。一个类里面的所有设置都放在分类头下面。把长的key: value列表分组能增强可读性。类头以点(.)。如例5-9。

例 5-9 - 类别头与键类似,但是以.开头

all:
  .general:
    tax:        19.6

  mail:
    webmaster:  webmaster@example.com

在这个例子里,mail是一个键,general只是一个类别头。类别头可以当作不存在,如例5-10。tax参数实际上是all键的直接子元素。

例 5-10 - 类别头只用于增强可读性,实际上可以忽略

all:
  tax:          19.6

  mail:
    webmaster:  webmaster@example.com

SIDEBAR 如果你不喜欢YAML

YAML只是一个给PHP代码定义设置的界面,所以YAML里面定义的配置信息都会被转换成PHP代码。浏览一个应用程序,查看他的缓存的配置信息(例,在cache/myapp/dev/config/)。你会发现YAML配置对应的PHP文件。这一章后面我们会详细介绍配置缓存。

好消息是如果你不喜欢YAML文件,你可以自己动手,使用PHP代码或者其他的格式(XML,INI等)。在本书中,你会遇到其他的不使用YAML定义配置的方法,在第19章你会了解如何替换symfony的配置文件处理器。如果你用好它们,你可以利用这些技巧绕开配置文件或者定义你自己的格式。

救命 YAML文件把我的程序搞死了 Help, a YAML File Killed My App!

YAML文件会被解析成PHP哈希与数组,然后这些值会在程序的不同地方改变视图,控制器或者模型的行为。很多时候,配置文件里面的问题直到用到的时候才被察觉。而且,显示的错误信息通常不是明显与YAML配置文件有关的。

如果改变了配置文件之后程序突然停止运行了,应该检查一下你是否犯了下面的常见的YAML错误:

  • 键和值中间缺少空格:

    key1:value1      # 冒号:后缺少空格
    
  • 数组里面的键应该按照同样的方式缩进

    all:
      key1:  value1
       key2: value2  # 缩进与其他的数组元素不同
      key3:  value3
    
  • 键或值里有YAML保留字符而且没有用单引号

    message: tell him: go way    # :, [, ], { and } 是YAML保留字符
    message: 'tell him: go way'  # 正确的语法
    
  • 你在修改一个被注释了的行

    # key: value     # 由于前面的#,这行永远不会生效
    
  • 同一级别同样的键的值设定了两次

    key1: value1
    key2: value2
    key1: value3     # key1定义的两次,取最后一次定义的值
    
  • 你认为设置值应该是一个特定的类型,实际上如果你不转换它,设定值永远是字符串:

    income: 12,345   # 除非你转换它,否则它永远是字符串
    

配置文件概述 Overview of the Configuration Files

配置信息按照目的存放在不同的文件里面。这些文件包含参数定义或者设置。一些参数可以在不同的级别覆盖(项目,应用程序,模块);一些指针对特定级别。本节将介绍这些配置文件,第19章将更深入的介绍配置文件。

项目配置 Project Configuration

symfony项目有一些默认配置文件。下面是myproject/config/目录下面的配置文件:

  • config.php: 这是所有页面或者命令行方式PHP脚本之行的第一个文件。它包含symfony框架的路径,你可以把这个路径指定到另外一个symfony框架。如果你在这里增加一些define语句,这样定义的常量在项目的每个应用程序都可以访问得到。第19章将会深入介绍这个文件的使用。
  • databases.yml: 这个文件用来存放数据库连接设定(主机,登录名,密码等)。第8章有更详细的介绍。这个文件的配置信息可以在应用程序这一级别覆盖。
  • properties.ini: 这个文件存放命令行工具需要的参数,包括项目名称,远程服务器的连接设置。第16章将详细介绍此文件的功能。
  • rsync_exclude.txt: 这个文件定义同步服务器的时候哪些文件不需要同步。详见第16章。
  • schema.ymlpropel.ini: 这两个文件是Propel(symfony的ORM层)的数据访问配置文件。它们用来使Propel与symfony的类还有项目的数据协同工作。propel.ini 是自动生成的,所以你不用修改它。如果你不用Propel,就不需要这些文件。这两个文件的使用详见第8章。

这些文件多数时候是被外部组件或者命令行使用,或者symfony在YAML解析程序载入之前就要用到它们。所以有些文件不是YAML格式。

应用程序配置 Application Configuration

配置的主要部分是应用程序配置。前端控制器(在web/目录)里定义主要的常量,YAML文件在应用程序目录的config/目录里的里,i18n/目录里是国际化需要的文件,还有一些在框架文件里隐藏着的但是很有用的其他项目配置信息。

前端控制器配置 Front Controller Configuration

前端控制器里存放了最开始的应用程序配置信息; 它是一个请求最开始之行的脚本。请看例5-11种默认的web/index.php

例 5-11 - 默认的生产环境前端控制器

[php]
<?php

define('SF_ROOT_DIR',    dirname(__FILE__).'/..');
define('SF_APP',         'myapp');
define('SF_ENVIRONMENT', 'prod');
define('SF_DEBUG',       true);

require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');

sfContext::getInstance()->getController()->dispatch();

定义了应用程序名(myapp)与环境(prod)之后,先载入通用配置文件,然后继续分派请求。这里定义了一些有用的常量:

  • SF_ROOT_DIR: 项目根目录 (一般情况请保留默认值,除非想变更目录结构).
  • SF_APP: 项目中的应用程序名。需要它来生成文件路径。
  • SF_ENVIRONMENT: 环境名 (prod, dev, 或者其他你定义的本项目的环境)。用来决定使用哪一套配置信息。本章稍后会解释环境的概念。
  • SF_DEBUG: 是否启用调试模式 (详见第16章)。

如果你要改变这些值,那么你可能需要另一个前端控制器。下一章将介绍前端控制器还有如何新建一个前端控制器。

SIDEBAR 根目录可以在任何地方

只有web根目录(symfony项目的web/目录)里的脚本对外界公开。前端控制器脚本,图片,样式表,还有JavaScript文件是公开的。其他文件必须放在服务器web根目录之外--也就是说它们其他任何地方。

前端控制器通过SF_ROOT_DIR这个路径访问项目的非公开的文件。一般来说,项目根目录就是web/目录的上一层目录。但是你可以选择一个完全不同的文件结构。假设你的主目录结构由两个目录组成,一个公开另外一个私有:

symfony/    # 私有区域
  apps/
  batch/
  cache/
  ...
www/        # 公开区域
  images/
  css/
  js/
  index.php

在这种情况下,项目根目录是symfony/目录。所以index.php前端控制器只要这样定义整个应用程序就可以工作了:

define('SF_ROOT_DIR', dirname(__FILE__).'/../symfony');

第19章将会告诉你更多如何修改symfony来实现特殊的目录结构的信息。

主应用程序配置 Main Application Configuration

主应用程序配置存放在myproject/apps/myapp/config/目录下的文件里:

  • app.yml: 这个文件存放应用程序相关的配置信息,包括定义业务或者程序逻辑的全局变量,这些都不需要存放在数据库里。税率,运费,e-mail地址等经常存放在这个文件。这个文件默认是空的。
  • config.php: 这个文件引导应用程序,它会做所有的基础初始化来启动应用程序。这里你可以订制目录结构或者增加应用程序相关的常量(详见第19章)。他首先会包含项目的config.php文件。
  • factories.yml: symfony在这里定义处理视图、请求、回应、会话(session)等的类。如果你想用你自己的类取代symfony的类,你可以在这里定义它们。详见第19章。
  • filters.yml: 过滤器是在每个请求都被执行的一小段代码。这个文件用来定义哪些过滤器需要被执行,每个模块都可以改写过滤器配置。详见第6章。
  • logging.yml: 这个文件定义哪些情况需要被记录到日志里,从而管理与调试应用程序。详见第16章。
  • routing.yml: 路由规则,能把难以理解的不好记忆的URL变成"漂亮"的直接的形式。此配置文件用来存放这些信息。每个新应用程序都会有一些默认路由规则。详见第9章。
  • settings.yml: 这个文件存放symfony应用程序的主要配置信息。你的应用程序是否使用国际化功能,它的默认语言,请求timeout时间,是否开启缓存功能等都在这个文件里面定义。只要改变这个文件里的一行代码,你就可以关闭网站来执行维护升级。这些设置还有它们的用法详见第19章。
  • view.yml: 这个文件里定义默认视图的结构(布局的名称,标题,还有meta tag;默认载入的的样式表及Javascript;默认的content-type等)。还有默认的meta与标题标签。详见第7章。这些配置信息可以在模块里改写。

国际化配置 Internationalization Configuration

国际化的应用程序可以显示多种语言。这需要特殊的配置。国际化配置信息存放在这两个地方:

  • 应用程序config/目录里的i18n.yml: 这个文件定义一般的翻译设定,例如原文的语言、在数据库还是文件里面存放翻译信息还有翻译信息的格式等。
  • 应用程序i18n/目录里的翻译文件: 这些文件基本上是字典,里面包含程序模版里面出现的所有文字的翻译,这样切换语言的地方就会显示对应的翻译。

注意开启i18n(国际化)功能需要在setting.yml文件里面设置。详见第13章。

其它应用程序配置 Additional Application Configuration

还有一部分配置文件在symfony的安装目录里(在`$sf_symfony_data_dir/config/'),这些文件在所有的项目配置目录里都找不到。这是一些很少需要修改或者对于全部项目共用的配置信息。不过,如果你需要改动它们,只要在你的myproject/apps/myapp/config/里建立一个相同名字的空文件,然后在里面改写你要修改的配置信息就可以了。应用程序里的配置信息总是有先于框架的配置信息。下面是symfony安装目录的config/目录里的文件:

  • autoload.yml: 此文件包含了自动载入功能的配置信息。这个功能帮你从特定的目录自动载入你写的类。详见第19章。
  • constants.php: 此文件包含了默认的应用程序文件结构。请使用应用程序的config.php来覆盖这些配置信息。详见第19章。
  • core_compile.ymlbootstrap_compile.yml: 这两个文件记录启动应用程序(在bootstrap_compile.yml里)还有处理请求(在core_compile.yml里)需要载入哪些类。这些类被压缩在一个没有注释的PHP文件里,这样可以最小化文件处理从而加快执行速度(每个请求只载入1个文件而不是40多个文件)。这在没有安装PHP加速器的时候特别有效。优化技术详见第18章。
  • config_handlers.yml: 在这个文件里你可以增加或者修改处理配置文件的工具。详见第19章。
  • php.yml: 这个文件用来检查php.ini里的配置信息是否满足程序需要,并且可以帮你覆盖php.ini的配置。详见第19章。

模块配置 Module Configuration

默恩情况下,模块没有特别的配置信息。不过,如果你需要,你可以为某个模块覆盖应用程序级的配置。例如,你需要修改一个模块里所有动作的HTML描述信息,或是载入一个特定的Javascript文件。You can also choose to add new parameters restricted to a specific module to preserve encapsulation. FIXME

可能你已经猜到,模块配置文件必须放在myproject/apps/myapp/modules/mymodule/config/目录里,模块配置信息有下面这几个文件:

  • generator.yml: 根据数据库表自动生成的模块(脚手架与管理后台)会用这个文件, 它用来定义界面怎么显示行和列,用户可以执行哪些操作(过滤器,排序,按钮等)。详见第14章。
  • module.yml: 这个文件包含模块的特殊参数(相当于app.yml,但是是模块级的),还有动作的配置信息。详见第6章。
  • security.yml: 这个文件用来给动作设定访问限制。你可以在这里设定哪个页面只能给注册用户看或者是一部分有特殊全县的注册用户看。详见第6章。
  • view.yml: 这个文件包含模块的一个或者所有动作的视图配置信息。它会覆盖应用程序级的view.yml,详见第7章。
  • 数据验证文件: 虽然这些用来验证表单输入的数据的YAML数据验证文件存放在validate/目录而不是config/目录里,它们仍然属于模块配置文件。详见第10章。

大多数模块配置文件能让你为一个模块的所有的视图或者动作定义参数,也可以只为模块里的一部份视图或者动作定义参数。

SIDEBAR 文件太多了?

可能应用程序里的配置文件太多了,使你受到了打击。不过请注意:

大多数时候你都不用修改配置,因为默认的配置就能够满足大部分的需求。每个配置文件与一个特定的功能相关,以后的章节会一个一个详细介绍它们们的用法。当你关注某一个配置文件的时候,你就能清楚的了解它的用途还有它的组织形式。对于专业web开发,默认的配置不会经常被完全重写。配置文件使你不用修改一行代码情谊的改变symfony的功能。想想看要达到同样的目的需要多少PHP代码吧。如果所有的配置文件都存放在同一个文件里,那么这个文件不仅仅会变得完全无法阅读,同样你也无法在不同的级别重新定义配置信息(请看本章后面的"配置层叠"小节)。 配置系统是symfony重大优点之一,它使symfony适合于几乎所有类型的web应用程序,不仅限这个框架原本设计的目的。

环境 Environments

在开发应用程序的过程中,你可能同时需要好几套配置信息。例如,开发中的用来测试的数据库配置信息,还有生产环境的正式的数据库配置信息。symfony为满足同时使用不同配置信息的需求,提供了不同的环境。

什么是环境? What Is an Environment?

一个应用程序可以在不同的环境中运行。不同的环境共享相同的PHP代码(前端控制器除外),但是配置信息可能完全不同。symfony为每个应用程序提供三种默认的环境:生产(prod),测试(test),还有开发(dev)。只要你愿意你可以无限制的增加环境的数量。

所以基本上,环境与配置是同义词。例如,测试环境会记录警告与错误,生产(prod)环境只记录错误。缓存加速功能在开发dev环境下通常是关闭的,但是在测试(test)与生产(prod)环境下开启。开发与测试环境所需要的测试数据,存放在与生产环境不同的数据库里。所以两种环境的数据库培植会有所不同。所有的环境可以在一台机器上共存,不过通常一台正式的服务器只包含生产prod环境。

在开发环境下,日志与调试功能都是开启的,因为排除问题比性能更重要。相反,生产环境的配置默认是为性能优化的,所以生产环境会关闭一些功能。建议呆在开发环境直到你对开发的功能满意为止,然后切换到生产环境测试速度。

测试环境又与开发与生产环境有所不同。你只能通过命令行来访问这个环境,通常是作功能测试与执行批处理脚本。因此,测试环境与生产环境接近,但是不能通过浏览器访问。它能模拟coookie与其它HTTP相关的组件。

改变你正在访问的应用程序的环境,只要改变前端控制器就可以了。到目前为止,你只见过开发环境,因为例子里的URL都是开发环境前端控制器的:

http://localhost/myapp_dev.php/mymodule/index

不过,如果你想看看应用程序在生产环境中的样子,可以执行生产环境的前端控制器:

http://localhost/index.php/mymodule/index

如果你的web服务器支持mod_rewrite,你甚至可以在web/.htaccess里自定symfony重写规则。这些规则把生产环境的前端控制器作为默认的执行脚本能让URL看上去像这样:

http://localhost/mymodule/index

SIDEBAR 环境与服务器

不要把环境与服务器的概念混淆了。在symfon里,不同的环境是指不同的配置信息,对应不同的前端控制器(执行请求的脚本)。不同的服务器对应URL里的不同域名。

http://localhost/myapp_dev.php/mymodule/index
       _________ _____________
        服务器    环境

通常,开发人员在一台开发服务器上工作,这台服务器不与互联网相同,所有的服务与PHP配置文件都可以自由修改。到了发布应用程序的时候,程序文件会传到生产服务器上然后最终用户才能访问得到。

这意味着同一台服务器上可以有很多个环境。例如,你甚至可以在你的开发服务器上运行生产环境。不过,大多数时候,生产服务器上只能访问生产环境,这样可以避免服务器的配置信息泄露以减少安全方面的风险。

定义一个新环境,不需要建立目录或者使用symfony命令行工具。只要建立一个新的前端控制器,修改这个前端控制器里面定义的环境名就可以了。这个环境会继承所有默认配置信息还有所有环境的共同配置信息。下一章会有详细介绍。

配置层叠 Configuration Cascade

同样的配置信息可以在不同的地方定义多次。例如,你想把你的程序的所有页面的mime-type定义成text/html,只有一个rss模块例外,这个模块需要text/xml的mime-type。symfony可以让你在myapp/config/view.yml里面写第一个定义,然后再myapp/modules/rss/config/view.yml里面写第二个定义。配置系统了解模块级别的定义一定要覆盖应用程序级的定义。

实际上,symfony的配置信息分成好几级:

  • Granularity levels:
    • The default configuration located in the framework
    • The global configuration for the whole project (in myproject/config/)
    • The local configuration for an application of the project (in myproject/apps/myapp/config/)
    • The local configuration restricted to a module (in myproject/apps/myapp/modules/mymodule/config/)
  • Environment levels:
    • Specific to one environment
    • For all environments

Of all the properties that can be customized, many are environment-dependent. Consequently, many YAML configuration files are divided by environment, plus a tail section for all environments. The result is that typical symfony configuration looks like 例 5-12.

例 5-12 - The Structure of Symfony Configuration Files

# Production environment settings
prod:
  ...

# Development environment settings
dev:
  ...

# Test environment settings
test:
  ...

# Custom environment settings
myenv:
  ...

# Settings for all environments
all:
  ...

In addition, the framework itself defines default values in files that are not located in the project tree structure, but in the $sf_symfony_data_dir/config/ directory of your symfony installation. The default configuration is set in these files as shown in 例 5-13. These settings are inherited by all applications.

例 5-13 - The Default Configuration, in $sf_symfony_data_dir/config/settings.yml

 # Default settings:
 default:
   default_module:         default
   default_action:         index
   ...

These default definitions are repeated in the project, application, and module configuration files as comments, as shown in 例 5-14, so that you know that some parameters are defined by default and that they can be modified.

例 5-14 - The Default Configuration, Repeated for Information, in myapp/config/settings.yml

#all:
 #  default_module:         default
 #  default_action:         index
 ...

This means that a property can be defined several times, and the actual value results from a definition cascade. A parameter definition in a named environment has precedence over the same parameter definition for all environments, which has precedence over a definition in the default configuration. A parameter definition at the module level has precedence over the same parameter definition at the application level, which has precedence over a definition at the project level. This can be wrapped up in the following priority list:

  1. Module
  2. Application
  3. Project
  4. Specific environment
  5. All environments
  6. Default

配置缓存 The Configuration Cache

Parsing YAML and dealing with the configuration cascade at runtime represent a significant overhead for each request. Symfony has a built-in configuration cache mechanism designed to speed up requests.

The configuration files, whatever their format, are processed by some special classes, called handlers, that transform them into fast-processing PHP code. In the development environment, the handlers check the configuration for changes at each request, to promote interactivity. They parse the recently modified files so that you can see a change in a YAML file immediately. But in the production environment, the processing occurs once during the first request, and then the processed PHP code is stored in the cache for subsequent requests. The performance is guaranteed, since every request in production will just execute some well-optimized PHP code.

For instance, if the app.yml file contains this:

all:                   # Setting for all environments
  mail:
    webmaster:         webmaster@example.com

then the file config_app.yml.php, located in the cache/ folder of your project, will contain this:

[php]
<?php

sfConfig::add(array(
  'app_mail_webmaster' => 'webmaster@example.com',
));

As a consequence, most of the time, the YAML files aren't even parsed by the framework, which relies on the configuration cache instead. However, in the development environment, symfony will systematically compare the dates of modification of the YAML files and the cached files, and reprocess only the ones that have changed since the previous request.

This presents a major advantage over many PHP frameworks, where configuration files are compiled at every request, even in production. Unlike Java, PHP doesn't share an execution context between requests. For other PHP frameworks, keeping the flexibility of XML configuration files requires a major performance hit to process all the configuration at every request. This is not the case in symfony. Thanks to the cache system, the overhead caused by configuration is very low.

There is an important consequence of this mechanism. If you change the configuration in the production environment, you need to force the reparsing of all the configuration files for your modification to be taken into account. For that, you just need to clear the cache, either by deleting the content of the cache/ directory or, more easily, by calling the clear-cache symfony task:

> symfony clear-cache

从代码里访问配置信息 Accessing the Configuration from Code

All the configuration files are eventually transformed into PHP, and many of the settings they contain are automatically used by the framework, without further intervention. However, you sometimes need to access some of the settings defined in the configuration files from your code (in actions, templates, custom classes, and so on). The settings defined in settings.yml, app.yml, module.yml, logging.yml, and i18n.yml are available through a special class called sfConfig.

The sfConfig Class

You can access settings from within the application code through the sfConfig class. It is a registry for configuration parameters, with a simple getter class method, accessible from every part of the code:

[php]
// Retrieve a setting
parameter = sfConfig::get('param_name', $default_value);

Note that you can also define, or override, a setting from within PHP code:

[php]
// Define a setting
sfConfig::set('param_name', $value);

The parameter name is the concatenation of several elements, separated by underscores, in this order:

  • A prefix related to the configuration file name (sf_ for settings.yml, app_ for app.yml, mod_ for module.yml, sf_i18n_ for i18n.yml, and sf_logging_ for logging.yml)
  • The parent keys (if defined), in lowercase
  • The name of the key, in lowercase

The environment is not included, since your PHP code will have access only to the values defined for the environment in which it's executed.

For instance, if you need to access the values defined in the app.yml file shown in 例 5-15, you will need the code shown in 例 5-16.

例 5-15 - Sample app.yml Configuration

all:
  version:        1.5
  .general:
    tax:          19.6
  default_user:
    name:         John Doe
  mail:
    webmaster:    webmaster@example.com
    contact:      contact@example.com
dev:
  mail:
    webmaster:    dummy@example.com
    contact:      dummy@example.com

例 5-16 - Accessing Configuration Settings in PHP in the dev Environment

[php]
echo sfConfig::get('app_version');
 => '1.5'
echo sfConfig::get('app_tax');   // Remember that category headers are ignored
 => '19.6'
echo sfConfig::get('app_default_user_name);
 => 'John Doe'
echo sfConfig::get('app_mail_webmaster');
 => 'dummy@example.com'
echo sfConfig::get('app_mail_contact');
 => 'dummy@example.com'

So symfony configuration settings have all the advantages of PHP constants, but without the disadvantages, since the value can be changed.

On that account, the settings.yml file, where you can set the framework settings for an application, is the equivalent to a list of sfConfig::set() calls. 例 5-17 is interpreted as shown in 例 5-18.

例 5-17 - Extract of settings.yml

all:
  .settings:
    available:              on
    path_info_array:        SERVER
    path_info_key:          PATH_INFO
    url_format:             PATH

例 5-18 - What Symfony Does When Parsing settings.yml

[php]
sfConfig::add(array(
  'sf_available' => true,
  'sf_path_info_array' => 'SERVER',
  'sf_path_info_key' => 'PATH_INFO',
  'sf_url_format' => 'PATH',
));

Refer to Chapter 19 for the meanings of the settings found in the settings.yml file.

自定义应用程序配置与app.yml Custom Application Settings and app.yml

Most of the settings related to the features of an application should be stored in the app.yml file, located in the myproject/apps/myapp/config/ directory. This file is environment-dependent and empty by default. Put in every setting that you want to be easily changed, and use the sfConfig class to access these settings from your code. 例 5-19 shows an example.

例 5-19 - Sample app.yml to Define Credit Card Operators Accepted for a Given Site

all:
  creditcards:
    fake:             off
    visa:             on
    americanexpress:  on

dev:
  creditcards:
    fake:             on

To know if the fake credit cards are accepted in the current environment, get the value of:

[php]
sfConfig::get('app_creditcards_fake');

TIP Each time you are tempted to define a constant or a setting in one of your scripts, think about if it would be better located in the app.yml file. This is a very convenient place to store all application settings.

When your need for custom parameters becomes hard to handle with the app.yml syntax, you may need to define a syntax of your own. In that case, you can store the configuration in a new file, interpreted by a new configuration handler. Refer to Chapter 19 for more information about configuration handlers.

更好的使用配置文件的技巧 Tips for Getting More from Configuration Files

There are a few last tricks to learn before writing your own YAML files. They will allow you to avoid configuration duplication and to deal with your own YAML formats.

在YAML文件里使用常量 Using Constants in YAML Configuration Files

Some configuration settings rely on the value of other settings. To avoid setting the same value twice, symfony supports constants in YAML files. On encountering a setting name (one that can be accessed by sfConfig::get()) in capital letters enclosed in % signs, the configuration handlers replace them with their current value. See 例 5-20 for an example.

例 5-20 - Using Constants in YAML Files, Example from autoload.yml

autoload:
  symfony:
    name:           symfony
    path:           %SF_SYMFONY_LIB_DIR%
    recursive:      on
    exclude:        [vendor]

The path parameter will take the value returned by sfConfig::get('sf_symfony_lib_dir'). If you want one configuration file to rely on another, you need to make sure that the file you rely on is already parsed (look in the symfony source to find out the order in which the configuration files are parsed). app.yml is one of the last files parsed, so you may rely on others in it.

在配置文件里使用脚本 Using Scriptable Configuration

It may happen that your configuration relies on external parameters (such as a database or another configuration file). To deal with these particular cases, the symfony configuration files are parsed as PHP files before being passed to the YAML parser. It means that you can put PHP code in YAML files, as in 例 5-21.

例 5-21 - YAML Files Can Contain PHP

all:
  translation:
    format:  <?php echo sfConfig::get('sf_i18n') == true ? 'xliff' : 'none' ?>

But be aware that the configuration is parsed very early in the life of a request, so you will not have any symfony built-in methods or functions to help you.

CAUTION In the production environment, the configuration is cached, so the configuration files are parsed (and executed) only once after the cache is cleared.

浏览你的YAML文件 Browsing Your Own YAML File

Whenever you want to read a YAML file directly, you can use the sfYaml class. It is a YAML parser that can turn a YAML file into a PHP associative array. 例 5-22 presents a sample YAML file, and 例 5-23 shows you how to parse it.

例 5-22 - Sample test.yml File

house:
  family:
    name:     Doe
    parents:  [John, Jane]
    children: [Paul, Mark, Simone]
  address:
    number:   34
    street:   Main Street
    city:     Nowheretown
    zipcode:  12345

例 5-23 - Using the sfYaml Class to Turn a YAML File into an Associative Array

[php]
$test = sfYaml::load('/path/to/test.yml');
print_r($test);

Array(
  [house] => Array(
    [family] => Array(
      [name] => Doe
      [parents] => Array(
        [0] => John
        [1] => Jane
      )
      [children] => Array(
        [0] => Paul
        [1] => Mark
        [2] => Simone
      )
    )
    [address] => Array(
      [number] => 34
      [street] => Main Street
      [city] => Nowheretown
      [zipcode] => 12345
    )
  )
)

总结 Summary

The symfony configuration system uses the YAML language to be simple and readable. The ability to deal with multiple environments and to set parameters through a definition cascade offers versatility to the developer. Some of the configuration can be accessed from within the code via the sfConfig object, especially the application settings stored in the app.yml file.

Yes, symfony does have a lot of configuration files, but this approach makes it more adaptable. Remember that you don't need to bother with them unless your application requires a high level of customization.