+ -
当前位置:首页 → 问答吧 → Zf 分页类 之 曲高和寡

Zf 分页类 之 曲高和寡

时间:2008-08-01

来源:互联网

我的原则就是不改动Zf的代码,在中间加一层 Custom。
复制PHP内容到剪贴板
PHP代码:

<?php
//Model 直接继承这里就行
class Custom_Db_Table extends Zend_Db_Table
{
function preDispatch()
{
}

public function fetchPage($where = null, $order = null, $pagesize = 20, $currentpage = 1)
{
  $result = array();
  $result['count'] = $this->fetchAll($where, $order)->count();
  $result['pagecount'] = $result['count']/$pagesize>1 ? ceil($result['count']/$pagesize) : 1;
  $offset = ($currentpage-1)*$pagesize;
  $result['currentpage'] = $currentpage;
  $result['firstpage'] = 1;
  $result['lastpage'] = $result['pagecount'];
  $result['table'] = $this->fetchAll($where, $order, $pagesize, $offset)->toArray();
  return $result;
}
}
?>

复制PHP内容到剪贴板
PHP代码:

<?php
//这个是可以直接写SQL的
require_once 'Zend/Db/Adapter/Pdo/Mysql.php';
class Custom_Db_Adapter_Pdo_Mysql extends Zend_Db_Adapter_Pdo_Mysql
{
public function fatchPage($sql, $pagesize=20, $currentpage=1)
{
  $currentpage = is_numeric($currentpage) ? $currentpage : 1 ;
  $result = array();
  $result_array = $this->query($sql);
  $result['count'] = count($result_array->fetchAll());
  $result['pagecount'] = $result['count']/$pagesize>1 ? ceil($result['count']/$pagesize) : 1;
  $offset = ($currentpage-1)*$pagesize;
  $result['currentpage'] = $currentpage;
  $result['firstpage'] = 1;
  $result['lastpage'] = $result['pagecount'];
  $sql .= ' '.$this->select()->limit($pagesize, $offset)->__toString();
  $result['table'] = $this->query($sql)->fetchAll();
  return $result;
}
}
?>

将上面类返回的数组注入到下面方法中就能生成翻页
复制PHP内容到剪贴板
PHP代码:

<?php
/*
* 类名:Custom_Page
* 功能:翻页处理类
* 版本:1.0
* 日期:20080731
* 作者:王哲
* 版权:NIO
*/
class Custom_Page
{
public static function mToPage(array $Page)
{
  //firstpage
  //count
  //pagecount
  //lastpage
  //table
  //currentpage
  $url = 'http://'.$_SERVER ['HTTP_HOST'].$_SERVER["REQUEST_URI"];
  $result = '共'.$Page['count'].'条记录 共'.$Page['pagecount'].'页 第'.$Page['currentpage'].'页';
  $result .= '<select id="selectPage">';
  for($i=1; $i<=$Page['pagecount']; $i++)
  {
   if (preg_match ("/page[\=|\/]{1}(\d+)/i", $url))
   {
    if(preg_match ("/page[\=]{1}(\d+)/i", $url))
    {
     $pageurl = preg_replace("/page[\=]{1}(\d+)/i", 'page='.$i, $url);
    }
    elseif (preg_match ("/page[\/]{1}(\d+)/i", $url))
    {
     $pageurl = preg_replace("/page[\/]{1}(\d+)/i", 'page/'.$i, $url);
    }
   }
   else
   {
    $pageurl = '?page='.$i;
   }
   $selected = $Page['currentpage']==$i ? 'selected' : '';
   $result.='<option value="'.$pageurl.'" '.$selected.'>'.$i.'</option>';
  }
  $result .= '</select>';
  
  return array('showpage' => $result, 'table' => $Page['table']);
}
}
?>

Controller中的应用
复制PHP内容到剪贴板
PHP代码:
$list = Custom_Page::mToPage($dbAdapter->fatchPage('SELECT * FROM user JOIN type on (user.typeid=type.id)', 10, $this->_getParam('page')));
  $this->view->showPage = $list['showpage'];
  $this->view->table = $list['table'];

