Development

Documentation/zh_CN/jobeet/1.2/01

You must first sign up to be able to contribute.

第一天: 开始项目

简介

symfony ~框架~ 作为 ~开源~ 项目经过三年多发展,已经成为最流行的 PHP 框架之一了,这得归功于 她出众的性能和丰富的文档,而这个伟大的传统很早就开始了。

2005年12月,当 symfony 发布第一个官方版本时,我们发布了 "Askeet 系列教程", 由24个子教程组成,从12月1日到圣诞节,持续不断每天发布。

事实证明该教程是非常好的向新手推广 symfony 框架的工具。 许多开发者因为 askeet 而掌握了 symfony 框架, 而且很多公司到现在还在使用 askeet 作为主要的培训资料。

现在,当我们庆祝 symfony 1.2 版本发布之时,askeet 系列教程也日显过时, 因此我们决定发布一个新的教程 ——— Jobeet。

这份教程已经在 2008 年以每天一篇文章的形式发布在 symfony blog 上了, 你现在看到的是图书形式的版本。

挑战

只要持续每章/天用一小时,你就有机会学到使用 symfony 编写一个实际的 Web 站点的从头到尾的过程。

24个一小时等于一天,这正是我们估计的一个开发者要掌握 symfony 基础知识所需要的时间。 每天,我们都会向程序中加入新的功能,借开发过程向你展示 symfony 的新功能以及 symfony web 开发过程中的最佳实践。

对于 Askeet 来说,这21天可称作“一天修成 symfony 骨灰级专家”。 我们没有预先安排,而是由社区决定 askeet 的功能。 这非常成功,社区决定我们的程序中需要搜索引擎。当然,我们做到了。 事实证明,第21天的教程是 askeet 系列教程中最受欢迎的。

对 Jobeet 来说,我们要在第21天以“设计竞赛”来庆祝冬天的到来。 优胜的设计已经由 centre{source} 提交, 并且被本教程作为默认设计样式使用。同时它也被用于 Jobeet 站点。

这个教程与众不同

还记得在 PHP4 早期的时候, 真是一段美好的时光啊 ! PHP 作为最倾注于 web 的语言,学习起来非常容易。

但是随着 web 技术飞速发展,web 开发者需要掌握最新的最佳实践和工具。 获取这些知识的最佳途径当然是阅读博客、教程。 我们也读了不少,包括 PHP、Python、Java、Ruby 和 Perl 等各种语言编写的都有, 林林总总,但很多作者给出的示例代码片段却比较失败。

你可能会读到这样子的句子:

“在实际编程中,不要忘了添加验证代码并做适当的错误处理。”

或者

“安全问题留下来请读者当做练习。”

或者

“当然,你应事先编写测试用例。”

什么?这些都是很严肃的事情。在任何一份代码中,这差不多都是最重要的。作为读者, 你被丢下不管了。如果不解决这些实际问题,例子显得苍白无力。他们不能给你一个很好的启蒙。 这太不好了。为啥?安全、验证、错误处理和测试用例等都是严重关乎代码正确性的。

在这个教程中,我们会编写测试用例、错误处理、验证代码以确保我们开发的程序是安全可靠的, 你不会再有被丢下不管的感觉了。 因为,synfony 关心代码, 但更关心最佳实践和怎样开发专业的企业级应用。 我们能够提供这些丰富的功能,全都要归功于 symfony 为我们提供了必须的工具因而不需编写太多 代码就可完成任务。

在 symfony 的国度里,验证、错误处理、安全和测试用例是一等公民,无须我们花太多时间去解释。 这也是为什么在实际的项目开发中我们需要使用框架的原因。

本教程中的所有代码,你都可以用到实际开发的项目中去。我们鼓励你摘抄代码片段甚至整个拿去使用。

关于项目

我们计划的项目用“又一个博客引擎”来概括。但是我们需要使用 symfony 来创建一个有用的项目。 目地就是要证明只需付出小小的努力就可以用 symfony 开发出具有专业水准的带样式的应用程序。

项目的其他细节将作为秘密在后续的教程中一一揭晓,今天我们已经说了不少了。至少,你已经 知道我们的项目名称了:Jobeet

今天做什么呢?

