391 lines
8.1 KiB
PHP
391 lines
8.1 KiB
PHP
<?php
|
|
|
|
namespace Icinga\Data;
|
|
|
|
use Icinga\Exception;
|
|
|
|
abstract class AbstractQuery
|
|
{
|
|
/**
|
|
* Sort ascending
|
|
*/
|
|
const SORT_ASC = 1;
|
|
|
|
/**
|
|
* Sort descending
|
|
*/
|
|
const SORT_DESC = -1;
|
|
|
|
/**
|
|
* Query data source
|
|
*
|
|
* @var DatasourceInterface
|
|
*/
|
|
protected $ds;
|
|
|
|
/**
|
|
* The table you are going to query
|
|
*/
|
|
protected $table;
|
|
|
|
/**
|
|
* The columns you are interested in. All columns if empty
|
|
*/
|
|
protected $columns = array();
|
|
|
|
/**
|
|
* A list of filters
|
|
*/
|
|
protected $filters = array();
|
|
|
|
/**
|
|
* The columns you're using to sort the query result
|
|
*/
|
|
protected $order_columns = array();
|
|
|
|
/**
|
|
* Return not more than that many rows
|
|
*/
|
|
protected $limit_count;
|
|
|
|
/**
|
|
* Result starts with this row
|
|
*/
|
|
protected $limit_offset;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param DatasourceInterface $ds Your data source
|
|
*/
|
|
public function __construct(DatasourceInterface $ds, $columns = null)
|
|
{
|
|
$this->ds = $ds;
|
|
|
|
if ($columns === null) {
|
|
$columns = $this->getDefaultColumns();
|
|
}
|
|
if ($columns !== null) {
|
|
$this->columns($columns);
|
|
}
|
|
|
|
$this->init();
|
|
}
|
|
|
|
public function getDatasource()
|
|
{
|
|
return $this->ds;
|
|
}
|
|
|
|
protected function getDefaultColumns()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Choose a table and the colums you are interested in
|
|
*
|
|
* Query will return all available columns if none are given here
|
|
*
|
|
* @return self
|
|
*/
|
|
public function from($table, $columns = null)
|
|
{
|
|
$this->table = $table;
|
|
if ($columns !== null) {
|
|
$this->columns($columns);
|
|
} else {
|
|
// TODO: Really?
|
|
$this->columns = $this->getDefaultColumns();
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
public function columns($columns)
|
|
{
|
|
if (is_array($columns)) {
|
|
$this->columns = $columns;
|
|
} else {
|
|
$this->columns = array($columns);
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Use once or multiple times to filter result set
|
|
*
|
|
* Multiple where calls will be combined by a logical AND operation
|
|
*
|
|
* @param string $key Column or backend-specific search expression
|
|
* @param string $val Search value, must be escaped automagically
|
|
*
|
|
* @return self
|
|
*/
|
|
public function where($key, $val = null)
|
|
{
|
|
$this->filters[] = array($key, $val);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Sort query result by the given column name
|
|
*
|
|
* Sort direction can be ascending (self::SORT_ASC, being the default)
|
|
* or descending (self::SORT_DESC).
|
|
*
|
|
* Preferred usage:
|
|
* <code>
|
|
* $query->sort('column_name ASC')
|
|
* </code>
|
|
*
|
|
* @param string $col Column, may contain direction separated by space
|
|
* @param int $dir Sort direction
|
|
*
|
|
* @return self
|
|
*/
|
|
public function order($col, $dir = null)
|
|
{
|
|
if ($dir === null) {
|
|
if (($pos = strpos($col, ' ')) === false) {
|
|
$dir = $this->getDefaultSortDir($col);
|
|
} else {
|
|
$dir = strtoupper(substr($col, $pos + 1));
|
|
if ($dir === 'DESC') {
|
|
$dir = self::SORT_DESC;
|
|
} else {
|
|
$dir = self::SORT_ASC;
|
|
}
|
|
$col = substr($col, 0, $pos);
|
|
}
|
|
} else {
|
|
if (strtoupper($dir) === 'DESC') {
|
|
$dir = self::SORT_DESC;
|
|
} else {
|
|
$dir = self::SORT_ASC;
|
|
}
|
|
}
|
|
|
|
$this->order_columns[] = array($col, $dir);
|
|
return $this;
|
|
}
|
|
|
|
protected function getDefaultSortDir($col)
|
|
{
|
|
return self::SORT_ASC;
|
|
}
|
|
|
|
/**
|
|
* Limit the result set
|
|
*
|
|
* @param int $count Return not more than that many rows
|
|
* @param int $offset Result starts with this row
|
|
*
|
|
* @return self
|
|
*/
|
|
// Nur wenn keine stats, sonst im RAM!!
|
|
// Offset gibt es nicht, muss simuliert werden
|
|
public function limit($count = null, $offset = null)
|
|
{
|
|
if (! preg_match('~^\d+~', $count . $offset)) {
|
|
throw new Exception\ProgrammingError(
|
|
sprintf(
|
|
'Got invalid limit: %s, %s',
|
|
$count,
|
|
$offset
|
|
)
|
|
);
|
|
}
|
|
$this->limit_count = (int) $count;
|
|
$this->limit_offset = (int) $offset;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Wheter at least one order column has been applied to this Query
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function hasOrder()
|
|
{
|
|
return ! empty($this->order_columns);
|
|
}
|
|
|
|
/**
|
|
* Wheter a limit has been applied to this Query
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function hasLimit()
|
|
{
|
|
return $this->limit_count !== null;
|
|
}
|
|
|
|
/**
|
|
* Wheter a starting offset been applied to this Query
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function hasOffset()
|
|
{
|
|
return $this->limit_offset > 0;
|
|
}
|
|
|
|
/**
|
|
* Get the query limit
|
|
*
|
|
* @return int|null
|
|
*/
|
|
public function getLimit()
|
|
{
|
|
return $this->limit_count;
|
|
}
|
|
|
|
/**
|
|
* Get the query starting offset
|
|
*
|
|
* @return int|null
|
|
*/
|
|
public function getOffset()
|
|
{
|
|
return $this->limit_offset;
|
|
}
|
|
|
|
/**
|
|
* Get the columns that have been asked for with this query
|
|
*
|
|
* @return array
|
|
*/
|
|
public function listColumns()
|
|
{
|
|
return $this->columns;
|
|
}
|
|
|
|
/**
|
|
* Get the filters that have been applied to this query
|
|
*
|
|
* @return array
|
|
*/
|
|
public function listFilters()
|
|
{
|
|
return $this->filters;
|
|
}
|
|
|
|
/**
|
|
* Extend this function for things that should happen at construction time
|
|
*/
|
|
protected function init()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Extend this function for things that should happen before query execution
|
|
*/
|
|
protected function finish()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Total result size regardless of limit and offset
|
|
*
|
|
* @return int
|
|
*/
|
|
public function count()
|
|
{
|
|
return $this->ds->count($this);
|
|
}
|
|
|
|
/**
|
|
* Fetch result as an array of objects
|
|
*
|
|
* @return array
|
|
*/
|
|
public function fetchAll()
|
|
{
|
|
return $this->ds->fetchAll($this);
|
|
}
|
|
|
|
/**
|
|
* Fetch first result row
|
|
*
|
|
* @return object
|
|
*/
|
|
public function fetchRow()
|
|
{
|
|
return $this->ds->fetchRow($this);
|
|
}
|
|
|
|
/**
|
|
* Fetch first result column
|
|
*
|
|
* @return array
|
|
*/
|
|
public function fetchColumn()
|
|
{
|
|
return $this->ds->fetchColumn($this);
|
|
}
|
|
|
|
/**
|
|
* Fetch first column value from first result row
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function fetchOne()
|
|
{
|
|
return $this->ds->fetchOne($this);
|
|
}
|
|
|
|
/**
|
|
* Fetch result as a key/value pair array
|
|
*
|
|
* @return array
|
|
*/
|
|
public function fetchPairs()
|
|
{
|
|
return $this->ds->fetchPairs($this);
|
|
}
|
|
|
|
/**
|
|
* Return a pagination adapter for this query
|
|
*
|
|
* @return \Zend_Paginator
|
|
*/
|
|
public function paginate($limit = null, $page = null)
|
|
{
|
|
$this->finish();
|
|
if ($page === null && $limit === null) {
|
|
$request = \Zend_Controller_Front::getInstance()->getRequest();
|
|
|
|
if ($page === null) {
|
|
$page = $request->getParam('page', 0);
|
|
}
|
|
|
|
if ($limit === null) {
|
|
$limit = $request->getParam('limit', 20);
|
|
}
|
|
}
|
|
$this->limit($limit, $page * $limit);
|
|
|
|
$paginator = new \Zend_Paginator(
|
|
new \Icinga\Web\Paginator\Adapter\QueryAdapter($this)
|
|
);
|
|
|
|
$paginator->setItemCountPerPage($limit);
|
|
$paginator->setCurrentPageNumber($page);
|
|
|
|
return $paginator;
|
|
}
|
|
|
|
public function getColumns()
|
|
{
|
|
return $this->columns;
|
|
}
|
|
|
|
/**
|
|
* Destructor. Remove $ds, just to be on the safe side
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
unset($this->ds);
|
|
}
|
|
}
|