1. Go to this page and download the library: Download pecee/simple-router library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
use Pecee\SimpleRouter\SimpleRouter;
/* Load external routes file */
ify it each time.
* Can be overwritten by using the namespace config option on your routes.
*/
SimpleRouter::setDefaultNamespace('\Demo\Controllers');
// Start the routing
SimpleRouter::start();
use Pecee\SimpleRouter\SimpleRouter as Router;
use Pecee\Http\Url;
use Pecee\Http\Response;
use Pecee\Http\Request;
/**
* 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 \Pecee\Http\Url
* @throws \InvalidArgumentException
*/
function url(?string $name = null, $parameters = null, ?array $getParams = null): Url
{
return Router::getUrl($name, $parameters, $getParams);
}
/**
* @return \Pecee\Http\Response
*/
function response(): Response
{
return Router::response();
}
/**
* @return \Pecee\Http\Request
*/
function request(): Request
{
return Router::request();
}
/**
* Get input class
* @param string|null $index Parameter index name
* @param string|mixed|null $defaultValue Default return value
* @param array ...$methods Default methods
* @return \Pecee\Http\Input\InputHandler|array|string|null
*/
function input($index = null, $defaultValue = null, ...$methods)
{
if ($index !== null) {
return request()->getInputHandler()->value($index, $defaultValue, ...$methods);
}
return request()->getInputHandler();
}
/**
* @param string $url
* @param int|null $code
*/
function redirect(string $url, ?int $code = null): void
{
if ($code !== null) {
response()->httpCode($code);
}
response()->redirect($url);
}
/**
* Get current csrf-token
* @return string|null
*/
function csrf_token(): ?string
{
$baseVerifier = Router::router()->getCsrfVerifier();
if ($baseVerifier !== null) {
return $baseVerifier->getTokenProvider()->getToken();
}
return null;
}
SimpleRouter::group(['middleware' => \Demo\Middleware\Auth::class], function () {
SimpleRouter::get('/', function () {
// Uses Auth Middleware
});
SimpleRouter::get('/user/profile', function () {
// Uses Auth Middleware
});
});
SimpleRouter::group(['namespace' => 'Admin'], function () {
// Controllers Within The "App\Http\Controllers\Admin" Namespace
});
SimpleRouter::group(['prefix' => '/lang/{lang}'], function ($language) {
SimpleRouter::get('/about', function($language) {
// Will match /lang/da/about
});
});
SimpleRouter::group(['domain' => '{account}.myapp.com'], function () {
SimpleRouter::get('/user/{id}', function ($account, $id) {
//
});
});
SimpleRouter::group(['prefix' => '/admin'], function () {
SimpleRouter::get('/users', function () {
// Matches The "/admin/users" URL
});
});
SimpleRouter::group(['prefix' => '/lang/{language}'], function ($language) {
SimpleRouter::get('/users', function ($language) {
// Matches The "/lang/da/users" URL
});
});
SimpleRouter::partialGroup('/plugin/{name}', function ($plugin) {
// Add routes from plugin
});
namespace Demo\Middlewares;
use Pecee\Http\Middleware\BaseCsrfVerifier;
class CsrfVerifier extends BaseCsrfVerifier
{
/**
* CSRF validation will be ignored on the following urls.
*/
protected $except = ['/api/*'];
}
class SessionTokenProvider implements ITokenProvider
{
/**
* Refresh existing token
*/
public function refresh(): void
{
// Implement your own functionality here...
}
/**
* Validate valid CSRF token
*
* @param string $token
* @return bool
*/
public function validate($token): bool
{
// Implement your own functionality here...
}
/**
* Get token token
*
* @param string|null $defaultValue
* @return string|null
*/
public function getToken(?string $defaultValue = null): ?string
{
// Implement your own functionality here...
}
}
$verifier = new \Demo\Middlewares\CsrfVerifier();
$verifier->setTokenProvider(new SessionTokenProvider());
SimpleRouter::csrfVerifier($verifier);
namespace Demo\Middlewares;
use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request;
class CustomMiddleware implements IMiddleware {
public function handle(Request $request): void
{
// Authenticate user, will be available using request()->user
$request->user = User::authenticate();
// If authentication failed, redirect request to user-login page.
if($request->user === null) {
$request->setRewriteUrl(url('user.login'));
}
}
}
SimpleRouter::get('/not-found', 'PageController@notFound');
SimpleRouter::get('/forbidden', 'PageController@notFound');
SimpleRouter::error(function(Request $request, \Exception $exception) {
switch($exception->getCode()) {
// Page not found
case 404:
response()->redirect('/not-found');
// Forbidden
case 403:
response()->redirect('/forbidden');
}
});
namespace Demo\Handlers;
use Pecee\Http\Request;
use Pecee\SimpleRouter\Handlers\IExceptionHandler;
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
class CustomExceptionHandler implements IExceptionHandler
{
public function handleError(Request $request, \Exception $error): void
{
/* You can use the exception handler to format errors depending on the request and type. */
if ($request->getUrl()->contains('/api')) {
response()->json([
'error' => $error->getMessage(),
'code' => $error->getCode(),
]);
}
/* The router will throw the NotFoundHttpException on 404 */
if($error instanceof NotFoundHttpException) {
// Render custom 404-page
$request->setRewriteCallback('Demo\Controllers\PageController@notFound');
return;
}
/* Other error */
if($error instanceof MyCustomException) {
$request->setRewriteRoute(
// Add new route based on current url (minus query-string) and add custom parameters.
(new RouteUrl(url(null, null, []), 'PageController@error'))->setParameters(['exception' => $error])
);
return;
}
throw $error;
}
}
SimpleRouter::group(['exceptionHandler' => \Demo\Handlers\CustomExceptionHandler::class], function() {
// Your routes here
});
SimpleRouter::group(['prefix' => '/', 'exceptionHandler' => \Demo\Handlers\FirstExceptionHandler::class, 'mergeExceptionHandlers' => false], function() {
SimpleRouter::group(['prefix' => '/admin', 'exceptionHandler' => \Demo\Handlers\SecondExceptionHandler::class], function() {
// Both SecondExceptionHandler and FirstExceptionHandler will trigger (in that order).
});
SimpleRouter::group(['prefix' => '/user', 'exceptionHandler' => \Demo\Handlers\SecondExceptionHandler::class, 'mergeExceptionHandlers' => false], function() {
// Only SecondExceptionHandler will trigger.
});
});
# Grab the query-string parameter id from the current-url.
$id = url()->getParam('id');
# Get the absolute url for the current url.
$absoluteUrl = url()->getAbsoluteUrl();
/**
* Loop through a collection of files uploaded from a form on the page like this
* <input type="file" name="images[]" />
*/
/* @var $image \Pecee\Http\Input\InputFile */
foreach(input()->file('images', []) as $image)
{
if($image->getMime() === 'image/jpeg')
{
$destinationFilname = sprintf('%s.%s', uniqid(), $image->getExtension());
$image->move(sprintf('/uploads/%s', $destinationFilename));
}
}
# Get all
$values = input()->all();
# Only match specific keys
$values = input()->all([
'company_name',
'user_id'
]);
if(input()->exists(['name', 'lastname'])) {
// Do stuff
}
/* Similar to code above */
if(input()->exists('name') && input()->exists('lastname')) {
// Do stuff
}
use Pecee\SimpleRouter\Handlers\EventHandler;
use Pecee\SimpleRouter\Event\EventArgument;
// --- your routes goes here ---
$eventHandler = new EventHandler();
// Add event that fires when a route is rendered
$eventHandler->register(EventHandler::EVENT_RENDER_ROUTE, function(EventArgument $argument) {
// Get the route by using the special argument for this event.
$route = $argument->route;
// DO STUFF...
});
SimpleRouter::addEventHandler($eventHandler);
namespace Demo\Handlers;
use Pecee\SimpleRouter\Event\EventArgument;
use Pecee\SimpleRouter\Router;
class DatabaseDebugHandler implements IEventHandler
{
/**
* Debug callback
* @var \Closure
*/
protected $callback;
public function __construct()
{
$this->callback = function (EventArgument $argument) {
// todo: store log in database
};
}
/**
* Get events.
*
* @param string|null $name Filter events by name.
* @return array
*/
public function getEvents(?string $name): array
{
return [
$name => [
$this->callback,
],
];
}
/**
* Fires any events registered with given event-name
*
* @param Router $router Router instance
* @param string $name Event name
* @param array ...$eventArgs Event arguments
*/
public function fireEvents(Router $router, string $name, ...$eventArgs): void
{
$callback = $this->callback;
$callback(new EventArgument($router, $eventArgs));
}
/**
* Set debug callback
*
* @param \Closure $event
*/
public function setCallback(\Closure $event): void
{
$this->callback = $event;
}
}
$basePath = '/basepath';
$eventHandler = new EventHandler();
$eventHandler->register(EventHandler::EVENT_ADD_ROUTE, function(EventArgument $event) use($basePath) {
$route = $event->route;
// Skip routes added by group as these will inherit the url
if(!$event->isSubRoute) {
return;
}
switch (true) {
case $route instanceof ILoadableRoute:
$route->prependUrl($basePath);
break;
case $route instanceof IGroupRoute:
$route->prependPrefix($basePath);
break;
}
});
SimpleRouter::addEventHandler($eventHandler);
request()->setRewriteCallback('Example\MyCustomClass@hello');
// -- or you can rewrite by url --
request()->setRewriteUrl('/my-rewrite-url');
use Pecee\Http\Request;
use Pecee\SimpleRouter\IRouterBootManager;
use Pecee\SimpleRouter\Router;
class CustomRouterRules implement IRouterBootManager
{
/**
* Called when router is booting and before the routes is loaded.
*
* @param \Pecee\SimpleRouter\Router $router
* @param \Pecee\Http\Request $request
*/
public function boot(\Pecee\SimpleRouter\Router $router, \Pecee\Http\Request $request): void
{
$rewriteRules = [
'/my-cat-is-beatiful' => '/article/view/1',
'/horses-are-great' => '/article/view/2',
];
foreach($rewriteRules as $url => $rule) {
// If the current url matches the rewrite url, we use our custom route
if($request->getUrl()->contains($url)) {
$request->setRewriteUrl($rule);
}
}
}
}
use \Pecee\SimpleRouter\Router;
use \Pecee\SimpleRouter\Route\RouteUrl;
/* Create new Router instance */
$router = new Router();
$route = new RouteUrl('/answer/1', function() {
die('this callback will match /answer/1');
});
$route->addMiddleware(\Demo\Middlewares\AuthMiddleware::class);
$route->setNamespace('\Demo\Controllers');
$route->setPrefix('v1');
/* Add the route to the router */
$router->addRoute($route);
class MyCustomClassLoader implements IClassLoader
{
/**
* Load class
*
* @param string $class
* @return object
* @throws NotFoundHttpException
*/
public function loadClass(string $class)
{
if (\class_exists($class) === false) {
throw new NotFoundHttpException(sprintf('Class "%s" does not exist', $class), 404);
}
return new $class();
}
/**
* Called when loading class method
* @param object $class
* @param string $method
* @param array $parameters
* @return object
*/
public function loadClassMethod($class, string $method, array $parameters)
{
return call_user_func_array([$class, $method], array_values($parameters));
}
/**
* Load closure
*
* @param Callable $closure
* @param array $parameters
* @return mixed
*/
public function loadClosure(Callable $closure, array $parameters)
{
return \call_user_func_array($closure, array_values($parameters));
}
}
use Pecee\SimpleRouter\ClassLoader\IClassLoader;
use Pecee\SimpleRouter\Exceptions\ClassNotFoundHttpException;
class MyCustomClassLoader implements IClassLoader
{
protected $container;
public function __construct()
{
// Create our new php-di container
$this->container = (new \DI\ContainerBuilder())
->useAutowiring(true)
->build();
}
/**
* Load class
*
* @param string $class
* @return object
* @throws ClassNotFoundHttpException
*/
public function loadClass(string $class)
{
if ($this->container->has($class) === false) {
throw new ClassNotFoundHttpException($class, null, sprintf('Class "%s" does not exist', $class), 404, null);
}
return $this->container->get($class);
}
/**
* Called when loading class method
* @param object $class
* @param string $method
* @param array $parameters
* @return string
*/
public function loadClassMethod($class, string $method, array $parameters)
{
return (string)$this->container->call([$class, $method], $parameters);
}
/**
* Load closure
*
* @param Callable $closure
* @param array $parameters
* @return string
*/
public function loadClosure(callable $closure, array $parameters)
{
return (string)$this->container->call($closure, $parameters);
}
}
namespace Demo;
use Pecee\SimpleRouter\SimpleRouter;
class Router extends SimpleRouter {
public static function start() {
// change this to whatever makes sense in your project
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();
}