usePagedResults = false; } /** * Set the base dn to be used for this query * * @param string $base * * @return $this */ public function setBase($base) { $this->base = $base; return $this; } /** * Return the base dn being used for this query * * @return string */ public function getBase() { return $this->base; } /** * Set whether this query is permitted to utilize paged results * * @param bool $state * * @return $this */ public function setUsePagedResults($state = true) { $this->usePagedResults = (bool) $state; return $this; } /** * Return whether this query is permitted to utilize paged results * * @return bool */ public function getUsePagedResults() { return $this->usePagedResults; } /** * Set the attribute to be used to unfold the result * * @param string $attributeName * * @return $this */ public function setUnfoldAttribute($attributeName) { $this->unfoldAttribute = $attributeName; return $this; } /** * Return the attribute to use to unfold the result * * @return string */ public function getUnfoldAttribute() { return $this->unfoldAttribute; } /** * Set this query's native LDAP filter * * @param string $filter * * @return $this */ public function setNativeFilter($filter) { $this->nativeFilter = $filter; return $this; } /** * Return this query's native LDAP filter * * @return string */ public function getNativeFilter() { return $this->nativeFilter; } /** * Choose an objectClass and the columns you are interested in * * {@inheritdoc} This creates an objectClass filter. */ public function from($target, array $fields = null) { $this->where('objectClass', $target); return parent::from($target, $fields); } public function where($condition, $value = null) { $this->addFilter(Filter::expression($condition, '=', $value)); return $this; } public function addFilter(Filter $filter) { $this->makeCaseInsensitive($filter); return parent::addFilter($filter); } public function setFilter(Filter $filter) { $this->makeCaseInsensitive($filter); return parent::setFilter($filter); } protected function makeCaseInsensitive(Filter $filter) { if ($filter->isExpression()) { /** @var \Icinga\Data\Filter\FilterExpression $filter */ $filter->setCaseSensitive(false); } else { /** @var \Icinga\Data\Filter\FilterChain $filter */ foreach ($filter->filters() as $subFilter) { $this->makeCaseInsensitive($subFilter); } } } public function compare($a, $b, $orderIndex = 0) { if (array_key_exists($orderIndex, $this->order)) { $column = $this->order[$orderIndex][0]; $direction = $this->order[$orderIndex][1]; $flippedColumns = $this->flippedColumns ?: array_flip($this->columns); if (array_key_exists($column, $flippedColumns) && is_string($flippedColumns[$column])) { $column = $flippedColumns[$column]; } if (is_array($a->$column)) { // rfc2891 states: If a sort key is a multi-valued attribute, and an entry happens to // have multiple values for that attribute and no other controls are // present that affect the sorting order, then the server SHOULD use the // least value (according to the ORDERING rule for that attribute). $a = clone $a; $a->$column = array_reduce($a->$column, function ($carry, $item) use ($direction) { $result = $carry === null ? 0 : strcmp($item, $carry); return ($direction === self::SORT_ASC ? $result : $result * -1) < 1 ? $item : $carry; }); } if (is_array($b->$column)) { $b = clone $b; $b->$column = array_reduce($b->$column, function ($carry, $item) use ($direction) { $result = $carry === null ? 0 : strcmp($item, $carry); return ($direction === self::SORT_ASC ? $result : $result * -1) < 1 ? $item : $carry; }); } } return parent::compare($a, $b, $orderIndex); } /** * Fetch result as tree * * @return Root * * @todo This is untested waste, not being used anywhere and ignores the query's order and base dn. * Evaluate whether it's reasonable to properly implement and test it. */ public function fetchTree() { $result = $this->fetchAll(); $sorted = array(); $quotedDn = preg_quote($this->ds->getDn(), '/'); foreach ($result as $key => & $item) { $new_key = LdapUtils::implodeDN( array_reverse( LdapUtils::explodeDN( preg_replace('/,' . $quotedDn . '$/', '', $key) ) ) ); $sorted[$new_key] = $key; } ksort($sorted); $tree = Root::forConnection($this->ds); $root_dn = $tree->getDN(); foreach ($sorted as $sort_key => & $key) { if ($key === $root_dn) { continue; } $tree->createChildByDN($key, $result[$key]); } return $tree; } /** * Fetch the distinguished name of the first result * * @return string|false The distinguished name or false in case it's not possible to fetch a result * * @throws LdapException In case the query returns multiple results * (i.e. it's not possible to fetch a unique DN) */ public function fetchDn() { return $this->ds->fetchDn($this); } /** * Render and return this query's filter * * @return string */ public function renderFilter() { $filter = $this->ds->renderFilter($this->filter); if ($this->nativeFilter) { $filter = '(&(' . $this->nativeFilter . ')' . $filter . ')'; } return $filter; } /** * Return the LDAP filter to be applied on this query * * @return string */ public function __toString() { return $this->renderFilter(); } /** * Get LDAP search scope * * @return string */ public function getScope() { return $this->scope; } /** * Set LDAP search scope * * Valid: sub one base (Default: sub) * * @param string $scope * * @return LdapQuery * * @throws LogicException If scope value is invalid */ public function setScope($scope) { if (! in_array($scope, static::$scopes)) { throw new LogicException( 'Can\'t set scope %d, it is is invalid. Use one of %s or LdapQuery\'s constants.', $scope, implode(', ', static::$scopes) ); } $this->scope = $scope; return $this; } }