mirror of
https://github.com/dannyvankooten/AltoRouter.git
synced 2025-08-22 16:12:50 +02:00
Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9931b97642 | ||
|
41fcec6b8e | ||
|
9d62094f74 | ||
|
bc6b911a6d | ||
|
5159909a81 | ||
|
71389237e5 | ||
|
36f67da100 | ||
|
4270bb5ca2 | ||
|
77a2e14681 | ||
|
f327fbb5bf | ||
|
63bb784d76 | ||
|
bb7b009331 | ||
|
20674b8953 | ||
|
ac028a7f3f | ||
|
0a94ba4142 | ||
|
85c453b12c | ||
|
f6fede4f94 | ||
|
4efac02fad | ||
|
6ffb025022 | ||
|
127f6e9699 | ||
|
a80bb36f11 | ||
|
a51c74793a |
20
.github/workflows/php-check-syntax.yml
vendored
Normal file
20
.github/workflows/php-check-syntax.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Check PHP syntax
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: ['7.3', '7.4', '8.0', '8.1', '8.2', '8.3', 'highest']
|
||||
steps:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- run: composer run check-syntax
|
39
.github/workflows/php.yml
vendored
Normal file
39
.github/workflows/php.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: PHP
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: [ '7.3', 'highest' ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: composer
|
||||
|
||||
- name: Validate composer.json and composer.lock
|
||||
run: composer validate
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.composer-cache.outputs.cache-hit != 'true'
|
||||
run: composer install --no-progress
|
||||
|
||||
- name: Run test suite
|
||||
run: composer run-script test
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ build
|
||||
vendor
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
.phpunit.result.cache
|
21
.travis.yml
21
.travis.yml
@@ -1,21 +0,0 @@
|
||||
language: php
|
||||
php:
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
install:
|
||||
- composer update --prefer-source
|
||||
script:
|
||||
- vendor/bin/phpunit
|
||||
after_script:
|
||||
- vendor/bin/test-reporter
|
||||
env:
|
||||
global:
|
||||
secure: XnXSc7nxJMIrm/EJ1KuwlN4f+sj2R/sR0IFHdOdbOfMKyZ/u6WEgZ3vNrdeAsisiC/QUJJ00DGku1pAl3t3Hzvam0N/SiHtXjB1ZLVbX00S1PEZ6Z+h9zoaUBXWoN6+0OdKN0Xjmj2lwvTpvUxUZXNabilOw0F9WS/+JasofqBQ=
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- vendor
|
||||
- $HOME/.composer/cache
|
@@ -49,7 +49,7 @@ class AltoRouter
|
||||
* @param array $matchTypes
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(array $routes = [], $basePath = '', array $matchTypes = [])
|
||||
public function __construct(array $routes = [], string $basePath = '', array $matchTypes = [])
|
||||
{
|
||||
$this->addRoutes($routes);
|
||||
$this->setBasePath($basePath);
|
||||
@@ -61,7 +61,7 @@ class AltoRouter
|
||||
* Useful if you want to process or display routes.
|
||||
* @return array All routes.
|
||||
*/
|
||||
public function getRoutes()
|
||||
public function getRoutes(): array
|
||||
{
|
||||
return $this->routes;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ class AltoRouter
|
||||
* Useful if you are running your application from a subdirectory.
|
||||
* @param string $basePath
|
||||
*/
|
||||
public function setBasePath($basePath)
|
||||
public function setBasePath(string $basePath)
|
||||
{
|
||||
$this->basePath = $basePath;
|
||||
}
|
||||
@@ -117,7 +117,7 @@ class AltoRouter
|
||||
* @param string $name Optional name of this route. Supply if you want to reverse route this url in your application.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function map($method, $route, $target, $name = null)
|
||||
public function map(string $method, string $route, $target, ?string $name = null)
|
||||
{
|
||||
|
||||
$this->routes[] = [$method, $route, $target, $name];
|
||||
@@ -128,8 +128,6 @@ class AltoRouter
|
||||
}
|
||||
$this->namedRoutes[$name] = $route;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,11 +136,11 @@ class AltoRouter
|
||||
* Generate the URL for a named route. Replace regexes with supplied parameters
|
||||
*
|
||||
* @param string $routeName The name of the route.
|
||||
* @param array @params Associative array of parameters to replace placeholders with.
|
||||
* @param array $params Associative array of parameters to replace placeholders with.
|
||||
* @return string The URL of the route with named parameters in place.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function generate($routeName, array $params = [])
|
||||
public function generate(string $routeName, array $params = []): string
|
||||
{
|
||||
|
||||
// Check if named route exists
|
||||
@@ -186,7 +184,7 @@ class AltoRouter
|
||||
* @param string $requestMethod
|
||||
* @return array|boolean Array with route information on success, false on failure (no match).
|
||||
*/
|
||||
public function match($requestUrl = null, $requestMethod = null)
|
||||
public function match(?string $requestUrl = null, ?string $requestMethod = null)
|
||||
{
|
||||
|
||||
$params = [];
|
||||
@@ -204,6 +202,8 @@ class AltoRouter
|
||||
$requestUrl = substr($requestUrl, 0, $strpos);
|
||||
}
|
||||
|
||||
$lastRequestUrlChar = $requestUrl ? $requestUrl[strlen($requestUrl)-1] : '';
|
||||
|
||||
// set Request Method if it isn't passed as a parameter
|
||||
if ($requestMethod === null) {
|
||||
$requestMethod = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
|
||||
@@ -230,10 +230,12 @@ class AltoRouter
|
||||
// No params in url, do string comparison
|
||||
$match = strcmp($requestUrl, $route) === 0;
|
||||
} else {
|
||||
// Compare longest non-param string with url
|
||||
if (strncmp($requestUrl, $route, $position) !== 0) {
|
||||
// Compare longest non-param string with url before moving on to regex
|
||||
// Check if last character before param is a slash, because it could be optional if param is optional too (see https://github.com/dannyvankooten/AltoRouter/issues/241)
|
||||
if (strncmp($requestUrl, $route, $position) !== 0 && ($lastRequestUrlChar === '/' || $route[$position-1] !== '/')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$regex = $this->compileRoute($route);
|
||||
$match = preg_match($regex, $requestUrl, $params) === 1;
|
||||
}
|
||||
@@ -254,15 +256,16 @@ class AltoRouter
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the regex for a given route (EXPENSIVE)
|
||||
* @param $route
|
||||
* @param string $route
|
||||
* @return string
|
||||
*/
|
||||
protected function compileRoute($route)
|
||||
protected function compileRoute(string $route): string
|
||||
{
|
||||
if (preg_match_all('`(/|\.|)\[([^:\]]*+)(?::([^:\]]*+))?\](\?|)`', $route, $matches, PREG_SET_ORDER)) {
|
||||
$matchTypes = $this->matchTypes;
|
||||
|
15
README.md
15
README.md
@@ -1,4 +1,5 @@
|
||||
# AltoRouter [](http://travis-ci.org/dannyvankooten/AltoRouter) [](https://packagist.org/packages/altorouter/altorouter) [](https://packagist.org/packages/altorouter/altorouter) [](https://codeclimate.com/github/dannyvankooten/AltoRouter) [](https://codeclimate.com/github/dannyvankooten/AltoRouter)
|
||||
# AltoRouter  [](https://packagist.org/packages/altorouter/altorouter) [](https://packagist.org/packages/altorouter/altorouter)
|
||||
|
||||
AltoRouter is a small but powerful routing class, heavily inspired by [klein.php](https://github.com/chriso/klein.php/).
|
||||
|
||||
```php
|
||||
@@ -29,13 +30,13 @@ echo $router->generate('user-details', ['id' => 5]); // Output: "/users/5"
|
||||
|
||||
## Getting started
|
||||
|
||||
You need PHP >= 5.6 to use AltoRouter, although we highly recommend you [use an officially supported PHP version](https://secure.php.net/supported-versions.php) that is not EOL.
|
||||
You need PHP >= 7.3 to use AltoRouter, although we highly recommend you [use an officially supported PHP version](https://secure.php.net/supported-versions.php) that is not EOL.
|
||||
|
||||
- [Install AltoRouter](http://altorouter.com/usage/install.html)
|
||||
- [Rewrite all requests to AltoRouter](http://altorouter.com/usage/rewrite-requests.html)
|
||||
- [Map your routes](http://altorouter.com/usage/mapping-routes.html)
|
||||
- [Match requests](http://altorouter.com/usage/matching-requests.html)
|
||||
- [Process the request your preferred way](http://altorouter.com/usage/processing-requests.html)
|
||||
- [Install AltoRouter](https://dannyvankooten.github.io/AltoRouter//usage/install.html)
|
||||
- [Rewrite all requests to AltoRouter](https://dannyvankooten.github.io/AltoRouter//usage/rewrite-requests.html)
|
||||
- [Map your routes](https://dannyvankooten.github.io/AltoRouter//usage/mapping-routes.html)
|
||||
- [Match requests](https://dannyvankooten.github.io/AltoRouter//usage/matching-requests.html)
|
||||
- [Process the request your preferred way](https://dannyvankooten.github.io/AltoRouter//usage/processing-requests.html)
|
||||
|
||||
## Contributors
|
||||
- [Danny van Kooten](https://github.com/dannyvankooten)
|
||||
|
@@ -20,17 +20,17 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.0"
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "5.7.*",
|
||||
"codeclimate/php-test-reporter": "dev-master",
|
||||
"squizlabs/php_codesniffer": "3.4.2"
|
||||
"phpunit/phpunit": "9.6.*",
|
||||
"squizlabs/php_codesniffer": "3.6.2"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["AltoRouter.php"]
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vendor/bin/phpunit"
|
||||
"test": "vendor/bin/phpunit",
|
||||
"check-syntax": "find . -name '*.php' -not -path './vendor/*' -print0 | xargs -0 -n1 php -l"
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,17 @@
|
||||
<phpunit
|
||||
colors="true"
|
||||
verbose="true">
|
||||
<testsuites>
|
||||
<testsuite name="altorouter">
|
||||
<directory>./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<file>./AltoRouter.php</file>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="coverage-clover" target="build/logs/clover.xml"/>
|
||||
</logging>
|
||||
</phpunit>
|
||||
<?xml version="1.0"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" verbose="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||
<coverage>
|
||||
<include>
|
||||
<file>./AltoRouter.php</file>
|
||||
</include>
|
||||
<report>
|
||||
<clover outputFile="build/logs/clover.xml"/>
|
||||
</report>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="altorouter">
|
||||
<directory>./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<logging/>
|
||||
</phpunit>
|
||||
|
@@ -25,23 +25,26 @@ class SimpleTraversable implements Iterator
|
||||
['POST', '/bar', 'bar_action', 'second_route']
|
||||
];
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function current()
|
||||
{
|
||||
return $this->_data[$this->_position];
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function key()
|
||||
{
|
||||
return $this->_position;
|
||||
}
|
||||
public function next()
|
||||
public function next() : void
|
||||
{
|
||||
++$this->_position;
|
||||
}
|
||||
public function rewind()
|
||||
public function rewind() : void
|
||||
{
|
||||
$this->_position = 0;
|
||||
}
|
||||
public function valid()
|
||||
public function valid() : bool
|
||||
{
|
||||
return isset($this->_data[$this->_position]);
|
||||
}
|
||||
@@ -58,19 +61,11 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
* Sets up the fixture, for example, opens a network connection.
|
||||
* This method is called before a test is executed.
|
||||
*/
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->router = new AltoRouterDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tears down the fixture, for example, closes a network connection.
|
||||
* This method is called after a test is executed.
|
||||
*/
|
||||
protected function tearDown()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers AltoRouter::getRoutes
|
||||
*/
|
||||
@@ -81,7 +76,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
$target = static function () {
|
||||
};
|
||||
|
||||
$this->assertInternalType('array', $this->router->getRoutes());
|
||||
$this->assertIsArray($this->router->getRoutes());
|
||||
// $this->assertIsArray($this->router->getRoutes()); // for phpunit 7.x
|
||||
$this->router->map($method, $route, $target);
|
||||
$this->assertEquals([[$method, $route, $target, null]], $this->router->getRoutes());
|
||||
@@ -96,14 +91,14 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
$route = '/[:controller]/[:action]';
|
||||
$target = static function () {
|
||||
};
|
||||
|
||||
|
||||
$this->router->addRoutes([
|
||||
[$method, $route, $target],
|
||||
[$method, $route, $target, 'second_route']
|
||||
]);
|
||||
|
||||
|
||||
$routes = $this->router->getRoutes();
|
||||
|
||||
|
||||
$this->assertEquals([$method, $route, $target, null], $routes[0]);
|
||||
$this->assertEquals([$method, $route, $target, 'second_route'], $routes[1]);
|
||||
}
|
||||
@@ -115,15 +110,15 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
{
|
||||
$traversable = new SimpleTraversable();
|
||||
$this->router->addRoutes($traversable);
|
||||
|
||||
|
||||
$traversable->rewind();
|
||||
|
||||
|
||||
$first = $traversable->current();
|
||||
$traversable->next();
|
||||
$second = $traversable->current();
|
||||
|
||||
|
||||
$routes = $this->router->getRoutes();
|
||||
|
||||
|
||||
$this->assertEquals($first, $routes[0]);
|
||||
$this->assertEquals($second, $routes[1]);
|
||||
}
|
||||
@@ -134,6 +129,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
*/
|
||||
public function testAddRoutesThrowsExceptionOnInvalidArgument()
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->router->addRoutes(new stdClass);
|
||||
}
|
||||
|
||||
@@ -142,10 +138,10 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
*/
|
||||
public function testSetBasePath()
|
||||
{
|
||||
$basePath = $this->router->setBasePath('/some/path');
|
||||
$this->router->setBasePath('/some/path');
|
||||
$this->assertEquals('/some/path', $this->router->getBasePath());
|
||||
|
||||
$basePath = $this->router->setBasePath('/some/path');
|
||||
|
||||
$this->router->setBasePath('/some/path');
|
||||
$this->assertEquals('/some/path', $this->router->getBasePath());
|
||||
}
|
||||
|
||||
@@ -158,11 +154,11 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
$route = '/[:controller]/[:action]';
|
||||
$target = static function () {
|
||||
};
|
||||
|
||||
|
||||
$this->router->map($method, $route, $target);
|
||||
|
||||
|
||||
$routes = $this->router->getRoutes();
|
||||
|
||||
|
||||
$this->assertEquals([$method, $route, $target, null], $routes[0]);
|
||||
}
|
||||
|
||||
@@ -176,15 +172,15 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
$target = static function () {
|
||||
};
|
||||
$name = 'myroute';
|
||||
|
||||
|
||||
$this->router->map($method, $route, $target, $name);
|
||||
|
||||
|
||||
$routes = $this->router->getRoutes();
|
||||
$this->assertEquals([$method, $route, $target, $name], $routes[0]);
|
||||
|
||||
|
||||
$named_routes = $this->router->getNamedRoutes();
|
||||
$this->assertEquals($route, $named_routes[$name]);
|
||||
|
||||
|
||||
try {
|
||||
$this->router->map($method, $route, $target, $name);
|
||||
$this->fail('Should not be able to add existing named route');
|
||||
@@ -203,21 +199,21 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
'controller' => 'test',
|
||||
'action' => 'someaction'
|
||||
];
|
||||
|
||||
|
||||
$this->router->map('GET', '/[:controller]/[:action]', static function () {
|
||||
}, 'foo_route');
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
'/test/someaction',
|
||||
$this->router->generate('foo_route', $params)
|
||||
);
|
||||
|
||||
|
||||
$params = [
|
||||
'controller' => 'test',
|
||||
'action' => 'someaction',
|
||||
'type' => 'json'
|
||||
];
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
'/test/someaction',
|
||||
$this->router->generate('foo_route', $params)
|
||||
@@ -231,23 +227,23 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
{
|
||||
$this->router->map('GET', '/[:controller]/[:action].[:type]?', static function () {
|
||||
}, 'bar_route');
|
||||
|
||||
|
||||
$params = [
|
||||
'controller' => 'test',
|
||||
'action' => 'someaction'
|
||||
];
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
'/test/someaction',
|
||||
$this->router->generate('bar_route', $params)
|
||||
);
|
||||
|
||||
|
||||
$params = [
|
||||
'controller' => 'test',
|
||||
'action' => 'someaction',
|
||||
'type' => 'json'
|
||||
];
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
'/test/someaction.json',
|
||||
$this->router->generate('bar_route', $params)
|
||||
@@ -262,18 +258,18 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
{
|
||||
$this->router->map('GET', '/[i:page]?', static function () {
|
||||
}, 'bare_route');
|
||||
|
||||
|
||||
$params = [
|
||||
'page' => 1
|
||||
];
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
'/1',
|
||||
$this->router->generate('bare_route', $params)
|
||||
);
|
||||
|
||||
|
||||
$params = [];
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
'/',
|
||||
$this->router->generate('bare_route', $params)
|
||||
@@ -292,7 +288,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
$this->assertEquals("Route 'nonexisting_route' does not exist.", $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @covers AltoRouter::match
|
||||
* @covers AltoRouter::compileRoute
|
||||
@@ -300,7 +296,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
public function testMatch()
|
||||
{
|
||||
$this->router->map('GET', '/foo/[:controller]/[:action]', 'foo_action', 'foo_route');
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'foo_action',
|
||||
'params' => [
|
||||
@@ -309,9 +305,9 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
],
|
||||
'name' => 'foo_route'
|
||||
], $this->router->match('/foo/test/do', 'GET'));
|
||||
|
||||
|
||||
$this->assertFalse($this->router->match('/foo/test/do', 'POST'));
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'foo_action',
|
||||
'params' => [
|
||||
@@ -346,7 +342,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
public function testMatchWithFixedParamValues()
|
||||
{
|
||||
$this->router->map('POST', '/users/[i:id]/[delete|update:action]', 'usersController#doAction', 'users_do');
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'usersController#doAction',
|
||||
'params' => [
|
||||
@@ -355,7 +351,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
],
|
||||
'name' => 'users_do'
|
||||
], $this->router->match('/users/1/delete', 'POST'));
|
||||
|
||||
|
||||
$this->assertFalse($this->router->match('/users/1/delete', 'GET'));
|
||||
$this->assertFalse($this->router->match('/users/abc/delete', 'POST'));
|
||||
$this->assertFalse($this->router->match('/users/1/create', 'GET'));
|
||||
@@ -369,9 +365,9 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
$router = $this->getMockBuilder('AltoRouterDebug')
|
||||
->setMethods(['compileRoute'])
|
||||
->getMock();
|
||||
|
||||
|
||||
// this should prove that compileRoute is not called when the route doesn't
|
||||
// have any params in it, but this doesn't work because compileRoute is private.
|
||||
// have any params in it
|
||||
$router->expects($this->never())
|
||||
->method('compileRoute');
|
||||
|
||||
@@ -384,8 +380,6 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
'name' => 'contact'
|
||||
], $router->match('/contact', 'GET'));
|
||||
|
||||
$router->map('GET', '/page/[:id]', 'pages#show', 'page');
|
||||
|
||||
// no prefix match, so no regex compilation necessary
|
||||
$this->assertFalse($router->match('/page1', 'GET'));
|
||||
}
|
||||
@@ -396,10 +390,10 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
public function testMatchWithServerVars()
|
||||
{
|
||||
$this->router->map('GET', '/foo/[:controller]/[:action]', 'foo_action', 'foo_route');
|
||||
|
||||
|
||||
$_SERVER['REQUEST_URI'] = '/foo/test/do';
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'foo_action',
|
||||
'params' => [
|
||||
@@ -416,7 +410,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
public function testMatchWithOptionalUrlParts()
|
||||
{
|
||||
$this->router->map('GET', '/bar/[:controller]/[:action].[:type]?', 'bar_action', 'bar_route');
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'bar_action',
|
||||
'params' => [
|
||||
@@ -426,7 +420,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
],
|
||||
'name' => 'bar_route'
|
||||
], $this->router->match('/bar/test/do.json', 'GET'));
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'bar_action',
|
||||
'params' => [
|
||||
@@ -436,7 +430,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
'name' => 'bar_route'
|
||||
], $this->router->match('/bar/test/do', 'GET'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* GitHub #98
|
||||
* @covers AltoRouter::match
|
||||
@@ -444,7 +438,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
public function testMatchWithOptionalPartOnBareUrl()
|
||||
{
|
||||
$this->router->map('GET', '/[i:page]?', 'bare_action', 'bare_route');
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'bare_action',
|
||||
'params' => [
|
||||
@@ -452,7 +446,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
],
|
||||
'name' => 'bare_route'
|
||||
], $this->router->match('/1', 'GET'));
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'bare_action',
|
||||
'params' => [],
|
||||
@@ -467,7 +461,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
{
|
||||
$this->router->map('GET', '/a', 'foo_action', 'foo_route');
|
||||
$this->router->map('GET', '*', 'bar_action', 'bar_route');
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'bar_action',
|
||||
'params' => [],
|
||||
@@ -480,13 +474,13 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
public function testMatchWithCustomRegexp()
|
||||
{
|
||||
$this->router->map('GET', '@^/[a-z]*$', 'bar_action', 'bar_route');
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'bar_action',
|
||||
'params' => [],
|
||||
'name' => 'bar_route'
|
||||
], $this->router->match('/everything', 'GET'));
|
||||
|
||||
|
||||
$this->assertFalse($this->router->match('/some-other-thing', 'GET'));
|
||||
}
|
||||
/**
|
||||
@@ -505,9 +499,9 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
// 'ZERO WIDTH NON-JOINER'
|
||||
$pattern .= '\x{200C}';
|
||||
$pattern .= ']+)';
|
||||
|
||||
|
||||
$this->router->map('GET', '@' . $pattern, 'unicode_action', 'unicode_route');
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'unicode_action',
|
||||
'name' => 'unicode_route',
|
||||
@@ -515,10 +509,23 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
'path' => '大家好'
|
||||
]
|
||||
], $this->router->match('/大家好', 'GET'));
|
||||
|
||||
|
||||
$this->assertFalse($this->router->match('/﷽', 'GET'));
|
||||
}
|
||||
|
||||
public function testMatchWithSlashBeforeOptionalPart()
|
||||
{
|
||||
$this->router->map('GET', '/archives/[lmin:category]?', 'Article#archives');
|
||||
$expected = [
|
||||
'target' => 'Article#archives',
|
||||
'params' => [],
|
||||
'name' => null
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, $this->router->match('/archives/', 'GET'));
|
||||
$this->assertEquals($expected, $this->router->match('/archives', 'GET'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers AltoRouter::addMatchTypes
|
||||
*/
|
||||
@@ -526,7 +533,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
{
|
||||
$this->router->addMatchTypes(['cId' => '[a-zA-Z]{2}[0-9](?:_[0-9]++)?']);
|
||||
$this->router->map('GET', '/bar/[cId:customId]', 'bar_action', 'bar_route');
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'bar_action',
|
||||
'params' => [
|
||||
@@ -542,7 +549,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
],
|
||||
'name' => 'bar_route'
|
||||
], $this->router->match('/bar/AB1_0123456789', 'GET'));
|
||||
|
||||
|
||||
$this->assertFalse($this->router->match('/some-other-thing', 'GET'));
|
||||
}
|
||||
/**
|
||||
@@ -557,10 +564,10 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
$pattern .= '\x{FE70}-\x{FEFF}';
|
||||
$pattern .= '\x{0750}-\x{077F}';
|
||||
$pattern .= ']+';
|
||||
|
||||
|
||||
$this->router->addMatchTypes(['nonArabic' => $pattern]);
|
||||
$this->router->map('GET', '/bar/[nonArabic:string]', 'non_arabic_action', 'non_arabic_route');
|
||||
|
||||
|
||||
$this->assertEquals([
|
||||
'target' => 'non_arabic_action',
|
||||
'name' => 'non_arabic_route',
|
||||
@@ -568,7 +575,7 @@ class AltoRouterTest extends PHPUnit\Framework\TestCase
|
||||
'string' => 'some-path'
|
||||
]
|
||||
], $this->router->match('/bar/some-path', 'GET'));
|
||||
|
||||
|
||||
$this->assertFalse($this->router->match('/﷽', 'GET'));
|
||||
}
|
||||
}
|
||||
|
106
tests/benchmark-parse-api.php
Normal file
106
tests/benchmark-parse-api.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Benchmark Altorouter
|
||||
*
|
||||
* Usage: php ./tests/benchmark-parse-api.php <iterations>
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* <iterations>:
|
||||
* The number of routes to map & match. Defaults to 1000.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
$routes = [
|
||||
["POST", "/1/classes/[a:className]"],
|
||||
["GET", "/1/classes/[a:className]/[i:objectId]"],
|
||||
["PUT", "/1/classes/[a:className]/[i:objectId]"],
|
||||
["GET", "/1/classes/[a:className]"],
|
||||
["DELETE", "/1/classes/[a:className]/[i:objectId]"],
|
||||
|
||||
// Users
|
||||
["POST", "/1/users"],
|
||||
["GET", "/1/login"],
|
||||
["GET", "/1/users/[i:objectId]"],
|
||||
["PUT", "/1/users/[i:objectId]"],
|
||||
["GET", "/1/users"],
|
||||
["DELETE", "/1/users/[i:objectId]"],
|
||||
["POST", "/1/requestPasswordReset"],
|
||||
|
||||
// Roles
|
||||
["POST", "/1/roles"],
|
||||
["GET", "/1/roles/[i:objectId]"],
|
||||
["PUT", "/1/roles/[i:objectId]"],
|
||||
["GET", "/1/roles"],
|
||||
["DELETE", "/1/roles/[i:objectId]"],
|
||||
|
||||
// Files
|
||||
["POST", "/1/files/:fileName"],
|
||||
|
||||
// Analytics
|
||||
["POST", "/1/events/[a:eventName]"],
|
||||
|
||||
// Push Notifications
|
||||
["POST", "/1/push"],
|
||||
|
||||
// Installations
|
||||
["POST", "/1/installations"],
|
||||
["GET", "/1/installations/[i:objectId]"],
|
||||
["PUT", "/1/installations/[i:objectId]"],
|
||||
["GET", "/1/installations"],
|
||||
["DELETE", "/1/installations/[i:objectId]"],
|
||||
|
||||
// Cloud Functions
|
||||
["POST", "/1/functions"],
|
||||
];
|
||||
$total_time = 0;
|
||||
$router = new AltoRouter();
|
||||
|
||||
// map requests
|
||||
$start = microtime(true);
|
||||
foreach ($routes as $r) {
|
||||
$router->map($r[0], $r[1], '');
|
||||
}
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Map time: %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
// match a static route
|
||||
$start = microtime(true);
|
||||
$router->match('/1/login', 'GET');
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Match time (existing route, no params): %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
// match a route with 1 parameter
|
||||
$start = microtime(true);
|
||||
$res = $router->match('/1/classes/foo', 'GET');
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Match time (existing route, 1 param): %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
// match a route with 2 parameters
|
||||
$start = microtime(true);
|
||||
$res = $router->match('/1/classes/foo/500', 'GET');
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Match time (existing route, 2 params): %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
|
||||
// match unexisting route
|
||||
$start = microtime(true);
|
||||
$router->match('/55-foo-bar', 'GET');
|
||||
$end = microtime(true);
|
||||
$time = $end - $start;
|
||||
$total_time += $time;
|
||||
echo sprintf('Match time (unexisting route): %.3f ms', $time * 1000) . PHP_EOL;
|
||||
|
||||
// print totals
|
||||
echo sprintf('Total time: %.3f ms', $total_time * 1000) . PHP_EOL;
|
||||
echo sprintf('Memory usage: %d KB', round(memory_get_usage() / 1024)) . PHP_EOL;
|
||||
echo sprintf('Peak memory usage: %d KB', round(memory_get_peak_usage(true) / 1024)) . PHP_EOL;
|
@@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Benchmark Altorouter
|
||||
*
|
||||
* Usage: php ./tests/benchmark.php <iterations>
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* <iterations>:
|
||||
* The number of routes to map & match. Defaults to 1000.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
global $argv;
|
||||
$n = isset($argv[1]) ? intval($argv[1]) : 1000;
|
||||
|
||||
// generates a random request url
|
||||
function random_request_url()
|
||||
{
|
||||
$characters = 'abcdefghijklmnopqrstuvwxyz';
|
||||
$charactersLength = strlen($characters);
|
||||
$randomString = '/';
|
||||
|
||||
// create random path of 5-20 characters
|
||||
for ($i = 0; $i < rand(5, 20); $i++) {
|
||||
$randomString .= $characters[rand(0, $charactersLength - 1)];
|
||||
|
||||
if (rand(1, 10) === 1) {
|
||||
$randomString .= '/';
|
||||
}
|
||||
}
|
||||
|
||||
// add dynamic route with 10% chance
|
||||
if (rand(1, 10) === 1) {
|
||||
$randomString = rtrim($randomString, '/') . '/[:part]';
|
||||
}
|
||||
|
||||
return $randomString;
|
||||
}
|
||||
|
||||
// generate a random request method
|
||||
function random_request_method()
|
||||
{
|
||||
static $methods = [ 'GET', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE' ];
|
||||
$random_key = array_rand($methods);
|
||||
return $methods[ $random_key ];
|
||||
}
|
||||
|
||||
// prepare benchmark data
|
||||
$requests = [];
|
||||
for ($i=0; $i<$n; $i++) {
|
||||
$requests[] = [
|
||||
'method' => random_request_method(),
|
||||
'url' => random_request_url(),
|
||||
];
|
||||
}
|
||||
|
||||
$router = new AltoRouter();
|
||||
|
||||
// map requests
|
||||
$start = microtime(true);
|
||||
foreach ($requests as $r) {
|
||||
$router->map($r['method'], $r['url'], '');
|
||||
}
|
||||
$end = microtime(true);
|
||||
$map_time = ($end - $start) * 1000;
|
||||
echo sprintf('Map time: %.2f ms', $map_time) . PHP_EOL;
|
||||
|
||||
|
||||
// pick random route to match
|
||||
$r = $requests[array_rand($requests)];
|
||||
|
||||
// match random known route
|
||||
$start = microtime(true);
|
||||
$router->match($r['url'], $r['method']);
|
||||
$end = microtime(true);
|
||||
$match_time_known_route = ($end - $start) * 1000;
|
||||
echo sprintf('Match time (known route): %.2f ms', $match_time_known_route) . PHP_EOL;
|
||||
|
||||
// match unexisting route
|
||||
$start = microtime(true);
|
||||
$router->match('/55-foo-bar', 'GET');
|
||||
$end = microtime(true);
|
||||
$match_time_unknown_route = ($end - $start) * 1000;
|
||||
echo sprintf('Match time (unknown route): %.2f ms', $match_time_unknown_route) . PHP_EOL;
|
||||
|
||||
// print totals
|
||||
echo sprintf('Total time: %.2f seconds', ($map_time + $match_time_known_route + $match_time_unknown_route)) . PHP_EOL;
|
||||
echo sprintf('Memory usage: %d KB', round(memory_get_usage() / 1024)) . PHP_EOL;
|
||||
echo sprintf('Peak memory usage: %d KB', round(memory_get_peak_usage(true) / 1024)) . PHP_EOL;
|
Reference in New Issue
Block a user