Posts Tagged ‘symfony’

Doctrine2.0入门和提高

July 2nd, 2010

Doctrine是众多PHP ORM框架中的一个。symfony从版本1.3后就默认开始使用Doctrine1.x,而不是Propel。在年底发布的Symfony2.0也将毫无疑问的使用Doctrine2.0。
因为使用Symfony和Doctrine的2年多了,觉得有必要分享一些经验,所以就有想写《Doctrine2.0入门和提高》这样的一系列文章,希望能坚持到底:-).
—-正题—
首先Doctrine项目从2.0版本开始作者将Doctrine分成了五个子项目(包),每个子项目都有独立的文档,这样做的好处是开发者可以根据需要使用。Doctrine2.0只支持PHP5.3以上版本,为获得更高的性能,建议采用APC加速PHP。

Object Relational Mapper

对象关系映射建立于数据库抽象层DBAL(Database Abstraction Layer),主要提供了DQL(Doctrine Query Language),DQL的设计灵感来源于HQL(Hibernate),主要是给开发者提供了一个基于对象的查询语法,是开发者维护更少的代码。

Database Abstraction Layer

主要提供数据库schema的检查,管理和PDO抽象

MongoDB Object Document Mapper

特别针对MongoDB开发的数据库接口

Doctrine Migrations

同样构建于DBAL, 能够方便的进行数据库版本控制,修改和迁移。

Common

包涵了所有其他子项目的依赖包
--

安装

Doctrine2.0提供了多种安装方式
使用PEAR

# 安装Common
$ sudo pear install pear.doctrine-project.org/DoctrineCommon-2.0.0
# 安装DBAL和Common
$ sudo pear install pear.doctrine-project.org/DoctrineDBAL-2.0.0
# 安装ORM和Common
$ sudo pear install pear.doctrine-project.org/DoctrineORM-2.0.0

使用PEAR安装后,可以这样导入Doctrine类

require 'Doctrine/Common/ClassLoader.php';
$classLoader = new \Doctrine\Common\ClassLoader();

包安装,下载
git安装

$ git clone git://github.com/doctrine/doctrine2.git doctrine

subversion安装

$ svn co http://svn.github.com/doctrine/doctrine2.git doctrine2

安装完成后运行doctrine(PEAR安装),或者运行bin/doctrine,得到如下信息

Doctrine Command Line Interface version 2.0.0BETA2

Usage:
  [options] command [arguments]

Options:
  --help           -h Display this help message.
  --quiet          -q Do not output any message.
  --verbose        -v Increase verbosity of messages.
  --version        -V Display this program version.
  --color          -c Force ANSI color output.
  --no-interaction -n Do not ask any interactive question.

Available commands:
  help                         Displays help for a command (?)
  list                         Lists commands
dbal
  :import                      Import SQL file(s) directly to Database.
  :run-sql                     Executes arbitrary SQL directly from the command line.
orm
  :convert-d1-schema           Converts Doctrine 1.X schema into a Doctrine 2.X schema.
  :convert-mapping             Convert mapping information between supported formats.
  :ensure-production-settings  Verify that Doctrine is properly configured for a production environment.
  :generate-entities           Generate entity classes and method stubs from your mapping information.
  :generate-proxies            Generates proxy classes for entity classes.
  :generate-repositories       Generate repository classes from your mapping information.
  :run-dql                     Executes arbitrary DQL directly from the command line.
  :validate-schema             Validate that the mapping files.
orm:clear-cache
  :metadata                    Clear all metadata cache of the various cache drivers.
  :query                       Clear all query cache of the various cache drivers.
  :result                      Clear result cache of the various cache drivers.
orm:schema-tool
  :create                      Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output.
  :drop                        Processes the schema and either drop the database schema of EntityManager Storage Connection or generate the SQL output.
  :update                      Processes the schema and either update the database schema of EntityManager Storage Connection or generate the SQL output.

国外主流PHP框架比较-CodeIgniter、CakePHP、ZendFramework、Symfony

January 7th, 2010

来源:http://www.phpchina.com/index.php?action-viewnews-itemid-35342

最近简单的使用了目前在国内用的比较多的几个主流国外PHP框架(不包括国内框架),大致对这些框架有个直观上的感受,简单分享一下,对于哪些做框架选型的时候,权当一个参考。

主要参考的框架包括:CodeIgniter、CakePHP、ZendFramework、Symfony

说明:我对很多框架也没有认真使用,只是简单试用了一下,可能很多看法不成熟或者是错误的,请大家指正,一起成长。

【 CodeIgniter 】

官方网站:http://codeigniter.com

中文网站:http://codeigniter.org.cn

中文手册:http://codeigniter.org.cn/user_guide

视频教程:http://codeigniter.org.cn/tutorials

测试版本:CodeIgniter_1.6.1

优点:

1. 配置简单,全部的配置使用PHP脚本来配置,执行效率高;具有基本的路由功能,能够进行一定程度的路由;具有初步的Layout功能,能够制作一定程度的界面外观;数据库层封装的不错,具有基本的MVC功能

2. 快速简洁,代码不多,执行性能高,框架简单,容易上手,学习成本低,文档详细;自带了很多简单好用的library,框架适合小型应用

缺点:

1. 把Model层简单的理解为数据库操作

2. 框架略显简单,只能够满足小型应用,略微不太能够满足中型应用需要

评价:

