Url: Consider urls with a leading slash as absolute..

..and make it possible to have a url without a base.

refs #5600
This commit is contained in:
Johannes Meyer 2015-09-22 14:14:41 +02:00
parent 57e08e92d4
commit 7321d67b4f
2 changed files with 73 additions and 32 deletions

View File

@ -46,12 +46,11 @@ class Url
protected $path = ''; protected $path = '';
/** /**
* The baseUrl that will be appended to @see Url::$path in order to * The baseUrl that will be appended to @see Url::$path
* create an absolute Url
* *
* @var string * @var string
*/ */
protected $baseUrl = '/'; protected $baseUrl = '';
protected function __construct() protected function __construct()
{ {
@ -156,17 +155,24 @@ class Url
$baseUrl = $urlParts['host'] . (isset($urlParts['port']) ? (':' . $urlParts['port']) : ''); $baseUrl = $urlParts['host'] . (isset($urlParts['port']) ? (':' . $urlParts['port']) : '');
$urlObject->setIsExternal(); $urlObject->setIsExternal();
} else { } else {
$baseUrl = '';
}
if (isset($urlParts['path'])) {
$urlPath = $urlParts['path'];
if ($urlPath && $urlPath[0] === '/') {
$baseUrl = '';
} elseif (! $baseUrl) {
$baseUrl = $request->getBaseUrl(); $baseUrl = $request->getBaseUrl();
} }
$urlObject->setBaseUrl($baseUrl); if ($baseUrl && !$urlObject->isExternal() && strpos($urlPath, $baseUrl) === 0) {
$urlObject->setPath(substr($urlPath, strlen($baseUrl)));
if (isset($urlParts['path'])) {
if ($baseUrl && !$urlObject->isExternal() && strpos($urlParts['path'], $baseUrl) === 0) {
$urlObject->setPath(substr($urlParts['path'], strlen($baseUrl)));
} else { } else {
$urlObject->setPath($urlParts['path']); $urlObject->setPath($urlPath);
} }
} elseif (! $baseUrl) {
$baseUrl = $request->getBaseUrl();
} }
// TODO: This has been used by former filter implementation, remove it: // TODO: This has been used by former filter implementation, remove it:
@ -178,6 +184,7 @@ class Url
$urlObject->setAnchor($urlParts['fragment']); $urlObject->setAnchor($urlParts['fragment']);
} }
$urlObject->setBaseUrl($baseUrl);
$urlObject->setParams($params); $urlObject->setParams($params);
return $urlObject; return $urlObject;
} }
@ -205,19 +212,13 @@ class Url
/** /**
* Overwrite the baseUrl * Overwrite the baseUrl
* *
* If an empty Url is given '/' is used as the base
*
* @param string $baseUrl The url path to use as the Url Base * @param string $baseUrl The url path to use as the Url Base
* *
* @return $this * @return $this
*/ */
public function setBaseUrl($baseUrl) public function setBaseUrl($baseUrl)
{ {
if (($baseUrl = rtrim($baseUrl, '/ ')) === '') { $this->baseUrl = rtrim($baseUrl, '/ ');
$baseUrl = '/';
}
$this->baseUrl = $baseUrl;
return $this; return $this;
} }
@ -280,17 +281,42 @@ class Url
} }
/** /**
* Return the relative url with query parameters as a string * Return the relative url
* *
* @return string * @return string
*
* @throws ProgrammingError In case no relative url path is set or it is absolute
*/ */
public function getRelativeUrl($separator = '&') public function getRelativeUrl($separator = '&')
{ {
if ($this->params->isEmpty()) { $path = $this->getPath();
return $this->path . $this->anchor; if (! $path) {
} else { throw new ProgrammingError('Unable to provide a relative URL. No path set');
return $this->path . '?' . $this->params->toString($separator) . $this->anchor; } elseif ($path[0] === '/') {
throw new ProgrammingError('Cannot provide a relative URL. Path is absolute');
} }
return $this->buildPathQueryAndFragment($separator);
}
/**
* Return this url's path with its query parameters and fragment as string
*
* @return string
*/
protected function buildPathQueryAndFragment($querySeparator)
{
$anchor = $this->getAnchor();
if ($anchor) {
$anchor = '#' . $anchor;
}
$query = $this->getQueryString($querySeparator);
if ($query) {
$query = '?' . $query;
}
return $this->getPath() . $query . $anchor;
} }
public function setQueryString($queryString) public function setQueryString($queryString)
@ -299,9 +325,9 @@ class Url
return $this; return $this;
} }
public function getQueryString() public function getQueryString($separator = null)
{ {
return (string) $this->params; return $this->params->toString($separator);
} }
/** /**
@ -311,12 +337,17 @@ class Url
*/ */
public function getAbsoluteUrl($separator = '&') public function getAbsoluteUrl($separator = '&')
{ {
$relativeUrl = $this->getRelativeUrl($separator); $path = $this->buildPathQueryAndFragment($separator);
if ($relativeUrl === '#') { if ($path && ($path === '#' || $path[0] === '/')) {
return $relativeUrl; return $path;
} }
return $this->baseUrl . ($this->baseUrl !== '/' && $relativeUrl ? '/' : '') . $relativeUrl; $baseUrl = $this->getBaseUrl();
if (! $baseUrl) {
$baseUrl = '/';
}
return $baseUrl . ($baseUrl !== '/' && $path ? '/' : '') . $path;
} }
/** /**
@ -434,10 +465,20 @@ class Url
*/ */
public function setAnchor($anchor) public function setAnchor($anchor)
{ {
$this->anchor = '#' . $anchor; $this->anchor = $anchor;
return $this; return $this;
} }
/**
* Return the url anchor-part
*
* @return string The site's anchor string without the '#'
*/
public function getAnchor()
{
return $this->anchor;
}
/** /**
* Remove provided key (if string) or keys (if array of string) from the query parameter array * Remove provided key (if string) or keys (if array of string) from the query parameter array
* *

View File

@ -82,13 +82,13 @@ class UrlTest extends BaseTestCase
$url = Url::fromPath('/my/test/url.html'); $url = Url::fromPath('/my/test/url.html');
$this->assertEquals( $this->assertEquals(
'/', '',
$url->getBaseUrl(), $url->getBaseUrl(),
'Url::fromPath does not recognize the correct base url' 'Url::fromPath does not recognize the correct base url'
); );
$this->assertEquals( $this->assertEquals(
'my/test/url.html', '/my/test/url.html',
$url->getPath(), $url->getAbsoluteUrl(),
'Url::fromPath does not recognize the correct url path' 'Url::fromPath does not recognize the correct url path'
); );
} }