Custom_DB类,让偶重写了。
复制PHP内容到剪贴板
PHP代码:

<?php
require_once 'Zend/Db.php';
require_once 'Custom\Db\Adapter\Pdo\Mysql.php';
class Custom_Db extends Zend_Db
{
public static function myfactory($config = array())
{
  $adapterName = 'Custom_Db_Adapter_Pdo_Mysql';
  $dbAdapter = new $adapterName($config);
  return $dbAdapter;
}
}
?>

index.php 引导页
复制PHP内容到剪贴板
PHP代码:
$dbAdapter = Custom_Db::myfactory($config->db->config->toArray());
Custom_Db_Table::setDefaultAdapter($dbAdapter);
$dbAdapter->query('SET NAMES UTF8');
Zend_Registry::set('dbAdapter', $dbAdapter);

index.html 模板,我这里用的是Smarty
复制PHP内容到剪贴板
PHP代码:
<{section name=key loop=$table}>
      <{$table[key].name}><br>
<{/section}>
<{$showPage}>

效果


[ 本帖最后由 wz_910 于 2008-8-19 14:35 编辑 ]
附件: 您所在的用户组无法下载或查看附件

作者: wz_910   发布时间: 2008-08-01

难道又是“曲高和寡”?

作者: wz_910   发布时间: 2008-08-01

引用:
原帖由 wz_910 于 2008-8-1 14:06 发表
难道又是“曲高和寡”?
可能是因为ZF自己已经有这个组件了
http://framework.zend.com/manual/en/zend.paginator.html

作者: jasonqi   发布时间: 2008-08-01

代码包里没有啊,那就送给那些,图省事的朋友吧。

作者: wz_910   发布时间: 2008-08-01

引用:
原帖由 wz_910 于 2008-8-1 14:42 发表
代码包里没有啊,那就送给那些,图省事的朋友吧。
1.6版里应该有,实在不行就SVN吧

作者: jasonqi   发布时间: 2008-08-01

不改动ZF代码是一个基本的封装原则,除非你的代码不打算重用和可扩展,或者你想将ZF的模块抽出来用。
SHOW一下我的CRUD界面,基本的功能有增加,删除,更新,查询,分页,排序,刷新,校验,装饰和过滤。并且能很灵活配置和扩展。基本上我都是拿别人的轮子自己组装的。使用ZF封装了三个jquery的插件,flexigrid,thickbox,和ajaxform,直接在php脚本中就可以对这些插件的参数进行配置。
呵呵,封装之后,从数据表设计到生成CRUD页面只需要10分钟,甚至更少。
下面的是调用的页面,以tbl_test为例。建好数据表,注释好字段(注释之后就不用翻译字段名了)
在M层定义一个Form模型和Table模型,基本上空的就可以了。一共要写6行代码
复制PHP内容到剪贴板
PHP代码:
//Form_Test模型
class Form_Test extends Itc_Form
{  
}
//Tbl_Test模型
class Tbl_Test extends Itc_DB_Table
{  
}

C层比较多一些代码。不过基本上都可以复制粘贴的。其实还可以进一步封装,但为了方便细节控制就没有做了。
复制PHP内容到剪贴板
PHP代码:
public function testAction()
    {
        //创建数据库对象
        $tbl = new Tbl_Test();        
       //获得提交的类型
        $type = $this->_getType();
        if('GRID' == $type){  //如果是grid的提交,则让数据库对象处理提交内容,然后返回json数据
            $this->_helper->json($tbl->ajaxQuery($this->_request));    
        }
        else{
               //创建一个表单对象
            $form = new Form_Test();
            //将表单关联数据对象
            $form->setTable($tbl);
           //将数据库字段转换成表单元素,构造表单的html代码,并设置校验器,过滤器和装饰器。
            $form->setTableElements();
            //设置form的action为当前action
            $form->setAction($this->view->url());
            if ('POST' ==  $type){ //如果是表单提交
                 //获得表单值
                $formData = $this->_request->getPost(); 
                 //校验
                if ($form->isValid($formData)){
                  try{
                    //保存,如果是新增就插入,否则就是update,自动判断
                    $tbl->save($formData);
                }
                catch (Exception $e){
                   //报错
                    $message = $this->_('Error: Data can not be saved');
                    $this->_helper->json(array('error'=>$e->getMessage()));
                    exit;
                }
                //返回表单提交成功消息
                $this->_helper->json(true);
              }
              else{
                  //返回校验失败信息
                  $this->_helper->json($form->getMessages());
              }
             }
             else{
                  //创建一个grid对象
                 $grid = new Itc_Grid();
                 //设置标题
                 $gridOptions['title'] = '用户一览';
                //设置检索的字段
                 $gridOptions['searchitems'] = array('code','name','rate');
                 $grid->setOptions($gridOptions);
                 //将数据对象关联Grid对象,目的为了获得字段的注释内容
                 $grid->setTable($tbl);
                 //将grid对象和form对象交给view去处理
                 $this->view->grid = $grid;
                 $this->view->form = $form;       
             }   
        }
    }