总体来说,拿CodeIgniter来完成简单快速的应用还是值得,同时能够构造一定程度的layout,便于模板的复用,数据操作层来说封装的不错,并且CodeIgniter没有使用很多太复杂的设计模式,执行性能和代码可读性上都不错。至于附加的 library 也还不错,简洁高效。

【 CakePHP 】

官方网站:http://www.cakephp.org

中文手册:http://www.1x3x.net/cakephp

视频教程:http://search.you.video.sina.com.cn/s?key=cakephp

测试版本:cake_1.1.19.6305

优点:

1. CakePHP是最类似于RoR的框架,包括设计方式,数据库操作的Active Record方式;设计层面很优雅,没有自带多余的 library,所有的功能都是纯粹的框架,执行效率还不错;数据库层的 hasOne, hasMany 功能很强大,对于复杂业务处理比较合适;路由功能,配置功能还不错;自动构建脚手架(scaffold)很强大;适合中型应用;基本实现过了MVC每一 层;具有自动操作命令行脚本功能;

2. 文档比较全,在国内推广的比较成功,大部分都知道CakePHP,学习成本中等

缺点:

1. CakePHP非常严重的问题是把Model理解为数据库层操作,严重影响了除了数据库之外的操作能力

2. CakePHP的cache功能略显薄弱,配置功能稍嫌弱;CakePHP不适合大型应用,只适合中型应用,小型应用来说略微的学习成本高了点

评价:

总体来说CakePHP框架代表了PHP框架很重要的一个时代和代表,并且目前发挥着很重要的作用,不少自己写的框架都模仿了CakePHP的方式,是个里程碑式的产品;CakePHP透露着RoR的敏捷开发方式和把数据库操作认为是唯一Model的设计思想,作为开发快速应用和原型是绝好的工具;同样,用来做Web2.0网站的开发框架,也是值得选择的。

Zend Framework 】

官方网站:http://framework.zend.com

中文手册:http://www.phpeye.com/zf

视频教程:http://framework.zend.com/docs/screencasts

测试版本:ZendFramework-1.5.0

优点:

1. 官方出品,自带了非常多的 library,框架本身使用了很多设计模式来编写,架构上很优雅,执行效率中等;MVC设计中,比较简洁,具有路由功能,配置文件比较强大(能够处理 XML和php INI),各种 library 很强大,是所有PHP框架中各种功能最全面的,包括它不仅是一个框架,更是一个大类库(取代PEAR),这是它的主要特色;能够直观的支持除数据库操作之 外的Model层(比 CodeIgniter 和 CakePHP 强),并且能够很轻易的使用Loader功能加载其他新增加的Class;Cache功能很强大,从前端Cache到后端Cache都支持,后端 Cache支持Memcache、APC、SQLite、文件等等方式;数据库操作功能很强大,支持各种驱动(适配器)

2. 文档很全,在国内社区很成熟,并且目前不少Web 2.0网站在使用,学习成本中等

缺点:

1. MVC功能完成比较弱,View层简单实现(跟没实现一样),无法很强大的控制前端页面

2. 没有自动化脚本,创建一个应用,包括入口文件,全部必须自己手工构建,入门成本高

3. Zend Framework 作为一个中型应用框架问题不大,也能够勉强作为大型应用的框架,但是作为一个很成熟的大型PHP框架来说,还需要一些努力

评价:

作 为官方出品的框架,Zend Framework的野心是可以预见的,想把其他框架挤走,同时封装很多强大的类库,能够提供一站式的框架服务,并且他们的开发团队很强大,完全足够有能 力开发很强大的产品出来,所以基本可以确定的是Zend Framework前途无量,如果花费更多的时间去完善框架。同样的,Zend Framework架构本身也是比较优雅的,说明Zend官方是有很多高手的,设计理念上比较先进,虽然有一些功能实现的不够完善,比如View层,自动 化脚本等等,这些都有赖于未来的升级。总体来说Zend Framework是最值得期待的框架,当然,你目前要投入你的项目中使用也是完全没问题的。

【 Symfony 】

官方网站:http://www.symfony-project.org

中文网站:http://symfony-project.cn

权威指南:http://www.symfony-project.org/book

学习参考:http://sf.thecodecentral.com

测试版本:symfony-1.0.13

优点:

1. Symfony 是我了解的PHP框架中功能最强大的,而且我使用时间比较长,但是很多功能还是没有挖掘出来;它完整实现了MVC三层,封装了所有东西,包括 $_POST,$_GET 数据,异常处理,调试功能,数据检测;包含强大的缓存功能,自动加载Class(这个功能很爽),强大的i18n国家化支持;具有很强大的view层操 作,能够零碎的包含单个多个文件;非常强大的配置功能,使用yml配置能够控制所有框架和程序运行行为,强大到让人无语;能够很随意的定义各种自己的 class,并且symfony能够自动加载(auto load)这些class,能够在程序中随意调用;包含强大的多层级项目和应用管理:Project –> Application –> Module –> Action,能够满足一个项目下多个应用的需要,并且每层可以定义自己的类库,配置文件,layout;非常强大的命令行操作功能,包括建立项目、建立 应用、建立模块、刷新缓存等等;

2. Symfony绝对是开发大型复杂项目的首选,因为使用了Symfony,将大大节约开发成本,并且多人协作的时候,不会出现问题,在Project级别定义好基础Class以后,任何模块都能够重用,大大复用代码

缺点:

1. 数据库操作model采用了重量级的propel和creole,不过在我测试的版本中已经把他们移到了addon里,可用可不用

2. 缓存功能无法控制,每次开发调试总是缓存,需要执行 symfony cc, symfony rc 来清除和重建缓存;

3. 效率不是很高,特别是解析模板和读取配置文件的过程,花费时间不少;

4. 学习成本很高,并且国内没有成熟的社区和文档,连中文手册都没有,相应的要掌握所有功能,需要花费比较多的时间

评价:

Symfony绝对是企业级的框架,唯一能够貌似能够跟Java领 域哪些强悍框架抗衡的东西;强悍的东西,自然学习复杂,但是相应的对项目开发也比较有帮助,自然是推荐复杂的项目使用Symfony来处理,觉得是值得, 后期的维护成本比较低,复用性很强。相应的如果使用Symfony的应该都是比较复杂的互联网项目,那么相应的就要考虑关于数据库分布的问题,那么就需要 抛弃Symfony自带的数据库操作层,需要自己定义,当然了,Symfony支持随意的构造model层。

【 总评 】

以上数款框架,各有特色,而且都是开源项 目,不过框架针对的项目不一样,一般来说 CodeIngiter 比较适合小型项目,CakePHP 和 Zend Framework 比较适合中型项目,Symfony 比较适合大型重量级项目,在项目选型的时候,要充分考虑框架的可以定制性、扩展性,因为每个项目都无法确定你是否会随着需求的变化进行改变。

相 对来说,Zend Framework 和 Symfony 应对变化的能力比较强,特别是能够随意定制 model 层的Class,能够非常方便增加自己业务或者数据处理类,我是个人比较推荐在中大型项目中使用的框架。CodeIngiter 和 CakePHP 在中小型项目中同样能够发挥重大作用,快速开发和原型构建,非常适合目标不清晰的原型项目的开发。了解一个框架最好的方式就是使用它,学习它最好的方式就 是看视频。:-)

仁者见仁,智者见智,在项目挑选框架的时候,请先认真考察项目的需求和未来的变化,然后选择合适的框架,让项目开发速度和后期维护性得到一个合理的平衡,当然了,也许,自己写一个框架更适合。 :-)

泛泛的评价了几款框架,估计很多东西都没有说到点子上,大家就姑且看之,同样欢迎提出看法指正!

More with symfony 1.3 & 1.4-提高你的生产力

January 6th, 2010

提高你的生产力

作者: Fabien Potencier 翻译:逗派

使用symfony本身是web开发人员提高生产力的好方法。当然,每个知道symfony的异常细节和web 调试工具条的人都可以很大程度的提高生产力。 本章将告诉你一些提示和技巧,通过使用一些新的或很少被人所知的功能来更高的提高你的生产力。

启动速度更快:自定义项目创建过程

通过symfony中CLI的工具,创建一个新的symfony的项目,是快速,简单:

$ php /path/to/symfony generate:project foo --orm=Doctrine

generate:project 任务为您生成新项目的默认目录结构,并创建设置合理的默认值的配置文件。然后,您可以使用symfony的任务创造应用系统,安装插件,配置你的模型等等。

但是,创建一个新项目的第一个步骤通常总是不尽相同:您创建一个主应用程序,安装一堆的插件,根据你的需求调整一些默认配置等等。

随着symfony 1.3构架,该项目创建过程可以自定义和自动化。

由于所有symfony的任务都是类,所以可以很容易定制和扩展他们。但是generate:project任务并不能很容易的自定义,因为当执行这个任务的时候,项目还没有存在。

generate:project 任务有一个--installer选项,它可以指定在创建项目的过程中执行一个php脚本 :

$ php /path/to/symfony generate:project --installer=/somewhere/my_installer.php

/somewhere/my_installer.php脚本在 sfGenerateProjectTask实例的环境下运行,所以可以通过使用 $this对象来使用该任务的方法。 以下各节描述所有你可以用来自定义您的项目创建过程的方法。

如果你在php.ini中开启了include()方法的url file-access功能, 你甚至可以可以把URL作为参数传给–installer(当然当你使用了一个你完全不知道内容的脚本你需要非常小心):

$ symfony generate:project
 --installer=http://example.com/sf_installer.php

installDir()

installDir() 方法映射一个目录结构(包括子目录和文件)到新建的项目中:

$this->installDir(dirname(__FILE__).'/skeleton');

runTask()

runTask() 方法执行一个symfony任务。 它需要一个任务名称,一个作为任务的参数和选项的字符串两个参数:

$this->runTask('configure:author', "'Fabien Potencier'");

参数和选项也可以使用数组传递:

$this->runTask('configure:author', array('author' => 'Fabien Potencier'));

正如期望的,symfony任务的简写也可以使用:

$this->runTask('cc');

这个方法当然可以用来安装插件:

$this->runTask('plugin:install', 'sfDoctrineGuardPlugin');

为了安装特定版本的插件,只需要传递必要的选项就可以了:

