diff --git a/README.md b/README.md
index 58f4919..b7eb3ac 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,89 @@
# 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.
-## Installation
+**Note: this documentation is currently work-in-progress. Feel free to contribute.**
+
+### Notes
+
+The goal of this project is to create a router that is more or less 100% compatible with the Laravel documentation, while remaining as simple as possible, and as easy to integrate and change without compromising either speed or complexity. Being lightweight is the #1 priority.
+
+### Ideas and issues
+
+If you want a great new feature or experience any issues what-so-ever, please feel free to leave an issue and i'll look into it whenever possible.
+
+---
+
+## Table of Contents
+
+- Gettings started
+ - Requirements
+ - Notes
+ - Features
+ - Installation
+ - Setting up Apache
+ - Setting up Nginx
+ - Setting up simple-php-router
+ - Helper methods
+
+- Routes
+ - Basic routing
+ - Available methods
+ - Multiple HTTP-verbs
+ - Route parameters
+ - Required parameters
+ - Optional parameters
+ - Regular expression constraints
+ - Regular expression route-match
+ - Named routes
+ - Generating URLs To Named Routes
+ - Router groups
+ - Middleware
+ - Namespaces
+ - Subdomain-routing
+ - Route prefixes
+ - Form Method Spoofing
+ - Accessing The Current Route
+ - Other examples
+
+- CSRF-protection
+ - Adding CSRF-verifier
+ - Getting CSRF-token
+
+- Middleware
+ - Example
+- ExceptionHandler
+ - Example
+
+- Urls
+ - Get by name (single route)
+ - Get by name (controller route)
+ - Get by class
+ - Get by custom names for methods on a controller/resource route
+ - Getting REST/resource controller urls
+
+- Input & parameters
+ - Return single parameter value
+ - Return single parameter object
+ - Managing files
+ - Return all parameters
+
+- Advanced
+ - Bootmanager: loading routes dynamically
+ - Ovewrite route about to be loaded
+ - Examples
+ - Rewriting to new route
+ - Changing callback
+
+ - Adding routes manually
+ - Extending
+
+- Credits
+ - Sites
+ - License
+
+___
+
+# Getting started
Add the latest version of Simple PHP Router running this command.
```
@@ -11,12 +93,29 @@ composer require pecee/simple-router
## Requirements
- PHP 5.4 or greater
+- mcrypt extension
## Notes
-The goal of this project is to create a router that is 100% compatible with the Laravel documentation, but as simple as possible and as easy to integrate and change as possible.
+We've included a simple demo project for the router which can be found in the `demo-project` folder. This project should give you a basic understanding of how to setup and use simple-php-router project.
-### Features
+Please note that the demo-project only covers how to integrate the `simple-php-router` in a project without an existing framework. If you are using a framework in your project, the implementation might vary.
+
+You can find the demo-project here: [https://github.com/skipperbent/simple-router-demo](https://github.com/skipperbent/simple-router-demo)
+
+**What we won't cover:**
+
+- How to setup a solution that fits your need. This is a basic demo to help you get started.
+- Understanding of MVC; including Controllers, Middlewares or ExceptionHandlers.
+- How to integrate into third party frameworks.
+
+**What we cover:**
+
+- How to get up and running fast - from scratch.
+- How to get ExceptionHandlers, Middlewares and Controllers working.
+- How to setup your webservers.
+
+## Features
- Basic routing (`GET`, `POST`, `PUT`, `PATCH`, `UPDATE`, `DELETE`) with support for custom multiple verbs.
- Regular Expression Constraints for parameters.
@@ -32,27 +131,50 @@ The goal of this project is to create a router that is 100% compatible with the
- Custom boot managers to rewrite urls to "nicer" ones.
- Input manager; easily manage `GET`, `POST` and `FILE` values.
-## Installation and demo
+## Installation
-We've included a simple demo project for the router which can be found in the `demo-project` folder.
-
-Please refer to the demo-project documentation for further reading on how to setup and install simple-php-router:
-
-[Link to demo documentation](demo-project/README.md)
-
-## Initialising the router
-
-In your ```index.php``` require your ```routes.php``` and call the ```routeRequest()``` method when all your custom routes has been loaded. This will trigger and do the actual routing of the requests.
-
-This is an example of a basic ```index.php``` file:
+1. Navigate to your project folder in terminal and run the following command:
```php
-use \Pecee\SimpleRouter\SimpleRouter;
+composer require pecee/simple-router
+```
-// Load external routes file
+### Setting up Nginx
+
+If you are using Nginx please make sure that url-rewriting is enabled.
+
+You can easily enable url-rewriting by adding the following configuration for the Nginx configuration-file for the demo-project.
+
+```
+location / {
+ try_files $uri $uri/ /index.php?$query_string;
+}
+```
+
+### Setting up Apache
+
+Nothing special is required for Apache to work. We've include the `.htaccess` file in the `public` folder. If rewriting is not working for you, please check that the `mod_rewrite` module (htaccess support) is enabled in the Apache configuration.
+
+### Setting up simple-php-router
+
+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.
+
+**WARNING: NEVER PLACE YOUR ROUTES.PHP IN YOUR PUBLIC FOLDER!**
+
+In your ```index.php``` require your newly-created ```routes.php``` and call the ```SimpleRouter::start()``` method. This will trigger and do the actual routing of the requests.
+
+It's not required, but you can set `SimpleRouter::setDefaultNamespace('\Demo\Controllers');` to prefix all routes with the namespace to your controllers. This will simplify things a bit, as you won't have to specify the namespace for your controllers on each route.
+
+**This is an example of a basic ```index.php``` file:**
+
+```php
+ 'Middlewares\Site', 'exceptionHandler' => 'Handlers\CustomExceptionHandler'], function() {
-
-
- SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show', ['where' => ['id' => '[0-9]+']]);
-
- /**
- * Using optional parameters
- */
- SimpleRouter::get('/answers/{id?}', 'ControllerAnswers@show');
-
-
- /**
- * This example will route url when matching the regular expression to the method.
- * For example route: domain.com/ajax/music/world -> ControllerAjax@process (parameter: music/world)
- */
-
- SimpleRouter::all('/ajax', 'ControllerAjax@process')->setMatch('.*?\\/ajax\\/([A-Za-z0-9\\/]+)');
-
-
- /**
- * Restful resource (see IRestController interface for available methods)
- */
-
- SimpleRouter::resource('/rest', 'ControllerRessource');
-
-
- /**
- * Load the entire controller (where url matches method names - getIndex(), postIndex(), putIndex()).
- * The url paths will determine which method to render.
- *
- * For example:
- *
- * GET /animals => getIndex()
- * GET /animals/view => getView()
- * POST /animals/save => postSave()
- *
- * etc.
- */
-
- SimpleRouter::controller('/animals', 'ControllerAnimals');
-
-
- /**
- * Example of providing callback instead of Controller
- */
-
- SimpleRouter::post('/something', function() {
-
- die('Callback example');
-
- });
-
-});
-
-SimpleRouter::get('/page/404', 'ControllerPage@notFound', ['as' => 'page.notfound']);
-
-```
-
-#### ExceptionHandler example
-
-This is a basic example of an ExceptionHandler implementation (please see "[Easily overwrite route about to be loaded](#easily-overwrite-route-about-to-be-loaded)" for examples on how to change callback).
-
-```php
-namespace Demo\Handlers;
-
-use Pecee\Handlers\IExceptionHandler;
-use Pecee\Http\Request;
-use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
-use Pecee\SimpleRouter\Route\ILoadableRoute;
-
-class CustomExceptionHandler implements IExceptionHandler
-{
- public function handleError(Request $request, ILoadableRoute &$route = null, \Exception $error)
- {
-
- /* You can use the exception handler to format errors depending on the request and type. */
-
- if (stripos($request->getUri(), '/api') !== false) {
-
- response()->json([
- 'error' => $error->getMessage(),
- 'code' => $error->getCode(),
- ]);
-
- }
-
- /* The router will throw the NotFoundHttpException on 404 */
- if($error instanceof NotFoundHttpException) {
-
- /*
- * Render your own custom 404-view, rewrite the request to another route,
- * or simply return the $request object to ignore the error and continue on rendering the route.
- *
- * The code below will make the router render our page.notfound route.
- */
-
- $request->setUri(url('page.notfound'));
- return $request;
-
- }
-
- throw $error;
-
- }
-
-}
-```
-
-### Sub-domain routing
-
-Route groups may also be used to route wildcard sub-domains. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the ```domain``` key on the group attribute array:
-
-```php
-Route::group(['domain' => '{account}.myapp.com'], function () {
-
- Route::get('user/{id}', function ($account, $id) {
- // Do stuff...
- });
-
-});
-```
-
-The prefix group array attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with admin:
-
-### Adding routes manually (with no helper)
-
-The ```SimpleRouter``` class referenced in the previous example, is just a simple helper class that knows how to communicate with the ```Router``` class.
-If you are up for a challenge, want the full control or simply just want to create your own ```Router``` helper class, this example is for you.
-
-```php
-use \Pecee\SimpleRouter\Router;
-use \Pecee\SimpleRouter\Route\RouteUrl;
-
-/* Grap the router instance */
-$router = Router::getInstance();
-
-$route = new RouteUrl('/answer/1', function() {
-
- die('this callback will match /answer/1');
-
-});
-
-$route->setMiddleware('\Demo\Middlewares\AuthMiddleware');
-$route->setNamespace('\Demo\Controllers');
-$route->setPrefix('v1');
-
-/* Add the route to the router */
-$router->addRoute($route);
-```
-
-### Extending
-
-This is a simple example of an integration into a framework.
-
-The framework has it's own ```Router``` class which inherits from the ```SimpleRouter``` class. This allows the framework to add custom functionality like loading a custom `routes.php` file or add debugging information etc.
-
-```php
-namespace Demo;
-
-use Pecee\SimpleRouter\SimpleRouter;
-
-class Router extends SimpleRouter {
-
- public static function start() {
-
- // change this to whatever makes sense in your project
- require_once 'routes.php';
-
- // change default namespace for all routes
- parent::setDefaultNamespace('\Demo\Controllers');
-
- // Do initial stuff
- parent::start();
-
- }
-
-}
-```
-
-## Helper functions
-
-To simplify to use of simple-router functionality, we recommend you add these helper functions to your project.
+To implement the functions below, simply copy the code to a new file and require the file before initializing the router.
```php
+where('name', '[A-Za-z]+');
+
+SimpleRouter::get('/user/{id}', function ($id) {
+ //
+})->where('id', '[0-9]+');
+
+SimpleRouter::get('/user/{id}/{name}', function ($id, $name) {
+ //
+})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
+```
+
+### Regular expression route-match
+
+You can define a regular-expression match for the entire route if you wish.
+
+This is useful if you for example are creating a model-box which loads urls from ajax.
+
+The example below is using the following regular expression: `/ajax/([\w]+)/?([0-9]+)?/?` which basically just matches `/ajax/` and exspects the next parameter to be a string - and the next to be a number (but optional).
+
+**Matches:** `/ajax/abc/`, `/ajax/abc/123/`
+
+**Doesn't match:** `/ajax/`
+
+Match groups specified in the regex will be passed on as parameters:
+
+```php
+SimpleRouter::all('/ajax/abc/123', function($param1, $param2) {
+ // param1 = abc
+ // param2 = 123
+})->setMatch('/\/ajax\/([\w]+)\/?([0-9]+)?\/?/is');
+```
+
+## Named routes
+
+Named routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route by chaining the name method onto the route definition:
+
+```php
+SimpleRouter::get('/user/profile', function () {
+ //
+})->name('profile');
+```
+
+You can also specify names for Controller-actions:
+
+```php
+SimpleRouter::get('/user/profile', 'UserController@profile')->name('profile');
+```
+
+### Generating URLs To Named Routes
+
+Once you have assigned a name to a given route, you may use the route's name when generating URLs or redirects via the global `url` helper-function (see helpers section):
+
+```php
+// Generating URLs...
+$url = url('profile');
+```
+
+If the named route defines parameters, you may pass the parameters as the second argument to the `url` function. The given parameters will automatically be inserted into the URL in their correct positions:
+
+```php
+SimpleRouter::get('/user/{id}/profile', function ($id) {
+ //
+})->name('profile');
+
+$url = url('profile', ['id' => 1]);
+```
+
+For more information on urls, please see the [Urls](#urls) section.
+
+## Router groups
+
+Route groups allow you to share route attributes, such as middleware or namespaces, across a large number of routes without needing to define those attributes on each individual route. Shared attributes are specified in an array format as the first parameter to the `SimpleRouter::group` method.
+
+### Middleware
+
+To assign middleware to all routes within a group, you may use the middleware key in the group attribute array. Middleware are executed in the order they are listed in the array:
+
+```php
+SimpleRouter::group(['middleware' => '\Demo\Middleware\Auth'], function () {
+ SimpleRouter::get('/', function () {
+ // Uses Auth Middleware
+ });
+
+ SimpleRouter::get('/user/profile', function () {
+ // Uses Auth Middleware
+ });
+});
+```
+
+### Namespaces
+
+Another common use-case for route groups is assigning the same PHP namespace to a group of controllers using the `namespace` parameter in the group array:
+
+```php
+SimpleRouter::group(['namespace' => 'Admin'], function () {
+ // Controllers Within The "App\Http\Controllers\Admin" Namespace
+});
+```
+
+### Subdomain-routing
+
+Route groups may also be used to handle sub-domain routing. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the `domain` key on the group attribute array:
+
+```php
+SimpleRouter::group(['domain' => '{account}.myapp.com'], function () {
+ SimpleRouter::get('/user/{id}', function ($account, $id) {
+ //
+ });
+});
+```
+
+### Route prefixes
+
+The `prefix` group attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with `admin`:
+
+```php
+SimpleRouter::group(['prefix' => '/admin'], function () {
+ SimpleRouter::get('/users', function () {
+ // Matches The "/admin/users" URL
+ });
+});
+```
+
+## Form Method Spoofing
+
+HTML forms do not support `PUT`, `PATCH` or `DELETE` actions. So, when defining `PUT`, `PATCH` or `DELETE` routes that are called from an HTML form, you will need to add a hidden `_method` field to the form. The value sent with the `_method` field will be used as the HTTP request method:
+
+```php
+
+```
+
+## Accessing The Current Route
+
+You can access information about the current route loaded by using the following method:
+
+```php
+SimpleRouter::router()->getLoadedRoute();
+```
+
+## Other examples
+
+You can find many more examples in the `routes.php` example-file below:
+
+```php
+ '\Demo\Middlewares\Site', 'exceptionHandler' => 'Handlers\CustomExceptionHandler'], function() {
+
+
+ SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show', ['where' => ['id' => '[0-9]+']]);
+
+
+ /**
+ * Restful resource (see IRestController interface for available methods)
+ */
+
+ SimpleRouter::resource('/rest', 'ControllerRessource');
+
+
+ /**
+ * Load the entire controller (where url matches method names - getIndex(), postIndex(), putIndex()).
+ * The url paths will determine which method to render.
+ *
+ * For example:
+ *
+ * GET /animals => getIndex()
+ * GET /animals/view => getView()
+ * POST /animals/save => postSave()
+ *
+ * etc.
+ */
+
+ SimpleRouter::controller('/animals', 'ControllerAnimals');
+
+});
+
+SimpleRouter::get('/page/404', 'ControllerPage@notFound', ['as' => 'page.notfound']);
+
+```
+
+---
+
+# CSRF Protection
+
+Any forms posting to `POST`, `PUT` or `DELETE` routes should include the CSRF-token. We strongly recommend that you create your enable CSRF-verification on your site.
+
+Create a new class and extend the ```BaseCsrfVerifier``` middleware class provided with simple-php-router.
+
+Add the property ```except``` with an array of the urls to the routes you would like to exclude/whitelist from the CSRF validation. Using ```*``` at the end for the url will match the entire url.
+
+**Here's a basic example on a CSRF-verifier class:**
+
+```php
+namespace Demo\Middlewares;
+
+use Pecee\Http\Middleware\BaseCsrfVerifier;
+
+class CsrfVerifier extends BaseCsrfVerifier
+{
+ /**
+ * CSRF validation will be ignored on the following urls.
+ */
+ protected $except = ['/api/*'];
+}
+```
+
+## Adding CSRF-verifier
+
+When you've created your CSRF verifier - you need to tell simple-php-router that it should use it. You can do this by adding the following line in your `routes.php` file:
+
+```php
+Router::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
+```
+
+## Getting CSRF-token
+
+When posting to any of the urls that has CSRF-verification enabled, you need post your CSRF-token or else the request will get rejected.
+
+You can get the CSRF-token by calling the helper method:
+
+```php
+csrf_token();
+```
+
+---
+
+# Middlewares
+
+Middlewares are classes that loads before the route is rendered. A middleware can be used to verify that a user is logged in - or to set parameters specific for the current request/route. Middlewares must implement the `IMiddleware` interface.
+
+## Example
+
+```php
+namespace Demo\Middlewares;
+
+use Pecee\Http\Middleware\IMiddleware;
+use Pecee\Http\Request;
+use Pecee\SimpleRouter\Route\ILoadableRoute;
+
+class CustomMiddleware implements Middleware {
+
+ public function handle(Request $request, ILoadableRoute &$route) {
+
+ $request->setUri(url('home'));
+
+ }
+}
+```
+
+---
+
+# ExceptionHandler
+
+ExceptionHandler are classes that handles all exceptions. ExceptionsHandlers must implement the `IExceptionHandler` interface.
+
+## Example
+
+Resource controllers can implement the `IRestController` interface, but is not required.
+
+This is a basic example of an ExceptionHandler implementation (please see "[Easily overwrite route about to be loaded](#easily-overwrite-route-about-to-be-loaded)" for examples on how to change callback).
+
+```php
+namespace Demo\Handlers;
+
+use Pecee\Handlers\IExceptionHandler;
+use Pecee\Http\Request;
+use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
+use Pecee\SimpleRouter\Route\ILoadableRoute;
+
+class CustomExceptionHandler implements IExceptionHandler
+{
+ public function handleError(Request $request, ILoadableRoute &$route = null, \Exception $error)
+ {
+
+ /* You can use the exception handler to format errors depending on the request and type. */
+
+ if (stripos($request->getUri(), '/api') !== false) {
+
+ response()->json([
+ 'error' => $error->getMessage(),
+ 'code' => $error->getCode(),
+ ]);
+
+ }
+
+ /* The router will throw the NotFoundHttpException on 404 */
+ if($error instanceof NotFoundHttpException) {
+
+ /*
+ * Render your own custom 404-view, rewrite the request to another route,
+ * or simply return the $request object to ignore the error and continue on rendering the route.
+ *
+ * The code below will make the router render our page.notfound route.
+ */
+
+ $request->setUri(url('page.notfound'));
+ return $request;
+
+ }
+
+ throw $error;
+
+ }
+
+}
+```
+
+---
+
+# Urls
By default all controller and resource routes will use a simplified version of their url as name.
-**Get routes using custom name (single route)**
+### Get routes using custom name (single route)
```php
SimpleRouter::get('/product-view/{id}', 'ProductsController@show', ['as' => 'product']);
url('product', ['id' => 22], ['category' => 'shoes']);
+url('product', null, ['category' => 'shoes']);
# output
# /product-view/22/?category=shoes
+# /product-view/?category=shoes
```
-**Getting the url using the name (controller route)**
+### Getting the url using the name (controller route)
```php
SimpleRouter::controller('/images', 'ImagesController', ['as' => 'picture']);
url('picture@getView', null, ['category' => 'shoes']);
url('picture', 'getView', ['category' => 'shoes']);
+url('picture', 'view');
# output
# /images/view/?category=shows
# /images/view/?category=shows
+# /images/view/
```
-**Getting the url using class**
+### Getting the url using class
```php
SimpleRouter::get('/product-view/{id}', 'ProductsController@show', ['as' => 'product']);
@@ -370,10 +700,10 @@ url('ImagesController@getImage', null, ['id' => 22]);
# output
# /product-view/22/?category=shoes
-# /images/image/?category=shows
+# /images/image/?id=22
```
-**Using custom names for methods on a controller/resource route**
+### Using custom names for methods on a controller/resource route
```php
SimpleRouter::controller('gadgets', 'GadgetsController', ['names' => ['getIphoneInfo' => 'iphone']]);
@@ -384,7 +714,7 @@ url('gadgets.iphone');
# /gadgets/iphoneinfo/
```
-**Getting REST/resource controller urls**
+### Getting REST/resource controller urls
```php
SimpleRouter::resource('/phones', 'PhonesController');
@@ -402,39 +732,136 @@ url('phones.edit');
# /phones/edit/
```
-**Return the current url**
+### Return the current url
+
```php
url();
+url(null, null, ['q' => 'cars']);
+
+# output
+# /CURRENT-URL/
+# /CURRENT-URL/?q=cars
```
-## Custom CSRF verifier
+# Input & parameters
-Create a new class and extend the ```BaseCsrfVerifier``` middleware class provided with simple-php-router.
+## Using the Input class to manage parameters
-Add the property ```except``` with an array of the urls to the routes you would like to exclude from the CSRF validation. Using ```*``` at the end for the url will match the entire url.
+We've added the `Input` class to easy access and manage parameters from your Controller-classes.
-Querystrings are ignored.
+**Return single parameter value (matches both GET, POST, FILE):**
+
+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
-use Pecee\Http\Middleware\BaseCsrfVerifier;
+$value = input()->get($index, $defaultValue);
+```
-class CsrfVerifier extends BaseCsrfVerifier {
+**Return parameter object (matches both GET, POST, FILE):**
- protected $except = [
- '/companies/*',
- '/api',
- ];
+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.
+
+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.
+
+```php
+$object = input()->getObject($index);
+```
+
+**Return specific GET parameter (where name is the name of your parameter):**
+
+```php
+# -- match any (default) --
+
+/*
+ * This is the recommended way to go for normal usage
+ * as it will strip empty values, ensuring that
+ * $defaultValue is returned if the value is empty.
+ */
+
+$id = input()->get($index, $defaultValue);
+
+# -- match specific --
+
+$object = input()->get($index, $defaultValue, 'get');
+$object = input()->get($index, $defaultValue, 'post');
+$object = input()->get($index, $defaultValue, 'file');
+
+# -- or --
+
+$object = input()->findGet($index, $defaultValue);
+$object = input()->findPost($index, $defaultValue);
+$object = input()->findFile($index, $defaultValue);
+
+# -- examples --
+
+/**
+ * In this small example we loop through a collection of files
+ * added on the page like this
+ *
+ */
+
+/* @var $image \Pecee\Http\Input\InputFile */
+foreach(input()->get('images', []) as $image)
+{
+ if($image->getMime() === 'image/jpeg') {
+
+ $destinationFilname = sprintf('%s.%s', uniqid(), $image->getExtension());
+
+ $image->move('/uploads/' . $destinationFilename);
+
+ }
}
```
-Register the new class in your ```routes.php```, custom ```Router``` class or wherever you register your routes.
+**Return all parameters:**
```php
-SimpleRouter::csrfVerifier(new \Demo\Middleware\CsrfVerifier());
+// Get all
+$values = input()->all();
+
+// Only match certain keys
+$values = input()->all([
+ 'company_name',
+ 'user_id'
+]);
```
-## Using router bootmanager to make custom rewrite rules
+All object implements the `IInputItem` interface and will always contain these methods:
+
+- `getIndex()` - returns the index/key of the input.
+- `getName()` - returns a human friendly name for the input (company_name will be Company Name etc).
+- `getValue()` - returns the value of the input.
+
+`InputFile` has the same methods as above along with some other file-specific methods like:
+- `getTmpName()` - get file temporary name.
+- `getSize()` - get file size.
+- `move($destination)` - move file to destination.
+- `getContents()` - get file content.
+- `getType()` - get mime-type for file.
+- `getError()` - get file upload error.
+- `hasError()` - returns `bool` if an error occurred while uploading (if getError is not 0).
+- `toArray()` - returns raw array
+
+Below example requires you to have the helper functions added. Please refer to the helper functions section in the documentation.
+
+```php
+// Get parameter site_id or default-value 2
+$siteId = input()->get('site_id', 2);
+```
+
+---
+
+# Advanced
+
+## Load routes dynamicially using the router bootmanager
Sometimes it can be necessary to keep urls stored in the database, file or similar. In this example, we want the url ```/my-cat-is-beatiful``` to load the route ```/article/view/1``` which the router knows, because it's defined in the ```routes.php``` file.
@@ -466,7 +893,6 @@ class CustomRouterRules implement IRouterBootManager {
}
}
-
```
The above should be pretty self-explanatory and can easily be changed to loop through urls store in the database, file or cache.
@@ -477,6 +903,10 @@ By doing this the route will now load the url ```/article/view/1``` instead of `
The last thing we need to do, is to add our custom boot-manager to the ```routes.php``` file. You can create as many bootmanagers as you like and easily add them in your ```routes.php``` file.
+```php
+SimpleRouter::addBootManager(new CustomRouterRules());
+```
+
## Easily overwrite route about to be loaded
Sometimes it can be useful to manipulate the route about to be loaded.
simple-php-router allows you to easily change the route about to be executed.
@@ -497,7 +927,6 @@ $route->setClass('Example\MyCustomClass');
$route->setMethod('hello');
```
-
### Examples
It's only possible to change the route BEFORE the route has initially been loaded. If you want to redirect to another route, we highly recommend that you
@@ -524,9 +953,7 @@ class CustomMiddleware implements Middleware {
$request->setUri(url('home'));
}
-
}
-
```
#### Changing callback
@@ -556,69 +983,64 @@ class CustomMiddleware implements Middleware {
}
```
-## Using the Input class to manage parameters
+## Adding routes manually
-We've added the `Input` class to easy access parameters from your Controller-classes.
-
-**Return single parameter value (matches both GET, POST, FILE):**
+The ```SimpleRouter``` class referenced in the previous example, is just a simple helper class that knows how to communicate with the ```Router``` class.
+If you are up for a challenge, want the full control or simply just want to create your own ```Router``` helper class, this example is for you.
```php
-$value = input()->get('name');
+use \Pecee\SimpleRouter\Router;
+use \Pecee\SimpleRouter\Route\RouteUrl;
+
+/* Grap the router instance */
+$router = Router::getInstance();
+
+$route = new RouteUrl('/answer/1', function() {
+
+ die('this callback will match /answer/1');
+
+});
+
+$route->setMiddleware('\Demo\Middlewares\AuthMiddleware');
+$route->setNamespace('\Demo\Controllers');
+$route->setPrefix('v1');
+
+/* Add the route to the router */
+$router->addRoute($route);
```
-**Return parameter object (matches both GET, POST, FILE):**
+## Extending
+
+This is a simple example of an integration into a framework.
+
+The framework has it's own ```Router``` class which inherits from the ```SimpleRouter``` class. This allows the framework to add custom functionality like loading a custom `routes.php` file or add debugging information etc.
```php
-$object = input()->getObject('name');
+namespace Demo;
+
+use Pecee\SimpleRouter\SimpleRouter;
+
+class Router extends SimpleRouter {
+
+ public static function start() {
+
+ // change this to whatever makes sense in your project
+ require_once 'routes.php';
+
+ // change default namespace for all routes
+ parent::setDefaultNamespace('\Demo\Controllers');
+
+ // Do initial stuff
+ parent::start();
+
+ }
+
+}
```
-**Return specific GET parameter (where name is the name of your parameter):**
+---
-```php
-$object = input()->get->name;
-$object = input()->post->name;
-$object = input()->file->name;
-
-# -- or --
-
-$object = input()->get->get($key, $defaultValue);
-$object = input()->post->get($key, $defaultValue);
-$object = input()->file->get($key, $defaultValue);
-```
-
-**Return all parameters:**
-
-```php
-// Get all
-$values = input()->all();
-
-// Only match certain keys
-$values = input()->all([
- 'company_name',
- 'user_id'
-]);
-```
-
-All object inherits from `InputItem` class and will always contain these methods:
-
-- `getValue()` - returns the value of the input.
-- `getIndex()` - returns the index/key of the input.
-- `getName()` - returns a human friendly name for the input (company_name will be Company Name etc).
-
-`InputFile` has the same methods as above along with some other file-specific methods like:
-- `getTmpName()` - get file temporary name.
-- `getSize()` - get file size.
-- `move($destination)` - move file to destination.
-- `getContents()` - get file content.
-- `getType()` - get mime-type for file.
-- `getError()` - get file upload error.
-
-Below example requires you to have the helper functions added. Please refer to the helper functions section in the documentation.
-
-```php
-// Get parameter site_id or default-value 2
-$siteId = input()->get('site_id', 2);
-```
+# Credits
## Sites
This is some sites that uses the simple-router project in production.
@@ -628,18 +1050,9 @@ This is some sites that uses the simple-router project in production.
- [bookandbegin.com](https://bookandbegin.com)
- [dscuz.com](https://www.dscuz.com)
-## Documentation
-While I work on a better documentation, please refer to the Laravel 5 routing documentation here:
+## License
-http://laravel.com/docs/5.1/routing
-
-## Easily extendable
-The router can be easily extended to customize your needs.
-
-## Ideas and issues
-If you want a great new feature or experience any issues what-so-ever, please feel free to leave an issue and i'll look into it whenever possible.
-
-## The MIT License (MIT)
+### The MIT License (MIT)
Copyright (c) 2016 Simon Sessingø / simple-php-router
diff --git a/demo-project/README.md b/demo-project/README.md
deleted file mode 100644
index ee0ec84..0000000
--- a/demo-project/README.md
+++ /dev/null
@@ -1,100 +0,0 @@
-# Simple PHP router demo project
-
-This project is here to give you a basic understanding of how to setup and using simple-php-router.
-
-Please note that this demo-project only covers how to integrate the `simple-php-router` in a project without a framework. If you are using some sort of PHP framework in your project the implementation might vary.
-
-**What we won't cover:**
-
-- How to setup a solution that fits your need. This is a basic demo to help you get started.
-- Understanding of MVC; including Controllers, Middlewares or ExceptionHandlers.
-- How to integrate into third party frameworks.
-
-**What we cover:**
-
-- How to get up and running fast - from scratch.
-- How to get ExceptionHandlers, Middlewares and Controllers working.
-- How to setup your webservers.
-
-## Installation
-
-- Navigate to the `demo-project` folder in terminal and run `composer update` to install the latest version.
-- Point your webserver to `demo-project/public`.
-
-### Setting up Nginx
-
-If you are using Nginx please make sure that url-rewriting is enabled.
-
-You can easily enable url-rewriting by adding the following configuration for the Nginx configuration-file for the demo-project.
-
-```
-location / {
- try_files $uri $uri/ /index.php?$query_string;
-}
-```
-
-### Setting up Apache
-
-Nothing special is required for Apache to work. We've include the `.htaccess` file in the `public` folder. If rewriting is not working for you, please check that the `mod_rewrite` module (htaccess support) is enabled in the Apache configuration.
-
-## Folder structure
-
-| Folder | Description |
-| ------------- |-------------|
-| app |Contains projects-specific PHP classes|
-| public |Public folder which are accessible through the web.|
-
-## Notes
-
-The demo project has it's own `Router` class implementation which extends the `SimpleRouter` class with further functionality.
-This class can be useful adding additional functionality that are required before and after routing occurs or any extra functionality belonging to the router itself.
-
-In this project we also use our custom router-class to autoload the `routes.php` file from our custom location (`app/routes.php`).
-
-Please check the `routes.php` file in `demo-project/app` for all the urls/rules available in the project.
-
-### CSRF-verifier
-
-For the purpose of this demo, we've added a custom CSRF-verifier middleware called `CsrfVerifier` and disabled CSRF checks for all calls to `/api/*`. This will ensure that CSRF form-checks are not applied when calling our demo api url.
-
-### Exception handlers
-
-The included `CustomExceptionHandler` class returns a very basic json response for errors received on calls to `/api/*` or otherwise just a simple formatted error response.
-
-### Middlewares
-
-`ApiVerification` class is added to all calls to `/api/*`. This simple class just adds some data to the `Request` object, which is returned in one of the methods in the `ApiController` class. We've added this class to demonstrate that you can use middlewares to ensure that the user has the correct authentication - before router loads the controller itself.
-
-### Urls
-
-Please see `routes.php` for all routes and rules.
-
-| URL |
-| ------------- |
-| / |
-| /api/demo |
-| /companies |
-| /companies/[id] |
-| /contact |
-
-## The MIT License (MIT)
-
-Copyright (c) 2016 Simon Sessingø / simple-php-router
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/demo-project/app/Controllers/ApiController.php b/demo-project/app/Controllers/ApiController.php
deleted file mode 100644
index e163233..0000000
--- a/demo-project/app/Controllers/ApiController.php
+++ /dev/null
@@ -1,16 +0,0 @@
- request()->authenticated
- ]);
- }
-
-}
\ No newline at end of file
diff --git a/demo-project/app/Controllers/DefaultController.php b/demo-project/app/Controllers/DefaultController.php
deleted file mode 100644
index ee1f9ff..0000000
--- a/demo-project/app/Controllers/DefaultController.php
+++ /dev/null
@@ -1,27 +0,0 @@
- index (?fun=%s)', input()->get('fun'));
- }
-
- public function contact()
- {
- echo 'DefaultController -> contact';
- }
-
- public function companies($id = null)
- {
- echo 'DefaultController -> companies -> id: ' . $id;
- }
-
- public function notFound()
- {
- echo 'Page not found';
- }
-
-}
\ No newline at end of file
diff --git a/demo-project/app/Handlers/CustomExceptionHandler.php b/demo-project/app/Handlers/CustomExceptionHandler.php
deleted file mode 100644
index 6eca147..0000000
--- a/demo-project/app/Handlers/CustomExceptionHandler.php
+++ /dev/null
@@ -1,44 +0,0 @@
-getUri(), '/api') !== false) {
-
- response()->json([
- 'error' => $error->getMessage(),
- 'code' => $error->getCode(),
- ]);
-
- }
-
- /* The router will throw the NotFoundHttpException on 404 */
- if($error instanceof NotFoundHttpException) {
-
- /*
- * Render your own custom 404-view, rewrite the request to another route,
- * or simply return the $request object to ignore the error and continue on rendering the route.
- *
- * The code below will make the router render our page.notfound route.
- */
-
- $request->setUri(url('page.notfound'));
- return $request;
-
- }
-
- throw $error;
-
- }
-
-}
\ No newline at end of file
diff --git a/demo-project/app/Middlewares/ApiVerification.php b/demo-project/app/Middlewares/ApiVerification.php
deleted file mode 100644
index ce9e177..0000000
--- a/demo-project/app/Middlewares/ApiVerification.php
+++ /dev/null
@@ -1,18 +0,0 @@
-authenticated = true;
-
- return $request;
- }
-
-}
\ No newline at end of file
diff --git a/demo-project/app/Middlewares/CsrfVerifier.php b/demo-project/app/Middlewares/CsrfVerifier.php
deleted file mode 100644
index 636dd12..0000000
--- a/demo-project/app/Middlewares/CsrfVerifier.php
+++ /dev/null
@@ -1,13 +0,0 @@
-getToken();
-}
-
-/**
- * Get request object
- * @return \Pecee\Http\Request
- */
-function request()
-{
- return SimpleRouter::request();
-}
-
-/**
- * Get response object
- * @return \Pecee\Http\Response
- */
-function response()
-{
- return SimpleRouter::response();
-}
-
-/**
- * Get input class
- * @return \Pecee\Http\Input\Input
- */
-function input()
-{
- return SimpleRouter::request()->getInput();
-}
\ No newline at end of file
diff --git a/demo-project/app/routes.php b/demo-project/app/routes.php
deleted file mode 100644
index 4b5e3f7..0000000
--- a/demo-project/app/routes.php
+++ /dev/null
@@ -1,25 +0,0 @@
- 'Demo\Handlers\CustomExceptionHandler'], function () {
-
- Router::get('/', 'DefaultController@index')->setName('home');
-
- Router::get('/contact', 'DefaultController@contact')->setName('contact');
-
- Router::get('/404', 'DefaultController@notFound')->setName('404');
-
- Router::basic('/companies/{id?}', 'DefaultController@companies')->setName('companies');
-
- // Api
- Router::group(['prefix' => '/api', 'middleware' => 'Demo\Middlewares\ApiVerification'], function () {
- Router::resource('/demo', 'ApiController');
- });
-
-});
\ No newline at end of file
diff --git a/demo-project/composer.json b/demo-project/composer.json
deleted file mode 100644
index 61c531c..0000000
--- a/demo-project/composer.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "pecee/simple-router-demo",
- "description": "Simple router demo project",
- "keywords": [
- "simple-router",
- "php",
- "php-simple-router"
- ],
- "license": "MIT",
- "type": "project",
- "require": {
- "php": ">=5.4.0",
- "pecee/simple-router": "2.*"
- },
- "require-dev": {
-
- },
- "config": {
- "preferred-install": "dist"
- },
- "autoload": {
- "psr-4": {
- "Demo\\": "app/"
- }
- }
-}
\ No newline at end of file
diff --git a/demo-project/public/.htaccess b/demo-project/public/.htaccess
deleted file mode 100644
index aa7a5f6..0000000
--- a/demo-project/public/.htaccess
+++ /dev/null
@@ -1,5 +0,0 @@
-RewriteEngine on
-RewriteCond %{SCRIPT_FILENAME} !-f
-RewriteCond %{SCRIPT_FILENAME} !-d
-RewriteCond %{SCRIPT_FILENAME} !-l
-RewriteRule ^(.*)$ index.php/$1
\ No newline at end of file
diff --git a/demo-project/public/index.php b/demo-project/public/index.php
deleted file mode 100644
index ea01d8d..0000000
--- a/demo-project/public/index.php
+++ /dev/null
@@ -1,7 +0,0 @@
-request = $request;
- $this->post = new InputCollection();
- $this->get = new InputCollection();
- $this->file = new InputCollection();
-
if ($request->getMethod() !== 'get') {
$requestContentType = $request->getHeader('http-content-type');
@@ -60,29 +56,17 @@ class Input
if ($this->invalidContentType === false) {
$this->parseInputs();
}
+
}
protected function parseInputs()
{
/* Parse get requests */
-
if (count($_GET) > 0) {
-
- $max = count($_GET) - 1;
- $keys = array_keys($_GET);
-
- for ($i = $max; $i >= 0; $i--) {
-
- $key = $keys[$i];
- $value = $_GET[$key];
-
- $this->get->{$key} = new InputItem($key, $value);
- }
-
+ $this->get = $this->handleGetPost($_GET);
}
/* Parse post requests */
-
$postVars = $_POST;
if (in_array($this->request->getMethod(), ['put', 'patch', 'delete']) === true) {
@@ -90,18 +74,7 @@ class Input
}
if (count($postVars) > 0) {
-
- $max = count($postVars) - 1;
- $keys = array_keys($postVars);
-
- for ($i = $max; $i >= 0; $i--) {
-
- $key = $keys[$i];
- $value = $postVars[$key];
-
- $this->post->{strtolower($key)} = new InputItem($key, $value);
- }
-
+ $this->post = $this->handleGetPost($postVars);
}
/* Parse get requests */
@@ -119,56 +92,96 @@ class Input
// Handle array input
if (is_array($value['name']) === false) {
$values['index'] = $key;
- $this->file->{strtolower($key)} = InputFile::createFromArray($values);
+ $this->file[$key] = InputFile::createFromArray(array_merge($value, $values));
continue;
}
- $output = new InputCollection();
+ $subMax = count($value['name']) - 1;
+ $keys = array_keys($value['name']);
+ $output = [];
- foreach ($value['name'] as $k => $val) {
+ for ($i = $subMax; $i >= 0; $i--) {
- $output->{$k} = InputFile::createFromArray([
+ $output[$keys[$i]] = InputFile::createFromArray([
'index' => $key,
- 'error' => $value['error'][$k],
- 'tmp_name' => $value['tmp_name'][$k],
- 'type' => $value['type'][$k],
- 'size' => $value['size'][$k],
- 'name' => $value['name'][$k],
+ 'error' => $value['error'][$keys[$i]],
+ 'tmp_name' => $value['tmp_name'][$keys[$i]],
+ 'type' => $value['type'][$keys[$i]],
+ 'size' => $value['size'][$keys[$i]],
+ 'name' => $value['name'][$keys[$i]],
]);
}
- $this->file->{strtolower($key)} = $output;
+ $this->file[$key] = $output;
}
}
-
}
- public function getObject($index, $default = null)
+ protected function handleGetPost($array)
{
- $key = (strpos($index, '[') > -1) ? substr($index, strpos($index, '[') + 1, strpos($index, ']') - strlen($index)) : null;
- $index = (strpos($index, '[') > -1) ? substr($index, 0, strpos($index, '[')) : $index;
+ $tmp = [];
- $element = $this->get->findFirst($index);
+ $max = count($array) - 1;
+ $keys = array_keys($array);
- if ($element !== null) {
- return ($key !== null) ? $element[$key] : $element;
- }
+ for ($i = $max; $i >= 0; $i--) {
- if ($this->request->getMethod() !== 'get') {
+ $key = $keys[$i];
+ $value = $array[$key];
- $element = $this->post->findFirst($index);
- if ($element !== null) {
- return ($key !== null) ? $element[$key] : $element;
+ // Handle array input
+ if (is_array($value) === false) {
+ $tmp[$key] = new InputItem($key, $value);
+ continue;
}
- $element = $this->file->findFirst($index);
- if ($element !== null) {
- return ($key !== null) ? $element[$key] : $element;
+ $subMax = count($value) - 1;
+ $keys = array_keys($value);
+ $output = [];
+
+ for ($i = $subMax; $i >= 0; $i--) {
+ $output[$keys[$i]] = new InputItem($key, $value[$keys[$i]]);
}
+
+ $tmp[$key] = $output;
}
- return $default;
+ return $tmp;
+ }
+
+ public function findPost($index, $default = null)
+ {
+ return isset($this->post[$index]) ? $this->post[$index] : $default;
+ }
+
+ public function findFile($index, $default = null)
+ {
+ return isset($this->file[$index]) ? $this->file[$index] : $default;
+ }
+
+ public function findGet($index, $default = null)
+ {
+ return isset($this->get[$index]) ? $this->get[$index] : $default;
+ }
+
+ public function getObject($index, $default = null, $method = null)
+ {
+ $element = null;
+
+ if ($method === null || strtolower($method) === 'get') {
+ $element = $this->findGet($index);
+ }
+
+ if ($element === null && $method === null || strtolower($method) === 'post') {
+ $element = $this->findPost($index);
+ }
+
+ if ($element === null && $method === null || strtolower($method) === 'file') {
+ $element = $this->findFile($index);
+ }
+
+ return ($element === null) ? $default : $element;
}
/**
@@ -176,22 +189,18 @@ class Input
*
* @param string $index
* @param string|null $default
+ * @param string|null $method
* @return InputItem|string
*/
- public function get($index, $default = null)
+ public function get($index, $default = null, $method = null)
{
- $item = $this->getObject($index);
+ $input = $this->getObject($index, $default, $method);
- if ($item !== null) {
-
- if ($item instanceof InputCollection || $item instanceof InputFile) {
- return $item;
- }
-
- return (!is_array($item->getValue()) && trim($item->getValue()) === '') ? $default : $item;
+ if ($input instanceof InputItem) {
+ return (trim($input->getValue()) === '') ? $default : $input->getValue();
}
- return $default;
+ return $input;
}
public function exists($index)
diff --git a/src/Pecee/Http/Input/InputCollection.php b/src/Pecee/Http/Input/InputCollection.php
deleted file mode 100644
index b4227c2..0000000
--- a/src/Pecee/Http/Input/InputCollection.php
+++ /dev/null
@@ -1,91 +0,0 @@
-data) > 0) {
-
- if (isset($this->data[$index])) {
- return $this->data[$index];
- }
-
- foreach ($this->data as $key => $input) {
- if (strtolower($index) === strtolower($key)) {
- return $input;
- }
- }
- }
-
- return $default;
- }
-
- /**
- * Get input element value matching index
- *
- * @param string $index
- * @param string|null $default
- * @return string|null
- */
- public function get($index, $default = null)
- {
- $input = $this->findFirst($index);
-
- if ($input !== null && trim($input->getValue()) !== '') {
- return $input->getValue();
- }
-
- return $default;
- }
-
- /**
- * @param string $index
- * @throws \InvalidArgumentException
- * @return InputItem
- */
- public function __get($index)
- {
- $item = $this->findFirst($index);
- // Ensure that item are always available
- if ($item === null) {
- $this->data[$index] = new InputItem($index, null);
-
- return $this->data[$index];
- }
-
- return $item;
- }
-
- public function __set($index, $value)
- {
- $this->data[$index] = $value;
- }
-
- public function getData()
- {
- return $this->data;
- }
-
- /**
- * Retrieve an external iterator
- * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
- * @return \Traversable An instance of an object implementing Iterator or
- * Traversable
- * @since 5.0.0
- */
- public function getIterator()
- {
- return new \ArrayIterator($this->data);
- }
-
-}
\ No newline at end of file
diff --git a/src/Pecee/Http/Input/InputFile.php b/src/Pecee/Http/Input/InputFile.php
index 6cd1b35..8a38794 100644
--- a/src/Pecee/Http/Input/InputFile.php
+++ b/src/Pecee/Http/Input/InputFile.php
@@ -1,13 +1,39 @@
index = $index;
+
+ // Make the name human friendly, by replace _ with space
+ $this->name = ucfirst(str_replace('_', ' ', $this->index));
+ }
+
+ /**
+ * @return string
+ */
+ public function getIndex()
+ {
+ return $this->index;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
/**
* @return string
*/
@@ -60,6 +86,13 @@ class InputFile extends InputItem
return file_get_contents($this->tmpName);
}
+ public function setName($name)
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
/**
* Set file temp. name
* @param string $name
@@ -68,6 +101,7 @@ class InputFile extends InputItem
public function setTmpName($name)
{
$this->tmpName = $name;
+
return $this;
}
@@ -79,6 +113,7 @@ class InputFile extends InputItem
public function setSize($size)
{
$this->size = $size;
+
return $this;
}
@@ -90,6 +125,7 @@ class InputFile extends InputItem
public function setType($type)
{
$this->type = $type;
+
return $this;
}
@@ -101,6 +137,7 @@ class InputFile extends InputItem
public function setError($error)
{
$this->error = (int)$error;
+
return $this;
}
@@ -109,7 +146,8 @@ class InputFile extends InputItem
return $this->getTmpName();
}
- public function hasError() {
+ public function hasError()
+ {
return ($this->getError() !== 0);
}
@@ -120,28 +158,33 @@ class InputFile extends InputItem
*/
public static function createFromArray(array $values)
{
- if(!isset($values['index'])) {
+ if (!isset($values['index'])) {
throw new \InvalidArgumentException('Index key is required');
}
$input = new static($values['index']);
- $input->setError((isset($values['error']) ? $values['error'] : null));
- $input->setName((isset($values['name']) ? $values['name'] : null));
- $input->setSize((isset($values['size']) ? $values['size'] : null));
- $input->setType((isset($values['type']) ? $values['type'] : null));
- $input->setTmpName((isset($values['tmp_name']) ? $values['tmp_name'] : null));
+ $input->setError(isset($values['error']) ? $values['error'] : null);
+ $input->setName(isset($values['name']) ? $values['name'] : null);
+ $input->setSize(isset($values['size']) ? $values['size'] : null);
+ $input->setType(isset($values['type']) ? $values['type'] : null);
+ $input->setTmpName(isset($values['tmp_name']) ? $values['tmp_name'] : null);
return $input;
}
- public function toArray() {
+ public function toArray()
+ {
return [
'tmp_name' => $this->tmpName,
- 'type' => $this->type,
- 'size' => $this->size,
- 'name' => $this->name,
- 'error' => $this->error,
+ 'type' => $this->type,
+ 'size' => $this->size,
+ 'name' => $this->name,
+ 'error' => $this->error,
];
}
+ public function __toString()
+ {
+ return $this->getValue();
+ }
}
\ No newline at end of file
diff --git a/src/Pecee/Http/Input/InputItem.php b/src/Pecee/Http/Input/InputItem.php
index 71d0253..934477b 100644
--- a/src/Pecee/Http/Input/InputItem.php
+++ b/src/Pecee/Http/Input/InputItem.php
@@ -1,7 +1,7 @@
name = ucfirst(str_replace('_', ' ', $this->index));
}
+ /**
+ * @return string
+ */
+ public function getIndex()
+ {
+ return $this->index;
+ }
+
/**
* @return string
*/
@@ -32,14 +40,6 @@ class InputItem
return $this->value;
}
- /**
- * @return string
- */
- public function getIndex()
- {
- return $this->index;
- }
-
/**
* Set input name
* @param string $name
diff --git a/src/Pecee/Http/Middleware/BaseCsrfVerifier.php b/src/Pecee/Http/Middleware/BaseCsrfVerifier.php
index 14c6732..ba10ff8 100644
--- a/src/Pecee/Http/Middleware/BaseCsrfVerifier.php
+++ b/src/Pecee/Http/Middleware/BaseCsrfVerifier.php
@@ -20,7 +20,7 @@ class BaseCsrfVerifier implements IMiddleware
$this->csrfToken = new CsrfToken();
// Generate or get the CSRF-Token from Cookie.
- $this->token = (!$this->hasToken()) ? $this->generateToken() : $this->csrfToken->getToken();
+ $this->token = ($this->hasToken() === false) ? $this->generateToken() : $this->csrfToken->getToken();
}
/**
@@ -34,7 +34,11 @@ class BaseCsrfVerifier implements IMiddleware
return false;
}
- foreach ($this->except as $url) {
+ $max = count($this->except) - 1;
+
+ for ($i = $max; $i >= 0; $i--) {
+ $url = $this->except[$i];
+
$url = rtrim($url, '/');
if ($url[strlen($url) - 1] === '*') {
$url = rtrim($url, '*');
@@ -43,7 +47,7 @@ class BaseCsrfVerifier implements IMiddleware
$skip = ($url === rtrim($request->getUri(), '/'));
}
- if ($skip) {
+ if ($skip === true) {
return true;
}
}
@@ -54,16 +58,16 @@ class BaseCsrfVerifier implements IMiddleware
public function handle(Request $request, ILoadableRoute &$route = null)
{
- if ($request->getMethod() !== 'get' && !$this->skip($request)) {
+ if (in_array($request->getMethod(), ['post', 'put', 'delete']) === true && $this->skip($request) === false) {
- $token = $request->getInput()->post->get(static::POST_KEY);
+ $token = $request->getInput()->get(static::POST_KEY, null, 'post');
// If the token is not posted, check headers for valid x-csrf-token
if ($token === null) {
$token = $request->getHeader(static::HEADER_KEY);
}
- if (!$this->csrfToken->validate($token)) {
+ if ($this->csrfToken->validate($token) === false) {
throw new TokenMismatchException('Invalid csrf-token.');
}
diff --git a/src/Pecee/Http/Request.php b/src/Pecee/Http/Request.php
index 0f14387..584dbab 100644
--- a/src/Pecee/Http/Request.php
+++ b/src/Pecee/Http/Request.php
@@ -17,7 +17,7 @@ class Request
$this->parseHeaders();
$this->host = $this->getHeader('http-host');;
$this->uri = $this->getHeader('request-uri');
- $this->method = strtolower($this->getHeader('request-method'));
+ $this->method = $this->input->get('_method', strtolower($this->getHeader('request-method')));
$this->input = new Input($this);
}
@@ -25,9 +25,15 @@ class Request
{
$this->headers = [];
- foreach ($_SERVER as $name => $value) {
- $this->headers[strtolower($name)] = $value;
- $this->headers[strtolower(str_replace('_', '-', $name))] = $value;
+ $max = count($_SERVER) - 1;
+ $keys = array_keys($_SERVER);
+
+ for($i = $max; $i >= 0; $i--) {
+ $key = $keys[$i];
+ $value = $_SERVER[$key];
+
+ $this->headers[strtolower($key)] = $value;
+ $this->headers[strtolower(str_replace('_', '-', $key))] = $value;
}
}
diff --git a/src/Pecee/SimpleRouter/Route/RouteController.php b/src/Pecee/SimpleRouter/Route/RouteController.php
index e62d1f3..f8657da 100644
--- a/src/Pecee/SimpleRouter/Route/RouteController.php
+++ b/src/Pecee/SimpleRouter/Route/RouteController.php
@@ -59,7 +59,12 @@ class RouteController extends LoadableRoute implements IControllerRoute
/* Remove requestType from method-name, if it exists */
if ($method !== null) {
- foreach (static::$requestTypes as $requestType) {
+ $max = count(static::$requestTypes);
+
+ for ($i = 0; $i < $max; $i++) {
+
+ $requestType = static::$requestTypes[$i];
+
if (stripos($method, $requestType) === 0) {
$method = substr($method, strlen($requestType));
break;
diff --git a/src/Pecee/SimpleRouter/Route/RouteGroup.php b/src/Pecee/SimpleRouter/Route/RouteGroup.php
index 13a83d8..0cbe242 100644
--- a/src/Pecee/SimpleRouter/Route/RouteGroup.php
+++ b/src/Pecee/SimpleRouter/Route/RouteGroup.php
@@ -19,8 +19,12 @@ class RouteGroup extends Route implements IGroupRoute
public function matchDomain(Request $request)
{
if (count($this->domains) > 0) {
- foreach ($this->domains as $domain) {
+ $max = count($this->domains);
+
+ for ($i = 0; $i < $max; $i++) {
+
+ $domain = $this->domains[$i];
$parameters = $this->parseParameters($domain, $request->getHost(), '.*');
if ($parameters !== null) {
diff --git a/src/Pecee/SimpleRouter/Route/RouteUrl.php b/src/Pecee/SimpleRouter/Route/RouteUrl.php
index e7a73f6..23f47cf 100644
--- a/src/Pecee/SimpleRouter/Route/RouteUrl.php
+++ b/src/Pecee/SimpleRouter/Route/RouteUrl.php
@@ -19,8 +19,12 @@ class RouteUrl extends LoadableRoute
// Match on custom defined regular expression
if ($this->regex !== null) {
$parameters = [];
- if (preg_match('/(' . $this->regex . ')/is', $request->getHost() . $url, $parameters)) {
- $this->parameters = (array)$parameters[0];
+ if (preg_match($this->regex, $request->getHost() . $url, $parameters)) {
+ /* Remove global match */
+ if(count($parameters) > 1) {
+ array_shift($parameters);
+ $this->parameters = $parameters;
+ }
return true;
}
diff --git a/src/Pecee/SimpleRouter/Router.php b/src/Pecee/SimpleRouter/Router.php
index a5c867c..a34e66c 100644
--- a/src/Pecee/SimpleRouter/Router.php
+++ b/src/Pecee/SimpleRouter/Router.php
@@ -140,8 +140,12 @@ class Router
protected function processRoutes(array $routes, IGroupRoute $group = null, IRoute $parent = null)
{
// Loop through each route-request
+ $max = count($routes) - 1;
+
/* @var $route IRoute */
- foreach ($routes as $route) {
+ for ($i = $max; $i >= 0; $i--) {
+
+ $route = $routes[$i];
if ($route instanceof IGroupRoute) {
@@ -238,10 +242,10 @@ class Router
$this->originalUrl = $this->request->getUri();
}
- $max = count($this->processedRoutes);
+ $max = count($this->processedRoutes) - 1;
/* @var $route IRoute */
- for ($i = 0; $i < $max; $i++) {
+ for ($i = $max; $i >= 0; $i--) {
$route = $this->processedRoutes[$i];