From 0a79788582fd6273081cbc21645b8a430e2b65b7 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Sat, 17 Feb 2018 12:23:45 +0200 Subject: [PATCH] Improve Uri class by adding useful tests --- .../src/Grav/Framework/Psr7/AbstractUri.php | 17 +- system/src/Grav/Framework/Uri/Uri.php | 99 ++++++++- system/src/Grav/Framework/Uri/UriHelper.php | 193 ------------------ 3 files changed, 109 insertions(+), 200 deletions(-) delete mode 100644 system/src/Grav/Framework/Uri/UriHelper.php diff --git a/system/src/Grav/Framework/Psr7/AbstractUri.php b/system/src/Grav/Framework/Psr7/AbstractUri.php index 750f49f6c..984032ea3 100644 --- a/system/src/Grav/Framework/Psr7/AbstractUri.php +++ b/system/src/Grav/Framework/Psr7/AbstractUri.php @@ -9,7 +9,6 @@ namespace Grav\Framework\Psr7; use Grav\Framework\Uri\UriFilter; -use Grav\Framework\Uri\UriHelper; use Psr\Http\Message\UriInterface; /** @@ -19,6 +18,11 @@ use Psr\Http\Message\UriInterface; */ abstract class AbstractUri implements UriInterface { + protected static $defaultPorts = [ + 'http' => 80, + 'https' => 443 + ]; + /** @var string Uri scheme. */ private $scheme = ''; @@ -384,9 +388,18 @@ abstract class AbstractUri implements UriInterface } } + protected function isDefaultPort() + { + $scheme = $this->scheme; + $port = $this->port; + + return $this->port === null + || (isset(static::$defaultPorts[$scheme]) && $port === static::$defaultPorts[$scheme]); + } + private function unsetDefaultPort() { - if ($this->port !== null && UriHelper::isDefaultPort($this)) { + if ($this->isDefaultPort()) { $this->port = null; } } diff --git a/system/src/Grav/Framework/Uri/Uri.php b/system/src/Grav/Framework/Uri/Uri.php index 717df6074..3d7fddecc 100644 --- a/system/src/Grav/Framework/Uri/Uri.php +++ b/system/src/Grav/Framework/Uri/Uri.php @@ -9,6 +9,7 @@ namespace Grav\Framework\Uri; use Grav\Framework\Psr7\AbstractUri; +use GuzzleHttp\Psr7\Uri as GuzzleUri; use Psr\Http\Message\UriInterface; /** @@ -18,10 +19,11 @@ use Psr\Http\Message\UriInterface; */ class Uri extends AbstractUri { - protected $queryParams; + /** @var array Array of Uri query. */ + private $queryParams; /** - * Uri constructor. + * You can use `UriFactory` functions to create new `Uri` objects. * * @param array $parts * @throws \InvalidArgumentException @@ -88,7 +90,7 @@ class Uri extends AbstractUri */ public function withoutQueryParam($key) { - return UriHelper::withoutQueryParam($this, $key); + return GuzzleUri::withoutQueryValue($this, $key); } /** @@ -98,7 +100,7 @@ class Uri extends AbstractUri */ public function withQueryParam($key, $value) { - return UriHelper::withQueryParam($this, $key, $value); + return GuzzleUri::withQueryValue($this, $key, $value); } /** @@ -120,6 +122,93 @@ class Uri extends AbstractUri */ public function withQueryParams(array $params) { - return empty($params) ? $this->withQuery('') : UriHelper::withQueryParams($this, $params); + $query = $params ? http_build_query($params) : ''; + + return $this->withQuery($query); + } + + /** + * Whether the URI has the default port of the current scheme. + * + * `$uri->getPort()` may return the standard port. This method can be used for some non-http/https Uri. + * + * @return bool + */ + public function isDefaultPort() + { + return $this->getPort() === null || GuzzleUri::isDefaultPort($this); + } + + /** + * Whether the URI is absolute, i.e. it has a scheme. + * + * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true + * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative + * to another URI, the base URI. Relative references can be divided into several forms: + * - network-path references, e.g. '//example.com/path' + * - absolute-path references, e.g. '/path' + * - relative-path references, e.g. 'subpath' + * + * @return bool + * @link https://tools.ietf.org/html/rfc3986#section-4 + */ + public function isAbsolute() + { + return GuzzleUri::isAbsolute($this); + } + + /** + * Whether the URI is a network-path reference. + * + * A relative reference that begins with two slash characters is termed an network-path reference. + * + * @return bool + * @link https://tools.ietf.org/html/rfc3986#section-4.2 + */ + public function isNetworkPathReference() + { + return GuzzleUri::isNetworkPathReference($this); + } + + /** + * Whether the URI is a absolute-path reference. + * + * A relative reference that begins with a single slash character is termed an absolute-path reference. + * + * @return bool + * @link https://tools.ietf.org/html/rfc3986#section-4.2 + */ + public function isAbsolutePathReference() + { + return GuzzleUri::isAbsolutePathReference($this); + } + + /** + * Whether the URI is a relative-path reference. + * + * A relative reference that does not begin with a slash character is termed a relative-path reference. + * + * @return bool + * @link https://tools.ietf.org/html/rfc3986#section-4.2 + */ + public function isRelativePathReference() + { + return GuzzleUri::isRelativePathReference($this); + } + + /** + * Whether the URI is a same-document reference. + * + * A same-document reference refers to a URI that is, aside from its fragment + * component, identical to the base URI. When no base URI is given, only an empty + * URI reference (apart from its fragment) is considered a same-document reference. + * + * @param UriInterface|null $base An optional base URI to compare against + * @return bool + * @link https://tools.ietf.org/html/rfc3986#section-4.4 + */ + public function isSameDocumentReference(UriInterface $base = null) + { + return GuzzleUri::isSameDocumentReference($this, $base); } } diff --git a/system/src/Grav/Framework/Uri/UriHelper.php b/system/src/Grav/Framework/Uri/UriHelper.php deleted file mode 100644 index 48dfea028..000000000 --- a/system/src/Grav/Framework/Uri/UriHelper.php +++ /dev/null @@ -1,193 +0,0 @@ - 80, - 'https' => 443, - 'ftp' => 21, - 'telnet' => 23, - ]; - - private static $replaceQuery = ['=' => '%3D', '&' => '%26']; - - /** - * Whether the URI has the default port of the current scheme. - * - * `Psr\Http\Message\UriInterface::getPort` may return null or the standard port. This method can be used - * independently of the implementation. - * - * @param UriInterface $uri - * @return bool - */ - public static function isDefaultPort(UriInterface $uri) - { - $port = $uri->getPort(); - $scheme = $uri->getScheme(); - - return $port === null || (isset(static::$defaultPorts[$scheme]) && $port === static::$defaultPorts[$scheme]); - } - - /** - * Whether the URI is absolute, i.e. it has a scheme. - * - * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true - * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative - * to another URI, the base URI. Relative references can be divided into several forms: - * - network-path references, e.g. '//example.com/path' - * - absolute-path references, e.g. '/path' - * - relative-path references, e.g. 'subpath' - * - * @param UriInterface $uri - * @return bool - * @link https://tools.ietf.org/html/rfc3986#section-4 - */ - public static function isAbsolute(UriInterface $uri) - { - return $uri->getScheme() !== ''; - } - - /** - * Whether the URI is a network-path reference. - * - * A relative reference that begins with two slash characters is termed an network-path reference. - * - * @param UriInterface $uri - * - * @return bool - * @link https://tools.ietf.org/html/rfc3986#section-4.2 - */ - public static function isNetworkPathReference(UriInterface $uri) - { - return $uri->getScheme() === '' && $uri->getAuthority() !== ''; - } - - /** - * Whether the URI is a absolute-path reference. - * - * A relative reference that begins with a single slash character is termed an absolute-path reference. - * - * @param UriInterface $uri - * - * @return bool - * @link https://tools.ietf.org/html/rfc3986#section-4.2 - */ - public static function isAbsolutePathReference(UriInterface $uri) - { - $path = $uri->getPath(); - - return $uri->getScheme() === '' && $uri->getAuthority() === '' && isset($path[0]) && $path[0] === '/'; - } - - /** - * Whether the URI is a relative-path reference. - * - * A relative reference that does not begin with a slash character is termed a relative-path reference. - * - * @param UriInterface $uri - * - * @return bool - * @link https://tools.ietf.org/html/rfc3986#section-4.2 - */ - public static function isRelativePathReference(UriInterface $uri) - { - $path = $uri->getPath(); - - return $uri->getScheme() === '' && $uri->getAuthority() === '' && (!isset($path[0]) || $path[0] !== '/'); - } - - /** - * Creates a new URI with a specific query string value removed. - * - * Any existing query string values that exactly match the provided key are - * removed. - * - * @param UriInterface $uri URI to use as a base. - * @param string $key Query string key to remove. - * - * @return UriInterface - */ - public static function withoutQueryParam(UriInterface $uri, $key) - { - $current = $uri->getQuery(); - if ($current === '') { - return $uri; - } - - $decodedKey = rawurldecode($key); - $result = array_filter(explode('&', $current), function ($part) use ($decodedKey) { - return rawurldecode(explode('=', $part)[0]) !== $decodedKey; - }); - - return $uri->withQuery(implode('&', $result)); - } - - /** - * Creates a new URI with a specific query string value. - * - * Any existing query string values that exactly match the provided key are - * removed and replaced with the given key value pair. - * - * A value of null will set the query string key without a value, e.g. "key" - * instead of "key=value". - * - * @param UriInterface $uri URI to use as a base. - * @param string $key Key to set. - * @param string|null $value Value to set - * - * @return UriInterface - */ - public static function withQueryParam(UriInterface $uri, $key, $value) - { - $current = $uri->getQuery(); - - if ($current === '') { - $result = []; - } else { - $decodedKey = rawurldecode($key); - $result = array_filter(explode('&', $current), function ($part) use ($decodedKey) { - return rawurldecode(explode('=', $part)[0]) !== $decodedKey; - }); - } - - // Query string separators ("=", "&") within the key or value need to be encoded - // (while preventing double-encoding) before setting the query string. All other - // chars that need percent-encoding will be encoded by withQuery(). - $key = strtr($key, static::$replaceQuery); - - if ($value !== null) { - $result[] = $key . '=' . strtr($value, static::$replaceQuery); - } else { - $result[] = $key; - } - - return $uri->withQuery(implode('&', $result)); - } - - /** - * @param UriInterface $uri - * @param array $params - * @return UriInterface - */ - public static function withQueryParams(UriInterface $uri, array $params) - { - $query = http_build_query($params); - - return $uri->withQuery($query); - } -}