今天需要在 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;
}
function sort($sortSpec,
$sortDir =
'ASC') { 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);
$datagrid->
setDefaultSort(array ( 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
$pager =
$smarty->
smartyGetPaging(array ( '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>