用24个小时来开发一个 symfony 项目时间是非常充沛的,但我们今天不写 PHP 代码。 尽管不编写任何代码,你仍然可以开启一个新的项目,仅仅这一点就能让你体会到使用 symfony 这样的框架所带来的好处了。

今天的目标是搭建开发环境并能在浏览器中访问项目页面,包括了安装 symfony 、创建项目和 配置 web 服务器等步骤。

准备工作

首先,你得有一个已经配置好的 web 开发环境,包括 web 服务器(如:Apache)、数据库 (如:MySQL、PostgreSQL 或 SQLite)以及 5.2.4 以上版本的 PHP。

因为我们会更多的使用命令行,你最好使用类 Unix 风格的操作系统。 当然,如果你使用 Windows 系统,也没关系,只是会在 cmd 窗口的命令提示符下多敲不少的命令而已。

Note:在 ~Windows~ 环境下配置 Unix 命令行也是很容易的。 如果你希望在 Windows 环境下使用诸如 tar, gzip, 和 grep 等工具, 可以安装 Cygwin。官方的文档或许不够用,你可以在 这里 找到一篇很好的安装教程。 喜欢钻研的同志不妨去试试微软自己的 Windows Services for Unix

由于本教程主要关注 symfony 框架本身,我们假定你已经具有扎实的 PHP5 和面向对象编程相关知识的背景。

~安装~ symfony

首先,创建一个目录来保存 Jobeet 项目的文件:

$ mkdir -p /home/sfprojects/jobeet
$ cd /home/sfprojects/jobeet

在 Windows 下:

c:\> mkdir c:\development\sfprojects\jobeet
c:\> cd c:\development\sfprojects\jobeet

Note:建议 Windows 用户避免在诸如 Documents and Settings 目录 和 My Documents 等带有空格的目录下使用 symfony 搭建项目。

创建存放 symfony 框架文件的目录。

$ mkdir -p lib/vendor

在 symfony 站点的安装页面 列出并比较了所有的 symfony 可用版本。

因为本教程是为 symfony1.2 编写的, 请到 symfony 1.2 下载。

在 "Source Download" 部分,你会找到 .tgz 或者 .zip 格式的安装包, 下载并保存到刚创建的 lib/vendor 目录里解压缩:

$ cd lib/vendor
$ tar zxpf symfony-1.2.2.tgz
$ mv symfony-1.2.2 symfony
$ rm symfony-1.2.2.tgz

在 Windows 下可直接在文件管理器中解压 zip 文件。将目录重命名为 symfony , 完整路径为 c:\development\sfprojects\jobeet\lib\vendor\symfony

因为每台机器上的 PHP 配置或许与发布版会有许多不同,所以我们需要检查 PHP 的配置是否满足 symfony 的最低要求。 从命令行运行 symfony 提供的配置检测脚本:

$ cd ../..
$ php lib/vendor/symfony/data/bin/check_configuration.php

若有问题,会输出如何修复的提示信息。你还应该在浏览器里执行这个检测脚本, 因为其 PHP 配置可能不同。 复制脚本文件到 web 服务器的根文档目录,然后访问此脚本。 不要忘记在执行检测配置后从 web 服务器的根文档目录删除此脚本:

$ rm web/check_configuration.php

Configuration check

如果脚本没有输出任何错误,使用 symfony 的 ~命令行~ 显示 symfony 版本号(注意是大写的V), 从而检查 symfony 是否正确被安装了:

$ cd ../..
$ php lib/vendor/symfony/data/bin/symfony -V

在 Windows 下:

c:\> cd ..\..
c:\> php lib\vendor\symfony\data\bin\symfony -V

如果你对这个命令行工具的功能感到好奇,可以直接运行 symfony 列出所有支持的选项和任务。

$ php lib/vendor/symfony/data/bin/symfony

在 Windows 下:

c:\> php lib\vendor\symfony\data\bin\symfony

symfony 命令行是开发者的好朋友。它提供了大量的工具来提高你日常工作的效率, 比如清除缓存、生成代码等等。

建立项目

在 symfony 中,使用相同的数据模型的 ~应用程序(applications)~ 组成 项目(projects)。以 Jobeet 项目为例,我们会有两个不同的应用程序:~前台~和~后台~。

创建项目

jobeet 目录下运行 symfony 任务 generate:project 生成 symfony 项目:

