多条件组合查询主要用到yii的CDbCriteria,这个类很多oem框架都有,非常好用。
前台表单
前台查询表单效果是这样的,多个条件组,每个组里放多个input,name为数组。当任何一个复选框被勾选上,发起ajax请求,当然,最顶层的复选框勾上时判断是否有子项,有的话把所有的子项勾选上。
但提交一次请求会向服务端post这样一个表单
其中currentPage是隐藏字段,当分页按钮被点击是这个字段的值会发生变化,并且发起查询请求。
Action代码
这个表单会提交到如下的action中进行处理
<?php class XXXController extends Controller
{
//...
public function actionAjaxSearch(){
//print_r($_POST);
$result = array(
'examItems'=>array(),
);
$c = new CDbCriteria;
$c->with = array('paper','course'); // 连接表 // 全局设置
$c->addCondition("course.type='program'");
$c->order = 't.create_time desc';
$keywords = FALSE;
if (isset($_POST['keywords']) AND ! empty($_POST['keywords']))
{
$keywords = preg_replace('/\s+/', '%', $_POST['keywords']);
$keywords = '%'.$keywords.'%';
$c->addSearchCondition('t.title', $keywords, FALSE);
} $keyRegions = array();
if(isset($_POST['region'])){
$keyRegions = $_POST['region'];
}
if(!empty($keyRegions)){
//$regions = implode(',',$keyRegions);
$regions = "";
foreach($keyRegions as $r){
$regions .= "'".$r."',";
}
$regions = rtrim($regions,','); $c->addCondition("paper.event_id in (select id from exam_events where type in (".$regions."))");
} if (isset($_POST['course']))
{
$c->addInCondition('t.course_id', $_POST['course']);
} // 判断类型条件
$keyTypes = array();
if(isset($_POST['type'])){
$tps = $_POST['type'];
foreach ($tps as $t)
{
$keyTypes[] = $t;
}
}
if(!empty($keyTypes)){
$c->addInCondition('t.type',$keyTypes);
} $currentPage = isset($_GET['currentPage']) ? $_GET['currentPage'] : 1 ;
$eleItemCount = = ExamItems::model()->count($c);
$pages = PagingTools::getPages($eleItemCount,$currentPage,10,4); $c->limit = $pages['limit'];
$c->offset = $pages['offset']; $result['examItems'] = ExamItems::model()->findAll($c);
$this->renderPartial('result', array('result'=>$result,'pages'=>$pages,'keywords'=>$_POST['keywords'])); }
//...
}
这里利用CDbCriteria对多条件进行组合,并在最后确定分页结果,传递到视图。
分页工具
这里因为是ajax分页,当时我把yii的分页找了个遍发现都没有符合心意的分页工具。于是打算自己来写这个分页。
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 15-5-3
* Time: 上午9:24
*/ class PagingTools{
// /**
// * @var int 每个页面容纳项目数
// */
// public $pageEleItemCount;
// /**
// * @var int 最多显示多少页面按钮
// */
// public $pageMaxCount;
// /**
// * @var int 总的元素个数
// */
// public $eleItemCount;
// /**
// * @var int 当前页
// */
// public $currentPage = 1; // public function getPages(){
//
// $pages = array(
// /* 所求页面总数 */
// 'count'=>1,
// /* 起始页面 */
// 'start'=>1,
// /* 结束页面 */
// 'end'=>1,
// );
//
// if($this->eleItemCount > $this->pageEleItemCount){
// //需要分页
// $pages['count'] = intval($this->eleItemCount / $this->pageEleItemCount);
// if($this->eleItemCount != $pages['count']*$this->pageEleItemCount) $pages['count']+=1;
// if($pages['count'] > $this->pageMaxCount){//多于10页
// $this->pageMaxCount -= 1;//数学问题3 到 6 的距离等于 6 - 3 + 1
// //从中取10页,包含当前页
// if($this->currentPage <= intval($this->pageMaxCount/2)){//很靠近首页
// $pages['start'] = 1;
// }
// else if($pages['count']-$this->currentPage < $this->pageMaxCount/2){//很靠近尾页
// $pages['start'] = $pages['count'] - $this->pageMaxCount ;
// }else{
// $pages['start'] = $this->currentPage - intval($this->pageMaxCount/2);
// }
// $pages['end'] = $this->pageMaxCount+$pages['start'] > $pages['count'] ? $pages['count'] : $this->pageMaxCount+$pages['start'];
// }else{
// $pages['start'] = 1;$pages['end'] = $pages['count'];
// }
// }
//
// return $pages;
/**
* 获取分页参数
*
* @param int $eleItemCount 总的项目个数
* @param int $currentPage 当前页
* @param int $limit 每个页面容纳项目数
* @param int $pageMaxCount 最多显示多少页面按钮
* @return array
*/
public static function getPages($eleItemCount,$currentPage = 1,$limit = 10,$pageMaxCount = 7){
$pages = array(
/* 所求页面总数 */
'count' => 1,
/* 起始页面 */
'start' => 1,
/* 结束页面 */
'end' => 1 ,
/* 查询偏移 */
'offset' => 0 ,
/* 默认参数直接返回 */
'currentPage' => $currentPage,
'limit' => $limit,
'pageMaxCount' => $pageMaxCount,
); if($eleItemCount > $limit){
//需要分页
$pages['count'] = intval($eleItemCount / $limit);
if($eleItemCount != $pages['count']*$limit) $pages['count']+=1;
if($pages['count'] > $pageMaxCount){//多于10页
$pageMaxCount -= 1;//数学问题3 到 6 的距离等于 6 - 3 + 1
//从中取10页,包含当前页
if($currentPage <= intval($pageMaxCount/2)){//很靠近首页
$pages['start'] = 1;
}
else if($pages['count']-$currentPage < $pageMaxCount/2){//很靠近尾页
$pages['start'] = $pages['count'] - $pageMaxCount ;
}else{
$pages['start'] = $currentPage - intval($pageMaxCount/2);
}
$pages['end'] = $pageMaxCount+$pages['start'] > $pages['count'] ? $pages['count'] : $pageMaxCount+$pages['start'];
}else{
$pages['start'] = 1;$pages['end'] = $pages['count'];
}
$pages['offset'] = ($currentPage - 1 ) * $limit;
}
return $pages;
} }
这里的视图放在与PageingTool相同目录的views目录下,
<?php
$isMobile = isset($isMobile) ? intval($isMobile) : 0;
$pagelinks = array(
'start'=>array('首页','<<'),
'prev'=>array('上一页','<'),
'next'=>array('下一页','>'),
'end'=>array('末页','>>'),
);
?>
<?php if($pages['count'] > 1):?>
<div class="paging-container">
<ul class="pagination">
<li class="page first <?=$pages['currentPage']==1 ? 'disabled' :''?>"><a href="javascript:void(0)" data-page="1"><?=$pagelinks['start'][$isMobile]?></a></li>
<li class="page pprev <?=$pages['currentPage']==1 ? 'disabled' :''?>"><a href="javascript:void(0)" aria-label="Previous" data-page="<?=$pages['currentPage']-1?>"><?=$pagelinks['prev'][$isMobile]?></a></li>
<?php for($i=$pages['start'];$i<=$pages['end'] ;$i++):?>
<li class="page <?=$pages['currentPage'] == $i ? 'active' : ''?>"><a href="javascript:void(0)" data-page="<?=$i?>"><?=$i?></a></li>
<?php endfor;?>
<li class="page pnext <?=$pages['currentPage']==$pages['count'] ? 'disabled' :''?>"><a href="javascript:void(0)" aria-label="Next" data-page="<?=$pages['currentPage']+1?>"><?=$pagelinks['next'][$isMobile]?></a></li>
<li class="page last <?=$pages['currentPage']==$pages['count'] ? 'disabled' :''?>"><a href="javascript:void(0)" data-page="<?=$pages['count']?>"><?=$pagelinks['end'][$isMobile]?></a></li>
</ul>
</div>
<?php endif;?>
最后为分页按钮增加事件
$(document).ready(function(){
$('.list-area').ajaxSuccess(function(){
var _this = $(this);
function toPage(v){
// 修改隐藏的input[name=currentPage]
// 异步提交表单
}
$('.paging-container .page a').click(function(){
var _this = $(this);
if(!(_this.parent('li').hasClass('disabled'))) {
toPage(_this.attr('data-page'));
}
});
});
});
效果
这个分页希望实现如下的效果,按钮数量有个上限,并尽量保证活动的按钮最好居中。效果如下。
视图代码
在视图当中,有了result和pages之后,就可以迭代出结果和分页
<?php foreach ($result['examItems'] as $item) : ?>
<div class="row pt15 pb15 bb1-gray">
<div class="col-md-12 search-table" see-url="<?=$this->createUrl('examItems/ajaxViewItem')?>">
<div class="row">
<a href="javascript:void(0)" class="item-title" style="font-size: 15px;color: #6c6c6c">
<?=Tools::getShortTitle($item->title,80,true,$keywords,'code');?>
</a>
<div class="pull-right">
<a href="javascript:void(0)" class="see" data-id="<?=$item->id?>"><i class="fa fa-eye"></i><span>查看</span></a>
</div>
</div>
<div class="row itemCt" style="display: none;padding:8px"></div>
<div class="row">
<div class="col-md-12">
<div class="col-md-5 pull-left pt10">
<span class="col-md-3 mr10 badge badge-default"><?=$tps[$item->type]?></span>
<span class="col-md-3 badge badge-default"><?=isset($item->paper) ? isset($item->paper->event) ? $cgs[$item->paper->event->type] : '' : '' ;?></span>
</div>
<div class="pull-right mt5">
<?php if(isset($item->paper)):?>
<a data-auth href="<?=$this->createUrl('course/exam/'.$item->paper->id)?>" target="_blank" class="icon icon-clock text-blue ml15 text-gray">
<span><?=$item->paper->title?></span>
</a>
<?php endif;?>
</div>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
<div class="list-paging text-center pb10">
<?php
$this->renderPartial('application.components.views.paging',array('pages'=>$pages,'isMobile'=>false));
?>
</div>