diff options
Diffstat (limited to 'library/Icinga/Web/UrlParams.php')
-rw-r--r-- | library/Icinga/Web/UrlParams.php | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/library/Icinga/Web/UrlParams.php b/library/Icinga/Web/UrlParams.php new file mode 100644 index 0000000..2265235 --- /dev/null +++ b/library/Icinga/Web/UrlParams.php @@ -0,0 +1,433 @@ +<?php +/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */ + +namespace Icinga\Web; + +use Icinga\Exception\MissingParameterException; + +class UrlParams +{ + protected $separator = '&'; + + protected $params = array(); + + protected $index = array(); + + public function isEmpty() + { + return empty($this->index); + } + + public function setSeparator($separator) + { + $this->separator = $separator; + return $this; + } + + /** + * Get the given parameter + * + * Returns the last URL param if defined multiple times, $default if not + * given at all + * + * @param string $param The parameter you're interested in + * @param string|int|bool|null $default An optional default value + * + * @return mixed + */ + public function get($param, $default = null) + { + if (! $this->has($param)) { + return $default; + } + + return rawurldecode($this->params[ end($this->index[$param]) ][ 1 ]); + } + + /** + * Require a parameter + * + * @param string $name Name of the parameter + * @param bool $strict Whether the parameter's value must not be the empty string + * + * @return mixed + * + * @throws MissingParameterException If the parameter was not given + */ + public function getRequired($name, $strict = true) + { + if ($this->has($name)) { + $value = $this->get($name); + if (! $strict || strlen($value) > 0) { + return $value; + } + } + $e = new MissingParameterException(t('Required parameter \'%s\' missing'), $name); + $e->setParameter($name); + throw $e; + } + + /** + * Get all instances of the given parameter + * + * Returns an array containing all values defined for a given parameter, + * $default if none. + * + * @param string $param The parameter you're interested in + * @param array $default An optional default value + * + * @return mixed + */ + public function getValues($param, $default = array()) + { + if (! $this->has($param)) { + return $default; + } + + $ret = array(); + foreach ($this->index[$param] as $key) { + $ret[] = rawurldecode($this->params[$key][1]); + } + return $ret; + } + + /** + * Whether the given parameter exists + * + * Returns true if such a parameter has been defined, false otherwise. + * + * @param string $param The parameter you're interested in + * + * @return boolean + */ + public function has($param) + { + return array_key_exists($param, $this->index); + } + + /** + * Get and remove the given parameter + * + * Returns the last URL param if defined multiple times, $default if not + * given at all. The parameter will be removed from this object. + * + * @param string $param The parameter you're interested in + * @param string $default An optional default value + * + * @return mixed + */ + public function shift($param = null, $default = null) + { + if ($param === null) { + if (empty($this->params)) { + return $default; + } + $ret = array_shift($this->params); + $ret[0] = rawurldecode($ret[0]); + $ret[1] = rawurldecode($ret[1]); + } else { + if (! $this->has($param)) { + return $default; + } + $key = reset($this->index[$param]); + $ret = rawurldecode($this->params[$key][1]); + unset($this->params[$key]); + } + + $this->reIndexAll(); + return $ret; + } + + /** + * Require and remove a parameter + * + * @param string $name Name of the parameter + * @param bool $strict Whether the parameter's value must not be the empty string + * + * @return mixed + * + * @throws MissingParameterException If the parameter was not given + */ + public function shiftRequired($name, $strict = true) + { + if ($this->has($name)) { + $value = $this->get($name); + if (! $strict || strlen($value) > 0) { + $this->shift($name); + return $value; + } + } + $e = new MissingParameterException(t('Required parameter \'%s\' missing'), $name); + $e->setParameter($name); + throw $e; + } + + public function addEncoded($param, $value = true) + { + $this->params[] = array($param, $this->cleanupValue($value)); + $this->indexLastOne(); + return $this; + } + + protected function urlEncode($value) + { + return rawurlencode($value instanceof Url ? $value->getAbsoluteUrl() : (string) $value); + } + + /** + * Add the given parameter with the given value + * + * This will add the given parameter, regardless of whether it already + * exists. + * + * @param string $param The parameter you're interested in + * @param string|bool $value The value to be stored + * + * @return $this + */ + public function add($param, $value = true) + { + return $this->addEncoded($this->urlEncode($param), $this->urlEncode($value)); + } + + /** + * Adds a list of parameters + * + * This may be used with either a list of values for a single parameter or + * with a list of parameter / value pairs. + * + * @param string|array $param Parameter name or param/value list + * @param ?array $value The value to be stored + * + * @return $this + */ + public function addValues($param, $values = null) + { + if ($values === null && is_array($param)) { + foreach ($param as $k => $v) { + $this->add($k, $v); + } + } else { + foreach ($values as $value) { + $this->add($param, $value); + } + } + + return $this; + } + + protected function clearValues() + { + $this->params = array(); + $this->index = array(); + } + + public function mergeValues($param, $values = null) + { + if ($values === null && is_array($param)) { + foreach ($param as $k => $v) { + $this->set($k, $v); + } + } else { + if (! is_array($values)) { + $values = array($values); + } + foreach ($values as $value) { + $this->set($param, $value); + } + } + + return $this; + } + + public function setValues($param, $values = null) + { + $this->clearValues(); + return $this->addValues($param, $values); + } + + /** + * Add the given parameter with the given value in front of all other values + * + * This will add the given parameter in front of all others, regardless of + * whether it already exists. + * + * @param string $param The parameter you're interested in + * @param string $value The value to be stored + * + * @return $this + */ + public function unshift($param, $value) + { + array_unshift($this->params, array($this->urlEncode($param), $this->urlEncode($value))); + $this->reIndexAll(); + return $this; + } + + /** + * Set the given parameter with the given value + * + * This will set the given parameter, and override eventually existing ones. + * + * @param string $param The parameter you want to set + * @param string $value The value to be stored + * + * @return $this + */ + public function set($param, $value) + { + if (! $this->has($param)) { + return $this->add($param, $value); + } + + while (count($this->index[$param]) > 1) { + $remove = array_pop($this->index[$param]); + unset($this->params[$remove]); + } + + $this->params[$this->index[$param][0]] = array( + $this->urlEncode($param), + $this->urlEncode($this->cleanupValue($value)) + ); + $this->reIndexAll(); + + return $this; + } + + public function remove($param) + { + $changed = false; + + if (! is_array($param)) { + $param = array($param); + } + + foreach ($param as $p) { + if ($this->has($p)) { + foreach ($this->index[$p] as $key) { + unset($this->params[$key]); + } + $changed = true; + } + } + + if ($changed) { + $this->reIndexAll(); + } + + return $this; + } + + public function without($param) + { + $params = clone $this; + return $params->remove($param); + } + + // TODO: push, pop? + + protected function indexLastOne() + { + end($this->params); + $key = key($this->params); + $param = $this->params[$key][0]; + $this->addParamToIndex($param, $key); + } + + protected function addParamToIndex($param, $key) + { + if (! $this->has($param)) { + $this->index[$param] = array(); + } + $this->index[$param][] = $key; + } + + protected function reIndexAll() + { + $this->index = array(); + $this->params = array_values($this->params); + foreach ($this->params as $key => & $param) { + $this->addParamToIndex($param[0], $key); + } + } + + protected function cleanupValue($value) + { + return is_bool($value) ? $value : (string) $value; + } + + protected function parseQueryString($queryString) + { + $parts = preg_split('~&~', $queryString, -1, PREG_SPLIT_NO_EMPTY); + foreach ($parts as $part) { + $this->parseQueryStringPart($part); + } + } + + protected function parseQueryStringPart($part) + { + if (strpos($part, '=') === false) { + $this->addEncoded($part, true); + } else { + list($key, $val) = preg_split('/=/', $part, 2); + $this->addEncoded($key, $val); + } + } + + /** + * Return the parameters of this url as sequenced or associative array + * + * @param bool $sequenced + * + * @return array + */ + public function toArray($sequenced = true) + { + if ($sequenced) { + return $this->params; + } + + $params = array(); + foreach ($this->params as $param) { + if ($param[1] === true) { + $params[] = $param[0]; + } else { + $params[$param[0]] = $param[1]; + } + } + + return $params; + } + + public function toString($separator = null) + { + if ($separator === null) { + $separator = $this->separator; + } + $parts = array(); + foreach ($this->params as $p) { + if ($p[1] === true) { + $parts[] = $p[0]; + } else { + $parts[] = $p[0] . '=' . $p[1]; + } + } + return implode($separator, $parts); + } + + public function __toString() + { + return $this->toString(); + } + + public static function fromQueryString($queryString = null) + { + if ($queryString === null) { + $queryString = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; + } + $params = new static(); + $params->parseQueryString($queryString); + + return $params; + } +} |