$ php lib/vendor/symfony/data/bin/symfony generate:project jobeet

在 Windows 下:

c:\> php lib\vendor\symfony\data\bin\symfony generate:project jobeet

generate:project 任务生成了 symfony 项目默认的文件和目录~结构~:

| 目录 | 说明 | ----------- | ---------------------------------- | apps/ | 存放项目的所有应用程序 | cache/ | 框架的缓存文件 | config/ | 项目配置文件 | lib/ | 项目使用到的类和库 | log/ | 项目日志文件 | plugins/ | 安装的插件 | test/ | 单元测试和功能测试文件 | web/ | 网站根目录(见下文)

NOTE 为什么 symfony 生成了这么多文件?使用全栈式框架的主要好处是标准化你的开发。 得益于 symfny 的默认文件目录结构,任何具有 symfony 知识的开发者都可以接手任何 symfony 项目。大约几分钟后,他就能够深入到代码中修正 bug、增加新的功能。

generate:project 任务还在 Jobeet 项目的根目录创建了一个 symfony 快捷方式 来减少你运行任务时需要键入的命令代码。

因此,从现在起,你可以只输入 symfony 来调用 symfony 命令了。

生成应用程序

现在,运行 generate:app 任务生成前台应用程序。

$ php symfony generate:app --escaping-strategy=on
  ➥ --csrf-secret=UniqueSecret frontend

TIP 因为 symfony 快捷文件是可执行的,Unix 用户在后面遇到的所有的 'php symfony' 都可以用 './symfony' 替代。

Windows 下的用户可以拷贝 'symfony.bat' 文件到项目根目录, 使用 'symfony' 替代 'php symfony':

c:\> copy lib\vendor\symfony\data\bin\symfony.bat .

根据给出的应用程序名称参数generate:app 任务 在 apps/frontend 目录下创建了应用程序所需的默认目录结构:

| 目录 | 说明 | ------------ | ------------------------------------- | config/ | 应用程序配置文档 | lib/ | 应用程序需要的类和库 | modules/ | 应用程序的代码 (MVC) | templates/ | 全局的模板文件

TIP 除非特别说明,所有的 symfony 命令都应该在项目的根目录下运行。

当我们运行 generate:app 任务时,我们还传入了两个和安全相关的选项

  • --escaping-strategy: 激活输出转义来避免 ~XSS~ 攻击
  • --csrf-secret: 激活 session 密码来避免 ~CSRF~ 攻击

通过传递这两个可选选项给任务,我们已经让即将开发的应用程序直接针对目前网络上流 传甚广的两大安全隐患免疫。symfony 会自动替我们处理~安全~问题,很棒吧。

NOTE 如果你还不知道 XSSCSRF 的话,花点时间了解更多的关于这些安全隐患吧。

symfony 路径

你可以通过运行如下命令来获得 symfony 版本:

$ php symfony -V

-V 选项还会在结果中显示 symfony 的安装路径, 这可以在 config/ProjectConfiguration.class.php 中找到:

[php]
// config/ProjectConfiguration.class.php
require_once '/Users/fabien/work/symfony/dev/1.2/lib/autoload/sfCoreAutoload.class.php';

为方便移植项目,修改到 symfony 的绝对路径为相对路径:

[php]
// config/ProjectConfiguration.class.php
require_once dirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';

这样,把 Jobeet 项目移动到本机或其他机器的任意目录都可以正常运行。

~环境~

web/目录下的两个 PHP 文件 index.phpfrontend_dev.php 被称作前端控制器: 向应用程序发送的所有请求都通过他们来转达。但我们只有一个应用程序,为何要有两个前端控制器呢?

两个文件都指向同一个应用程序但适用于不同的环境。除非直接在生产服务器上开发应用程序, 你至少需要如下几个~环境~:

  • 开发环境: web 开发者可用它为应用程序添加新特性、修订bug ...
  • 测试环境: 此环境用于自动测试应用程序。
  • 阶段环境: 用于客户 测试应用程序和报告Bug和缺失的功能。
  • 生产环境: 这才和最终用户打交道。

