Entries tagged as technique
一个 # 不够,那么就多来几个吧 Wed, Sep 3. 2008
网页中经常要做的一件事情就是让一个链接来执行一个 JavaScript 脚本,例如:< href="#" onClick="some_js_here();">Some text</a>,不过这样的副作用是因为有 href="#"。所以导致点击完后页面会滚动到最上面。
以前用的几种解决方案:
- 不写 href,这样会导致很多浏览器不会把 a 标签按照你预期的方式渲染;
- 在href 里面直接写 JavaScript 脚本,这样不完全符合 W3C 的规范。
其实要解决这个问题,不让浏览器把页面滚动到最上面,很简单,href="" 里面 多写几个 # 就行了,我一般用 6 个比较保险,这个方法适用于 IE5、IE6、IE7、FF2、FF3。虽然不知道为什么但是很好用。猜测是因为 # 表示进行页内书签的跳转,但是多个 # 浏览器就不知道什么意思了,干脆罢工好了,哈哈。
解决 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>
MySQL 对于 COUNT(*) 和 LIMIT 同时使用的 BUG Sun, Aug 17. 2008
对一个有 29 条记录的表进行如下操作:
- SELECT COUNT( sys_uia_account.ID ) FROM sys_uia_account结果 29
- SELECT COUNT( sys_uia_account.ID ) FROM sys_uia_account LIMIT 10结果 29
- SELECT COUNT( sys_uia_account.ID ) FROM sys_uia_account LIMIT 10 , 10没有结果
看来以后使用 COUNT(*) 的时候不能同时使用 LIMIT offset, row_count 这种表达方式了。
PS:如果统计全表记录,使用下面的方法会更加快捷:
- SELECT SQL_CALC_FOUND_ROWS *
- FROM sys_uia_account;
- SELECT FOUND_ROWS( ) ;
唯一需要注意的就是,这两个查询必须在一起进行,因为 SQL_CALC_FOUND_ROWS 不对结果进行任何缓存。
MySQL 中用 GKB 来让 UTF-8 字段中的中文按照拼音排序 Sat, Aug 16. 2008
UTF-8 中的中文不是按照拼音排序的,因此对于 使用 UTF-8 编码集的字段就无法按照拼音进行排序,最简单的解决方法就是转成 GBK 编码。
实例代码:
- SELECT *
- FROM `test`
- ORDER BY CONVERT( `test`.`name`
- USING GBK )
- LIMIT 0 , 30
数据库表结构:
- CREATE TABLE IF NOT EXISTS `test` (
- `id` int(3) NOT NULL AUTO_INCREMENT,
- `name` varchar(10) COLLATE utf8_bin NOT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;
测试环境:Windows 2003 Standard Edition,MySQL 5.1.22-rc-community。
对于偶正在使用的 Symfony 框架,因为使用了 propel 做 ORM,比较难直接操作SQL,除非使用 RAW SQL,而且使用 RAW SQL会导致很多高级特性无法使用,解决方式:
- $criteria->addAscendingOrderByColumn('CONVERT(' . TestPeer::NAME . ' USING GBK)');