$this->runTask('plugin:install', 'sfDoctrineGuardPlugin', array('release' => '10.0.0', 'stability' => beta'));

为了执行一个新安装的插件里的任务,首先需要重新加载任务:

$this->reloadTasks();

如果你创建了一个新的应用程序,想使用一个依赖特定应用程序的任务,像generate:module,你一定要自己手动变换配置环境:

$this->setConfiguration($this->createConfiguration('frontend', 'dev'));

日志

在安装脚本运行时为了给开发者回馈信息,您可以将一些东西很容易的写入日志中:

// 一个简单日志
$this->log('some installation message');

// 记录一个日志块
$this->logBlock('Fabien\'s Crazy Installer', 'ERROR_LARGE');

// 记录一个日志模块
$this->logSection('install', 'install some crazy files');

用户交互

askConfirmation(), askAndValidate()ask() 方法允许你问问题,使得你的安装过程可以动态配置。

如果你只需要确认,请使用 askConfirmation() 方法:

if (!$this->askConfirmation('Are you sure you want to run this crazy installer?'))
{
  $this->logSection('install', 'You made the right choice!');

  return;
}

通过使用ask()方法你也可以问任何问题,并获得一个字符串代表的用户答案:

$secret = $this->ask('Give a unique string for the CSRF secret:');

如果你想验证答案,使用askAndValidate() 方法:

$validator = new sfValidatorEmail(array(), array('invalid' => 'hmmm, it does not look like an email!'));
$email = $this->askAndValidate('Please, give me your email:', $validator);

文件系统操作

如果你想改变文件系统,你可以通过symfony的文件系统对象:

$this->getFilesystem()->...();

Sandbox应用的创建过程

symfony sandbox是一个预先打包的symfony项目,包括一个现成的应用程序和预先设定的SQLite数据库。任何人可以通过使用安装脚本创建一个sandbox :

$ php symfony generate:project --installer=/path/to/symfony/data/bin/sandbox_installer.php

symfony/data/bin/sandbox_installer.php 脚本是一个安装脚本的实际例子,值得一读。

安装脚本只是一个php脚本文件。所以,你可以做任何你想做的事情 。不象创建一个新项目时一而在再而三执行相同的任务,您可以创建自己的安装程序脚本,调整成您想要的symfony项目安装方式。 通过安装程序创建一个新的项目要快得多,并防止丢失步骤。您甚至可以与他人分享您的安装脚本!

第六章 , 我们将使用一个自定义的安装脚本。 你可以附件 B中找到源代码。

更快的开发

从PHP代码到CLI任务,编程意味着无尽的敲打键盘。让我们看看如何把输入降低至最低限度。

选择你的IDE

使用IDE能够帮助开发者在从多种的途径提高效率。

首先,绝大多数的现代化IDE提供PHP的自动完成功能。这意味着你只要打一个方法名字的开始几个字母。这也意味这即使你不记得方法的名字,你也不用去查询API文档,因为IDE会提示当前对象的所有可用方法。

此外,有的像PHPEdit或NetBeans的IDE,了解了更多的Symfony,能够对symfony的项目提供更具体的集成。

文本编辑器

有些用户更喜欢文本编辑器来编写代码,主要原因是文本编辑器比IDE快很多。 当然,文本编辑器没有提供IDE那么多的功能。但是绝大多数流行的编辑器,也提供插件或扩展用于增强用户体验,使得编辑PHP和symfony项目更加的有效。

比如,很多Linux用户倾向于使用VIM来工作。对于这些开发者,可以使用vim-symfony 扩展。 VIM-symfony 是一系列VIM脚本把symony集成到你喜爱的编辑器中。使用vim-symfony, 你可以容易的创建vim宏和命令来简化你的symfony开发。它还捆绑了默认的命令集,许多配置文件(模式,路由等)也是触手可及,使您可以轻松地从action切换到template。

有些MacOS X用户喜欢使用TextMate。这些开发者可以安装 symfony bundle, 它添加了很多日常开发中省时的宏和快捷方式。

使用支持symfony的IDE

有些IDE,比如 PHPEdit 3.4NetBeans 6.8, 本身支持symfony,所以给框架提供了精细粒度的集成。看看它们的文档,了解他们的symfony中的具体支持,以及如何可以帮助你更快地发展。

帮助IDE

在IDE自动完成PHP的只能是明确的,在PHP代码中定义的方法。但是如果你的代码使用了 __call()__get() 魔法方法,IDE就没有办法猜测可用的方法或属性。好消息是,你可以在PHPDoc块中提供方法和/或属性来帮助IDE(通过使用@method和@propterty标签)

比如我们有一个Message 类拥有一个动态属性  (message) 和一个动态方法 (getMessage())。 下面的代码向你展示怎样让IDE知道这些信息,而不需要在PHP代码中明确申明:

/**
 * @property clob $message
 *
 * @method clob getMessage() Returns the current message value
 */
class Message
{
  public function __get()
  {
    // ...
  }

  public function __call()
  {
    // ...
  }
}

即使 实际的getMessage() 方法不存在, 由于 @method 标签IDE还是能识别这个方法。 对于message属性也是同样的原理,因为我们添加了 @property 标签。

这个技术已经在doctrine:build-model 任务中使用了。比如,一个有两列(messagepriority)的Doctrine MailMessage 类看起来像下面代码:

/**
 * BaseMailMessage
 *
 * This class has been auto-generated by the Doctrine ORM Framework
 *
 * @property clob $message
 * @property integer $priority
 *
 * @method clob        getMessage()  Returns the current record's "message" value
 * @method integer     getPriority() Returns the current record's "priority" value
 * @method MailMessage setMessage()  Sets the current record's "message" value
 * @method MailMessage setPriority() Sets the current record's "priority" value
 *
 * @package    ##PACKAGE##
 * @subpackage ##SUBPACKAGE##
 * @author     ##NAME## <##EMAIL##>
 * @version    SVN: $Id: Builder.php 6508 2009-10-14 06:28:49Z jwage $
 */
abstract class BaseMailMessage extends sfDoctrineRecord
{
    public function setTableDefinition()
    {
        $this->setTableName('mail_message');
        $this->hasColumn('message', 'clob', null, array(
             'type' => 'clob',
             'notnull' => true,
             ));
        $this->hasColumn('priority', 'integer', null, array(
             'type' => 'integer',
             ));
    }

    public function setUp()
    {
        parent::setUp();
        $timestampable0 = new Doctrine_Template_Timestampable();
        $this->actAs($timestampable0);
    }
}

更快的查询文档

由于symfony是一个有丰富功能的大框架,记得所有可能的配置,或所有你要使用的类和方法是非常困难的。正如我们已经看到过,使用IDE可以提供你非常强大的自动完成功能。让我们探索如何利用现有的工具来尽可能快地找到可能的答案。

在线API

最快的方式找到一个类或方法的文档是在线浏览 API.

更有趣的是系统内建的API搜索引擎。搜索允许你只用几个字母就可以快速找到一个类和方法。在API页面的搜索框输入几个字母,一个带有有用提示的快速搜索框会实时出现。

你可以通过输入类名的开头来搜索:

API Search

或者一个方法的名称:

API Search

或者一个类名加::来列出所有可用方法:

API Search

或者再添加方法名的开头来提炼可能结果:

API Search

如果你想列出一个包所有的类,只要输入包名,提交请求就可以了。

你甚至可以集成symfony API搜索到你的浏览器种。这样,你甚至不需要访问symfony网站就能查找。这是因为symfony API搜索本身提供了 OpenSearch 支持.

如果你使用Firefox, symfony API搜索引擎会在搜索引擎菜单自动出现。你也可以点击在API文档上的  “API OpenSearch” 链接来添加到你的浏览器搜索框。

你可以在这个博客上查看截图,展示symfony api搜索引擎使如何很好的集成到Firefox中的。

备忘单

如果你想快速查看框架主要部分的信息,很多备忘单可供你选择:

有些备忘单还没有更新到symfony1.3

离线文档

关于配置的问题最好的答案是symfony参考指南。这是一本任何时候你用symfony开发时都需要放在身边的书。感谢非常详细的目录,术语的索引,夸章节引用等,这本书是找到每个可用配置的最快方法。你可以浏览在线版本,买一本打印版本,设置下载一个PDF 版本

在线工具

正如本章开始看到的,symfony中提供了一个很好的工具集来帮助您更快得开始。 最后,您将完成您的项目,并在一段时间后将其部署到生产。

要检查您的项目是否已经部署就绪,可以使用在线部署清单。 这个网站涵盖了你在产品上线前需要全都检查得重点。

更快的调试

当在开发环境下出现错误的时候,symfony展现一个包涵了有用信息的异常页面。例如你可以查看堆栈跟踪信息和已执行的文件,如果你设了在settings.yml(看下面的代码) 配置文件中设置了sf_file_link_format, 你甚至可以点击文件名,对应的文件就会在你喜欢的文本编辑器或IDE中打开。虽然这是一个在你调试问题时可以帮你节约很多时间的小功能,是一个非常棒的例子,。

当设置了sf_file_link_format参数,在Web调试工具条上的日志和可视面板显示的文件名(尤其当启用了XDebug)也可以点击。

默认情况下, sf_file_link_format 是空的。symfony将把php配置文件中 xdebug.file_link_format的值重新设为默认值。(在php.ini中设置 xdebug.file_link_format 允许现在的XDebug版本在堆栈跟踪添加所有文件的链接)。

sf_file_link_format的值根据你的IDE和操作系统不同而不同。比如,如果你想在TextMate中打开,添加下面的代码到settings.yml中:

dev:
  .settings:
    file_link_format: txmt://open?url=file://%f&line=%l

%f 占位符会由symfony替换位文件的绝对路径, %l 占位符由行号取代。

如果你使用VIM,在网上有更多的关于 symfonyXDebug的描述。

使用搜索引擎来学习配置你的IDE。你也可以通过同样的方式来查找关于sf_file_link_formatxdebug.file_link_format的配置。

更快的测试

记录你的功能测试

功能测试模拟用户的交互行为,以便全面测试集成的所有应用程序块。写功能测试虽然简单,但非常耗时。不过,每一个功能测试文件就是模拟用户浏览您的网站的一个场景,因为浏览网站比写php代码要快的多,如果你能够记录浏览的过程,并自动转换成php代码呢?谢天谢地,symfony中有这样的插件。它被称为swFunctionalTestGenerationPlugin,它让你在几分钟内产生一个现成的可自定义的测试框架。当然,你仍然需要添加适当的测试使之有用,但这仍然节省了大量时间。

该插件通过注册symfony过滤器(filter),拦截所有请求,并将其转换为功能测试代码。按通常的方式安装插件后,你需要启用它。打开您应用程序的filters.yml文件并在注释行后添加下面的内容:

functional_test:
  class: swFilterFunctionalTest

接下来,在你ProjectConfiguration类中启用插件:

// config/ProjectConfiguration.class.php
class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
    // ...

    $this->enablePlugin('swFunctionalTestGenerationPlugin');
  }
}

