Skip to content

Unify system variable $basePath #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .phpstorm.meta.php

This file was deleted.

2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
"dev-master": "4.0-dev"
}
}
}
8 changes: 4 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,14 +333,14 @@ Global filters give you the ability to adjust the behavior of the route in absol
If a parameter has a custom filter defined and a global filter exists at the same time, custom `FILTER_IN` is executed before the global and vice versa global `FILTER_OUT` is executed before the custom. Thus, inside the global filter are the values of the parameters `controller` resp. `action` written in PascalCase resp. camelCase style.


ONE_WAY flag
OneWay flag
------------

One-way routes are used to preserve the functionality of old URLs that the application no longer generates but still accepts. We flag them with `ONE_WAY`:
One-way routes are used to preserve the functionality of old URLs that the application no longer generates but still accepts. We flag them with `oneWay`:

```php
// old URL /product-info?id=123
$router->addRoute('product-info', [...], $router::ONE_WAY);
$router->addRoute('product-info', [...], oneWay: true);
// new URL /product/123
$router->addRoute('product/<id>', [...]);
```
Expand Down Expand Up @@ -450,7 +450,7 @@ SEO and Canonization

The framework increases SEO (search engine optimization) by preventing duplication of content at different URLs. If multiple addresses link to a same destination, eg `/index` and `/index.html`, the framework determines the first one as primary (canonical) and redirects the others to it using HTTP code 301. Thanks to this, search engines will not index pages twice and do not break their page rank. .

