分页功能

This commit is contained in:
yunwuxin
2016-05-06 18:09:43 +08:00
parent 2a42932f12
commit a00df4246e
13 changed files with 870 additions and 100 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.idea

View File

@@ -213,5 +213,10 @@ return [
// 指定从服务器序号
'slave_no' => '',
],
//分页配置
'paginate' => [
'type' => 'bootstrap',
'var_page' => 'page'
]
];

View File

@@ -0,0 +1,127 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: zhangyajun <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think;
use ArrayAccess;
use ArrayIterator;
use Countable;
use IteratorAggregate;
use JsonSerializable;
class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
{
protected $items = [];
public function __construct($items = [])
{
$this->items = $items instanceof self ? $items->all() : (array)$items;
}
public static function make($items = [])
{
return new static($items);
}
/**
* 是否为空
* @return bool
*/
public function isEmpty()
{
return empty($this->items);
}
public function toArray()
{
return array_map(function ($value) {
return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value;
}, $this->items);
}
public function all()
{
return $this->items;
}
/**
* 截取数组
*
* @param int $offset
* @param int $length
* @param bool $preserveKeys
* @return static
*/
public function slice($offset, $length = null, $preserveKeys = false)
{
return new static(array_slice($this->items, $offset, $length, $preserveKeys));
}
// ArrayAccess
public function offsetExists($offset)
{
return array_key_exists($offset, $this->items);
}
public function offsetGet($offset)
{
return $this->items[$offset];
}
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
$this->items[] = $value;
} else {
$this->items[$offset] = $value;
}
}
public function offsetUnset($offset)
{
unset($this->items[$offset]);
}
//Countable
public function count()
{
return count($this->items);
}
//IteratorAggregate
public function getIterator()
{
return new ArrayIterator($this->items);
}
//JsonSerializable
public function jsonSerialize()
{
return $this->toArray();
}
/**
* 转换当前数据集为JSON字符串
* @access public
* @param integer $options json参数
* @return string
*/
public function toJson($options = JSON_UNESCAPED_UNICODE)
{
return json_encode($this->toArray(), $options);
}
public function __toString()
{
return $this->toJson();
}
}

View File