因为插件使用web调试工具条作为它的主要用户界面,请务必将它激活(在默认开发环境情况下是激活的)当启用时,一个新的菜单名为“Functional Test”在工具条上出现。在这个面板上,您就可以点击“激活(Activate)”链接来开始录制,点击“重置(Reset)”按钮重新开始录制。当您完成了,复制并粘贴textarea中代码到一个测试文件,并开始对其进行自定义。

更快的运行测试套件

当你有一个大的测试套件,每次您更改后运行所有测试将是非常耗时的,尤其是当一些测试失败了。每次您修复一个测试,你应该运行整个测试套件以确保你没有破坏其他测试。但是直到失败的测试被修复了,否则就没有必要重新执行所有的测试。为了加速这个过程, test:all 任务有一个 --only-failed (可以简写为-f )选项,可以强制只执行上次测试失败的用例:

$ php symfony test:all --only-failed

在第一次执行时,所有的测试都正常运行。但随后的测试,只运行上次失败的测试。当您修复您的代码时,一些测试会通过,并从随后的测试中删除。当所有的测试都通过的时候,所有的测试会被重新运行…然后你就重复这样的过程。

More with symfony 1.3 & 1.4-高级路由 (第二部分)

December 31st, 2009

高级路由 (第二部分)

作者:Ryan Weaver 翻译:逗派