This process is called canonization. The canonical URL is the one generated by the router, i.e. by the first matching route in the [collection ](#route-collection) without the ONE_WAY flag. Therefore, in the collection, we list **primary routes first**.
This process is called canonization. The canonical URL is the one generated by the router, i.e. by the first matching route in the [collection ](#route-collection) without the OneWay flag. Therefore, in the collection, we list **primary routes first**.

Canonization is performed by the controller, more in the chapter [canonization ](controllers#Canonization).

Expand Down
28 changes: 19 additions & 9 deletions src/Routing/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public function match(Nette\Http\IRequest $httpRequest): ?array
? [$host]
: array_reverse(explode('.', $host));
$re = strtr($re, [
'/%basePath%/' => preg_quote($url->getBasePath(), '#'),
'/%basePath%/' => preg_quote($url->getBasePath() . '/', '#'),
'%tld%' => preg_quote($parts[0], '#'),
'%domain%' => preg_quote(isset($parts[1]) ? "$parts[1].$parts[0]" : $parts[0], '#'),
'%sld%' => preg_quote($parts[1] ?? '', '#'),
Expand All @@ -176,11 +176,11 @@ public function match(Nette\Http\IRequest $httpRequest): ?array

} elseif ($this->type === self::Relative) {
$basePath = $url->getBasePath();
if (strncmp($url->getPath(), $basePath, strlen($basePath)) !== 0) {
if (strncmp($url->getPath(), $basePath.'/', strlen($basePath.'/')) !== 0) {
return null;
}

$path = substr($url->getPath(), strlen($basePath));
$path = substr($url->getPath(), strlen($basePath.'/'));

} else {
$path = $url->getPath();
Expand Down Expand Up @@ -262,7 +262,7 @@ public function constructUrl(array $params, Nette\Http\UrlScript $refUrl): ?stri

// absolutize
if ($this->type === self::Relative) {
$url = (($tmp = $refUrl->getAuthority()) ? "//$tmp" : '') . $refUrl->getBasePath() . $url;
$url = (($tmp = $refUrl->getAuthority()) ? "//$tmp" : '') . $refUrl->getBasePath() . '/' . $url;

} elseif ($this->type === self::Path) {
$url = (($tmp = $refUrl->getAuthority()) ? "//$tmp" : '') . $url;
Expand All @@ -272,12 +272,13 @@ public function constructUrl(array $params, Nette\Http\UrlScript $refUrl): ?stri
$parts = ip2long($host)
? [$host]
: array_reverse(explode('.', $host));
$port = $refUrl->getDefaultPort() === ($tmp = $refUrl->getPort()) ? '' : ':' . $tmp;
$url = strtr($url, [
'/%basePath%/' => $refUrl->getBasePath(),
'%tld%' => $parts[0],
'%domain%' => isset($parts[1]) ? "$parts[1].$parts[0]" : $parts[0],
'/%basePath%/' => $refUrl->getBasePath() . '/',
'%tld%' => $parts[0] . $port,
'%domain%' => (isset($parts[1]) ? "$parts[1].$parts[0]" : $parts[0]) . $port,
'%sld%' => $parts[1] ?? '',
'%host%' => $host,
'%host%' => $host . $port,
]);
}

Expand Down Expand Up @@ -309,6 +310,14 @@ private function preprocessParams(array &$params): bool
$fixity = $meta[self::Fixity] ?? null;

if (!isset($params[$name])) {
if ($fixity === self::Constant) {
if ($meta[self::Value] === null) {
continue;
}

return false; // wrong parameter value
}

continue; // retains null values
}

Expand All @@ -319,7 +328,8 @@ private function preprocessParams(array &$params): bool
}

if ($fixity !== null) {
if ($params[$name] === $meta[self::Value]) { // remove default values; null values are retain
if ($params[$name] == $meta[self::Value]) { // default value may be object, intentionally ==
// remove default values; null values are retain
unset($params[$name]);
continue;

Expand Down
22 changes: 8 additions & 14 deletions src/Routing/RouteList.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,8 @@ public function __construct()

/**
* Maps HTTP request to an array.
* @final
*/
public function match(Nette\Http\IRequest $httpRequest): ?array
final public function match(Nette\Http\IRequest $httpRequest): ?array
{
if ($httpRequest = $this->prepareRequest($httpRequest)) {
foreach ($this->list as [$router]) {
Expand Down Expand Up @@ -68,7 +67,7 @@ protected function prepareRequest(Nette\Http\IRequest $httpRequest): ?Nette\Http
$url = $httpRequest->getUrl();
$relativePath = $url->getRelativePath();
if (strncmp($relativePath, $this->path, strlen($this->path)) === 0) {
$url = $url->withPath($url->getPath(), $url->getBasePath() . $this->path);
$url = $url->withPath($url->getPath(), $url->getBasePath() . '/' . $this->path);
} elseif ($relativePath . '/' === $this->path) {
$url = $url->withPath($url->getPath() . '/');
} else {
Expand Down Expand Up @@ -105,7 +104,7 @@ public function constructUrl(array $params, Nette\Http\UrlScript $refUrl): ?stri

if ($this->path) {
if (!isset($this->refUrlCache[$refUrl])) {
$this->refUrlCache[$refUrl] = $refUrl->withPath($refUrl->getBasePath() . $this->path);
$this->refUrlCache[$refUrl] = $refUrl->withPath($refUrl->getBasePath() . '/' . $this->path);
}

$refUrl = $this->refUrlCache[$refUrl];
Expand Down Expand Up @@ -187,7 +186,7 @@ public function warmupCache(): void
/**
* Adds a router.
*/
public function add(Router $router, int $oneWay = 0): static
public function add(Router $router, bool $oneWay = false): static
{
$this->list[] = [$router, $oneWay];
$this->ranks = null;
Expand All @@ -198,7 +197,7 @@ public function add(Router $router, int $oneWay = 0): static
/**
* Prepends a router.
*/
public function prepend(Router $router, int $oneWay = 0): void
public function prepend(Router $router, bool $oneWay = false): void
{
array_splice($this->list, 0, 0, [[$router, $oneWay]]);
$this->ranks = null;
Expand All @@ -220,12 +219,7 @@ protected function modify(int $index, ?Router $router): void
}


/**
* @param string $mask e.g. '<presenter>/<action>/<id \d{1,3}>'
* @param array $metadata default values or metadata
* @return static
*/
public function addRoute(string $mask, array $metadata = [], int $oneWay = 0)
public function addRoute(string $mask, array $metadata = [], bool $oneWay = false): static
{
$this->add(new Route($mask, $metadata), $oneWay);
return $this;
Expand Down Expand Up @@ -273,11 +267,11 @@ public function getRouters(): array


/**
* @return int[]
* @return bool[][]
*/
public function getFlags(): array
{
return array_column($this->list, 1);
return array_map(fn($info) => ['oneWay' => (bool) $info[1]], $this->list);
}


Expand Down
4 changes: 2 additions & 2 deletions src/Routing/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
*/
interface Router
{
/** for back compatibility */
public const ONE_WAY = 0b0001;
/** @deprecated */
public const ONE_WAY = true;

/**
* Maps HTTP request to an array.
Expand Down
4 changes: 1 addition & 3 deletions src/Routing/SimpleRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ public function constructUrl(array $params, Nette\Http\UrlScript $refUrl): ?stri
{
// remove default values; null values are retain
foreach ($this->defaults as $key => $value) {
if (isset($params[$key])
&& (is_scalar($params[$key]) ? (string) $params[$key] : $params[$key]) === (is_scalar($value) ? (string) $value : $value)
) {
if (isset($params[$key]) && $params[$key] == $value) { // default value may be object, intentionally ==
unset($params[$key]);
}
}
Expand Down
10 changes: 2 additions & 8 deletions tests/Route/fixedParameter.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ testRouteIn($route, '/?const=foo', ['const' => 'hello', 'test' => 'testvalue'],

testRouteIn($route, '/?const=hello', ['const' => 'hello', 'test' => 'testvalue'], '/?test=testvalue');

Assert::same(
'http://example.com/',
testRouteOut($route, [])
);
Assert::null(testRouteOut($route, []));

Assert::null(testRouteOut($route, ['const' => 'foo']));

Expand All @@ -33,7 +30,4 @@ Assert::same(
testRouteOut($route, ['const' => 'hello']),
);

Assert::same(
'http://example.com/',
testRouteOut($route, ['const' => null])
);
Assert::null(testRouteOut($route, ['const' => null]));
32 changes: 32 additions & 0 deletions tests/Route/objectParameter.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/**
* Test: Nette\Routing\Route object parameter default value.
*/

declare(strict_types=1);

use Nette\Routing\Route;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';


test('', function () {
$object = new stdClass;

$route = new Route('', [
'param' => $object,
]);

Assert::same(
'http://example.com/',
testRouteOut($route, ['param' => $object]),
);

Assert::same(
'http://example.com/',
testRouteOut($route, ['param' => new stdClass]),
);
});
5 changes: 1 addition & 4 deletions tests/Route/optional.autooptional3.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ use Tester\Assert;
require __DIR__ . '/../bootstrap.php';


$route = new Route('<presenter>/<default=123>/<required>', [
'action' => 'default',
]);
$route = new Route('<presenter>/<default=123>/<required>', []);

testRouteIn($route, '/presenter/');
testRouteIn($route, '/presenter/abc');
Expand All @@ -24,7 +22,6 @@ testRouteIn($route, '/presenter/abc/');
testRouteIn($route, '/presenter/abc/xyy', [
'presenter' => 'presenter',
'default' => 'abc',
'action' => 'default',
'test' => 'testvalue',
'required' => 'xyy',
], '/presenter/abc/xyy?test=testvalue');
Expand Down
29 changes: 29 additions & 0 deletions tests/Route/ports.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/**
* Test: Nette\Routing\Route ports
*/

declare(strict_types=1);

use Nette\Http\UrlScript;
use Nette\Routing\Route;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';


$route = new Route('//%domain%');

$url = $route->constructUrl(
[],
new UrlScript('https://example.org:8000'),
);
Assert::same('https://example.org:8000', $url);

$url = $route->constructUrl(
[],
new UrlScript('https://localhost:8000'),
);
Assert::same('https://localhost:8000', $url);
5 changes: 4 additions & 1 deletion tests/Route/scalarParams.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,8 @@ test('', function () {
testRouteOut($route, ['presenter' => 'homepage', 'param' => null]),
);

Assert::null(testRouteOut($route, ['presenter' => 'homepage', 'param' => '']));
Assert::same(
'http://example.com/homepage/',
testRouteOut($route, ['presenter' => 'homepage', 'param' => '']),
);
});
4 changes: 2 additions & 2 deletions tests/RouteList/addRoute.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ require __DIR__ . '/../bootstrap.php';


$list = new RouteList;
$list->addRoute('foo', ['route' => 'foo'], RouteList::ONE_WAY);
$list->addRoute('bar', ['route' => 'bar'], RouteList::ONE_WAY);
$list->addRoute('foo', ['route' => 'foo'], oneWay: true);
$list->addRoute('bar', ['route' => 'bar'], oneWay: true);
$list->addRoute('hello', ['route' => 'hello']);


Expand Down
2 changes: 1 addition & 1 deletion tests/RouteList/cache.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ $list = new RouteList;
$list->add(new Route('bar', ['presenter' => 'bar']));
$list->add(new Route('<foo>', ['presenter' => 'foo']));
$list->add(new Route('<presenter>/<action>', ['presenter' => 'xxx']));
$list->add(new Route('oneway'), $list::ONE_WAY);
$list->add(new Route('oneway'), oneWay: true);

[$r1, $r2, $r3, $r4] = $list->getRouters();

Expand Down
6 changes: 3 additions & 3 deletions tests/RouteList/oneWay.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ require __DIR__ . '/../bootstrap.php';


$list = new RouteList;
$list->add(new Route('foo', ['route' => 'foo']), RouteList::ONE_WAY);
$list->addRoute('bar', ['route' => 'bar'], RouteList::ONE_WAY);
$list->add(new Route('foo', ['route' => 'foo']), oneWay: true);
$list->addRoute('bar', ['route' => 'bar'], oneWay: true);
$list->add(new Route('hello', ['route' => 'hello']));

Assert::same([RouteList::ONE_WAY, RouteList::ONE_WAY, 0], $list->getFlags());
Assert::same([['oneWay' => true], ['oneWay' => true], ['oneWay' => false]], $list->getFlags());

testRouteIn($list, '/foo', ['route' => 'foo', 'test' => 'testvalue']);
testRouteIn($list, '/bar', ['route' => 'bar', 'test' => 'testvalue']);
Expand Down