是什么使环境如此不同?在一个实例的开发环境中,应用程序需要记录一次请求的所有细节 从而方便调试,但是必须关闭缓存系统以便所有的代码改动都能马上生效。 因此,开发环境必须针对开发者优化。最好的例子就是发生异常的时候。为了帮助开发者 快速调试出现的问题,symfony 会在浏览器显示有关当前请求的异常信息:

An exception in the dev environment

但是在生产环境中,必须启用缓存系统;应用程序应显示自定义的错误信息而不是原始的异常信息。 因此,生产环境必须针对性能和用户体验优化。

An exception in the prod environment

symfony 环境是一套特殊的配置设置,symfony 框架捆绑了三个环境:devtestprod。 在第22天,你将学会如何创建新环境,例如像 staging

如果你打开每个前端控制器文件,就会发现他们唯一的不同之处就是环境设置:

[php]
// web/index.php
<?php

require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');

$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false);
sfContext::createInstance($configuration)->dispatch();

NOTE 要定义一个新的 symfony 环境,我们只需简单的创建一个前端控制器。 后面我们会讨论如何修改一个环境下的配置。

蹩脚的~Web 服务器~配置

如果在前面的小节中你将 Jobeet 项目创建到了 web 服务器的根目录,你已经能够通过浏览器访问到这个项目了。

当然了,因为不需要任何配置,这很方便,但是当你试着访问 config/databases.yml 时, 就会发现偷懒所带来的严重后果。如果用户知道你的 Web 站点是基于 symfony 部署的, 他就能访问到许多敏感的文件。

永远不要在生产服务器上像这样配置 并请阅读下一小节从而正确的配置你的 web 服务器。

安全的 Web 服务器配置

一个良好的习惯是只将需要通过浏览器访问的如样式表、javascript 和图片等放到 ~web 根目录~。 而且,作为默认设置,我们推荐将这些文件保存在 symfony 项目的 web 子目录。

如果查看这个目录,你会发现一些保存 web ~组件~ 的子目录(css/ 和 images/)以及两个前端控制器文件。 前端控制器是唯一需要放在 web 服务器根目录下的 PHP 文件。 其他 PHP 文件都将隐藏在浏览器的后面,基于~安全~的考虑,这是个很好的主意。

web 服务器配置

是时候修改 ~Apache~ 配置让全世界人民都可以访问你的网站了。

找到并打开 httpd.conf 配置文件,在文末加入如下配置:

# 请确保下面这行在配置文件中只出现一次
NameVirtualHost 127.0.0.1:8080

# 这是针对 Jobeet 项目的配置
Listen 127.0.0.1:8080

<VirtualHost 127.0.0.1:8080>
  DocumentRoot "/home/sfprojects/jobeet/web"
  DirectoryIndex index.php
  <Directory "/home/sfprojects/jobeet/web">
    AllowOverride All
    Allow from All
  </Directory>

  Alias /sf /usr/local/symfony/data/web/sf
  <Directory "/usr/local/symfony/data/web/sf">
    AllowOverride All
    Allow from All
  </Directory>
</VirtualHost>

NOTE ~别名~ /sf 让你能够访问到完整显示 ~symfony 默认页~ 所需要的图片和 javascript 文件, 以及调试工具栏。

在 Windows 下, 你需要像下面这样替换 Alias 行:

Alias /sf "c:\development\symfony\data\web\sf"

并且 /home/sfprojects/jobeet/web 应替换为:

c:\development\sfprojects\jobeet\web

这样配置会使 Apache 监听本地主机的 8080 端口,因此可以使用如下 URL 访问 Jobeet:

http://~localhost~:8080/

你可以将 8080 替换为大于 1024 的任何端口,因为这不需要服务器管理员权限。

SIDEBAR 为 Jobeet 配置独立~域名~

如果你是服务器的管理员,最好是设置 ~虚拟主机~ 而不要每新增一个项目就新增一个端口。 也就是以选择合适的域名并加入 ServerName 指令来代替 选择端口并加入 Listen 指令的方式。

# This is the configuration for Jobeet
<VirtualHost 127.0.0.1:80>
  ServerName jobeet.localhost
  <!-- same configuration as before -->
</VirtualHost>

在 Apache 配置中使用的域名 jobeet.localhost 必须在本地声明并解析。 如果你使用的是 Linux 操作系统, 可以编辑 /etc/hosts文件。 如果你使用的是 Windows XP, 这个文件则在 C:\WINDOWS\system32\drivers\etc\ 目录下。