路由集合(Route Collections)

要完成Sympal Builder应用,我们需要创建一个管理平台,使得每个 Client 能管理他们的页面。 要做到这一点,我们需要一系列的action让我们能够创建,更新和删除 Page对象。 由于这些类型的模块(module)非常通用,symfony可以自动生存这些模块。从命令行执行下面的任务(task)在backend应用中生成一个 pageAdmin模块:

$ php symfony doctrine:generate-module backend pageAdmin Page --with-doctrine-route --with-show

上面的命令产生一个包含action和templates的管理模块,它能完成所有对Page对象的修改需求。有很多自定义选项可以修改自动生存的CRUD,但这超出了本章要讨论的范围。

虽然上述命令为我们准备了需要的module,但是我们还是需要为每个action创建路由。 通过附加给命令的--with-doctrine-route 选项,每个action都会有生存一个相应的对象路由。这样减少了在每个action中的代码。比如在 edit action 中只有简单的一行:

public function executeEdit(sfWebRequest $request)
{
  $this->form = new PageForm($this->getRoute()->getObject());
}

总共,我们需要给index, new, create, edit, updatedelete actions都分配一个路由。一般创建这些具有RESTful风格的路由需要在routing.yml做非常多的配置。

pageAdmin:
  url:         /pages
  class:       sfDoctrineRoute
  options:     { model: Page, type: list }
  params:      { module: page, action: index }
  requirements:
    sf_method: [get]
pageAdmin_new:
  url:        /pages/new
  class:      sfDoctrineRoute
  options:    { model: Page, type: object }
  params:     { module: page, action: new }
  requirements:
    sf_method: [get]
pageAdmin_create:
  url:        /pages
  class:      sfDoctrineRoute
  options:    { model: Page, type: object }
  params:     { module: page, action: create }
  requirements:
    sf_method: [post]
pageAdmin_edit:
  url:        /pages/:id/edit
  class:      sfDoctrineRoute
  options:    { model: Page, type: object }
  params:     { module: page, action: edit }
  requirements:
    sf_method: [get]
pageAdmin_update:
  url:        /pages/:id
  class:      sfDoctrineRoute
  options:    { model: Page, type: object }
  params:     { module: page, action: update }
  requirements:
    sf_method: [put]
pageAdmin_delete:
  url:        /pages/:id
  class:      sfDoctrineRoute
  options:    { model: Page, type: object }
  params:     { module: page, action: delete }
  requirements:
    sf_method: [delete]
pageAdmin_show:
  url:        /pages/:id
  class:      sfDoctrineRoute
  options:    { model: Page, type: object }
  params:     { module: page, action: show }
  requirements:
    sf_method: [get]

想要查看这些路由,可以使用 app:routes 命令, 它能展示一个特定应用程序的所有路由的摘要。

$ php symfony app:routes backend

>> app       Current routes for application "backend"
Name             Method Pattern
pageAdmin        GET    /pages
pageAdmin_new    GET    /pages/new
pageAdmin_create POST   /pages
pageAdmin_edit   GET    /pages/:id/edit
pageAdmin_update PUT    /pages/:id
pageAdmin_delete DELETE /pages/:id
pageAdmin_show   GET    /pages/:id

使用路由集合代替路由

幸运的是,symfony提供了一个更加方便的方法来指定包含传统的CRUD功能的所有路由。在routing.yml中用一个简单的路由替换上面所有的内容。

pageAdmin:
  class:   sfDoctrineRouteCollection
  options:
    model:        Page
    prefix_path:  /pages
    module:       pageAdmin

我们再次运行app:routes命令来查看所有的路由,正如你所看到的,前面的七个路由仍然存在。

$ php symfony app:routes backend

>> app       Current routes for application "backend"
Name             Method Pattern
pageAdmin        GET    /pages.:sf_format
pageAdmin_new    GET    /pages/new.:sf_format
pageAdmin_create POST   /pages.:sf_format
pageAdmin_edit   GET    /pages/:id/edit.:sf_format
pageAdmin_update PUT    /pages/:id.:sf_format
pageAdmin_delete DELETE /pages/:id.:sf_format
pageAdmin_show   GET    /pages/:id.:sf_format

路由集合是一种特殊类型的路由对象,它内部包含了许多个路由。 比如, sfDoctrineRouteCollection 路由自动生成做CRUD操作时七个最常用的路由。  sfDoctrineRouteCollection 幕后所做的无非就是创建我们先前在routing.yml配置的七个路由。路由集合主要是为创建一个通过路由组合而存在的快捷方式。

