解决 propel-convert-xml-schema 把 null 默认值处理为字符串的问题 Thu, Aug 21. 2008
通过 propel-convert-xml-schema 把 xml schema 转化成 PHP 代码的时候,如果一个字符型字段不能为空且没有明确输入默认值,例如:
- <column name="username" type="VARCHAR" size="128" required="true" default=""/>
生成的 PHP 代码中该字段的默认值是 'null' 而不是 null,导致页面输入框的默认值不是空值,而是一个字符串的 null,很恼火。因为要么在页面中每个字段都对 'null' 做特殊处理,要么修改生成的 PHP 类文件,但是一旦重新执行 propel-convert-xml-schema 就会重新覆盖。
解决办法:修改 propel-generator/classes/propel/phing/PropelCreoleTransformTask.php 文件(对于 Symfony 来说,就是 symfony/vendor/propel-generator/classes/propel/phing/PropelCreoleTransformTask.php)。应用如下 patch:
- 507,510c507
- < //$node->setAttribute("default", iconv($this->dbEncoding, 'utf-8', $defValue));
- < if(!empty($defValue)) {
- < $node->setAttribute("default", iconv($this->dbEncoding, 'utf-8', $defValue));
- < }
- ---
- > $node->setAttribute("default", iconv($this->dbEncoding, 'utf-8', $defValue));
参见:#2045 (propel-convert-xml-schema generate null text as default values) - symfony - Trac。
在 Symfony 中结合使用 Structures/DataGrid、sfSmartView、Propel Mon, Aug 18. 2008
今天需要在 symfony 中使用 datagrid 型控件对一个分页+排序的表格进行展示。但是 sfDataGrid 写得实在是太糟糕了,没有找到其他的比较好的 plugin。
PEAR 中的 Structures/DataGrid 倒是不错。但是两个问题:无法和现在偶使用的 sfSmartyView 直接结合,因为在 $datagrid->fill($smarty); 的时候,symfony 还没有生成 view instance,除非直接获取生成的 HTML_TABLE 或者类似的结果,这样不利于 MVC 的分离和对具体样式的控制;二是现有的 datasource 无法和 symfony 使用的 propel 直接结合,如果采用检索全部结果再传递给 Structures/DataGrid 进行分页处理,那么效率非常低下。
于是自己写一个 datasource,并且使用了一点技巧解决和 sfSmartyView 结合的问题。
Structures_DataGrid_DataSource_Propel 类的定义:
- class Structures_DataGrid_DataSource_Propel extends Structures_DataGrid_DataSource {
- protected $criteria = null;
- protected $con = null;
- protected $object = null;
- function __construct($object, $criteria, $con = null) {
- parent::Structures_DataGrid_DataSource();
- $this->object = new $object();
- $this->criteria = $criteria;
- $this->con = $con;
- }
- //TODO: this is not a good way, due to MySQL Bug #21787
- $this->criteria->setLimit(0);
- $this->criteria->setOffset(0);
- $result = $this->object->doCount($this->criteria);
- return $result;
- }
- case 'asc' :
- $this->criteria->addAscendingOrderByColumn($sortSpec);
- break;
- case 'desc' :
- $this->criteria->addDescendingOrderByColumn($sortSpec);
- break;
- default :
- return PEAR::raiseError("Sorting dir must be ASC or DESC!");
- }
- return true;
- }
- function fetch($offset = 0, $len = null) {
- $c = $this->criteria;
- $c->setOffset($offset);
- $c->setLimit($len);
- }
- $objects = $this->object->doSelect($c);
- foreach ($objects as $object) {
- $result[] = $object->toArray(BasePeer::TYPE_COLNAME);
- }
- return $result;
- }
- }
action 中的代码段:
- public function execute() {
- // get data source
- $c = new Criteria();
- $datasource = new Structures_DataGrid_DataSource_Propel('SysUiaAccountPeer', $c);
- // setup datagrid
- $datagrid = & new Structures_DataGrid(10);
- $datagrid->bindDataSource($datasource);
- SysUiaAccountPeer::USERNAME=>"DESC"
- ));
- $datagrid->addColumn(new Structures_DataGrid_Column('用户名', SysUiaAccountPeer::USERNAME, SysUiaAccountPeer::USERNAME, array (), ' ', ''));
- // add more columns here
- // use a tip to get output using smarty
- $smarty = $datagrid->setRenderer('smarty');
- // set pager params
- 'prevImg'=>"上一页", 'nextImg'=>"下一页", 'separator'=>"|", 'delta'=>"5", 'clearIfVoid'=>true, 'spacesBeforeSeparator'=>"1", 'spacesAfterSeparator'=>"1", 'firstPageText'=>'第一页', 'lastPageText'=>'最后页'
- ), $smarty);
- $this->dg = $datagrid->getOutput();
- $this->pager = $pager;
- return sfView::SUCCESS;
- }
模板中的处理:
- <!-- Build header -->
- {section name=col loop=$dg.columnSet}
- <th{$dg.columnSet[col].attributes}><!-- Check if the column is sortable -->
- {if $dg.columnSet[col].link != ""} <a href="{$dg.columnSet[col].link}">{$dg.columnSet[col].label}</a>
- <!-- Show the current ordering with an arrow --> {if
- $dg.columnSet[col].name == $smarty.request.orderBy} {if
- $smarty.request.direction == "ASC"}↑{elseif
- $smarty.request.direction == "DESC"}↓{/if} {/if} {else}
- {$dg.columnSet[col].label} {/if}</th>
- {/section}
- </tr>
- <!-- Build body -->
- {section name=row loop=$dg.recordSet}
- <tr {if $smarty.section.row.iteration is even}bgcolor="#EEEEEE"{/if}>
- {section name=col loop=$dg.recordSet[row]}
- <td{$columnSet[col].attributes}>{$dg.recordSet[row][col]}</td>
- {/section}
- </tr>
- {/section}
- <td colspan="...">{$pager}</td>
- </tr>
- </table>
symfony 学习笔记 - 2 - 开始运行 symfony Thu, Feb 28. 2008
安装 symfony 库
用 PEAR 方式安装
- # 在 PEAR 频道列表里添加 symfony 频道
- pear channel-discover pear.symfony-project.com
- # 查看该频道内可用的包
- pear remote-list -c symfony
- # 安装 symfony 包
- pear install symfony/symfony
- # 安装完毕后,查看版本,确认安装成功
- symfony -V
- # 用下面这句来安装最新的 beta 版
- install symfony/symfony-beta
Symfony 库被安装在以下目录内:
$php_dir/symfony/:核心库。$data_dir/symfony/:symfony 的程序框架,默认的模块和配置信息,全球化数据等。$doc_dir/symfony/:文档。$test_dir/symfony/:单元测试。
注:最新版本的 PEAR 安装 symfony 会出现错误,解决方法参见在 Linux 下用 PEAR 安装 Symfony 出现错误的解决方案。
通过 SVN 安装
- # 创建 symfony 库的目录
- mkdir /path/to/symfony
- cd /path/to/symfony
- # 通过 SVN 检出发行版文件
- svn checkout http://svn.symfony-project.com/tags/RELEASE_1_0_0/ .
- # 查看版本号,确认安装成功
- php /path/to/symfony/data/bin/symfony -V
如果你用 SVN 方式安装,那么你需要在 config/config.php
文件内修改下面两个变量的信息:
- $sf_symfony_lib_dir = '/path/to/symfony/lib/';
- $sf_symfony_data_dir = '/path/to/symfony/data/';
创建第一个程序
创建项目
- # 假设当前目录为 htdocs 目录
- mkdir myproject
- cd myproject
- # 下面这句适用于 PEAR 安装方式
- symfony init-project myproject
- # 下面这句适用于 SVN 安装方式
- php /path/to/symfony/data/bin/symfony init-project myproject
Symfony 会自动生成上一节说的那些目录结构。
创建应用
- symfony init-app myapp
建立 web/sf/ 目录。把 /path/to/symfony/data/web/sf/
拷贝到 myproject/web/sf/,或者创建对应的符号链接。
现在访问 http://localhost/myproject/web/myapp_dev.php/
应该能看到这样的界面:
如果你看到类似这样的界面,那么你的 symfony 第一步安装成功了。
symfony 学习笔记 - 1 - 基础知识 Wed, Feb 27. 2008
symfont 的 MVC 实现
- 模型层
- 数据库抽象层
- 数据访问
- 视图层
- 视图
- 模板
- 布局
- 控制层
- 前端控制
- 动作
symfont 的工作流:

代码组织
代码组织实例:

根目录文件树结构
apps/:一个子目录对应一个应用,通常是frontend对应前台,backend对应后台。frontend/backend/
batch/:需要从命令行运行或者周期性运行的 PHP 批处理脚本。cache/:配置信息的缓存,以及动作和和模板的缓存(如果你启用了的话)。用这个缓存机制来加速请求的响应速度,每个应用都有一个对应的目录,放置预处理过的 PHP 和 HTML 文件。config/:每个项目的常规配置信息。data/:项目里和数据相关的文件,比如数据库模式、SQL 文件,甚至是 SQLite 的数据库文件。sql/functional/
doc/:项目文档,包括你自己写的文档,和由 PHPDoc 生成的文档。lib/:外部的类或者库。你可以在这里添加需要在项目级共享的代码。model/目录里是项目整体的对象模型。model/
log/:由 symfony 直接生成的日志文件。plugins/:插件目录。test/:单元测试和功能测试脚本。在创建项目的过程中,symfony 会自动创建一些测试的。unit/functional/
web/:Web 服务器的根目录,只有这个目录里面的文件才能被访问到。css/images/js/uploads/
模型目录树文件结构
apps/[application name][module name]actions/:通常情况下这个目录里只有一个名为actions.class.php的文件,这个文件里是该模型的全部动作,你也可以分开成单独的文件。actions.class.php
config/:该模型的自定义配置信息,可以有本地化参数。lib/:该模型特有的类库。templates/:与每个动作对应的模板文件。在创建模型的时候会自动生成默认模板文件indexSuccess.php。indexSuccess.php
validate/:专门用来校验表单数据的配置文件。
Web 目录树文件结构
web/css/:样式表文件。images/:图形文件。js/:JavaScript 脚本文件。uploads/:用户上传的目录。
在 Linux 下用 PEAR 安装 Symfony 出现错误的解决方案 Wed, Jan 23. 2008
开发环境:
- Slackware Linux 12.0
- Apache httpd-2.2.6
- PHP 5.2.5
- PEAR 1.6.2
根据官方文档,用 PEAR 安装 Symfony的命令如下:
- pear channel-discover pear.symfony-project.com
- pear install symfony/symfony
但是运行 channel-discover 的时候报错:Discovery of channel "pear.symfony-project.com" failed。
原因:PEAR 本身的 bug,不支持 channel 的 url 中包含 - 字符。
解决方法:用命令 pear upgrade -f PEAR-1.4.6 把 PEAR 降级到 1.4.6 版,然后正常安装,再用命令 pear upgrade-all 升级 PEAR。
或者应用 PEAR 的 Bug #6960 补丁修补这个 Bug。此方法见参考链接 2。
参考链接:

