Improve Uri class by adding useful tests

This commit is contained in:
Matias Griese
2018-02-17 12:23:45 +02:00
parent ccf0f9c74e
commit 0a79788582
3 changed files with 109 additions and 200 deletions

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -1,193 +0,0 @@
<?php
/**
* @package Grav\Framework\Uri
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Uri;
use Psr\Http\Message\UriInterface;
/**
* Class Uri
* @package Grav\Framework\Uri
*/
class UriHelper
{
/** @var array List of default ports for the supported schemes. */
private static $defaultPorts = [
'http' => 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);
}
}