创建一个自定义的路由集合

在这点上,每个Client能够通过URL/pages在他的Page对象上做正常CRUD修改。 不幸的是,现在每个Client 能够看到和修改所有的Page对象-包括属于和不属于他的。比如,如,http://pete.sympalbuilder.com/backend.php/pages 会展现所有在fixtures.yml定义的Page的列表- Pete’s Pet Shop的 location页面和City Pub的 menu 页面。

要解决这个问题,我们需要重用在frontend创建的acClientObjectRoute。 sfDoctrineRouteCollection 类将生成一组sfDoctrineRoute 对象。但在这个应用中,我们需要生成一组 acClientObjectRoute 对象。

要做到这一点,我们将需要使用一个自定义的路由集合类。创建一个文件 acClientObjectRouteCollection.class.php ,并把它放到 lib/routing 目录。它的内容是难以置信的简单:

// lib/routing/acClientObjectRouteCollection.class.php
class acClientObjectRouteCollection extends sfObjectRouteCollection
{
  protected
    $routeClass = 'acClientObjectRoute';
}

$routeClass 属性定义了创建每个基本路由时使用的类型。现在每个基本路由都是使用acClientObjectRoute了,工作实际已经完成了。比如 , http://pete.sympalbuilder.com/backend.php/pages 现在指挥展现一个页面:Pete’s Pet Shop的 location页面。 感谢自定义路由类型,index action才能根据请求中的子域名展现只与正确的Client相关的Page对象。 只用了几行代码,我们就已经创建了整个可以被多个用户安全的使用的后台模块。

遗漏的部分:创建新页面

现在,当创建或编辑一个Page对象时会显示一个Client 选择框。替换允许用户选择Client(存在安全隐患)的功能,让我们根据请求中的子域名自动设置Client,

首先, 更新在 lib/form/PageForm.class.php文件中的PageForm对象

public function configure()
{
  $this->useFields(array(
    'title',
    'content',
  ));
}

现在这个选择框已经从Page的表单中消失了。但是,当创建了一个新的Page对象后,其client_id从没被设置过。为了解决这个问题,手动在new和create action中设置关联的 Client 信息。

public function executeNew(sfWebRequest $request)
{
  $page = new Page();
  $page->Client = $this->getRoute()->getClient();
  $this->form = new PageForm($page);
}

这里引入了的新方法getClient(),现在在acClientObjectRoute 类型中还没有 。 让我们通过一点小小的修改来把它加到类型中:

// lib/routing/acClientObjectRoute.class.php
class acClientObjectRoute extends sfDoctrineRoute
{
  // ...
 
  protected $client = null;
 
  public function matchesUrl($url, $context = array())
  {
    // ...
 
    $this->client = $client;
 
    return array_merge(array('client_id' => $client->id), $parameters);
  }
 
  public function getClient()
  {
    return $this->client;
  }
}

通过添加 $clien类属性,并在matchesUrl()方法中初始化,我们可以通过路由简单的获得这个Client对象。 现在新Page对象的client_id列会根据现在host中的子域名被自动正确的初始化。

自定义一个对象路由集合

通过使用路由框架,我们现在已经轻松的解决了创建Sympal Builder应用时提出的问题。随着应用的增长,  开发者能够在管理后台给其他模块重用自定义的路由(例如, 每个 Client 可以管理自己的图片相册).

创建自定义路由集合的另一个常见原因是添加额外的,常用的路由。比如,假设一个项目使用了很多model,每个model都有一个 is_active列。 在管理方面,需要有一个简单的方法来切换任何特定对象的is_active值。首先,修改 acClientObjectRouteCollection 指示它添加一个新的路由到集合中:

// lib/routing/acClientObjectRouteCollection.class.php
protected function generateRoutes()
{
  parent::generateRoutes();
 
  if (isset($this->options['with_is_active']) && $this->options['with_is_active'])
  {
    $routeName = $this->options['name'].'_toggleActive';
 
    $this->routes[$routeName] = $this->getRouteForToggleActive();
  }
}

当集合对象被初始化时调用sfObjectRouteCollection::generateRoutes() 方法,该方法负责创建所有需要的路由并把它们添加到$routes类属性中。在这个例子中,我们把实际创建路由的工作放到了新创建的getRouteForToggleActive()方法中:

protected function getRouteForToggleActive()
{
  $url = sprintf(
    '%s/:%s/toggleActive.:sf_format',
    $this->options['prefix_path'],
    $this->options['column']
  );
 
  $params = array(
    'module' => $this->options['module'],
    'action' => 'toggleActive',
    'sf_format' => 'html'
  );
 
  $requirements = array('sf_method' => 'put');
 
  $options = array(
    'model' => $this->options['model'],
    'type' => 'object',
    'method' => $this->options['model_methods']['object']
  );
 
  return new $this->routeClass(
    $url,
    $params,
    $requirements,
    $options
  );
}

唯一剩下的步骤是在routing.yml中设定这个路由集合。注意generateRoutes()在添加新的路由前需要查看 lwith_is_active参数。 添加这样的逻辑让我们在以后使用acClientObjectRouteCollection但不需要toggleActive的情况下有更多的控制能力:

# apps/frontend/config/routing.yml
pageAdmin:
  class:   acClientObjectRouteCollection
  options:
    model:          Page
    prefix_path:    /pages
    module:         pageAdmin
    with_is_active: true