加入如下行:

127.0.0.1         jobeet.localhost

测试新的配置

重启 Apache, 根据上一小节的 Apache 配置,打开浏览器访问 http://localhost:8080/index.php/, 或者 http://jobeet.localhost/index.php/,确保你现在能够访问新的应用程序。

Congratulations

Note: 如果你安装了 Apache 的 mod_rewrite 模块,可以删除 URL 中的 /index.php/ 部分。 这或许应该感谢在 web/.~htaccess~ 文件中默认配置好的重写规则。

你还应该试着访问开发环境下的应用程序。键入如下 URL:

http://jobeet.localhost/frontend_dev.php/

web 调试工具栏应该能显示在右上角,包括小图标,这表明我们前面的 sf/ 别名配置已经成功。

web debug toolbar

~web 调试工具~ 在开发环境的所有页面中呈现并且在点击不同的标签页时会给出许多访问信息: 包括当前应用程序的配置、当前请求的日志、数据库引擎执行的 SQL 语句、内存占用信息和 时间信息等。

Note 如果你在 Windows 环境下使用 IIS 服务器运行 symfony,配置会稍有不同。 寻找如何配置的相关教程

~Subversion~

开发期间采用源代码版本控制是非常好的主意。使用源码控制我们可以:

  • 信心满满的工作
  • 如果改动破坏了任何代码我们可以恢复到旧版本
  • 允许超过1个人有效的在项目下协同工作
  • 允许访问应用程序的每一个正确运行的版本

我们将在本节讲解怎样使用 Subversion 配合 symfony 项目开发。 如果你使用的是其他的源码版本控制系统,从我们介绍的 Subversion 迁移过去也是很容易的。

我们假定你已经有一台可以访问的 Subversion 服务器,并且可以通过 HTTP 访问了。

TIP 如果你还没有 subversion 服务器,你可以到 Google Code 免费申请,或者在 Google 搜索引擎中键入 "免费 subversion 版本仓库(free subversion repository)" 等关键词查找更多可用的服务器。

首先,在仓库服务器上为 jobeet 项目创建一个仓库:

$ svnadmin create http://svn.example.com/jobeet

在你的计算机上创建基本的目录结构:

$ svn mkdir -m "created default directory structure"
➥ http://svn.example.com/jobeet/trunk
➥ http://svn.example.com/jobeet/tags
➥ http://svn.example.com/jobeet/branches

检出空的 trunk/ 目录:

$ cd /home/sfprojects/jobeet
$ svn co http://svn.example.com/jobeet/trunk/ .

然后,清空cache/log/目录下的内容,我们不需要将他们纳入版本控制。

$ rm -rf cache/* log/*

现在,确保 cache 和 log 目录拥有写入权限以便 web 服务器能在其中写入内容:

$ chmod 777 cache/ log/

然后,导入所有的文件和目录:

$ svn add *

因为我们永远不需要提交 cache//log 目录下的内容,你可以设定忽略名单:

$ svn propedit svn:ignore cache

为 SVN 配置的默认文本编辑器将自动打开。我们需要 Subversion 忽略此目录下的所有内容:

*

存盘退出。做好了。

针对 log/ 目录重复如上操作:

$ svn propedit svn:ignore log

并键入:

*

最后,将这些改动提交到仓库:

$ svn import -m "made the initial import" .
  ➥ http://svn.example.com/jobeet/trunk

Tip ~Windows~ 用户可以使用 TortoiseSVN 这个很棒的客户端来管理 Subversion 仓库。

明天见

好了,今天的时间差不多了。虽然我们还没有开始讲到 symfony ,但我们已经搭建了可靠的 开发环境,还提到了web 开发的最佳实践,做好开始编码的准备了。

明天,我们将透露这个应用程序会做些什么并谈及在本教程中实现的需求。

Note 如果你想要检出今天的代码或者今后每天的代码,以每天为基础的可用代码可以 从 Jobeet 的 SVN 官方仓库 (http://svn.jobeet.org/##ORM_LOWER##/)获得。

例如:你可以使用 release_day_01 tag 检出今天的代码:

  $ svn co http://svn.jobeet.org/##ORM_LOWER##/tags/release_day_01/ jobeet/

ORM