Merge pull request #274 from skipperbent/v3

V3
This commit is contained in:
Simon Sessingø
2017-08-23 22:31:00 +02:00
committed by GitHub
15 changed files with 344 additions and 51 deletions
+73 -21
View File
@@ -22,6 +22,7 @@ If you want a great new feature or experience any issues what-so-ever, please fe
- [Installation](#installation)
- [Setting up Apache](#setting-up-apache)
- [Setting up Nginx](#setting-up-nginx)
- [Setting up IIS](#setting-up-iis)
- [Configuration](#configuration)
- [Helper functions](#helper-functions)
@@ -172,6 +173,45 @@ RewriteCond %{SCRIPT_FILENAME} !-l
RewriteRule ^(.*)$ index.php/$1
```
### Setting up IIS
On IIS you have to add some lines your `web.config` file in the `public` folder or create a new one. If rewriting is not working for you, please check that your IIS version have included the `url rewrite` module or download and install them from Microsoft web site.
#### web.config example
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 version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<!-- Remove slash '/' from the en of the url -->
<rule name="RewriteRequestsToPublic">
<match url="^(.*)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
</conditions>
<action type="Rewrite" url="/{R:0}" />
</rule>
<!-- When requested file or folder don't exists, will request again through index.php -->
<rule name="Imported Rule 1" stopProcessing="true">
<match url="^(.*)$" ignoreCase="true" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="/index.php/{R:1}" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
```
### Configuration
Create a new file, name it `routes.php` and place it in your library folder. This will be the file where you define all the routes for your project.
@@ -204,9 +244,9 @@ SimpleRouter::start();
### Helper functions
We recommend that you add these helper functions to your project. Theese will allow you to access functionality of the router more easily.
We recommend that you add these helper functions to your project. These will allow you to access functionality of the router more easily.
To implement the functions below, simply copy the code to a new file and require the file before initializing the router.
To implement the functions below, simply copy the code to a new file and require the file before initializing the router or copy the `helpers.php` we've included in this library.
```php
<?php
@@ -250,10 +290,18 @@ function request()
/**
* Get input class
* @return \Pecee\Http\Input\Input
* @param string|null $index Parameter index name
* @param string|null $defaultValue Default return value
* @param string|array|null $methods Default method
* @return \Pecee\Http\Input\Input|string
*/
function input()
function input($index = null, $defaultValue = null, $methods = null)
{
if($index !== null)
{
return request()->getInput()->get($index, $defaultValue, $methods);
}
return request()->getInput();
}
@@ -395,12 +443,12 @@ SimpleRouter::all('/ajax/abc/123', function($param1, $param2) {
### Custom regex for matching parameters
By default simple-php-router uses the `\w` regular expression when matching parameters.
By default simple-php-router uses the `\w` regular expression when matching parameters.
This decision was made with speed and reliability in mind, as this match will match both letters, number and most of the used symbols on the internet.
However, sometimes it can be necessary to add a custom regular expression to match more advanced characters like `-` etc.
However, sometimes it can be necessary to add a custom regular expression to match more advanced characters like `-` etc.
Instead of adding a custom regular expression to all your parameters, you can simply add a global regular expression which will be used on all the parameters on the route.
Instead of adding a custom regular expression to all your parameters, you can simply add a global regular expression which will be used on all the parameters on the route.
**Note:** If you the regular expression to be available across, we recommend using the global parameter on a group as demonstrated in the examples below.
@@ -663,18 +711,18 @@ ExceptionHandler are classes that handles all exceptions. ExceptionsHandlers mus
## Handling 404, 403 and other errors
If you simply want to catch a 404 (page not found) etc. you can use the `Router::error($callback)` static helper method.
If you simply want to catch a 404 (page not found) etc. you can use the `Router::error($callback)` static helper method.
This will add a callback method which is fired whenever an error occurs on all routes.
The basic example below simply redirect the page to `/not-found` if an `NotFoundHttpException` (404) occurred.
The basic example below simply redirect the page to `/not-found` if an `NotFoundHttpException` (404) occurred.
The code should be placed in the file that contains your routes.
```php
Router::get('/not-found', 'PageController@notFound');
Router::error(function(Request $request, \Exception $exception) {
if($exception instanceof NotFoundHttpException && $exception->getCode == 404) {
if($exception instanceof NotFoundHttpException && $exception->getCode() == 404) {
response()->redirect('/not-found');
}
});
@@ -698,7 +746,7 @@ class CustomExceptionHandler implements IExceptionHandler
/* You can use the exception handler to format errors depending on the request and type. */
if (stripos($request->getUri(), '/api') !== false) {
if (stripos($request->getUri()->getPath(), '/api') !== false) {
response()->json([
'error' => $error->getMessage(),
@@ -825,7 +873,7 @@ If items is grouped in the html, it will return an array of items.
**Note:** `get` will automatically trim the value and ensure that it's not empty. If it's empty the `$defaultValue` will be returned.
```php
$value = input()->get($index, $defaultValue, $methods);
$value = input($index, $defaultValue, $methods);
```
### Get parameter object
@@ -834,11 +882,11 @@ Will return an instance of `InputItem` or `InputFile` depending on the type.
You can use this in your html as it will render the value of the item.
However if you want to compare value in your if statements, you have to use
the `getValue` or use the `input()->get()` instead.
the `getValue` or use the `input()` instead.
If items is grouped in the html, it will return an array of items.
**Note:** `getObject` will only return `$defaultValue` if the item doesn't exist. If you want `$defaultValue` to be returned if the item is empty, please use `input()->get()` instead.
**Note:** `getObject` will only return `$defaultValue` if the item doesn't exist. If you want `$defaultValue` to be returned if the item is empty, please use `input()` instead.
```php
$object = input()->getObject($index, $defaultValue = null, $methods = null);
@@ -855,13 +903,17 @@ $object = input()->getObject($index, $defaultValue = null, $methods = null);
* $defaultValue is returned if the value is empty.
*/
$id = input()->get($index, $defaultValue);
$id = input()->get($index, $defaultValue, $method);
# -- shortcut to above --
$id = input($index, $defaultValue, $method);
# -- match specific --
$object = input()->get($index, $defaultValue, 'get');
$object = input()->get($index, $defaultValue, 'post');
$object = input()->get($index, $defaultValue, 'file');
$object = input($index, $defaultValue, 'get');
$object = input($index, $defaultValue, 'post');
$object = input($index, $defaultValue, 'file');
# -- or --
@@ -880,7 +932,7 @@ $object = input()->findFile($index, $defaultValue);
*/
/* @var $image \Pecee\Http\Input\InputFile */
foreach(input()->get('images', []) as $image)
foreach(input('images', []) as $image)
{
if($image->getMime() === 'image/jpeg') {
@@ -926,7 +978,7 @@ Below example requires you to have the helper functions added. Please refer to t
```php
/* Get parameter site_id or default-value 2 from either post-value or query-string */
$siteId = input()->get('site_id', 2, ['post', 'get']);
$siteId = input('site_id', 2, ['post', 'get']);
```
---
@@ -1079,7 +1131,7 @@ class CustomRouterRules implement IRouterBootManager {
// If the current uri matches the url, we use our custom route
if($request->getUri() === $url) {
if($request->getUri()->getPath() === $url) {
$request->setRewriteUrl($rule);
return $request;
}
+66
View File
@@ -0,0 +1,66 @@
<?php
use Pecee\SimpleRouter\SimpleRouter as Router;
/**
* Get url for a route by using either name/alias, class or method name.
*
* The name parameter supports the following values:
* - Route name
* - Controller/resource name (with or without method)
* - Controller class name
*
* When searching for controller/resource by name, you can use this syntax "route.name@method".
* You can also use the same syntax when searching for a specific controller-class "MyController@home".
* If no arguments is specified, it will return the url for the current loaded route.
*
* @param string|null $name
* @param string|array|null $parameters
* @param array|null $getParams
* @return string
*/
function url($name = null, $parameters = null, $getParams = null)
{
return Router::getUrl($name, $parameters, $getParams);
}
/**
* @return \Pecee\Http\Response
*/
function response()
{
return Router::response();
}
/**
* @return \Pecee\Http\Request
*/
function request()
{
return Router::request();
}
/**
* Get input class
* @param string|null $index Parameter index name
* @param string|null $defaultValue Default return value
* @param string|array|null $methods Default method
* @return \Pecee\Http\Input\Input|string
*/
function input($index = null, $defaultValue = null, $methods = null)
{
if ($index !== null) {
return request()->getInput()->get($index, $defaultValue, $methods);
}
return request()->getInput();
}
function redirect($url, $code = null)
{
if ($code !== null) {
response()->httpCode($code);
}
response()->redirect($url);
}
@@ -41,9 +41,9 @@ class BaseCsrfVerifier implements IMiddleware
$url = rtrim($url, '/');
if ($url[strlen($url) - 1] === '*') {
$url = rtrim($url, '*');
$skip = (stripos($request->getUri(), $url) === 0);
$skip = (stripos($request->getUri()->getPath(), $url) === 0);
} else {
$skip = ($url === rtrim($request->getUri(), '/'));
$skip = ($url === $request->getUri()->getPath());
}
if ($skip === true) {
+5 -5
View File
@@ -29,8 +29,8 @@ class Request
public function __construct()
{
$this->parseHeaders();
$this->host = $this->getHeader('http-host');
$this->uri = $this->getHeader('request-uri');
$this->setHost($this->getHeader('http-host'));
$this->setUri(new Uri($this->getHeader('request-uri')));
$this->input = new Input($this);
$this->method = strtolower($this->input->get('_method', $this->getHeader('request-method'), 'post'));
}
@@ -58,7 +58,7 @@ class Request
}
/**
* @return string
* @return Uri
*/
public function getUri()
{
@@ -215,9 +215,9 @@ class Request
}
/**
* @param string $uri
* @param Uri $uri
*/
public function setUri($uri)
public function setUri(Uri $uri)
{
$this->uri = $uri;
}
+1 -1
View File
@@ -41,7 +41,7 @@ class Response
public function refresh()
{
$this->redirect($this->request->getUri());
$this->redirect($this->request->getUri()->getPath());
}
/**
+172
View File
@@ -0,0 +1,172 @@
<?php
namespace Pecee\Http;
class Uri
{
private $originalUrl;
private $data = [
'scheme',
'host',
'port',
'user',
'pass',
'path',
'query',
'fragment',
];
public function __construct($url)
{
$this->originalUrl = $url;
$this->data = array_merge($this->data, $this->parseUrl($url));
if (isset($this->data['path']) === true && $this->data['path'] !== '/') {
$this->data['path'] = rtrim($this->data['path'], '/') . '/';
}
}
/**
* Check if url is using a secure protocol like https
* @return bool
*/
public function isSecure()
{
return (strtolower($this->getScheme()) === 'https');
}
/**
* Checks if url is relative
* @return bool
*/
public function isRelative()
{
return ($this->getHost() === null);
}
/**
* Get url scheme
* @return string|null
*/
public function getScheme()
{
return $this->data['scheme'];
}
/**
* Get url host
* @return string|null
*/
public function getHost()
{
return $this->data['host'];
}
/**
* Get url port
* @return int|null
*/
public function getPort()
{
return ($this->data['port'] !== null) ? (int)$this->data['port'] : null;
}
/**
* Parse username from url
* @return string|null
*/
public function getUserName()
{
return $this->data['user'];
}
/**
* Parse password from url
* @return string|null
*/
public function getPassword()
{
return $this->data['pass'];
}
/**
* Get path from url
* @return string
*/
public function getPath()
{
return $this->data['path'];
}
/**
* Get querystring from url
* @return string|null
*/
public function getQueryString()
{
return $this->data['query'];
}
/**
* Get fragment from url (everything after #)
* @return string|null
*/
public function getFragment()
{
return $this->data['fragment'];
}
/**
* @return string
*/
public function getOriginalUrl()
{
return $this->originalUrl;
}
/**
* UTF-8 aware parse_url() replacement.
* @param string $url
* @param int $component
* @throws \InvalidArgumentException
* @return array
*/
public function parseUrl($url, $component = -1)
{
$encodedUrl = preg_replace_callback(
'%[^:/@?&=#]+%u',
function ($matches) {
return urlencode($matches[0]);
},
$url
);
$parts = parse_url($encodedUrl, $component);
if ($parts === false) {
throw new \InvalidArgumentException('Malformed URL: ' . $url);
}
foreach ((array)$parts as $name => $value) {
$parts[$name] = urldecode($value);
}
return $parts;
}
/**
* Returns data array with information about the url
* @return array
*/
public function getData()
{
return $this->data;
}
public function __toString()
{
return $this->getOriginalUrl();
}
}
@@ -87,9 +87,6 @@ class RouteController extends LoadableRoute implements IControllerRoute
public function matchRoute($url, Request $request)
{
$url = parse_url(urldecode($url), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
/* Match global regular-expression for route */
$regexMatch = $this->matchRegex($request, $url);
@@ -79,9 +79,6 @@ class RouteResource extends LoadableRoute implements IControllerRoute
public function matchRoute($url, Request $request)
{
$url = parse_url(urldecode($url), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
/* Match global regular-expression for route */
$regexMatch = $this->matchRegex($request, $url);
@@ -14,9 +14,6 @@ class RouteUrl extends LoadableRoute
public function matchRoute($url, Request $request)
{
$url = parse_url(urldecode($url), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
/* Match global regular-expression for route */
$regexMatch = $this->matchRegex($request, $url);
+13 -8
View File
@@ -122,7 +122,7 @@ class Router
$exceptionHandlers = [];
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri();
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri()->getPath();
/* @var $route IRoute */
for ($i = $max; $i >= 0; $i--) {
@@ -224,7 +224,7 @@ class Router
}
}
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri();
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri()->getPath();
$max = count($this->processedRoutes) - 1;
@@ -248,6 +248,7 @@ class Router
if ($rewriteRoute !== null) {
$rewriteRoute->loadMiddleware($this->request);
return $rewriteRoute->renderRoute($this->request);
}
@@ -265,6 +266,7 @@ class Router
/* Render route */
$routeNotAllowed = false;
$this->request->setLoadedRoute($route);
return $route->renderRoute($this->request);
break;
@@ -284,9 +286,9 @@ class Router
$rewriteUrl = $this->request->getRewriteUrl();
if ($rewriteUrl !== null) {
$message = sprintf('Route not found: "%s" (rewrite from: "%s")', $rewriteUrl, $this->request->getUri());
$message = sprintf('Route not found: "%s" (rewrite from: "%s")', $rewriteUrl, $this->request->getUri()->getPath());
} else {
$message = sprintf('Route not found: "%s"', $this->request->getUri());
$message = sprintf('Route not found: "%s"', $this->request->getUri()->getPath());
}
$this->handleException(new NotFoundHttpException($message, 404));
@@ -300,7 +302,7 @@ class Router
*/
protected function handleException(\Exception $e)
{
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri();
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri()->getPath();
$max = count($this->exceptionHandlers);
@@ -323,6 +325,7 @@ class Router
if ($rewriteRoute !== null) {
$rewriteRoute->loadMiddleware($this->request);
return $rewriteRoute->renderRoute($this->request);
}
@@ -434,6 +437,10 @@ class Router
throw new \InvalidArgumentException('Invalid type for getParams. Must be array or null');
}
if ($name === '' && $parameters === '') {
return '/';
}
/* Only merge $_GET when all parameters are null */
if ($name === null && $parameters === null && $getParams === null) {
$getParams = $_GET;
@@ -443,9 +450,7 @@ class Router
/* Return current route if no options has been specified */
if ($name === null && $parameters === null) {
$url = rtrim(parse_url($this->request->getUri(), PHP_URL_PATH), '/');
return (($url === '') ? '/' : $url . '/') . $this->arrayToParams($getParams);
return $this->request->getUri()->getPath() . $this->arrayToParams($getParams);
}
$loadedRoute = $this->request->getLoadedRoute();
+1 -1
View File
@@ -7,7 +7,7 @@ class ExceptionHandlerFirst implements \Pecee\Handlers\IExceptionHandler
global $stack;
$stack[] = static::class;
$request->setUri('/');
$request->setUri(new \Pecee\Http\Uri('/'));
return $request;
}
@@ -7,7 +7,7 @@ class ExceptionHandlerSecond implements \Pecee\Handlers\IExceptionHandler
global $stack;
$stack[] = static::class;
$request->setUri('/');
$request->setUri(new \Pecee\Http\Uri('/'));
return $request;
}
+1 -1
View File
@@ -5,7 +5,7 @@ class TestRouter extends \Pecee\SimpleRouter\SimpleRouter
public static function debugNoReset($testUri, $testMethod = 'get')
{
static::request()->setUri($testUri);
static::request()->setUri(new \Pecee\Http\Uri($testUri));
static::request()->setMethod($testMethod);
static::start();
+1 -1
View File
@@ -64,7 +64,7 @@ class RouteRewriteTest extends PHPUnit_Framework_TestCase
TestRouter::error(function (\Pecee\Http\Request $request, \Exception $error) {
if (strtolower($request->getUri()) == '/my/test') {
if (strtolower($request->getUri()->getPath()) == '/my/test') {
$request->setRewriteUrl('/another-non-existing');
return $request;
+8 -1
View File
@@ -31,7 +31,7 @@ class RouterUrlTest extends PHPUnit_Framework_TestCase
public function testUnicodeCharacters()
{
// Test spanish characters
TestRouter::get('/cursos/listado/{listado?}/{category?}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-]+']);
TestRouter::get('/cursos/listado/{listado?}/{category?}', '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());
@@ -40,6 +40,13 @@ class RouterUrlTest extends PHPUnit_Framework_TestCase
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();
}