View层更简单了
复制PHP内容到剪贴板
PHP代码:
//输出grid
<?=$this->grid?>
//设置thickbox的title和长宽
<?=$this->thickbox('用户信息',300,220)?>
//设置ajax form
<?=$this->ajaxForm($this->form)?>
就这么多代码
显示效果如下:
表单列表界面

表单输入的界面
附件: 您所在的用户组无法下载或查看附件

作者: sentrychen   发布时间: 2008-08-01

一个分页都还要搞个几个类出来。。。。。。。。太强悍了

作者: fleaphp   发布时间: 2008-08-01

我的可不仅仅是分页

作者: sentrychen   发布时间: 2008-08-01

ZF本身就有分页解决方案

作者: 七月十五   发布时间: 2008-08-01

我说的楼主哈。

不过你的代码有个严重的安全漏洞:

$tbl->save($formData);

作者: fleaphp   发布时间: 2008-08-01

呵呵,有什么安全问题呢?不过我这个是快速版本,一般我会在Tbl_Test里面覆盖save方法做一些细节的处理。
但我看不出$tbl->save($formData)有啥安全问题,请指教。。。
附上save的代码
复制PHP内容到剪贴板
PHP代码:
public function save(array $data)
    {
        $primary = (array) $this->_primary;
        $pkData = array_intersect_key($data, array_flip($primary));
        $where = array();
        $data = array_intersect_key($data, array_flip($this->_cols));
        foreach ($primary as $key)
        {
            if (!isset($pkData[$key]) || '' === $pkData[$key])
            {
                return $this->insert($data);
            }
            $where[] = $this->_db->quoteInto($key . ' = ?', $pkData[$key]);
        }
        return $this->update($data, $where);
    }

作者: sentrychen   发布时间: 2008-08-01

假设我的用户 id 是 123,你的用户 ID 是 456。

你先前添加了一个记录,其 id 是 456-AAA。

现在我准备添加记录,但是我伪造了一个表单,提交了一个包含主键 ID 的字段,其值为 456-AAA。
很显然,由于 save() 方法根据自动判断是否有主键来更新记录。最终就是我更新了你添加的记录。

作者: fleaphp   发布时间: 2008-08-01

引用:
原帖由 sentrychen 于 2008-8-1 17:18 发表
C层比较多一些代码。不过基本上都可以复制粘贴的。其实还可以进一步封装,但为了方便细节控制就没有做了。
我已经做了进一步的封装,细节控制可以放模型(表单和数据库表的类)里做,发现运行效率还可以,这样,CRUD就是通用的了,表设计好了,效果就出来了。

作者: jasonqi   发布时间: 2008-08-02

引用:
原帖由 fleaphp 于 2008-8-1 23:54 发表
假设我的用户 id 是 123,你的用户 ID 是 456。

你先前添加了一个记录,其 id 是 456-AAA。

