Kanboard-Prod/app/Core/Paginator.php

544 lines
11 KiB
PHP

<?php
namespace Kanboard\Core;
use Kanboard\Core\Filter\FormatterInterface;
use Pimple\Container;
use PicoDb\Table;
/**
* Paginator Helper
*
* @package Kanboard\Core
* @author Frederic Guillot
*/
class Paginator
{
/**
* Container instance
*
* @access private
* @var \Pimple\Container
*/
private $container;
/**
* Total number of items
*
* @access private
* @var integer
*/
private $total = 0;
/**
* Page number
*
* @access private
* @var integer
*/
private $page = 1;
/**
* Offset
*
* @access private
* @var integer
*/
private $offset = 0;
/**
* Limit
*
* @access private
* @var integer
*/
private $limit = 0;
/**
* Sort by this column
*
* @access private
* @var string
*/
private $order = '';
/**
* Sorting direction
*
* @access private
* @var string
*/
private $direction = 'ASC';
/**
* Slice of items
*
* @access private
* @var array
*/
private $items = array();
/**
* PicoDb Table instance
*
* @access private
* @var \Picodb\Table
*/
private $query = null;
/**
* Controller name
*
* @access private
* @var string
*/
private $controller = '';
/**
* Action name
*
* @access private
* @var string
*/
private $action = '';
/**
* URL anchor
*
* @access private
* @var string
*/
private $anchor = '';
/**
* Url params
*
* @access private
* @var array
*/
private $params = array();
/**
* @var FormatterInterface
*/
protected $formatter = null;
/**
* Constructor
*
* @access public
* @param \Pimple\Container $container
*/
public function __construct(Container $container)
{
$this->container = $container;
}
/**
* Set a PicoDb query
*
* @access public
* @param \PicoDb\Table
* @return $this
*/
public function setQuery(Table $query)
{
$this->query = $query;
$this->total = $this->query->count();
return $this;
}
/**
* Set Formatter
*
* @param FormatterInterface $formatter
* @return $this
*/
public function setFormatter(FormatterInterface $formatter)
{
$this->formatter = $formatter;
return $this;
}
/**
* Execute a PicoDb query
*
* @access public
* @return array
*/
public function executeQuery()
{
if ($this->query !== null) {
$this->query
->offset($this->offset)
->limit($this->limit);
if (preg_match('/^[a-zA-Z0-9._]+$/', $this->order)) {
$this->query->orderBy($this->order, $this->direction);
} else {
$this->order = '';
}
if ($this->formatter !== null) {
return $this->formatter->withQuery($this->query)->format();
} else {
return $this->query->findAll();
}
}
return array();
}
/**
* Set url parameters
*
* @access public
* @param string $controller
* @param string $action
* @param array $params
* @param string $anchor
* @return $this
*/
public function setUrl($controller, $action, array $params = array(), $anchor = '')
{
$this->controller = $controller;
$this->action = $action;
$this->params = $params;
$this->anchor = $anchor;
return $this;
}
/**
* Add manually items
*
* @access public
* @param array $items
* @return $this
*/
public function setCollection(array $items)
{
$this->items = $items;
return $this;
}
/**
* Return the items
*
* @access public
* @return array
*/
public function getCollection()
{
return $this->items ?: $this->executeQuery();
}
/**
* Set the total number of items
*
* @access public
* @param integer $total
* @return $this
*/
public function setTotal($total)
{
$this->total = $total;
return $this;
}
/**
* Get the total number of items
*
* @access public
* @return integer
*/
public function getTotal()
{
return $this->total;
}
/**
* Set the default page number
*
* @access public
* @param integer $page
* @return $this
*/
public function setPage($page)
{
$this->page = $page;
return $this;
}
/**
* Get the number of current page
*
* @access public
* @return integer
*/
public function getPage()
{
return $this->page;
}
/**
* Set the default column order
*
* @access public
* @param string $order
* @return $this
*/
public function setOrder($order)
{
$this->order = $order;
return $this;
}
/**
* Set the default sorting direction
*
* @access public
* @param string $direction
* @return $this
*/
public function setDirection($direction)
{
$this->direction = $direction;
return $this;
}
/**
* Set the maximum number of items per page
*
* @access public
* @param integer $limit
* @return $this
*/
public function setMax($limit)
{
$this->limit = $limit;
return $this;
}
/**
* Get the maximum number of items per page.
*
* @return int
*/
public function getMax()
{
return $this->limit;
}
/**
* Return true if the collection is empty
*
* @access public
* @return boolean
*/
public function isEmpty()
{
return $this->total === 0;
}
/**
* Execute the offset calculation only if the $condition is true
*
* @access public
* @param boolean $condition
* @return $this
*/
public function calculateOnlyIf($condition)
{
if ($condition) {
$this->calculate();
}
return $this;
}
/**
* Calculate the offset value according to url params and the page number
*
* @access public
* @return $this
*/
public function calculate()
{
$this->page = $this->container['request']->getIntegerParam('page', 1);
$this->direction = $this->container['request']->getStringParam('direction', $this->direction);
$this->order = $this->container['request']->getStringParam('order', $this->order);
if ($this->page < 1) {
$this->page = 1;
}
$this->offset = (int) (($this->page - 1) * $this->limit);
return $this;
}
/**
* Get url params for link generation
*
* @access public
* @param integer $page
* @param string $order
* @param string $direction
* @return string
*/
public function getUrlParams($page, $order, $direction)
{
$params = array(
'page' => $page,
'order' => $order,
'direction' => $direction,
);
return array_merge($this->params, $params);
}
/**
* Generate the previous link
*
* @access public
* @return string
*/
public function generatePreviousLink()
{
$html = '<span class="pagination-previous">';
if ($this->offset > 0) {
$html .= $this->container['helper']->url->link(
'&larr; '.t('Previous'),
$this->controller,
$this->action,
$this->getUrlParams($this->page - 1, $this->order, $this->direction),
false,
'js-modal-replace',
t('Previous'),
false,
$this->anchor
);
} else {
$html .= '&larr; '.t('Previous');
}
$html .= '</span>';
return $html;
}
/**
* Generate the next link
*
* @access public
* @return string
*/
public function generateNextLink()
{
$html = '<span class="pagination-next">';
if (($this->total - $this->offset) > $this->limit) {
$html .= $this->container['helper']->url->link(
t('Next').' &rarr;',
$this->controller,
$this->action,
$this->getUrlParams($this->page + 1, $this->order, $this->direction),
false,
'js-modal-replace',
t('Next'),
false,
$this->anchor
);
} else {
$html .= t('Next').' &rarr;';
}
$html .= '</span>';
return $html;
}
/**
* Generate the page showing.
*
* @access public
* @return string
*/
public function generatePageShowing()
{
return '<span class="pagination-showing">'.t('Showing %d-%d of %d', (($this->getPage() - 1) * $this->getMax() + 1), min($this->getTotal(), $this->getPage() * $this->getMax()), $this->getTotal()).'</span>';
}
/**
* Return true if there is no pagination to show
*
* @access public
* @return boolean
*/
public function hasNothingToShow()
{
return $this->offset === 0 && ($this->total - $this->offset) <= $this->limit;
}
/**
* Generation pagination links
*
* @access public
* @return string
*/
public function toHtml()
{
$html = '';
if (! $this->hasNothingToShow()) {
$html .= '<div class="pagination">';
$html .= $this->generatePageShowing();
$html .= $this->generatePreviousLink();
$html .= $this->generateNextLink();
$html .= '</div>';
}
return $html;
}
/**
* Magic method to output pagination links
*
* @access public
* @return string
*/
public function __toString()
{
return $this->toHtml();
}
/**
* Column sorting
*
* @param string $label Column title
* @param string $column SQL column name
* @return string
*/
public function order($label, $column)
{
$prefix = '';
$direction = 'ASC';
if ($this->order === $column) {
$prefix = $this->direction === 'DESC' ? '&#9660; ' : '&#9650; ';
$direction = $this->direction === 'DESC' ? 'ASC' : 'DESC';
}
return $prefix.$this->container['helper']->url->link(
$label,
$this->controller,
$this->action,
$this->getUrlParams($this->page, $column, $direction),
false,
'js-modal-replace'
);
}
}