@@ -29,7 +29,8 @@ class Db
* @access public
* @param mixed $config 连接配置
* @param bool|string $name 连接标识 true 强制重新连接
* @return \think\db\Connection
* @return db\Connection
* @throws Exception
*/
public static function connect($config = [], $name = false)
{

View File

@@ -16,7 +16,13 @@ use think\Db;
use think\db\Query;
use think\Loader;
use think\model\Relation;
use think\paginator\Collection as PaginatorCollection;
/**
* Class Model
* @package think
* @method PaginatorCollection paginate(integer $listRows = 15, boolean $simple = false, array $config = []) static 分页查询
*/
abstract class Model implements \JsonSerializable, \ArrayAccess
{
@@ -172,7 +178,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
continue;
}
if ($val instanceof Model) {
if ($val instanceof Model || $val instanceof Collection) {
// 关联模型对象
$item[$key] = $val->toArray();
} elseif (is_array($val) && isset($val[0]) && $val[0] instanceof Model) {

245
library/think/Paginator.php Normal file
View File

@@ -0,0 +1,245 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: zhangyajun <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think;
use think\paginator\Collection as PaginatorCollection;
abstract class Paginator
{
/** @var bool 是否为简洁模式 */
protected $simple = false;
/** @var PaginatorCollection 数据集 */
protected $items;
/** @var integer 当前页 */
protected $currentPage;
/** @var integer 最后一页 */
protected $lastPage;
/** @var integer|null 数据总数 */
protected $total;
/** @var integer 每页的数量 */
protected $listRows;
/** @var bool 是否有下一页 */
protected $hasMore;
/** @var array 一些配置 */
protected $options = [
'var_page' => 'page',
'path' => '/',
'query' => [],
'fragment' => ''
];
public function __construct(Collection $items, $listRows, $currentPage = null, $simple = false, $total = null, $options = [])
{
$this->options = array_merge($this->options, $options);
$this->options['path'] = $this->options['path'] != '/' ? rtrim($this->options['path'], '/') : $this->options['path'];
$this->simple = $simple;
$this->listRows = $listRows;
if ($simple) {
$this->currentPage = $this->setCurrentPage($currentPage);
$this->hasMore = count($items) > ($this->listRows);
$items = $items->slice(0, $this->listRows);
} else {
$this->lastPage = (int)ceil($total / $listRows);
$this->currentPage = $this->setCurrentPage($currentPage);
$this->hasMore = $this->currentPage < $this->lastPage;
}
$this->items = PaginatorCollection::make($items, $this);
}
public function items()
{
return $this->items;
}
protected function setCurrentPage($currentPage)
{
if (!$this->simple && $currentPage > $this->lastPage) {
return $this->lastPage > 0 ? $this->lastPage : 1;
}
return $currentPage;
}
/**
* 获取页码对应的链接
*
* @param $page
* @return string
*/
protected function url($page)
{
if ($page <= 0) {
$page = 1;
}
if (strpos($this->options['path'], '[PAGE]') === false) {
$parameters = [$this->options['var_page'] => $page];
$path = $this->options['path'];
} else {
$parameters = [];
$path = str_replace('[PAGE]', $page, $this->options['path']);
}
if (count($this->options['query']) > 0) {
$parameters = array_merge($this->options['query'], $parameters);
}
$url = $path;
if (!empty($parameters)) {
$url .= '?' . urldecode(http_build_query($parameters, null, '&'));
}
return $url . $this->buildFragment();
}
/**
* 自动获取当前页码
* @param string $varPage
* @param int $default
* @return int
*/
public static function getCurrentPage($varPage = 'page', $default = 1)
{
$page = Input::request($varPage);
if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int)$page >= 1) {
return $page;
}
return $default;
}
/**
* 自动获取当前的path
* @return string
*/
public static function getCurrentPath()
{
//TODO 待Request类完善后这里再完善
return '/' . $_SERVER['PATH_INFO'];
}
public function total()
{
if ($this->simple) {
throw new \Exception('简洁模式下不能获取数据总数');
}
return $this->total;
}
public function listRows()
{
return $this->listRows;
}
public function currentPage()
{
return $this->currentPage;
}
public function lastPage()
{
if ($this->simple) {
throw new \Exception('简洁模式下不能获取最后一页');
}
return $this->lastPage;
}
/**
* 数据是否足够分页
*/
public function hasPages()
{
return !($this->currentPage == 1 && !$this->hasMore);
}
/**
* 创建一组分页链接
*
* @param int $start
* @param int $end
* @return array
*/
public function getUrlRange($start, $end)
{
$urls = [];
for ($page = $start; $page <= $end; $page++) {
$urls[$page] = $this->url($page);
}
return $urls;
}
/**
* 设置URL锚点
*
* @param string|null $fragment
* @return $this
*/
public function fragment($fragment)
{
$this->options['fragment'] = $fragment;
return $this;
}
/**
* 添加URL参数
*
* @param array|string $key
* @param string|null $value
* @return $this
*/
public function appends($key, $value = null)
{
if (!is_array($key)) {
$queries = [$key => $value];
} else {
$queries = $key;
}
foreach ($queries as $k => $v) {
if ($k !== $this->options['var_page']) {
$this->options['query'][$k] = $v;
}
}
return $this;
}
/**
* 构造锚点字符串
*
* @return string
*/
protected function buildFragment()
{
return $this->options['fragment'] ? '#' . $this->options['fragment'] : '';
}
/**
* 渲染分页html
* @return mixed
*/
abstract public function render();
}

View File

@@ -12,9 +12,8 @@
namespace think\db;
use PDO;
use think\Config;
use PDOStatement;
use think\Db;
use think\db\Query;
use think\Debug;
use think\Exception;
use think\exception\DbBindParamException;
@@ -23,13 +22,16 @@ use think\Log;
abstract class Connection
{
// PDO操作实例
/** @var PDOStatement PDO操作实例 */
protected $PDOStatement;
// 当前操作的数据表名
protected $table = '';
// 当前操作的数据对象名
protected $name = '';
// 当前SQL指令
/** @var string 当前SQL指令 */
protected $queryStr = '';
// 最后插入ID
protected $lastInsID;
@@ -43,10 +45,13 @@ abstract class Connection
protected $transLabel = '';
// 错误信息
protected $error = '';
// 数据库连接ID 支持多个连接
/** @var PDO[] 数据库连接ID 支持多个连接 */
protected $links = [];
// 当前连接ID
/** @var PDO 当前连接ID */
protected $linkID;
// 查询结果类型
protected $fetchType = PDO::FETCH_ASSOC;
// 字段属性大小写
@@ -207,8 +212,9 @@ abstract class Connection
* @access public
* @param array $config 连接参数
* @param integer $linkNum 连接序号
* @param false|array $autoConnection 是否自动连接主数据库(用于分布式)
* @return \PDO
* @param array|bool $autoConnection 是否自动连接主数据库(用于分布式)
* @return PDO
* @throws Exception
*/
public function connect(array $config = [], $linkNum = 0, $autoConnection = false)
{
@@ -290,6 +296,8 @@ abstract class Connection
* @param boolean $master 是否在主服务器读操作
* @param bool $returnPdo 是否返回 PDOStatement 对象
* @return mixed
* @throws DbBindParamException
* @throws PDOException
*/
public function query($sql, $bind = [], $fetch = false, $master = false, $returnPdo = false)
{
@@ -334,7 +342,9 @@ abstract class Connection
* @param array $bind 参数绑定
* @param boolean $fetch 不执行只是获取SQL
* @param boolean $getLastInsID 是否获取自增ID
* @return integer
* @return int
* @throws DbBindParamException
* @throws PDOException
*/
public function execute($sql, $bind = [], $fetch = false, $getLastInsID = false)
{
@@ -452,6 +462,7 @@ abstract class Connection
{
$this->startTrans(NOW_TIME);
try {
$result = null;
if (is_callable($callback)) {
$result = call_user_func_array($callback, []);
}
@@ -467,7 +478,7 @@ abstract class Connection
* 启动事务
* @access public
* @param string $label 事务标识
* @return void
* @return bool|null
*/
public function startTrans($label = '')
{
@@ -485,14 +496,15 @@ abstract class Connection
}
}
$this->transTimes++;
return;
return null;
}
/**
* 用于非自动提交状态下面的查询提交
* @access public
* @param string $label 事务标识
* @return boolen
* @return boolean
* @throws PDOException
*/
public function commit($label = '')
{
@@ -513,7 +525,8 @@ abstract class Connection
/**
* 事务回滚
* @access public
* @return boolen
* @return boolean
* @throws PDOException
*/
public function rollback()
{
@@ -745,10 +758,11 @@ abstract class Connection
* 连接分布式服务器
* @access protected
* @param boolean $master 主服务器
* @return void
* @return PDO
*/
protected function multiConnect($master = false)
{
$_config = [];
// 分布式数据库配置解析
foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) {
$_config[$name] = explode(',', $this->config[$name]);
@@ -759,8 +773,7 @@ abstract class Connection
if ($this->config['rw_separate']) {
// 主从式采用读写分离
if ($master)
// 主服务器写入
if ($master) // 主服务器写入
{
$r = $m;
} elseif (is_numeric($this->config['slave_no'])) {
@@ -774,12 +787,14 @@ abstract class Connection
// 读写操作不区分服务器 每次随机连接的数据库
$r = floor(mt_rand(0, count($_config['hostname']) - 1));
}
$dbMaster = false;
if ($m != $r) {
$dbMaster = [];
foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) {
$dbMaster[$name] = isset($_config[$name][$m]) ? $_config[$name][$m] : $_config[$name][0];
}
}
$dbConfig = [];
foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) {
$dbConfig[$name] = isset($_config[$name][$r]) ? $_config[$name][$r] : $_config[$name][0];
}

View File

@@ -13,12 +13,15 @@ namespace think\db;
use PDO;
use think\Cache;
use think\Collection;
use think\Config;
use think\Db;
use think\Exception;
use think\exception\DbException;
use think\Loader;
use think\Model;
use think\model\Relation;
use think\Paginator;
class Query
{
@@ -35,7 +38,8 @@ class Query
/**
* 架构函数
* @access public
* @param object $connection 数据库对象实例
* @param object|string $connection 数据库对象实例
* @throws Exception
*/
public function __construct($connection = '')
{
@@ -49,6 +53,8 @@ class Query
* @param string $method 方法名称
* @param array $args 调用参数
* @return mixed
* @throws DbException
* @throws Exception
*/
public function __call($method, $args)
{
@@ -156,7 +162,7 @@ class Query
$result = [];
}
}
if (isset($cache)) {
if (isset($cache) && isset($guid)) {
// 缓存数据
Cache::set($guid, $result, $cache['expire']);
}
@@ -482,7 +488,7 @@ class Query
/**
* 分析查询表达式
* @access public
* @param string|array|Closure $field 查询字段
* @param string|array|\Closure $field 查询字段
* @param mixed $op 查询表达式
* @param mixed $condition 查询条件
* @param string $operator and or
@@ -613,6 +619,51 @@ class Query
return $this;
}
/**
* 分页查询
* @param int $listRows 每页数量
* @param bool $simple 简洁模式
* @param array $config 配置参数
* page:当前页,
* path:url路径,
* query:url额外参数,
* fragment:url锚点,
* var_page:分页变量,
* type:分页类名,
* namespace:分页类命名空间
* @return \think\paginator\Collection
* @throws DbException
*/
public function paginate($listRows = 15, $simple = false, $config = [])
{
$config = array_merge(Config::get('paginate'), $config);
$class = (!empty($config['namespace']) ? $config['namespace'] : '\\think\\paginator\\driver\\') . ucwords($config['type']);
$page = isset($config['page']) ? (int)$config['page'] : call_user_func([
$class,
'getCurrentPage'
], $config['var_page']);
$page = $page < 1 ? 1 : $page;
$config['path'] = isset($config['path']) ? $config['path'] : call_user_func([$class, 'getCurrentPath']);
/** @var Paginator $paginator */
if (!$simple) {
$options = $this->getOptions();
$total = $this->count();
$results = $this->options($options)->page($page, $listRows)->select();
$paginator = new $class($results, $listRows, $page, $simple, $total, $config);
} else {
$results = $this->limit(($page - 1) * $listRows, $listRows + 1)->select();
$paginator = new $class($results, $listRows, $page, $simple, null, $config);
}
return $paginator->items();
}
/**
* 指定数据表
* @access public
@@ -992,6 +1043,8 @@ class Query
$i = 0;
$currentModel = $this->options['model'];
/** @var Model $class */
$class = new $currentModel;
foreach ($with as $key => $relation) {
$closure = false;
@@ -1005,6 +1058,7 @@ class Query
list($relation, $subRelation) = explode('.', $relation, 2);
}
/** @var Relation $model */
$model = $class->$relation();
$info = $class->getRelationInfo();
if (in_array($info['type'], [Relation::HAS_ONE, Relation::BELONGS_TO])) {
@@ -1035,7 +1089,7 @@ class Query
/**
* 设置当前字段添加的表别名
* @access public
* @param string $relation 关联名称
* @param string $via
* @return Db
*/
public function via($via = '')
@@ -1149,8 +1203,8 @@ class Query
* @access public
* @param string $fields 要插入的数据表字段名
* @param string $table 要插入的数据表名
* @param array $option 查询数据参数
* @return integer
* @return int
* @throws \think\exception\PDOException
*/
public function selectInsert($fields, $table)
{
@@ -1166,7 +1220,9 @@ class Query
* 更新记录
* @access public
* @param mixed $data 数据
* @return integer
* @return int
* @throws Exception
* @throws \think\exception\PDOException
*/
public function update(array $data)
{
@@ -1208,8 +1264,11 @@ class Query
/**
* 查找记录
* @access public
* @param array $options 表达式
* @return \PDOStatement|array|string|false
* @param array $data
* @return Collection|false|\PDOStatement|string
* @throws DbException
* @throws Exception
* @throws \think\exception\PDOException
*/
public function select($data = [])
{
@@ -1265,6 +1324,7 @@ class Query
// 生成模型对象
$model = $options['model'];
foreach ($resultSet as $key => $result) {
/** @var Model $result */
$result = new $model($result);
$result->isUpdate(true);
// 关联查询
@@ -1281,14 +1341,17 @@ class Query
} elseif (!empty($options['fail'])) {
throw new DbException('Data not Found', $options, $sql);
}
return $resultSet;
return Collection::make($resultSet);
}
/**
* 查找单条记录
* @access public
* @param array $data 表达式
* @return \think\Model|\PDOStatement|array|string|false
* @return array|false|\PDOStatement|string|Model
* @throws DbException
* @throws Exception
* @throws \think\exception\PDOException
*/
public function find($data = [])
{
@@ -1403,8 +1466,9 @@ class Query
/**
* 创建子查询SQL
* @access public
* @param array $data 表达式
* @param bool $sub
* @return string
* @throws DbException
*/
public function buildSql($sub = true)
{
@@ -1415,7 +1479,9 @@ class Query
* 删除记录
* @access public
* @param array $data 表达式
* @return integer
* @return int
* @throws Exception
* @throws \think\exception\PDOException
*/
public function delete($data = [])
{

View File

@@ -18,6 +18,13 @@ use think\Exception;
*/
class DbException extends Exception
{
/**
* DbException constructor.
* @param string $message
* @param array $config
* @param string $sql
* @param int $code
*/
public function __construct($message, Array $config, $sql, $code = 10500)
{
$this->message = $message;

View File

@@ -19,6 +19,13 @@ use think\exception\DbException;
*/
class PDOException extends DbException
{
/**
* PDOException constructor.
* @param \PDOException $exception
* @param array $config
* @param string $sql
* @param int $code
*/
public function __construct(\PDOException $exception, Array $config, $sql, $code = 10501)
{
$error = $exception->errorInfo;

View File

@@ -11,6 +11,7 @@
namespace think\model;
use think\Collection;
use think\Db;
use think\Exception;
use think\Loader;
@@ -26,7 +27,7 @@ class Relation
// 父模型对象
protected $parent;
// 当前关联的模型类
/** @var Model 当前关联的模型类 */
protected $model;
// 中间表模型
protected $middle;
@@ -118,6 +119,7 @@ class Relation
*/
public function eagerlyResultSet($resultSet, $relation)
{
/** @var array $relations */
$relations = is_string($relation) ? explode(',', $relation) : $relation;
foreach ($relations as $key => $relation) {
@@ -153,15 +155,19 @@ class Relation
}
if (!empty($range)) {
$data = $this->eagerlyOneToMany($model, [$foreignKey => ['in', $range]], $relation, $subRelation, $closure);
$data = $this->eagerlyOneToMany($model, [
$foreignKey => [
'in',
$range
]
], $relation, $subRelation, $closure);
// 关联数据封装
foreach ($resultSet as $result) {
if (isset($data[$result->$localKey])) {
$result->__set($relation, $data[$result->$localKey]);
} else {
$result->__set($relation, []);
if (!isset($data[$result->$localKey])) {
$data[$result->$localKey] = [];
}
$result->__set($relation, Collection::make($data[$result->$localKey]));
}
}
break;
@@ -177,20 +183,24 @@ class Relation
if (!empty($range)) {
// 查询关联数据
$data = $this->eagerlyManyToMany($model, ['pivot.' . $foreignKey => ['in', $range]], $relation, $subRelation);
$data = $this->eagerlyManyToMany($model, [
'pivot.' . $foreignKey => [
'in',
$range
]
], $relation, $subRelation);
// 关联数据封装
foreach ($resultSet as $result) {
if (isset($data[$result->$pk])) {
$result->__set($relation, $data[$result->$pk]);
} else {
$result->__set($relation, []);
if (!isset($data[$result->$pk])) {
$data[$result->$pk] = [];
}
$result->__set($relation, Collection::make($data[$result->$pk]));
}
}
break;
}
$this->relation = [];
}
return $resultSet;
}
@@ -233,7 +243,7 @@ class Relation
if (!isset($data[$result->$localKey])) {
$data[$result->$localKey] = [];
}
$result->__set($relation, $data[$result->$localKey]);
$result->__set($relation, Collection::make($data[$result->$localKey]));
}
break;
case self::BELONGS_TO_MANY:
@@ -247,7 +257,7 @@ class Relation
if (!isset($data[$pk])) {
$data[$pk] = [];
}
$result->__set($relation, $data[$pk]);
$result->__set($relation, Collection::make($data[$pk]));
}
break;
@@ -292,7 +302,8 @@ class Relation
* @param array $where 关联预查询条件
* @param string $relation 关联名
* @param string $subRelation 子关联
* @return void
* @param bool $closure
* @return array
*/
protected function eagerlyOneToMany($model, $where, $relation, $subRelation = '', $closure = false)
{
@@ -315,7 +326,7 @@ class Relation
* @param array $where 关联预查询条件
* @param string $relation 关联名
* @param string $subRelation 子关联
* @return void
* @return array
*/
protected function eagerlyManyToMany($model, $where, $relation, $subRelation = '')
{
@@ -367,7 +378,7 @@ class Relation
* @access public
* @param string $model 模型名
* @param string $foreignKey 关联外键
* @param string $localKey 关联主键
* @param string $otherKey 关联主键
* @return \think\db\Query|string
*/
public function belongsTo($model, $foreignKey, $otherKey)

View File

@@ -0,0 +1,72 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: zhangyajun <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think\paginator;
use Exception;
use think\Paginator;
/**
* Class Collection
* @package think\paginator
* @method integer total()
* @method integer listRows()
* @method integer currentPage()
* @method string render()
* @method Paginator fragment($fragment)
* @method Paginator appends($key, $value)
*/
class Collection extends \think\Collection
{
/** @var Paginator */
protected $paginator;
public function __construct($items = [], Paginator $paginator = null)
{
if (!$paginator instanceof Paginator) {
throw new \RuntimeException('Paginator Required!');
}
$this->paginator = $paginator;
parent::__construct($items);
}
public static function make($items = [], Paginator $paginator = null)
{
return new static($items, $paginator);
}
public function toArray()
{
try {
$total = $this->total();
} catch (Exception $e) {
$total = null;
}
return [
'total' => $total,
'per_page' => $this->listRows(),
'current_page' => $this->currentPage(),
'data' => parent::toArray()
];
}
public function __call($method, $args)
{
if (method_exists($this->paginator, $method)) {
return call_user_func_array([$this->paginator, $method], $args);
} else {
throw new Exception(__CLASS__ . ':' . $method . ' method not exist');
}
}
}

View File

@@ -0,0 +1,207 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: zhangyajun <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think\paginator\driver;
use think\Paginator;
class Bootstrap extends Paginator
{
/**
* 上一页按钮
* @param string $text
* @return string
*/
protected function getPreviousButton($text = "&laquo;")
{
if ($this->currentPage() <= 1) {
return $this->getDisabledTextWrapper($text);
}
$url = $this->url(
$this->currentPage() - 1
);
return $this->getPageLinkWrapper($url, $text);
}
/**
* 下一页按钮
* @param string $text
* @return string
*/
protected function getNextButton($text = '&raquo;')
{
if (!$this->hasMore) {
return $this->getDisabledTextWrapper($text);
}
$url = $this->url($this->currentPage() + 1);
return $this->getPageLinkWrapper($url, $text);
}
/**
* 页码按钮
* @return string
*/
protected function getLinks()
{
if ($this->simple)
return '';
$block = [
'first' => null,
'slider' => null,
'last' => null
];
$length = 3;
if ($this->lastPage < $length * 4) {
$block['first'] = $this->getUrlRange(1, $this->lastPage);
} elseif ($this->currentPage <= $length * 2) {
$block['first'] = $this->getUrlRange(1, $length * 2 + 2);
$block['last'] = $this->getUrlRange($this->lastPage - 1, $this->lastPage);
} elseif ($this->currentPage > ($this->lastPage - $length * 2)) {
$block['first'] = $this->getUrlRange(1, 2);
$block['last'] = $this->getUrlRange($this->lastPage - $length * 2 + 2, $this->lastPage);
} else {
$block['first'] = $this->getUrlRange(1, 2);
$block['slider'] = $this->getUrlRange($this->currentPage - $length, $this->currentPage + $length);
$block['last'] = $this->getUrlRange($this->lastPage - 1, $this->lastPage);
}
$html = '';
if (is_array($block['first'])) {
$html .= $this->getUrlLinks($block['first']);
}
if (is_array($block['slider'])) {
$html .= $this->getDots();
$html .= $this->getUrlLinks($block['slider']);
}
if (is_array($block['last'])) {
$html .= $this->getDots();
$html .= $this->getUrlLinks($block['last']);
}
return $html;
}
/**
* 渲染分页html
* @return mixed
*/
public function render()
{
if ($this->hasPages()) {
if ($this->simple) {
return sprintf(
'<ul class="pager">%s %s</ul>',
$this->getPreviousButton(),
$this->getNextButton()
);
} else {
return sprintf(
'<ul class="pagination">%s %s %s</ul>',
$this->getPreviousButton(),
$this->getLinks(),
$this->getNextButton()
);
}
}
}
/**
* 生成一个可点击的按钮
*
* @param string $url
* @param int $page
* @return string
*/
protected function getAvailablePageWrapper($url, $page)
{
return '<li><a href="' . htmlentities($url) . '">' . $page . '</a></li>';
}
/**
* 生成一个禁用的按钮
*
* @param string $text
* @return string
*/
protected function getDisabledTextWrapper($text)
{
return '<li class="disabled"><span>' . $text . '</span></li>';
}
/**
* 生成一个激活的按钮
*
* @param string $text
* @return string
*/
protected function getActivePageWrapper($text)
{
return '<li class="active"><span>' . $text . '</span></li>';
}
/**
* 生成省略号按钮
*
* @return string
*/
protected function getDots()
{
return $this->getDisabledTextWrapper('...');
}
/**
* 批量生成页码按钮.
*
* @param array $urls
* @return string
*/
protected function getUrlLinks(array $urls)
{
$html = '';
foreach ($urls as $page => $url) {
$html .= $this->getPageLinkWrapper($url, $page);
}
return $html;
}
/**
* 生成普通页码按钮
*
* @param string $url
* @param int $page
* @return string
*/
protected function getPageLinkWrapper($url, $page)
{
if ($page == $this->currentPage()) {
return $this->getActivePageWrapper($page);
}
return $this->getAvailablePageWrapper($url, $page);
}
}