mirror of
				https://github.com/Icinga/icingaweb2.git
				synced 2025-11-03 20:54:27 +01:00 
			
		
		
		
	This is needed because of exception handling. Exceptions can now bubble up for default handling. Method render() was renamed to create() because the method create a query. Adjust the test for method create(). refs #5536
		
			
				
	
	
		
			332 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
// {{{ICINGA_LICENSE_HEADER}}}
 | 
						|
// {{{ICINGA_LICENSE_HEADER}}}
 | 
						|
 | 
						|
namespace Icinga\Protocol\Ldap;
 | 
						|
 | 
						|
/**
 | 
						|
 * Search class
 | 
						|
 *
 | 
						|
 * @package Icinga\Protocol\Ldap
 | 
						|
 */
 | 
						|
/**
 | 
						|
 * 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>
 | 
						|
 * @package    Icinga\Protocol\Ldap
 | 
						|
 * @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;
 | 
						|
    protected $base;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructor
 | 
						|
     *
 | 
						|
     * @param Connection LDAP Connection object
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public function __construct(Connection $connection)
 | 
						|
    {
 | 
						|
        $this->connection = $connection;
 | 
						|
    }
 | 
						|
 | 
						|
    public function setBase($base)
 | 
						|
    {
 | 
						|
        $this->base = $base;
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function hasBase()
 | 
						|
    {
 | 
						|
        return $this->base !== null;
 | 
						|
    }
 | 
						|
 | 
						|
    public function getBase()
 | 
						|
    {
 | 
						|
        return $this->base;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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)
 | 
						|
    {
 | 
						|
        if (! preg_match('~^\d+~', $count . $offset)) {
 | 
						|
            throw new Exception(
 | 
						|
                'Got invalid limit: %s, %s',
 | 
						|
                $count,
 | 
						|
                $offset
 | 
						|
            );
 | 
						|
        }
 | 
						|
        $this->limit_count  = (int) $count;
 | 
						|
        $this->limit_offset = (int) $offset;
 | 
						|
        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();
 | 
						|
        $quotedDn = preg_quote($this->connection->getDN(), '/');
 | 
						|
        foreach ($result as $key => & $item) {
 | 
						|
            $new_key = LdapUtils::implodeDN(
 | 
						|
                array_reverse(
 | 
						|
                    LdapUtils::explodeDN(
 | 
						|
                        preg_replace('/,' . $quotedDn . '$/', '', $key)
 | 
						|
                    )
 | 
						|
                )
 | 
						|
            );
 | 
						|
            $sorted[$new_key] = $key;
 | 
						|
        }
 | 
						|
        unset($groups);
 | 
						|
        ksort($sorted);
 | 
						|
 | 
						|
        $tree = Root::forConnection($this->connection);
 | 
						|
        $root_dn = $tree->getDN();
 | 
						|
        foreach ($sorted as $sort_key => & $key) {
 | 
						|
            if ($key === $root_dn) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            $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:
 | 
						|
            new \Icinga\Web\Paginator\Adapter\QueryAdapter($this)
 | 
						|
        );
 | 
						|
        $paginator->setItemCountPerPage($limit);
 | 
						|
        $paginator->setCurrentPageNumber($page);
 | 
						|
        return $paginator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the LDAP filter that will be applied
 | 
						|
     *
 | 
						|
     * @string
 | 
						|
     */
 | 
						|
    public function create()
 | 
						|
    {
 | 
						|
        $parts = array();
 | 
						|
        if (! isset($this->filters['objectClass']) || $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)
 | 
						|
            );
 | 
						|
        }
 | 
						|
        if (count($parts) > 1) {
 | 
						|
            return '(&(' . implode(')(', $parts) . '))';
 | 
						|
        } else {
 | 
						|
            return '(' . $parts[0] . ')';
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Descructor
 | 
						|
     */
 | 
						|
    public function __destruct()
 | 
						|
    {
 | 
						|
        // To be on the safe side:
 | 
						|
        unset($this->connection);
 | 
						|
    }
 | 
						|
}
 |