mirror of
https://github.com/skipperbent/simple-php-router.git
synced 2026-06-15 18:23:26 +03:00
Development
- Better php7 support. - Added easier way to debug router. - Improvements and bugfixes. - Updated documentation.
This commit is contained in:
401
README.md
401
README.md
@@ -1,5 +1,6 @@
|
||||
# Simple PHP router
|
||||
Simple, fast and yet powerful PHP router that is easy to get integrated and in any project. Heavily inspired by the way Laravel handles routing, with both simplicity and expandability in mind.
|
||||
|
||||
Simple, fast and yet powerful PHP router that is easy to get integrated and in any project. Heavily inspired by the way Laravel handles routing, with both simplicity and expand-ability in mind.
|
||||
|
||||
**Please note that this documentation is currently work-in-progress. Feel free to contribute.**
|
||||
|
||||
@@ -11,7 +12,6 @@ Simple, fast and yet powerful PHP router that is easy to get integrated and in a
|
||||
- [Notes](#notes-1)
|
||||
- [Requirements](#requirements)
|
||||
- [Feedback and development](#feedback-and-development)
|
||||
- [Issues guidelines](#issues-guidelines)
|
||||
- [Contribution development guidelines](#contribution-development-guidelines)
|
||||
- [Features](#features)
|
||||
- [Installation](#installation)
|
||||
@@ -20,6 +20,14 @@ Simple, fast and yet powerful PHP router that is easy to get integrated and in a
|
||||
- [Setting up IIS](#setting-up-iis)
|
||||
- [Configuration](#configuration)
|
||||
- [Helper functions](#helper-functions)
|
||||
- [Help and support](#help-and-support)
|
||||
- [How to debug](#how-to-debug)
|
||||
- [Creating unit-tests](#creating-unit-tests)
|
||||
- [Debug information](#debug-information)
|
||||
- [Benchmark and log-info](#benchmark-and-log-info)
|
||||
- [Reporting a new issue](#reporting-a-new-issue)
|
||||
- [Procedure for reporting a new issue](#procedure-for-reporting-a-new-issue)
|
||||
- [Issue template](#issue-template)
|
||||
- [Routes](#routes)
|
||||
- [Basic routing](#basic-routing)
|
||||
- [Available methods](#available-methods)
|
||||
@@ -118,18 +126,14 @@ You can find the demo-project here: [https://github.com/skipperbent/simple-route
|
||||
|
||||
### Feedback and development
|
||||
|
||||
If you are missing a feature, experience problems or have ideas or feedback that you want us to hear, please feel free to create an issue.
|
||||
If the library is missing a feature that you need in your project or if you have feedback, we'd love to hear from you.
|
||||
Feel free to leave us feedback by [creating a new issue](https://github.com/skipperbent/simple-php-router/issues/new).
|
||||
|
||||
###### Issues guidelines
|
||||
**Experiencing an issue?**
|
||||
|
||||
- Please be as detailed as possible in the description when creating a new issue. This will help others to more easily understand- and solve your issue.
|
||||
For example: if you are experiencing issues, you should provide the necessary steps to reproduce the error within your description.
|
||||
Please refer to our [Help and support](#help-and-support) section in the documentation before reporting a new issue.
|
||||
|
||||
- We love to hear out any ideas or feedback to the library.
|
||||
|
||||
[Create a new issue here](https://github.com/skipperbent/simple-php-router/issues/new)
|
||||
|
||||
###### Contribution development guidelines
|
||||
##### Contribution development guidelines
|
||||
|
||||
- Please try to follow the PSR-2 codestyle guidelines.
|
||||
|
||||
@@ -206,7 +210,7 @@ Below is an example of an working `web.config` file used by simple-php-router.
|
||||
|
||||
Simply create a new `web.config` file in your projects `public` directory and paste the contents below in your newly created file. This will redirect all requests to your `index.php` file (see Configuration section below). If the `web.config` file already exists, add the `<rewrite>` section inside the `<system.webServer>` branch.
|
||||
|
||||
```
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
@@ -378,6 +382,379 @@ function csrf_token()
|
||||
|
||||
---
|
||||
|
||||
# Help and support
|
||||
|
||||
This section will go into details on how to debug the router and answer some of the commonly asked questions- and issues.
|
||||
|
||||
## How to debug
|
||||
|
||||
This section will show you how to write unit-tests for the router, view useful debugging information and answer some of the frequently asked questions.
|
||||
|
||||
It will also covers how to report any issue you might encounter.
|
||||
|
||||
### Creating unit-tests
|
||||
|
||||
The easiest and fastest way to debug any issues with the router, is to create a unit-test that represents the issue you are experiencing.
|
||||
|
||||
Unit-tests use a special `TestRouter` class, which simulates a request-method and requested url of a browser.
|
||||
|
||||
The `TestRouter` class can return the output directly or render a route silently.
|
||||
|
||||
```php
|
||||
public function testUnicodeCharacters()
|
||||
{
|
||||
// Add route containing two optional paramters with special spanish characters like "í".
|
||||
TestRouter::get('/cursos/listado/{listado?}/{category?}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-]+']);
|
||||
|
||||
// Start the routing and simulate the url "/cursos/listado/especialidad/cirugía local".
|
||||
TestRouter::debugNoReset('/cursos/listado/especialidad/cirugía local', 'GET');
|
||||
|
||||
// Verify that the url for the loaded route matches the expected route.
|
||||
$this->assertEquals('/cursos/listado/{listado?}/{category?}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
|
||||
|
||||
// Start the routing and simulate the url "/test/Dermatología" using "GET" as request-method.
|
||||
TestRouter::debugNoReset('/test/Dermatología', 'GET');
|
||||
|
||||
// Another route containing one parameter with special spanish characters like "í".
|
||||
TestRouter::get('/test/{param}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-\í]+']);
|
||||
|
||||
// Get all parameters parsed by the loaded route.
|
||||
$parameters = TestRouter::request()->getLoadedRoute()->getParameters();
|
||||
|
||||
// Check that the parameter named "param" matches the exspected value.
|
||||
$this->assertEquals('Dermatología', $parameters['param']);
|
||||
|
||||
// Add route testing danish special characters like "ø".
|
||||
TestRouter::get('/category/økse', 'DummyController@method1', ['defaultParameterRegex' => '[\w\ø]+']);
|
||||
|
||||
// Start the routing and simulate the url "/kategory/økse" using "GET" as request-method.
|
||||
TestRouter::debugNoReset('/category/økse', 'GET');
|
||||
|
||||
// Validate that the URL of the loaded-route matches the expected url.
|
||||
$this->assertEquals('/category/økse/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
|
||||
|
||||
// Reset the router, so other tests wont inherit settings or the routes we've added.
|
||||
TestRouter::router()->reset();
|
||||
}
|
||||
```
|
||||
|
||||
#### Using the TestRouter helper
|
||||
|
||||
Depending on your test, you can use the methods below when rendering routes in your unit-tests.
|
||||
|
||||
|
||||
| Method | Description |
|
||||
| ------------- |-------------|
|
||||
| ```TestRouter::debug($url, $method)``` | Will render the route without returning anything. Exceptions will be thrown and the router will be reset automatically. |
|
||||
| ```TestRouter::debugOutput($url, $method)``` | Will render the route and return any value that the route might output. Manual reset required by calling `TestRouter::router()->reset()`. |
|
||||
| ```TestRouter::debugNoReset($url, $method);``` | Will render the route without resetting the router. Useful if you need to get loaded route, parameters etc. from the router. Manual reset required by calling `TestRouter::router()->reset()`. |
|
||||
|
||||
### Debug information
|
||||
|
||||
The library can output debug-information, which contains information like loaded routes, the parsed request-url etc. It also contains info which are important when reporting a new issue like PHP-version, library version, server-variables, router debug log etc.
|
||||
|
||||
You can activate the debug-information by calling the alternative start-method.
|
||||
|
||||
The example below will start the routing an return array with debugging-information
|
||||
|
||||
**Example:**
|
||||
|
||||
```php
|
||||
$debugInfo = SimpleRouter::startDebug();
|
||||
echo sprintf('<pre>%s</pre>', var_export($debugInfo));
|
||||
exit;
|
||||
```
|
||||
|
||||
**The example above will provide you with an output containing:**
|
||||
|
||||
| Key | Description |
|
||||
| ------------- |------------- |
|
||||
| `url` | The parsed request-uri. This url should match the url in the browser.|
|
||||
| `method` | The browsers request method (example: `GET`, `POST`, `PUT`, `PATCH`, `DELETE` etc).|
|
||||
| `host` | The website host (example: `domain.com`).|
|
||||
| `loaded_routes` | List of all the routes that matched the `url` and that has been rendered/loaded. |
|
||||
| `all_routes` | All available routes |
|
||||
| `boot_managers` | All available BootManagers |
|
||||
| `csrf_verifier` | CsrfVerifier class |
|
||||
| `log` | List of debug messages/log from the router. |
|
||||
| `router_output` | The rendered callback output from the router. |
|
||||
| `library_version` | The version of simple-php-router you are using. |
|
||||
| `php_version` | The version of PHP you are using. |
|
||||
| `server_params` | List of all `$_SERVER` variables/headers. |
|
||||
|
||||
#### Benchmark and logging
|
||||
|
||||
You can activate benchmark debugging/logging by calling `setDebugEnabled` method on the `Router` instance.
|
||||
|
||||
You have to enable debugging BEFORE starting the routing.
|
||||
|
||||
**Example:**
|
||||
|
||||
```php
|
||||
SimpleRouter::router()->setDebugEnabled(true);
|
||||
SimpleRouter::start();
|
||||
```
|
||||
|
||||
When the routing is complete, you can get the debug-log by calling the `getDebugLog()` on the `Router` instance. This will return an `array` of log-messages each containing execution time, trace info and debug-message.
|
||||
|
||||
**Example:**
|
||||
|
||||
```php
|
||||
$messages = SimpleRouter::router()->getDebugLog();
|
||||
```
|
||||
|
||||
## Reporting a new issue
|
||||
|
||||
**Before reporting your issue, make sure that the issue you are experiencing aren't already answered in the [Common errors](#common-errors) section or by searching the [closed issues](https://github.com/skipperbent/simple-php-router/issues?q=is%3Aissue+is%3Aclosed) page on GitHub.**
|
||||
|
||||
To avoid confusion and to help you resolve your issue as quickly as possible, you should provide a detailed explanation of the problem you are experiencing.
|
||||
|
||||
### Procedure for reporting a new issue
|
||||
|
||||
1. Go to [this page](https://github.com/skipperbent/simple-php-router/issues/new) to create a new issue.
|
||||
2. Add a title that describes your problems in as few words as possible.
|
||||
3. Copy and paste the template below in the description of your issue and replace each step with your own information. If the step is not relevant for your issue you can delete it.
|
||||
|
||||
### Issue template
|
||||
|
||||
Copy and paste the template below into the description of your new issue and replace it with your own information.
|
||||
|
||||
You can check the [Debug information](#debug-information) section to see how to generate the debug-info.
|
||||
|
||||
<pre>
|
||||
### Description
|
||||
|
||||
The library fails to render the route `/user/æsel` which contains one parameter using a custom regular expression for matching special foreign characters. Routes without special characters like `/user/tom` renders correctly.
|
||||
|
||||
### Steps to reproduce the error
|
||||
|
||||
1. Add the following route:
|
||||
|
||||
```php
|
||||
SimpleRouter::get('/user/{name}', 'UserController@show')->where(['name' => '[\w]+']);
|
||||
```
|
||||
|
||||
2. Navigate to `/user/æsel` in browser.
|
||||
|
||||
3. `NotFoundHttpException` is thrown by library.
|
||||
|
||||
### Route and/or callback for failing route
|
||||
|
||||
*Route:*
|
||||
|
||||
```php
|
||||
SimpleRouter::get('/user/{name}', 'UserController@show')->where(['name' => '[\w]+']);
|
||||
```
|
||||
|
||||
*Callback:*
|
||||
|
||||
```php
|
||||
public function show($username) {
|
||||
return sprintf('Username is: %s', $username);
|
||||
}
|
||||
```
|
||||
|
||||
### Debug info
|
||||
|
||||
```php
|
||||
array (
|
||||
'url' =>
|
||||
Pecee\Http\Url::__set_state(array(
|
||||
'originalUrl' => NULL,
|
||||
'data' =>
|
||||
array (
|
||||
'scheme' => NULL,
|
||||
'host' => NULL,
|
||||
'port' => NULL,
|
||||
'user' => NULL,
|
||||
'pass' => NULL,
|
||||
'path' => NULL,
|
||||
'query' => NULL,
|
||||
'fragment' => NULL,
|
||||
),
|
||||
)),
|
||||
'method' => '',
|
||||
'host' => NULL,
|
||||
'loaded_routes' =>
|
||||
array (
|
||||
),
|
||||
'all_routes' =>
|
||||
array (
|
||||
0 =>
|
||||
Pecee\SimpleRouter\Route\RouteUrl::__set_state(array(
|
||||
'url' => '/user/{name}/',
|
||||
'name' => NULL,
|
||||
'regex' => NULL,
|
||||
'filterEmptyParams' => true,
|
||||
'defaultParameterRegex' => NULL,
|
||||
'paramModifiers' => '{}',
|
||||
'paramOptionalSymbol' => '?',
|
||||
'urlRegex' => '/^%s\\/?$/u',
|
||||
'group' => NULL,
|
||||
'parent' => NULL,
|
||||
'callback' => 'UserController@show',
|
||||
'defaultNamespace' => NULL,
|
||||
'namespace' => NULL,
|
||||
'requestMethods' =>
|
||||
array (
|
||||
0 => 'get',
|
||||
),
|
||||
'where' =>
|
||||
array (
|
||||
'name' => '[\\w]+',
|
||||
),
|
||||
'parameters' =>
|
||||
array (
|
||||
'name' => NULL,
|
||||
),
|
||||
'originalParameters' =>
|
||||
array (
|
||||
),
|
||||
'middlewares' =>
|
||||
array (
|
||||
),
|
||||
)),
|
||||
),
|
||||
'boot_managers' =>
|
||||
array (
|
||||
),
|
||||
'csrf_verifier' => NULL,
|
||||
'log' =>
|
||||
array (
|
||||
0 =>
|
||||
array (
|
||||
'message' => 'Started routing request (rewrite: no)',
|
||||
'time' => '0.0000069141',
|
||||
'trace' =>
|
||||
array (
|
||||
'file' => 'E:\\Workspace\\simple-php-router\\src\\Pecee\\SimpleRouter\\SimpleRouter.php',
|
||||
'line' => 57,
|
||||
'function' => 'routeRequest',
|
||||
'class' => 'Pecee\\SimpleRouter\\Router',
|
||||
'type' => '->',
|
||||
),
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'message' => 'Loading routes',
|
||||
'time' => '0.0036418438',
|
||||
'trace' =>
|
||||
array (
|
||||
'file' => 'E:\\Workspace\\simple-php-router\\src\\Pecee\\SimpleRouter\\Router.php',
|
||||
'line' => 273,
|
||||
'function' => 'loadRoutes',
|
||||
'class' => 'Pecee\\SimpleRouter\\Router',
|
||||
'type' => '->',
|
||||
),
|
||||
),
|
||||
2 =>
|
||||
array (
|
||||
'message' => 'Processing routes',
|
||||
'time' => '0.0069010258',
|
||||
'trace' =>
|
||||
array (
|
||||
'file' => 'E:\\Workspace\\simple-php-router\\src\\Pecee\\SimpleRouter\\Router.php',
|
||||
'line' => 251,
|
||||
'function' => 'processRoutes',
|
||||
'class' => 'Pecee\\SimpleRouter\\Router',
|
||||
'type' => '->',
|
||||
),
|
||||
),
|
||||
3 =>
|
||||
array (
|
||||
'message' => 'Processing route "Pecee\\SimpleRouter\\Route\\RouteUrl"',
|
||||
'time' => '0.0099139214',
|
||||
'trace' =>
|
||||
array (
|
||||
'file' => 'E:\\Workspace\\simple-php-router\\src\\Pecee\\SimpleRouter\\Router.php',
|
||||
'line' => 251,
|
||||
'function' => 'processRoutes',
|
||||
'class' => 'Pecee\\SimpleRouter\\Router',
|
||||
'type' => '->',
|
||||
),
|
||||
),
|
||||
4 =>
|
||||
array (
|
||||
'message' => 'Finished loading routes',
|
||||
'time' => '0.0130679607',
|
||||
'trace' =>
|
||||
array (
|
||||
'file' => 'E:\\Workspace\\simple-php-router\\src\\Pecee\\SimpleRouter\\Router.php',
|
||||
'line' => 273,
|
||||
'function' => 'loadRoutes',
|
||||
'class' => 'Pecee\\SimpleRouter\\Router',
|
||||
'type' => '->',
|
||||
),
|
||||
),
|
||||
5 =>
|
||||
array (
|
||||
'message' => 'Matching route "Pecee\\SimpleRouter\\Route\\RouteUrl"',
|
||||
'time' => '0.0160858631',
|
||||
'trace' =>
|
||||
array (
|
||||
'file' => 'E:\\Workspace\\simple-php-router\\src\\Pecee\\SimpleRouter\\SimpleRouter.php',
|
||||
'line' => 57,
|
||||
'function' => 'routeRequest',
|
||||
'class' => 'Pecee\\SimpleRouter\\Router',
|
||||
'type' => '->',
|
||||
),
|
||||
),
|
||||
6 =>
|
||||
array (
|
||||
'message' => 'Route not found: "/"',
|
||||
'time' => '0.0193598270',
|
||||
'trace' =>
|
||||
array (
|
||||
'file' => 'E:\\Workspace\\simple-php-router\\src\\Pecee\\SimpleRouter\\SimpleRouter.php',
|
||||
'line' => 57,
|
||||
'function' => 'routeRequest',
|
||||
'class' => 'Pecee\\SimpleRouter\\Router',
|
||||
'type' => '->',
|
||||
),
|
||||
),
|
||||
7 =>
|
||||
array (
|
||||
'message' => 'Starting exception handling for "Pecee\\SimpleRouter\\Exceptions\\NotFoundHttpException"',
|
||||
'time' => '0.0229449272',
|
||||
'trace' =>
|
||||
array (
|
||||
'file' => 'E:\\Workspace\\simple-php-router\\src\\Pecee\\SimpleRouter\\Router.php',
|
||||
'line' => 345,
|
||||
'function' => 'handleException',
|
||||
'class' => 'Pecee\\SimpleRouter\\Router',
|
||||
'type' => '->',
|
||||
),
|
||||
),
|
||||
8 =>
|
||||
array (
|
||||
'message' => 'Finished exception handling - exception not handled, throwing',
|
||||
'time' => '0.0258929729',
|
||||
'trace' =>
|
||||
array (
|
||||
'file' => 'E:\\Workspace\\simple-php-router\\src\\Pecee\\SimpleRouter\\Router.php',
|
||||
'line' => 345,
|
||||
'function' => 'handleException',
|
||||
'class' => 'Pecee\\SimpleRouter\\Router',
|
||||
'type' => '->',
|
||||
),
|
||||
),
|
||||
),
|
||||
'router_output' => NULL,
|
||||
'library_version' => false,
|
||||
'php_version' => '7.2.0',
|
||||
'server_params' =>
|
||||
array (),
|
||||
)
|
||||
```
|
||||
|
||||
</pre>
|
||||
|
||||
Remember that a more detailed issue- description and debug-info might suck to write, but it will help others understand- and resolve your issue without asking for the information.
|
||||
|
||||
**Note:** please be as detailed as possible in the description when creating a new issue. This will help others to more easily understand- and solve your issue. Providing the necessary steps to reproduce the error within your description, adding useful debugging info etc. will help others quickly resolve the issue you are reporting.
|
||||
|
||||
---
|
||||
|
||||
# Routes
|
||||
|
||||
Remember the ```routes.php``` file you required in your ```index.php```? This file be where you place all your custom rules for routing.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\Exceptions;
|
||||
|
||||
class InvalidArgumentException extends \InvalidArgumentException {
|
||||
class InvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -7,15 +7,15 @@ interface IInputItem
|
||||
|
||||
public function getIndex(): string;
|
||||
|
||||
public function setIndex($index): self;
|
||||
public function setIndex(string $index): self;
|
||||
|
||||
public function getName(): string;
|
||||
|
||||
public function setName($name): self;
|
||||
public function setName(string $name): self;
|
||||
|
||||
public function getValue(): string;
|
||||
|
||||
public function setValue($value): self;
|
||||
public function setValue(string $value): self;
|
||||
|
||||
public function __toString();
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ class InputFile implements IInputItem
|
||||
public $errors;
|
||||
public $tmpName;
|
||||
|
||||
public function __construct($index)
|
||||
public function __construct(string $index)
|
||||
{
|
||||
$this->index = $index;
|
||||
|
||||
@@ -48,7 +48,7 @@ class InputFile implements IInputItem
|
||||
];
|
||||
|
||||
return (new static($values['index']))
|
||||
->setSize($values['size'])
|
||||
->setSize((int)$values['size'])
|
||||
->setError($values['error'])
|
||||
->setType($values['type'])
|
||||
->setTmpName($values['tmp_name'])
|
||||
@@ -69,7 +69,7 @@ class InputFile implements IInputItem
|
||||
* @param string $index
|
||||
* @return static
|
||||
*/
|
||||
public function setIndex($index): IInputItem
|
||||
public function setIndex(string $index): IInputItem
|
||||
{
|
||||
$this->index = $index;
|
||||
|
||||
@@ -89,7 +89,7 @@ class InputFile implements IInputItem
|
||||
* @param int $size
|
||||
* @return static
|
||||
*/
|
||||
public function setSize($size): IInputItem
|
||||
public function setSize(int $size): IInputItem
|
||||
{
|
||||
$this->size = $size;
|
||||
|
||||
@@ -118,7 +118,7 @@ class InputFile implements IInputItem
|
||||
* @param string $type
|
||||
* @return static
|
||||
*/
|
||||
public function setType($type): IInputItem
|
||||
public function setType(string $type): IInputItem
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
@@ -152,7 +152,7 @@ class InputFile implements IInputItem
|
||||
* @param string $name
|
||||
* @return static
|
||||
*/
|
||||
public function setName($name): IInputItem
|
||||
public function setName(string $name): IInputItem
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
@@ -270,7 +270,7 @@ class InputFile implements IInputItem
|
||||
* @param string $value
|
||||
* @return static
|
||||
*/
|
||||
public function setValue($value): IInputItem
|
||||
public function setValue(string $value): IInputItem
|
||||
{
|
||||
$this->filename = $value;
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class InputHandler
|
||||
* Parse input values
|
||||
*
|
||||
*/
|
||||
public function parseInputs() : void
|
||||
public function parseInputs(): void
|
||||
{
|
||||
/* Parse get requests */
|
||||
if (\count($_GET) !== 0) {
|
||||
@@ -69,7 +69,7 @@ class InputHandler
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function parseFiles() : array
|
||||
public function parseFiles(): array
|
||||
{
|
||||
$list = [];
|
||||
|
||||
@@ -80,7 +80,7 @@ class InputHandler
|
||||
$values['index'] = $key;
|
||||
try {
|
||||
$list[$key] = InputFile::createFromArray($values + $value);
|
||||
} catch(InvalidArgumentException $e ){
|
||||
} catch (InvalidArgumentException $e) {
|
||||
|
||||
}
|
||||
continue;
|
||||
@@ -101,7 +101,7 @@ class InputHandler
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function rearrangeFiles(array $values, &$index, $original) : array
|
||||
protected function rearrangeFiles(array $values, &$index, $original): array
|
||||
{
|
||||
|
||||
$originalIndex = $index[0];
|
||||
@@ -132,7 +132,7 @@ class InputHandler
|
||||
$output[$key] = $file;
|
||||
continue;
|
||||
|
||||
} catch(InvalidArgumentException $e) {
|
||||
} catch (InvalidArgumentException $e) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -152,7 +152,7 @@ class InputHandler
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected function handleGetPost(array $array) : array
|
||||
protected function handleGetPost(array $array): array
|
||||
{
|
||||
$list = [];
|
||||
|
||||
@@ -179,7 +179,7 @@ class InputHandler
|
||||
* @param string|null $defaultValue
|
||||
* @return InputItem|string
|
||||
*/
|
||||
public function findPost($index, $defaultValue = null)
|
||||
public function findPost(string $index, ?string $defaultValue = null)
|
||||
{
|
||||
return $this->post[$index] ?? $defaultValue;
|
||||
}
|
||||
@@ -191,7 +191,7 @@ class InputHandler
|
||||
* @param string|null $defaultValue
|
||||
* @return InputFile|string
|
||||
*/
|
||||
public function findFile($index, $defaultValue = null)
|
||||
public function findFile(string $index, ?string $defaultValue = null)
|
||||
{
|
||||
return $this->file[$index] ?? $defaultValue;
|
||||
}
|
||||
@@ -203,7 +203,7 @@ class InputHandler
|
||||
* @param string|null $defaultValue
|
||||
* @return InputItem|string
|
||||
*/
|
||||
public function findGet($index, $defaultValue = null)
|
||||
public function findGet(string $index, ?string $defaultValue = null)
|
||||
{
|
||||
return $this->get[$index] ?? $defaultValue;
|
||||
}
|
||||
@@ -216,7 +216,7 @@ class InputHandler
|
||||
* @param array|string|null $methods
|
||||
* @return IInputItem|string
|
||||
*/
|
||||
public function getObject($index, $defaultValue = null, $methods = null)
|
||||
public function getObject(string $index, ?string $defaultValue = null, $methods = null)
|
||||
{
|
||||
if ($methods !== null && \is_string($methods) === true) {
|
||||
$methods = [$methods];
|
||||
@@ -247,7 +247,7 @@ class InputHandler
|
||||
* @param array|string|null $methods
|
||||
* @return InputItem|string
|
||||
*/
|
||||
public function get($index, $defaultValue = null, $methods = null)
|
||||
public function get(string $index, ?string $defaultValue = null, $methods = null)
|
||||
{
|
||||
$input = $this->getObject($index, $defaultValue, $methods);
|
||||
|
||||
@@ -264,7 +264,7 @@ class InputHandler
|
||||
* @param string $index
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($index) : bool
|
||||
public function exists(string $index): bool
|
||||
{
|
||||
return ($this->getObject($index) !== null);
|
||||
}
|
||||
@@ -274,7 +274,7 @@ class InputHandler
|
||||
* @param array|null $filter Only take items in filter
|
||||
* @return array
|
||||
*/
|
||||
public function all(array $filter = null) : array
|
||||
public function all(array $filter = null): array
|
||||
{
|
||||
$output = $_GET + $_POST;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ class InputItem implements IInputItem
|
||||
public $name;
|
||||
public $value;
|
||||
|
||||
public function __construct($index, $value = null)
|
||||
public function __construct(string $index, ?string $value = null)
|
||||
{
|
||||
$this->index = $index;
|
||||
$this->value = $value;
|
||||
@@ -25,7 +25,7 @@ class InputItem implements IInputItem
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
public function setIndex($index): IInputItem
|
||||
public function setIndex(string $index): IInputItem
|
||||
{
|
||||
$this->index = $index;
|
||||
|
||||
@@ -43,9 +43,9 @@ class InputItem implements IInputItem
|
||||
/**
|
||||
* Set input name
|
||||
* @param string $name
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setName($name): IInputItem
|
||||
public function setName(string $name): IInputItem
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
@@ -63,9 +63,9 @@ class InputItem implements IInputItem
|
||||
/**
|
||||
* Set input value
|
||||
* @param string $value
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setValue($value): IInputItem
|
||||
public function setValue(string $value): IInputItem
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\Http\Middleware\Exceptions;
|
||||
|
||||
class TokenMismatchException extends \Exception
|
||||
|
||||
@@ -10,7 +10,7 @@ use Pecee\SimpleRouter\SimpleRouter;
|
||||
class Request
|
||||
{
|
||||
private $data = [];
|
||||
protected $headers;
|
||||
protected $headers = [];
|
||||
protected $host;
|
||||
protected $url;
|
||||
protected $method;
|
||||
@@ -35,7 +35,11 @@ class Request
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->parseHeaders();
|
||||
foreach ($_SERVER as $key => $value) {
|
||||
$this->headers[strtolower($key)] = $value;
|
||||
$this->headers[strtolower(str_replace('_', '-', $key))] = $value;
|
||||
}
|
||||
|
||||
$this->setHost($this->getHeader('http-host'));
|
||||
|
||||
// Check if special IIS header exist, otherwise use default.
|
||||
@@ -45,17 +49,6 @@ class Request
|
||||
$this->method = strtolower($this->inputHandler->get('_method', $this->getHeader('request-method')));
|
||||
}
|
||||
|
||||
protected function parseHeaders(): void
|
||||
{
|
||||
$this->headers = [];
|
||||
|
||||
foreach ($_SERVER as $key => $value) {
|
||||
$this->headers[strtolower($key)] = $value;
|
||||
$this->headers[strtolower(str_replace('_', '-', $key))] = $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function isSecure(): bool
|
||||
{
|
||||
return $this->getHeader('http-x-forwarded-proto') === 'https' || $this->getHeader('https') !== null || $this->getHeader('server-port') === 443;
|
||||
@@ -221,9 +214,9 @@ class Request
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $host
|
||||
* @param string|null $host
|
||||
*/
|
||||
public function setHost($host): void
|
||||
public function setHost(?string $host): void
|
||||
{
|
||||
$this->host = $host;
|
||||
}
|
||||
@@ -231,7 +224,7 @@ class Request
|
||||
/**
|
||||
* @param string $method
|
||||
*/
|
||||
public function setMethod($method): void
|
||||
public function setMethod(string $method): void
|
||||
{
|
||||
$this->method = $method;
|
||||
}
|
||||
@@ -341,26 +334,32 @@ class Request
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the request contains a rewrite
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasRewrite(): bool
|
||||
{
|
||||
return $this->hasRewrite;
|
||||
}
|
||||
|
||||
public function setHasRewrite($value): self
|
||||
/**
|
||||
* Defines if the current request contains a rewrite.
|
||||
*
|
||||
* @param bool $boolean
|
||||
* @return Request
|
||||
*/
|
||||
public function setHasRewrite(bool $boolean): self
|
||||
{
|
||||
$this->hasRewrite = $value;
|
||||
$this->hasRewrite = $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isRewrite($url): bool
|
||||
{
|
||||
return ($this->rewriteUrl === $url);
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return array_key_exists($name, $this->data);
|
||||
return array_key_exists($name, $this->data) === true;
|
||||
}
|
||||
|
||||
public function __set($name, $value = null)
|
||||
|
||||
@@ -19,7 +19,7 @@ class Response
|
||||
* @param int $code
|
||||
* @return static
|
||||
*/
|
||||
public function httpCode($code): self
|
||||
public function httpCode(int $code): self
|
||||
{
|
||||
http_response_code($code);
|
||||
|
||||
@@ -32,7 +32,7 @@ class Response
|
||||
* @param string $url
|
||||
* @param int $httpCode
|
||||
*/
|
||||
public function redirect($url, $httpCode = null): void
|
||||
public function redirect(string $url, ?int $httpCode = null): void
|
||||
{
|
||||
if ($httpCode !== null) {
|
||||
$this->httpCode($httpCode);
|
||||
@@ -52,7 +52,7 @@ class Response
|
||||
* @param string $name
|
||||
* @return static
|
||||
*/
|
||||
public function auth($name = ''): self
|
||||
public function auth(string $name = ''): self
|
||||
{
|
||||
$this->headers([
|
||||
'WWW-Authenticate: Basic realm="' . $name . '"',
|
||||
@@ -62,19 +62,19 @@ class Response
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cache($eTag, $lastModified = 2592000): self
|
||||
public function cache(string $eTag, int $lastModifiedTime = 2592000): self
|
||||
{
|
||||
|
||||
$this->headers([
|
||||
'Cache-Control: public',
|
||||
'Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModified) . ' GMT',
|
||||
'Etag: ' . $eTag,
|
||||
sprintf('Last-Modified: %s GMT', gmdate('D, d M Y H:i:s', $lastModifiedTime)),
|
||||
sprintf('Etag: %s', $eTag),
|
||||
]);
|
||||
|
||||
$httpModified = $this->request->getHeader('http-if-modified-since');
|
||||
$httpIfNoneMatch = $this->request->getHeader('http-if-none-match');
|
||||
|
||||
if (($httpIfNoneMatch !== null && $httpIfNoneMatch === $eTag) || ($httpModified !== null && strtotime($httpModified) === $lastModified)) {
|
||||
if (($httpIfNoneMatch !== null && $httpIfNoneMatch === $eTag) || ($httpModified !== null && strtotime($httpModified) === $lastModifiedTime)) {
|
||||
|
||||
$this->header('HTTP/1.1 304 Not Modified');
|
||||
exit(0);
|
||||
@@ -90,7 +90,7 @@ class Response
|
||||
* @param int $dept JSON debt.
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function json($value, $options = null, $dept = 512): void
|
||||
public function json($value, ?int $options = null, int $dept = 512): void
|
||||
{
|
||||
if (($value instanceof \JsonSerializable) === false && \is_array($value) === false) {
|
||||
throw new InvalidArgumentException('Invalid type for parameter "value". Must be of type array or object implementing the \JsonSerializable interface.');
|
||||
@@ -106,7 +106,7 @@ class Response
|
||||
* @param string $value
|
||||
* @return static
|
||||
*/
|
||||
public function header($value): self
|
||||
public function header(string $value): self
|
||||
{
|
||||
header($value);
|
||||
|
||||
|
||||
@@ -45,9 +45,9 @@ class CookieTokenProvider implements ITokenProvider
|
||||
* @param string $token
|
||||
* @return bool
|
||||
*/
|
||||
public function validate($token): bool
|
||||
public function validate(string $token): bool
|
||||
{
|
||||
if ($token !== null && $this->getToken() !== null) {
|
||||
if ($this->getToken() !== null) {
|
||||
return hash_equals($token, $this->getToken());
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class CookieTokenProvider implements ITokenProvider
|
||||
*
|
||||
* @param string $token
|
||||
*/
|
||||
public function setToken($token): void
|
||||
public function setToken(string $token): void
|
||||
{
|
||||
$this->token = $token;
|
||||
setcookie(static::CSRF_KEY, $token, time() + 60 * $this->cookieTimeoutMinutes, '/');
|
||||
@@ -71,7 +71,7 @@ class CookieTokenProvider implements ITokenProvider
|
||||
* @param string|null $defaultValue
|
||||
* @return string|null
|
||||
*/
|
||||
public function getToken($defaultValue = null): ?string
|
||||
public function getToken(?string $defaultValue = null): ?string
|
||||
{
|
||||
$this->token = ($this->hasToken() === true) ? $_COOKIE[static::CSRF_KEY] : null;
|
||||
|
||||
@@ -108,9 +108,9 @@ class CookieTokenProvider implements ITokenProvider
|
||||
|
||||
/**
|
||||
* Set cookie timeout in minutes
|
||||
* @param $minutes
|
||||
* @param int $minutes
|
||||
*/
|
||||
public function setCookieTimeoutMinutes($minutes): void
|
||||
public function setCookieTimeoutMinutes(int $minutes): void
|
||||
{
|
||||
$this->cookieTimeoutMinutes = $minutes;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\Http\Security\Exceptions;
|
||||
|
||||
class SecurityException extends \Exception {
|
||||
class SecurityException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@ interface ITokenProvider
|
||||
* @param string $token
|
||||
* @return bool
|
||||
*/
|
||||
public function validate($token): bool;
|
||||
public function validate(string $token): bool;
|
||||
|
||||
/**
|
||||
* Get token token
|
||||
@@ -24,6 +24,6 @@ interface ITokenProvider
|
||||
* @param string|null $defaultValue
|
||||
* @return string|null
|
||||
*/
|
||||
public function getToken($defaultValue = null);
|
||||
public function getToken(?string $defaultValue = null): ?string;
|
||||
|
||||
}
|
||||
@@ -23,15 +23,16 @@ class Url
|
||||
* @param string $url
|
||||
* @throws MalformedUrlException
|
||||
*/
|
||||
public function __construct($url)
|
||||
public function __construct(?string $url)
|
||||
{
|
||||
$this->originalUrl = $url;
|
||||
$this->data = $this->parseUrl($url) + $this->data;
|
||||
if ($url !== null) {
|
||||
$this->data = $this->parseUrl($url) + $this->data;
|
||||
|
||||
if (isset($this->data['path']) === true && $this->data['path'] !== '/') {
|
||||
$this->data['path'] = rtrim($this->data['path'], '/') . '/';
|
||||
if (isset($this->data['path']) === true && $this->data['path'] !== '/') {
|
||||
$this->data['path'] = rtrim($this->data['path'], '/') . '/';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +104,7 @@ class Url
|
||||
*/
|
||||
public function getPath(): ?string
|
||||
{
|
||||
return $this->data['path'];
|
||||
return $this->data['path'] ?? '/';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +140,7 @@ class Url
|
||||
* @throws MalformedUrlException
|
||||
* @return array
|
||||
*/
|
||||
public function parseUrl($url, $component = -1): array
|
||||
public function parseUrl(string $url, int $component = -1): array
|
||||
{
|
||||
$encodedUrl = preg_replace_callback(
|
||||
'/[^:\/@?&=#]+/u',
|
||||
@@ -158,9 +159,29 @@ class Url
|
||||
return array_map('urldecode', $parts);
|
||||
}
|
||||
|
||||
public function contains($value): bool
|
||||
/**
|
||||
* Get position of value.
|
||||
* Returns -1 on failure.
|
||||
*
|
||||
* @param string $value
|
||||
* @return int
|
||||
*/
|
||||
public function indexOf(string $value): int
|
||||
{
|
||||
return (stripos($this->getOriginalUrl(), $value) === false);
|
||||
$index = stripos($this->getOriginalUrl(), $value);
|
||||
|
||||
return ($index === false) ? -1 : $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if url contains value.
|
||||
*
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public function contains(string $value): bool
|
||||
{
|
||||
return (stripos($this->getOriginalUrl(), $value) !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\SimpleRouter\Exceptions;
|
||||
|
||||
class HttpException extends \Exception
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\SimpleRouter\Exceptions;
|
||||
|
||||
class NotFoundHttpException extends HttpException
|
||||
|
||||
@@ -17,6 +17,6 @@ interface IControllerRoute extends IRoute
|
||||
* @param string $controller
|
||||
* @return static
|
||||
*/
|
||||
public function setController($controller): self;
|
||||
public function setController(string $controller): self;
|
||||
|
||||
}
|
||||
@@ -19,15 +19,15 @@ interface IGroupRoute extends IRoute
|
||||
* Add exception handler
|
||||
*
|
||||
* @param IExceptionHandler|string $handler
|
||||
* @return static $this;
|
||||
* @return static
|
||||
*/
|
||||
public function addExceptionHandler($handler);
|
||||
public function addExceptionHandler($handler): self;
|
||||
|
||||
/**
|
||||
* Set exception-handlers for group
|
||||
*
|
||||
* @param array $handlers
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setExceptionHandlers(array $handlers);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Router;
|
||||
|
||||
interface ILoadableRoute extends IRoute
|
||||
{
|
||||
@@ -18,22 +19,32 @@ interface ILoadableRoute extends IRoute
|
||||
public function findUrl($method = null, $parameters = null, $name = null): string;
|
||||
|
||||
/**
|
||||
* Loads and renders middlewares-classes
|
||||
* Loads and renders middleware-classes
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Router $router
|
||||
*/
|
||||
public function loadMiddleware(Request $request);
|
||||
public function loadMiddleware(Request $request, Router $router): void;
|
||||
|
||||
public function getUrl();
|
||||
/**
|
||||
* Get url
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl(): string;
|
||||
|
||||
public function setUrl($url);
|
||||
/**
|
||||
* Set url
|
||||
* @param string $url
|
||||
* @return static
|
||||
*/
|
||||
public function setUrl(string $url): self;
|
||||
|
||||
/**
|
||||
* Returns the provided name for the router.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getName(): string;
|
||||
public function getName(): ?string;
|
||||
|
||||
/**
|
||||
* Check if route has given name.
|
||||
@@ -41,7 +52,7 @@ interface ILoadableRoute extends IRoute
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasName($name): bool;
|
||||
public function hasName(string $name): bool;
|
||||
|
||||
/**
|
||||
* Sets the router name, which makes it easier to obtain the url or router at a later point.
|
||||
@@ -49,14 +60,14 @@ interface ILoadableRoute extends IRoute
|
||||
* @param string $name
|
||||
* @return static
|
||||
*/
|
||||
public function setName($name): self;
|
||||
public function setName(string $name): self;
|
||||
|
||||
/**
|
||||
* Get regular expression match used for matching route (if defined).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMatch(): string;
|
||||
public function getMatch(): ?string;
|
||||
|
||||
/**
|
||||
* Add regular expression match for the entire route.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Router;
|
||||
|
||||
interface IRoute
|
||||
{
|
||||
@@ -20,10 +21,11 @@ interface IRoute
|
||||
* Returns class to be rendered.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Router $router
|
||||
* @throws \Pecee\SimpleRouter\Exceptions\NotFoundHttpException
|
||||
* @return string
|
||||
*/
|
||||
public function renderRoute(Request $request): ?string;
|
||||
public function renderRoute(Request $request, Router $router): ?string;
|
||||
|
||||
/**
|
||||
* Returns callback name/identifier for the current route based on the callback.
|
||||
@@ -103,15 +105,20 @@ interface IRoute
|
||||
* @param string $method
|
||||
* @return static
|
||||
*/
|
||||
public function setMethod($method): self;
|
||||
public function setMethod(string $method): self;
|
||||
|
||||
public function getClass();
|
||||
/**
|
||||
* Get class
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getClass(): ?string;
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
* @return static
|
||||
*/
|
||||
public function setNamespace($namespace);
|
||||
public function setNamespace(string $namespace): self;
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
@@ -122,9 +129,13 @@ interface IRoute
|
||||
* @param string $namespace
|
||||
* @return static
|
||||
*/
|
||||
public function setDefaultNamespace($namespace);
|
||||
public function setDefaultNamespace($namespace): IRoute;
|
||||
|
||||
public function getDefaultNamespace();
|
||||
/**
|
||||
* Get default namespace
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDefaultNamespace(): ?string;
|
||||
|
||||
/**
|
||||
* Get parameter names.
|
||||
@@ -139,7 +150,7 @@ interface IRoute
|
||||
* @param array $options
|
||||
* @return static
|
||||
*/
|
||||
public function setWhere(array $options);
|
||||
public function setWhere(array $options): self;
|
||||
|
||||
/**
|
||||
* Get parameters
|
||||
@@ -152,18 +163,18 @@ interface IRoute
|
||||
* Get parameters
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setParameters(array $parameters);
|
||||
public function setParameters(array $parameters): self;
|
||||
|
||||
/**
|
||||
* Merge with information from another route.
|
||||
*
|
||||
* @param array $settings
|
||||
* @param bool $merge
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $settings, $merge = false);
|
||||
public function setSettings(array $settings, bool $merge = false): self;
|
||||
|
||||
/**
|
||||
* Export route settings to array so they can be merged with another route.
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Pecee\SimpleRouter\Route;
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Exceptions\HttpException;
|
||||
use Pecee\SimpleRouter\Router;
|
||||
|
||||
abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
{
|
||||
@@ -24,10 +25,13 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* Loads and renders middlewares-classes
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Router $router
|
||||
* @throws HttpException
|
||||
*/
|
||||
public function loadMiddleware(Request $request) : void
|
||||
public function loadMiddleware(Request $request, Router $router): void
|
||||
{
|
||||
$router->debug('Loading middlewares');
|
||||
|
||||
foreach ($this->getMiddlewares() as $middleware) {
|
||||
|
||||
if (\is_object($middleware) === false) {
|
||||
@@ -38,11 +42,15 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
throw new HttpException($middleware . ' must be inherit the IMiddleware interface');
|
||||
}
|
||||
|
||||
$router->debug('Loading middleware "%s"', \get_class($middleware));
|
||||
$middleware->handle($request);
|
||||
$router->debug('Finished loading middleware');
|
||||
}
|
||||
|
||||
$router->debug('Finished loading middlewares');
|
||||
}
|
||||
|
||||
public function matchRegex(Request $request, $url) : ?bool
|
||||
public function matchRegex(Request $request, $url): ?bool
|
||||
{
|
||||
/* Match on custom defined regular expression */
|
||||
|
||||
@@ -59,7 +67,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* @param string $url
|
||||
* @return static
|
||||
*/
|
||||
public function setUrl($url) : self
|
||||
public function setUrl(string $url): ILoadableRoute
|
||||
{
|
||||
$this->url = ($url === '/') ? '/' : '/' . trim($url, '/') . '/';
|
||||
|
||||
@@ -75,7 +83,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUrl() : string
|
||||
public function getUrl(): string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
@@ -89,7 +97,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* @param string|null $name
|
||||
* @return string
|
||||
*/
|
||||
public function findUrl($method = null, $parameters = null, $name = null) : string
|
||||
public function findUrl($method = null, $parameters = null, $name = null): string
|
||||
{
|
||||
$url = $this->getUrl();
|
||||
|
||||
@@ -144,7 +152,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() : string
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
@@ -155,7 +163,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasName($name) : bool
|
||||
public function hasName(string $name): bool
|
||||
{
|
||||
return strtolower($this->name) === strtolower($name);
|
||||
}
|
||||
@@ -166,7 +174,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* @param string $regex
|
||||
* @return static
|
||||
*/
|
||||
public function setMatch($regex) : ILoadableRoute
|
||||
public function setMatch($regex): ILoadableRoute
|
||||
{
|
||||
$this->regex = $regex;
|
||||
|
||||
@@ -178,7 +186,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMatch() : string
|
||||
public function getMatch(): string
|
||||
{
|
||||
return $this->regex;
|
||||
}
|
||||
@@ -191,7 +199,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* @param string|array $name
|
||||
* @return static
|
||||
*/
|
||||
public function name($name) : ILoadableRoute
|
||||
public function name($name): ILoadableRoute
|
||||
{
|
||||
return $this->setName($name);
|
||||
}
|
||||
@@ -202,7 +210,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* @param string $name
|
||||
* @return static
|
||||
*/
|
||||
public function setName($name) : ILoadableRoute
|
||||
public function setName(string $name): ILoadableRoute
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
@@ -216,7 +224,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, $merge = false): IRoute
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
{
|
||||
if (isset($values['as']) === true) {
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Pecee\SimpleRouter\Route;
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
|
||||
use Pecee\SimpleRouter\Router;
|
||||
|
||||
abstract class Route implements IRoute
|
||||
{
|
||||
@@ -59,10 +60,10 @@ abstract class Route implements IRoute
|
||||
/**
|
||||
* Load class by name
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @return object
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
protected function loadClass($name)
|
||||
protected function loadClass($name): object
|
||||
{
|
||||
if (class_exists($name) === false) {
|
||||
throw new NotFoundHttpException(sprintf('Class "%s" does not exist', $name), 404);
|
||||
@@ -75,21 +76,25 @@ abstract class Route implements IRoute
|
||||
* Render route
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Router $router
|
||||
* @return string|null
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function renderRoute(Request $request): ?string
|
||||
public function renderRoute(Request $request, Router $router): ?string
|
||||
{
|
||||
$router->debug('Starting rendering route');
|
||||
|
||||
$callback = $this->getCallback();
|
||||
|
||||
if ($callback === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$router->debug('Parsing parameters');
|
||||
$parameters = $this->getParameters();
|
||||
$router->debug('Finished parsing parameters');
|
||||
|
||||
/* Filter parameters with null-value */
|
||||
|
||||
if ($this->filterEmptyParams === true) {
|
||||
$parameters = array_filter($parameters, function ($var) {
|
||||
return ($var !== null);
|
||||
@@ -98,7 +103,10 @@ abstract class Route implements IRoute
|
||||
|
||||
/* Render callback function */
|
||||
if (\is_callable($callback) === true) {
|
||||
$router->debug('Executing callback');
|
||||
|
||||
/* When the callback is a function */
|
||||
|
||||
return \call_user_func_array($callback, $parameters);
|
||||
}
|
||||
|
||||
@@ -109,6 +117,7 @@ abstract class Route implements IRoute
|
||||
|
||||
$className = ($namespace !== null && $controller[0][0] !== '\\') ? $namespace . '\\' . $controller[0] : $controller[0];
|
||||
|
||||
$router->debug('Loading class %s', $className);
|
||||
$class = $this->loadClass($className);
|
||||
$method = $controller[1];
|
||||
|
||||
@@ -116,6 +125,8 @@ abstract class Route implements IRoute
|
||||
throw new NotFoundHttpException(sprintf('Method "%s" does not exist in class "%s"', $method, $className), 404);
|
||||
}
|
||||
|
||||
$router->debug('Executing callback');
|
||||
|
||||
return \call_user_func_array([$class, $method], $parameters);
|
||||
}
|
||||
|
||||
@@ -300,7 +311,7 @@ abstract class Route implements IRoute
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getClass()
|
||||
public function getClass(): ?string
|
||||
{
|
||||
if (\is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
|
||||
$tmp = explode('@', $this->callback);
|
||||
@@ -311,14 +322,14 @@ abstract class Route implements IRoute
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setMethod($method): IRoute
|
||||
public function setMethod(string $method): IRoute
|
||||
{
|
||||
$this->callback = sprintf('%s@%s', $this->getClass(), $method);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setClass($class)
|
||||
public function setClass(string $class): IRoute
|
||||
{
|
||||
$this->callback = sprintf('%s@%s', $class, $this->getMethod());
|
||||
|
||||
@@ -327,9 +338,9 @@ abstract class Route implements IRoute
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setNamespace($namespace)
|
||||
public function setNamespace(string $namespace): IRoute
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
|
||||
@@ -338,16 +349,16 @@ abstract class Route implements IRoute
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setDefaultNamespace($namespace)
|
||||
public function setDefaultNamespace($namespace): IRoute
|
||||
{
|
||||
$this->defaultNamespace = $namespace;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDefaultNamespace()
|
||||
public function getDefaultNamespace(): ?string
|
||||
{
|
||||
return $this->defaultNamespace;
|
||||
}
|
||||
@@ -397,9 +408,9 @@ abstract class Route implements IRoute
|
||||
*
|
||||
* @param array $values
|
||||
* @param bool $merge
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, $merge = false)
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
{
|
||||
if ($this->namespace === null && isset($values['namespace']) === true) {
|
||||
$this->setNamespace($values['namespace']);
|
||||
@@ -445,7 +456,7 @@ abstract class Route implements IRoute
|
||||
* @param array $options
|
||||
* @return static
|
||||
*/
|
||||
public function setWhere(array $options)
|
||||
public function setWhere(array $options): IRoute
|
||||
{
|
||||
$this->where = $options;
|
||||
|
||||
@@ -486,9 +497,9 @@ abstract class Route implements IRoute
|
||||
* Get parameters
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setParameters(array $parameters)
|
||||
public function setParameters(array $parameters): IRoute
|
||||
{
|
||||
/*
|
||||
* If this is the first time setting parameters we store them so we
|
||||
@@ -556,7 +567,7 @@ abstract class Route implements IRoute
|
||||
* This is used when no custom parameter regex is found.
|
||||
*
|
||||
* @param string $regex
|
||||
* @return static $this
|
||||
* @return static
|
||||
*/
|
||||
public function setDefaultParameterRegex($regex)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasName($name): bool
|
||||
public function hasName(string $name): bool
|
||||
{
|
||||
if ($this->name === null) {
|
||||
return false;
|
||||
@@ -134,7 +134,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
* @param string $controller
|
||||
* @return static
|
||||
*/
|
||||
public function setController($controller): IControllerRoute
|
||||
public function setController(string $controller): IControllerRoute
|
||||
{
|
||||
$this->controller = $controller;
|
||||
|
||||
@@ -157,7 +157,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
* @param string $method
|
||||
* @return static
|
||||
*/
|
||||
public function setMethod($method): IRoute
|
||||
public function setMethod(string $method): IRoute
|
||||
{
|
||||
$this->method = $method;
|
||||
|
||||
@@ -171,7 +171,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, $merge = false): IRoute
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
{
|
||||
if (isset($values['names']) === true) {
|
||||
$this->names = $values['names'];
|
||||
|
||||
@@ -147,7 +147,7 @@ class RouteGroup extends Route implements IGroupRoute
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, $merge = false): IRoute
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
{
|
||||
|
||||
if (isset($values['prefix']) === true) {
|
||||
|
||||
@@ -42,7 +42,7 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasName($name): bool
|
||||
public function hasName(string $name): bool
|
||||
{
|
||||
if ($this->name === null) {
|
||||
return false;
|
||||
@@ -154,14 +154,14 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
* @param string $controller
|
||||
* @return static
|
||||
*/
|
||||
public function setController($controller): IControllerRoute
|
||||
public function setController(string $controller): IControllerRoute
|
||||
{
|
||||
$this->controller = $controller;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setName($name): ILoadableRoute
|
||||
public function setName(string $name): ILoadableRoute
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
@@ -208,7 +208,7 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, $merge = false): IRoute
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
{
|
||||
if (isset($values['names']) === true) {
|
||||
$this->names = $values['names'];
|
||||
|
||||
@@ -66,6 +66,32 @@ class Router
|
||||
*/
|
||||
protected $exceptionHandlers;
|
||||
|
||||
/**
|
||||
* List of loaded exception that has been loaded.
|
||||
* Used to ensure that exception-handlers aren't loaded twice when rewriting route.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $loadedExceptionHandlers;
|
||||
|
||||
/**
|
||||
* Enable or disabled debugging
|
||||
* @var bool
|
||||
*/
|
||||
protected $debugEnabled = false;
|
||||
|
||||
/**
|
||||
* The start time used when debugging is enabled
|
||||
* @var float
|
||||
*/
|
||||
protected $debugStartTime;
|
||||
|
||||
/**
|
||||
* List containing all debug messages
|
||||
* @var array
|
||||
*/
|
||||
protected $debugList = [];
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
* @throws \Pecee\Http\Exceptions\MalformedUrlException
|
||||
@@ -78,7 +104,7 @@ class Router
|
||||
/**
|
||||
* @throws \Pecee\Http\Exceptions\MalformedUrlException
|
||||
*/
|
||||
public function reset() : void
|
||||
public function reset(): void
|
||||
{
|
||||
$this->processingRoute = false;
|
||||
$this->request = new Request();
|
||||
@@ -87,6 +113,7 @@ class Router
|
||||
$this->routeStack = [];
|
||||
$this->processedRoutes = [];
|
||||
$this->exceptionHandlers = [];
|
||||
$this->loadedExceptionHandlers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +121,7 @@ class Router
|
||||
* @param IRoute $route
|
||||
* @return IRoute
|
||||
*/
|
||||
public function addRoute(IRoute $route) : IRoute
|
||||
public function addRoute(IRoute $route): IRoute
|
||||
{
|
||||
/*
|
||||
* If a route is currently being processed, that means that the route being added are rendered from the parent
|
||||
@@ -102,10 +129,12 @@ class Router
|
||||
*/
|
||||
if ($this->processingRoute === true) {
|
||||
$this->routeStack[] = $route;
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
$this->routes[] = $route;
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
@@ -115,10 +144,11 @@ class Router
|
||||
* @param IRoute $route
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
protected function renderAndProcess(IRoute $route) : void {
|
||||
protected function renderAndProcess(IRoute $route): void
|
||||
{
|
||||
|
||||
$this->processingRoute = true;
|
||||
$route->renderRoute($this->request);
|
||||
$route->renderRoute($this->request, $this);
|
||||
$this->processingRoute = false;
|
||||
|
||||
if (\count($this->routeStack) !== 0) {
|
||||
@@ -139,13 +169,17 @@ class Router
|
||||
* @param IGroupRoute|null $group
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
protected function processRoutes(array $routes, IGroupRoute $group = null) : void
|
||||
protected function processRoutes(array $routes, ?IGroupRoute $group = null): void
|
||||
{
|
||||
$this->debug('Processing routes');
|
||||
|
||||
// Loop through each route-request
|
||||
$exceptionHandlers = [];
|
||||
|
||||
// Stop processing routes if no valid route is found.
|
||||
if($this->request->getRewriteRoute() === null && $this->request->getUrl() === null) {
|
||||
if ($this->request->getRewriteRoute() === null && $this->request->getUrl() === null) {
|
||||
$this->debug('Halted route-processing as no valid route was found');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,6 +188,8 @@ class Router
|
||||
/* @var $route IRoute */
|
||||
foreach ($routes as $route) {
|
||||
|
||||
$this->debug('Processing route "%s"', \get_class($route));
|
||||
|
||||
if ($group !== null) {
|
||||
/* Add the parent group */
|
||||
$route->setGroup($group);
|
||||
@@ -199,16 +235,22 @@ class Router
|
||||
* @throws NotFoundHttpException
|
||||
* @return void
|
||||
*/
|
||||
public function loadRoutes() : void
|
||||
public function loadRoutes(): void
|
||||
{
|
||||
$this->debug('Loading routes');
|
||||
|
||||
/* Initialize boot-managers */
|
||||
/* @var $manager IRouterBootManager */
|
||||
foreach ($this->bootManagers as $manager) {
|
||||
$this->debug('Rendering bootmanager %s', \get_class($manager));
|
||||
$manager->boot($this->request);
|
||||
$this->debug('Finished rendering bootmanager');
|
||||
}
|
||||
|
||||
/* Loop through each route-request */
|
||||
$this->processRoutes($this->routes);
|
||||
|
||||
$this->debug('Finished loading routes');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,9 +261,11 @@ class Router
|
||||
* @throws HttpException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function routeRequest($rewrite = false) : ?string
|
||||
public function routeRequest(bool $rewrite = false): ?string
|
||||
{
|
||||
$routeNotAllowed = false;
|
||||
$this->debug('Started routing request (rewrite: %s)', $rewrite === true ? 'yes' : 'no');
|
||||
|
||||
$methodNotAllowed = false;
|
||||
|
||||
try {
|
||||
|
||||
@@ -233,8 +277,6 @@ class Router
|
||||
/* Verify csrf token for request */
|
||||
$this->csrfVerifier->handle($this->request);
|
||||
}
|
||||
} else {
|
||||
$this->request->setHasRewrite(false);
|
||||
}
|
||||
|
||||
$url = $this->request->getRewriteUrl() ?? $this->request->getUrl()->getPath();
|
||||
@@ -242,38 +284,39 @@ class Router
|
||||
/* @var $route ILoadableRoute */
|
||||
foreach ($this->processedRoutes as $key => $route) {
|
||||
|
||||
$this->debug('Matching route "%s"', \get_class($route));
|
||||
|
||||
/* If the route matches */
|
||||
if ($route->matchRoute($url, $this->request) === true) {
|
||||
|
||||
/* Check if request method matches */
|
||||
if (\count($route->getRequestMethods()) !== 0 && \in_array($this->request->getMethod(), $route->getRequestMethods(), true) === false) {
|
||||
$routeNotAllowed = true;
|
||||
$this->debug('Method "%s" not allowed', $this->request->getMethod());
|
||||
$methodNotAllowed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$route->loadMiddleware($this->request);
|
||||
$route->loadMiddleware($this->request, $this);
|
||||
|
||||
if ($this->hasRewrite($url) === true) {
|
||||
unset($this->processedRoutes[$key]);
|
||||
|
||||
return $this->routeRequest(true);
|
||||
$output = $this->handleRouteRewrite($key, $url);
|
||||
if ($output !== null) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
/* Render route */
|
||||
$routeNotAllowed = false;
|
||||
$methodNotAllowed = false;
|
||||
|
||||
$this->request->addLoadedRoute($route);
|
||||
|
||||
$output = $route->renderRoute($this->request);
|
||||
$output = $route->renderRoute($this->request, $this);
|
||||
|
||||
if ($output !== null) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
if ($this->hasRewrite($url) === true) {
|
||||
unset($this->processedRoutes[$key]);
|
||||
|
||||
return $this->routeRequest(true);
|
||||
$output = $this->handleRouteRewrite($key, $url);
|
||||
if ($output !== null) {
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -282,7 +325,7 @@ class Router
|
||||
$this->handleException($e);
|
||||
}
|
||||
|
||||
if ($routeNotAllowed === true) {
|
||||
if ($methodNotAllowed === true) {
|
||||
$message = sprintf('Route "%s" or method "%s" not allowed.', $this->request->getUrl()->getPath(), $this->request->getMethod());
|
||||
$this->handleException(new HttpException($message, 403));
|
||||
}
|
||||
@@ -297,35 +340,45 @@ class Router
|
||||
$message = sprintf('Route not found: "%s"', $this->request->getUrl()->getPath());
|
||||
}
|
||||
|
||||
$this->handleException(new NotFoundHttpException($message, 404));
|
||||
$this->debug($message);
|
||||
|
||||
return $this->handleException(new NotFoundHttpException($message, 404));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function hasRewrite($url) : bool
|
||||
/**
|
||||
* Handle route-rewrite
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $url
|
||||
* @return string|null
|
||||
* @throws HttpException
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function handleRouteRewrite($key, string $url): ?string
|
||||
{
|
||||
|
||||
/* If the request has changed */
|
||||
if ($this->request->hasRewrite() === true) {
|
||||
|
||||
if ($this->request->getRewriteRoute() !== null) {
|
||||
/* Render rewrite-route */
|
||||
$this->processedRoutes[] = $this->request->getRewriteRoute();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->request->isRewrite($url) === false) {
|
||||
|
||||
/* Render rewrite-url */
|
||||
$this->processedRoutes = array_values($this->processedRoutes);
|
||||
|
||||
return true;
|
||||
}
|
||||
if ($this->request->hasRewrite() === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return false;
|
||||
$route = $this->request->getRewriteRoute();
|
||||
|
||||
if ($route !== null) {
|
||||
/* Add rewrite route */
|
||||
$this->processedRoutes[] = $route;
|
||||
}
|
||||
|
||||
if ($this->request->getRewriteUrl() !== $url) {
|
||||
unset($this->processedRoutes[$key]);
|
||||
$this->request->setHasRewrite(false);
|
||||
|
||||
return $this->routeRequest(true);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -334,8 +387,10 @@ class Router
|
||||
* @throws \Exception
|
||||
* @return string|null
|
||||
*/
|
||||
protected function handleException(\Exception $e) : ?string
|
||||
protected function handleException(\Exception $e): ?string
|
||||
{
|
||||
$this->debug('Starting exception handling for "%s"', \get_class($e));
|
||||
|
||||
/* @var $handler IExceptionHandler */
|
||||
foreach ($this->exceptionHandlers as $key => $handler) {
|
||||
|
||||
@@ -343,17 +398,22 @@ class Router
|
||||
$handler = new $handler();
|
||||
}
|
||||
|
||||
$this->debug('Processing exception-handler "%s"', \get_class($handler));
|
||||
|
||||
if (($handler instanceof IExceptionHandler) === false) {
|
||||
throw new HttpException('Exception handler must implement the IExceptionHandler interface.', 500);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$this->debug('Start rendering exception handler');
|
||||
$handler->handleError($this->request, $e);
|
||||
$this->debug('Finished rendering exception-handler');
|
||||
|
||||
if ($this->request->hasRewrite() === true) {
|
||||
unset($this->exceptionHandlers[$key]);
|
||||
$this->exceptionHandlers = array_values($this->exceptionHandlers);
|
||||
if (isset($this->loadedExceptionHandlers[$key]) === false && $this->request->hasRewrite() === true) {
|
||||
$this->loadedExceptionHandlers[$key] = $handler;
|
||||
|
||||
$this->debug('Exception handler contains rewrite, reloading routes');
|
||||
|
||||
return $this->routeRequest(true);
|
||||
}
|
||||
@@ -361,12 +421,15 @@ class Router
|
||||
} catch (\Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
$this->debug('Finished processing');
|
||||
}
|
||||
|
||||
$this->debug('Finished exception handling - exception not handled, throwing');
|
||||
throw $e;
|
||||
}
|
||||
|
||||
public function arrayToParams(array $getParams = [], $includeEmpty = true) : string
|
||||
public function arrayToParams(array $getParams = [], bool $includeEmpty = true): string
|
||||
{
|
||||
if (\count($getParams) !== 0) {
|
||||
|
||||
@@ -388,18 +451,25 @@ class Router
|
||||
* @param string $name
|
||||
* @return ILoadableRoute|null
|
||||
*/
|
||||
public function findRoute($name) : ?ILoadableRoute
|
||||
public function findRoute(string $name): ?ILoadableRoute
|
||||
{
|
||||
|
||||
$this->debug('Finding route by name "%s"', $name);
|
||||
|
||||
/* @var $route ILoadableRoute */
|
||||
foreach ($this->processedRoutes as $route) {
|
||||
|
||||
/* Check if the name matches with a name on the route. Should match either router alias or controller alias. */
|
||||
if ($route->hasName($name) === true) {
|
||||
$this->debug('Found route "%s" by name "%s"', $route->getUrl(), $name);
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
/* Direct match to controller */
|
||||
if ($route instanceof IControllerRoute && strtolower($route->getController()) === strtolower($name)) {
|
||||
$this->debug('Found route "%s" by controller "%s"', $route->getUrl(), $name);
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
@@ -408,6 +478,8 @@ class Router
|
||||
[$controller, $method] = array_map('strtolower', explode('@', $name));
|
||||
|
||||
if ($controller === strtolower($route->getClass()) && $method === strtolower($route->getMethod())) {
|
||||
$this->debug('Found route "%s" by controller "%s" and method "%s"', $route->getUrl(), $controller, $method);
|
||||
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
@@ -417,16 +489,22 @@ class Router
|
||||
|
||||
/* Check if the entire callback is matching */
|
||||
if (strpos($route->getCallback(), $name) === 0 || strtolower($route->getCallback()) === strtolower($name)) {
|
||||
$this->debug('Found route "%s" by callback "%s"', $route->getUrl(), $name);
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
/* Check if the class part of the callback matches (class@method) */
|
||||
if (strtolower($name) === strtolower($route->getClass())) {
|
||||
$this->debug('Found route "%s" by class "%s"', $route->getUrl(), $name);
|
||||
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->debug('Route not found');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -448,8 +526,10 @@ class Router
|
||||
* @throws InvalidArgumentException
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl($name = null, $parameters = null, $getParams = null) : string
|
||||
public function getUrl(?string $name = null, $parameters = null, $getParams = null): string
|
||||
{
|
||||
$this->debug('Finding url', \func_get_args());
|
||||
|
||||
if ($getParams !== null && \is_array($getParams) === false) {
|
||||
throw new InvalidArgumentException('Invalid type for getParams. Must be array or null');
|
||||
}
|
||||
@@ -513,28 +593,28 @@ class Router
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bootmanagers
|
||||
* Get BootManagers
|
||||
* @return array
|
||||
*/
|
||||
public function getBootManagers() : array
|
||||
public function getBootManagers(): array
|
||||
{
|
||||
return $this->bootManagers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bootmanagers
|
||||
* Set BootManagers
|
||||
* @param array $bootManagers
|
||||
*/
|
||||
public function setBootManagers(array $bootManagers) : void
|
||||
public function setBootManagers(array $bootManagers): void
|
||||
{
|
||||
$this->bootManagers = $bootManagers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bootmanager
|
||||
* Add BootManager
|
||||
* @param IRouterBootManager $bootManager
|
||||
*/
|
||||
public function addBootManager(IRouterBootManager $bootManager) : void
|
||||
public function addBootManager(IRouterBootManager $bootManager): void
|
||||
{
|
||||
$this->bootManagers[] = $bootManager;
|
||||
}
|
||||
@@ -544,7 +624,7 @@ class Router
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getProcessedRoutes() : array
|
||||
public function getProcessedRoutes(): array
|
||||
{
|
||||
return $this->processedRoutes;
|
||||
}
|
||||
@@ -552,7 +632,7 @@ class Router
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getRoutes() : array
|
||||
public function getRoutes(): array
|
||||
{
|
||||
return $this->routes;
|
||||
}
|
||||
@@ -563,7 +643,7 @@ class Router
|
||||
* @param array $routes
|
||||
* @return static
|
||||
*/
|
||||
public function setRoutes(array $routes) : self
|
||||
public function setRoutes(array $routes): self
|
||||
{
|
||||
$this->routes = $routes;
|
||||
|
||||
@@ -575,7 +655,7 @@ class Router
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
public function getRequest() : Request
|
||||
public function getRequest(): Request
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
@@ -584,7 +664,7 @@ class Router
|
||||
* Get csrf verifier class
|
||||
* @return BaseCsrfVerifier
|
||||
*/
|
||||
public function getCsrfVerifier() : BaseCsrfVerifier
|
||||
public function getCsrfVerifier(): ?BaseCsrfVerifier
|
||||
{
|
||||
return $this->csrfVerifier;
|
||||
}
|
||||
@@ -602,4 +682,47 @@ class Router
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new debug message
|
||||
* @param string $message
|
||||
* @param array $args
|
||||
*/
|
||||
public function debug(string $message, ...$args): void
|
||||
{
|
||||
if ($this->debugEnabled === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
||||
$this->debugList[] = [
|
||||
'message' => vsprintf($message, $args),
|
||||
'time' => number_format(microtime(true) - $this->debugStartTime, 10),
|
||||
'trace' => end($trace),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disables debugging
|
||||
*
|
||||
* @param bool $boolean
|
||||
*/
|
||||
public function setDebugEnabled(bool $boolean): void
|
||||
{
|
||||
if ($boolean === true) {
|
||||
$this->debugStartTime = microtime(true);
|
||||
}
|
||||
|
||||
$this->debugEnabled = $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list containing all debug messages.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDebugLog(): array
|
||||
{
|
||||
return $this->debugList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,6 +46,8 @@ class SimpleRouter
|
||||
protected static $router;
|
||||
|
||||
/**
|
||||
* Start routing
|
||||
*
|
||||
* @throws \Pecee\Http\Exceptions\MalformedUrlException
|
||||
* @throws HttpException
|
||||
* @throws \Exception
|
||||
@@ -56,21 +58,55 @@ class SimpleRouter
|
||||
}
|
||||
|
||||
/**
|
||||
* Get debug info array
|
||||
* Start the routing an return array with debugging-information
|
||||
*
|
||||
* @return array
|
||||
* @throws \Pecee\Http\Exceptions\MalformedUrlException
|
||||
*/
|
||||
public static function debugInfo(): array
|
||||
public static function startDebug(): array
|
||||
{
|
||||
$routerOutput = null;
|
||||
|
||||
try {
|
||||
ob_start();
|
||||
static::router()->setDebugEnabled(true);
|
||||
static::start();
|
||||
$routerOutput = ob_get_contents();
|
||||
ob_end_clean();
|
||||
} catch (\Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
// Try to parse library version
|
||||
$composerFile = \dirname(__DIR__, 3) . '/composer.lock';
|
||||
$version = false;
|
||||
|
||||
if (is_file($composerFile) === true) {
|
||||
$composerInfo = json_decode(file_get_contents($composerFile), true);
|
||||
|
||||
if (isset($composerInfo['packages']) === true && \is_array($composerInfo['packages']) === true) {
|
||||
foreach ($composerInfo['packages'] as $package) {
|
||||
if (isset($package['name']) === true && strtolower($package['name']) === 'pecee/simple-router') {
|
||||
$version = $package['version'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'url' => static::request()->getUrl(),
|
||||
'method' => static::request()->getMethod(),
|
||||
'host' => static::request()->getHost(),
|
||||
'loaded_routes' => static::request()->getLoadedRoutes(),
|
||||
'all_routes' => static::router()->getRoutes(),
|
||||
'boot_managers' => static::router()->getBootManagers(),
|
||||
'csrf_verifier' => static::router()->getCsrfVerifier(),
|
||||
'url' => static::request()->getUrl(),
|
||||
'method' => static::request()->getMethod(),
|
||||
'host' => static::request()->getHost(),
|
||||
'loaded_routes' => static::request()->getLoadedRoutes(),
|
||||
'all_routes' => static::router()->getRoutes(),
|
||||
'boot_managers' => static::router()->getBootManagers(),
|
||||
'csrf_verifier' => static::router()->getCsrfVerifier(),
|
||||
'log' => static::router()->getDebugLog(),
|
||||
'router_output' => $routerOutput,
|
||||
'library_version' => $version,
|
||||
'php_version' => PHP_VERSION,
|
||||
'server_params' => static::request()->getHeaders(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -31,21 +31,22 @@ class RouterUrlTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
// Test spanish characters
|
||||
TestRouter::get('/cursos/listado/{listado?}/{category?}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-]+']);
|
||||
TestRouter::get('/test/{param}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-\í]+']);
|
||||
TestRouter::debugNoReset('/cursos/listado/especialidad/cirugía local', 'get');
|
||||
|
||||
$this->assertEquals('/cursos/listado/{listado?}/{category?}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
|
||||
|
||||
TestRouter::debugNoReset('/test/Dermatología');
|
||||
$parameters = TestRouter::request()->getLoadedRoute()->getParameters();
|
||||
|
||||
$this->assertEquals('Dermatología', $parameters['param']);
|
||||
|
||||
// Test danish characters
|
||||
TestRouter::get('/kategori/økse', 'DummyController@method1', ['defaultParameterRegex' => '[\w\ø]+']);
|
||||
TestRouter::debugNoReset('/kategori/økse', 'get');
|
||||
|
||||
$this->assertEquals('/kategori/økse/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
|
||||
|
||||
TestRouter::get('/test/{param}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-\í]+']);
|
||||
TestRouter::debugNoReset('/test/Dermatología');
|
||||
|
||||
$parameters = TestRouter::request()->getLoadedRoute()->getParameters();
|
||||
|
||||
$this->assertEquals('Dermatología', $parameters['param']);
|
||||
|
||||
TestRouter::router()->reset();
|
||||
}
|
||||
|
||||
|
||||
9
tests/debug.php
Normal file
9
tests/debug.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
use \Pecee\SimpleRouter\SimpleRouter;
|
||||
|
||||
SimpleRouter::get('/user/{name}', 'UserController@show')->where(['name' => '[\w]+']);
|
||||
$debugInfo = SimpleRouter::startDebug();
|
||||
echo sprintf('<pre>%s</pre>', var_export($debugInfo, true));
|
||||
exit;
|
||||
Reference in New Issue
Block a user