运行app:routes命令,验证新的 toggleActive路由已经存在。唯一剩下要做的是创建一个action来完成实际的工作。因为你可能需要在多个模块中使用这个路由集合和相应的action。在apps/backend/lib/action(你需要创建这个目录)目录中新建backendActions.class.php:

# apps/backend/lib/action/backendActions.class.php
class backendActions extends sfActions
{
  public function executeToggleActive(sfWebRequest $request)
  {
    $obj = $this->getRoute()->getObject();
 
    $obj->is_active = !$obj->is_active;
 
    $obj->save();
 
    $this->redirect($this->getModuleName().'/index');
  }
}

最后,把pageAdminActions类的基类换成backendActions类。

class pageAdminActions extends backendActions
{
  // ...
}

我们刚才完成了什么呢? 通过添加路由到路由集合和一个关联的基类action,任何新的模块只要使用acClientObjectRouteCollection和扩展backendActions类就可以自动使用这些功能。这样,通用的功能可以很容易地在许多模块共享。

路由集合的配置选项

对象路由包含了一系列的选项,允许它可以高度自定义。在很多情况下,开发人员可以使用这些选项配置路由集合而不需要创建一个新的自定义路由集合类。一份详细的路由集合选项列表可以在《symfony参考指南》中查到。

Action路由

每个对象路由集合接收三个不同的选项,它们决定在集合中需要生成的正确的路由。不做深入的探讨,下面配置的集合会生成7个默认的路由以及一个额外的集合路由和对象路由:

pageAdmin:
  class:   acClientObjectRouteCollection
  options:
    # ...
    actions:      [list, new, create, edit, update, delete, show]
    collection_actions:
      indexAlt:   [get]
    object_actions:
      toggle:     [put]

默认情况下,使用model的主健来生成所有的url和查询对象。这个,当然,也可以简单的改变。 比如,下面的代码会使用slug列而不是主健:

pageAdmin:
  class:   acClientObjectRouteCollection
  options:
    # ...
    column: slug

Model方法

默认情况下,路由会获取集合路由中所有关联的对象和查询对象路由中指定的列。如果你需要重写这些,在路由上添加 model_methods选项。在这个例子中,fetchAll()findForRoute() 方法 需要被添加到PageTable 类中。两个方法都会接收一个request参数数组作为参数。

pageAdmin:
  class:   acClientObjectRouteCollection
  options:
    # ...
    model_methods:
      list:       fetchAll
      object:     findForRoute

默认参数

最后,假设你需要在请求中添加特定参数,并在集合中的每个路由可用。这个可以通过default_params选项简单的实现:

pageAdmin:
  class:   acClientObjectRouteCollection
  options:
    # ...
    default_params:
      foo:   bar

最后的思考

传统的路由框架功能是-匹配和生成url- 已发展成为一个完全可定制的,能满足项目最复杂的URL需求的能力的系统。通过控制路由对象,特定的URL结构能够从业务逻辑中抽象出来,并完全独立存在在路由框架中。最终的结果是更可控制,更灵活和更易于管理的代码。

Master & Slave connections in Doctrine 1.2 and Symfony 1.3

December 21st, 2009

http://snippets.symfony-project.org/snippet/373

1. 配置database.yml,设置master,slave数据库连接

2. 覆写Doctrine默认的Query 和Record

public function configureDoctrine(Doctrine_Manager $manager)
{
    // Configure custom query and custom record classes
    $manager->setAttribute(Doctrine::ATTR_QUERY_CLASS, 'MyQuery');
    $options = array('baseClassName' => 'MyRecord');
    sfConfig::set('doctrine_model_builder_options', $options);
}

3. 创建自定义的Query

class MyQuery extends Doctrine_Query
{
  public function preQuery()
  {
      // If this is a select query then set connection to the slave
      if (Doctrine_Query::SELECT == $this->getType()) {
          $this->_conn = Doctrine_Manager::getInstance()->getConnection('slave');
      // All other queries are writes so they need to go to the master
      } else {
          $this->_conn = Doctrine_Manager::getInstance()->getConnection('master');
      }
  }
}

4.创建自定义的Record

abstract class MyRecord extends sfDoctrineRecord
{
    public function save(Doctrine_Connection $conn = null)
    {
      $conn = Doctrine_Manager::getInstance()->getConnection('master');
      parent::save($conn);
    }
}

5. 如果你使用的Doctrine Behaviour(比如Versionable)需要创建表,也需要指明

Entity:
  ActAs:
    Versionable:
      builderOptions:
        baseClassName: MyRecord

如果你有多个slave服务器,就在ProjectConfiguration中配置在启动的时候选择一个,同时修改Query对象获得得connection名字

4 web framework like ROR

December 19th, 2009

well , ROR is definitely a great framework for web developers, it‘s young but full of energy and charming.

but unfortunately, I don’t like Ruby grammar…

there should be many other frameworks cloning ROR , but the next 3 is my favorite in their languages,

all of them are full stack framework, which means they all support MVC, template, route, security, ORM etc.

1. Symfony

http://www.symfony-project.org/

written in PHP which is the most used program language in web development.

the greatest point of symfony is its easy database migrate with ORM, a lot of caches mechanism and a very simple but effective view template

2. Grails

http://www.grails.org/

written in Groovy,
the greatest point is that it’s fully compatible with JDK

3. Django

http://www.djangoproject.com/
written in Python

4. Spring Roo

http://www.springsource.com/download/community?project=Spring%20Roo

it’s spring native guy, you know what it means