2013-06-03 17:02:08 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Icinga\Protocol\Ldap;
|
2013-06-07 13:29:11 +02:00
|
|
|
|
2013-07-12 13:41:48 +02:00
|
|
|
/**
|
|
|
|
* Search class
|
|
|
|
*
|
|
|
|
* @package Icinga\Protocol\Ldap
|
|
|
|
*/
|
2013-06-03 17:02:08 +02:00
|
|
|
/**
|
|
|
|
* Search abstraction class
|
|
|
|
*
|
|
|
|
* Usage example:
|
|
|
|
*
|
|
|
|
* <code>
|
|
|
|
* $connection->select()->from('user')->where('sAMAccountName = ?', 'icinga');
|
|
|
|
* </code>
|
|
|
|
*
|
|
|
|
* @copyright Copyright (c) 2013 Icinga-Web Team <info@icinga.org>
|
|
|
|
* @author Icinga-Web Team <info@icinga.org>
|
2013-07-12 13:41:48 +02:00
|
|
|
* @package Icinga\Protocol\Ldap
|
2013-06-03 17:02:08 +02:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
|
|
|
|
*/
|
|
|
|
class Query
|
|
|
|
{
|
|
|
|
protected $connection;
|
|
|
|
protected $filters = array();
|
|
|
|
protected $fields = array();
|
|
|
|
protected $limit_count;
|
|
|
|
protected $limit_offset;
|
|
|
|
protected $sort_columns = array();
|
|
|
|
protected $count;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
2013-07-12 13:41:48 +02:00
|
|
|
* @param Connection LDAP Connection object
|
|
|
|
* @return void
|
2013-06-03 17:02:08 +02:00
|
|
|
*/
|
|
|
|
public function __construct(Connection $connection)
|
|
|
|
{
|
|
|
|
$this->connection = $connection;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Count result set, ignoring limits
|
|
|
|
*
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function count()
|
|
|
|
{
|
|
|
|
if ($this->count === null) {
|
|
|
|
$this->count = $this->connection->count($this);
|
|
|
|
}
|
|
|
|
return $this->count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Count result set, ignoring limits
|
|
|
|
*
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function limit($count = null, $offset = null)
|
|
|
|
{
|
2013-07-12 13:41:48 +02:00
|
|
|
if (! preg_match('~^\d+~', $count . $offset)) {
|
2013-06-07 13:29:11 +02:00
|
|
|
throw new Exception(
|
|
|
|
sprintf(
|
|
|
|
'Got invalid limit: %s, %s',
|
|
|
|
$count,
|
|
|
|
$offset
|
|
|
|
)
|
|
|
|
);
|
2013-06-03 17:02:08 +02:00
|
|
|
}
|
2013-07-12 13:41:48 +02:00
|
|
|
$this->limit_count = (int) $count;
|
|
|
|
$this->limit_offset = (int) $offset;
|
2013-06-03 17:02:08 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether a limit has been set
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function hasLimit()
|
|
|
|
{
|
|
|
|
return $this->limit_count !== null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether an offset (limit) has been set
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function hasOffset()
|
|
|
|
{
|
|
|
|
return $this->limit_offset > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve result limit
|
|
|
|
*
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function getLimit()
|
|
|
|
{
|
|
|
|
return $this->limit_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve result offset
|
|
|
|
*
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function getOffset()
|
|
|
|
{
|
|
|
|
return $this->limit_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch result as tree
|
|
|
|
*
|
|
|
|
* @return Node
|
|
|
|
*/
|
|
|
|
public function fetchTree()
|
|
|
|
{
|
|
|
|
$result = $this->fetchAll();
|
|
|
|
$sorted = array();
|
2013-07-12 13:41:48 +02:00
|
|
|
$quotedDn = preg_quote($this->connection->getDN(), '/');
|
2013-06-07 13:29:11 +02:00
|
|
|
foreach ($result as $key => & $item) {
|
|
|
|
$new_key = LdapUtils::implodeDN(
|
|
|
|
array_reverse(
|
|
|
|
LdapUtils::explodeDN(
|
2013-07-12 13:41:48 +02:00
|
|
|
preg_replace('/,' . $quotedDn . '$/', '', $key)
|
2013-06-07 13:29:11 +02:00
|
|
|
)
|
2013-06-03 17:02:08 +02:00
|
|
|
)
|
2013-06-07 13:29:11 +02:00
|
|
|
);
|
2013-06-03 17:02:08 +02:00
|
|
|
$sorted[$new_key] = $key;
|
|
|
|
}
|
|
|
|
unset($groups);
|
|
|
|
ksort($sorted);
|
|
|
|
|
|
|
|
$tree = Root::forConnection($this->connection);
|
2013-07-12 13:41:48 +02:00
|
|
|
$root_dn = $tree->getDN();
|
2013-06-03 17:02:08 +02:00
|
|
|
foreach ($sorted as $sort_key => & $key) {
|
2013-07-12 13:41:48 +02:00
|
|
|
if ($key === $root_dn) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-06-03 17:02:08 +02:00
|
|
|
$tree->createChildByDN($key, $result[$key]);
|
|
|
|
}
|
|
|
|
return $tree;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch result as an array of objects
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function fetchAll()
|
|
|
|
{
|
|
|
|
return $this->connection->fetchAll($this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch first result row
|
|
|
|
*
|
|
|
|
* @return object
|
|
|
|
*/
|
|
|
|
public function fetchRow()
|
|
|
|
{
|
|
|
|
return $this->connection->fetchRow($this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch first column value from first result row
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
public function fetchOne()
|
|
|
|
{
|
|
|
|
return $this->connection->fetchOne($this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch a key/value list, first column is key, second is value
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function fetchPairs()
|
|
|
|
{
|
|
|
|
// STILL TODO!!
|
|
|
|
return $this->connection->fetchPairs($this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Where to select (which fields) from
|
|
|
|
*
|
|
|
|
* This creates an objectClass filter
|
|
|
|
*
|
|
|
|
* @return Query
|
|
|
|
*/
|
|
|
|
public function from($objectClass, $fields = array())
|
|
|
|
{
|
|
|
|
$this->filters['objectClass'] = $objectClass;
|
|
|
|
$this->fields = $fields;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a new filter to the query
|
|
|
|
*
|
|
|
|
* @param string Column to search in
|
|
|
|
* @param string Filter text (asterisks are allowed)
|
|
|
|
* @return Query
|
|
|
|
*/
|
|
|
|
public function where($key, $val)
|
|
|
|
{
|
|
|
|
$this->filters[$key] = $val;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort by given column
|
|
|
|
*
|
|
|
|
* TODO: Sort direction is not implemented yet
|
|
|
|
*
|
|
|
|
* @param string Order column
|
|
|
|
* @param string Order direction
|
|
|
|
* @return Query
|
|
|
|
*/
|
|
|
|
public function order($column, $direction = 'ASC')
|
|
|
|
{
|
|
|
|
$this->sort_columns[] = array($column, $direction);
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve a list of the desired fields
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function listFields()
|
|
|
|
{
|
|
|
|
return $this->fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve a list containing current sort columns
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getSortColumns()
|
|
|
|
{
|
|
|
|
return $this->sort_columns;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a pagination adapter for the current query
|
|
|
|
*
|
|
|
|
* @return \Zend_Paginator
|
|
|
|
*/
|
|
|
|
public function paginate($limit = null, $page = null)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$paginator = new \Zend_Paginator(
|
|
|
|
// TODO: Adapter doesn't fit yet:
|
2013-07-12 13:41:48 +02:00
|
|
|
new \Icinga\Web\Paginator\Adapter\QueryAdapter($this)
|
2013-06-03 17:02:08 +02:00
|
|
|
);
|
|
|
|
$paginator->setItemCountPerPage($limit);
|
|
|
|
$paginator->setCurrentPageNumber($page);
|
|
|
|
return $paginator;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the LDAP filter that will be applied
|
|
|
|
*
|
|
|
|
* @string
|
|
|
|
*/
|
|
|
|
public function __toString()
|
|
|
|
{
|
|
|
|
return $this->render();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the LDAP filter that will be applied
|
|
|
|
*
|
|
|
|
* @string
|
|
|
|
*/
|
|
|
|
protected function render()
|
|
|
|
{
|
|
|
|
$parts = array();
|
|
|
|
if ($this->filters['objectClass'] === null) {
|
|
|
|
throw new Exception('Object class is mandatory');
|
|
|
|
}
|
|
|
|
foreach ($this->filters as $key => $value) {
|
|
|
|
$parts[] = sprintf(
|
|
|
|
'%s=%s',
|
|
|
|
LdapUtils::quoteForSearch($key),
|
|
|
|
LdapUtils::quoteForSearch($value, true)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return '(&(' . implode(')(', $parts) . '))';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-07-12 13:41:48 +02:00
|
|
|
* Descructor
|
2013-06-03 17:02:08 +02:00
|
|
|
*/
|
|
|
|
public function __destruct()
|
|
|
|
{
|
|
|
|
// To be on the safe side:
|
|
|
|
unset($this->connection);
|
|
|
|
}
|
|
|
|
}
|