现在我准备添加记录,但是我伪造了一个表单,提交了一个包含主键 ID 的字段,其值为 456-AAA。
很显然,由于 save( ...
呵呵,你说的这个问题我有考虑过,不过我写的这个方法是最基本的实现方法,一般是用在和用户无关的数据方面。对于涉及到用户安全的数据,我写了一个表单校验器,是根据当前用户和主键ID进行判断的,一般在save之前就校验好了,也可以通过覆盖save方法来控制。我的Tbl_Test和Form_Test两个模型都是空的,里面可以做很多细节的控制。如果我认为这些数据是和具体用户无关只和操作权限有关,那么在action里面控制好了权限,凡是有权限的用户他爱伪造就伪造吧,反正他不伪造也可以直接编辑的。
呵呵,还是谢谢你提出这个问题。其实你说的这个问题,我在使用你的fleaphp将里面的shop范例改成多用户多shop的时候就碰到了,不过只要考虑到了,就很好解决的。

作者: sentrychen   发布时间: 2008-08-02

代码我就不贴了,大致说一下我是如何做的。

1) 在Url 添加一个参数对,传递表信息,其实就是表的名称,如 /tb/role,这样对应于CRUD的Urls就出来了,例如:
/dbform/edit/tb/role/id/4,其中 dbform是控制器,edit是动作, 表名是 role, id = 4。在控制器里,做4个对应的动作方法。

2)在模型里,处理关于表的细节,例如字段标题,我使用 MySQL ,表里没有这些信息,我就手工在模型里做个数组(缺点是,修改表结构的时候,一定要记住在这里做相应的修改)

这是我的demo,你可以看一下
http://dev.tmclubs.org/
其中,role和club管理是用上述方法做的,其它还是老方法(我主要是想对比一下)

作者: jasonqi   发布时间: 2008-08-03

愿意搞自己开板块去,从这侃什么

[ 本帖最后由 wz_910 于 2008-8-4 09:48 编辑 ]

作者: wz_910   发布时间: 2008-08-04

现在封装得越来越多,越来越深,都快失去PHP的“敏捷”特性了。

作者: peacock   发布时间: 2008-08-04

呵呵,太好了。1.6里面的新东东呀!

作者: liumingl   发布时间: 2008-08-04

唉!!
相当费劲!!

[ 本帖最后由 hmly 于 2008-8-4 16:53 编辑 ]

作者: hmly   发布时间: 2008-08-04

各有所长,不过zend做的确实越来越多了,但是后面讨论的话题和楼主人家要表达的思想偏离了。后面的同志都是展示自己的东西了。没有说出楼主代码的优缺点来。

[ 本帖最后由 lei0535 于 2008-8-4 17:20 编辑 ]

作者: lei0535   发布时间: 2008-08-04

呵呵,不好意思偶走题了。。。是偶的错。
zf的分页算法我也没有看过。但个人觉得楼主的分页算法还算不上曲高吧。
提几点个人的意见:
1,分页算法至少要能自动获取和解析分页参数值,比如page的值,query的值,然后根据这些值去获取分页内容。这个应该是分页类最基本的工作。
2,扩展Zend_Db和Zend_Db_Table是很好的,但如果只是为了分页而去扩展实在没有必要。你对Zend_Db_Adapter_Pdo_Mysql的扩展让我很惊讶,这样做的目的是什么呢?是为了说明这个分页类只能适用mysql数据库?说实话利用Zend_Db中的query方法能做得更好,还可以兼容各种数据库。
3,
复制PHP内容到剪贴板
PHP代码:
$result['count'] = $this->fetchAll($where, $order)->count();
$result['table'] = $this->fetchAll($where, $order, $pagesize, $offset)->toArray();

这个问题不小,你将数据全部取出来,只是为了计算数据数量,然后再重复查询数据库获得某一范围的数据。为何不直接从第一次查询的结果中提取你要的数据呢?可以减少一次数据库查询。另外你都这么有空扩展了这么多的类,为啥就不肯多写一个计算count的方法呢?select cout(*) 要比select * 效率高。建议要么写一个count的方法,要么将fetchAll的数据缓存起来,下一页的时候直接从缓存中读取。

作者: sentrychen   发布时间: 2008-08-05

谢谢,这才是我要看到的,很有道理,我收下。

作者: wz_910   发布时间: 2008-08-05

热门下载

更多