PHP code example of developermarius / simple-router
1. Go to this page and download the library: Download developermarius/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();
class ArticleController{
use \Pecee\SimpleRouter\RouterUtils;
public function create(){
$data = $this->input()->values();
[...]
}
}
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::group('/lang/{language}', function ($language) {
SimpleRouter::get('/users', function ($language) {
// Matches The "/lang/da/users" URL
});
});
use Pecee\SimpleRouter\SimpleRouter;
/* Adding custom csrfVerifier here */
SimpleRouter::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
SimpleRouter::group(['middleware' => \Demo\Middlewares\Site::class, 'exceptionHandler' => \Demo\Handlers\CustomExceptionHandler::class], function() {
SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show', ['where' => ['id' => '[0-9]+']]);
/**
* Class hinting is supported too
*/
SimpleRouter::get('/answers/{id}', [ControllerAnswers::class, 'show'], ['where' => ['id' => '[0-9]+']]);
/**
* Restful resource (see IRestController interface for available methods)
*/
SimpleRouter::resource('/rest', ControllerResource::class);
/**
* 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::class);
});
SimpleRouter::get('/page/404', 'ControllerPage@notFound', ['as' => 'page.notfound']);
InputValidator::make()->setRules([
'title' => 'string|min:3|max:200',
'description' => 'string|min:20|max:500'
])->validateData(array(
'title' => 'Example title',
'description' => 'This is an example description.'
))->passes();
use \Pecee\Http\Input\InputValidator;
InputValidator::getFactory()->messages()->default('de');
InputValidator::getFactory()->addRule('example', new ExampleRule());
use Pecee\Http\Input\Attributes\ValidatorAttribute;
#[
ValidatorAttribute('title', 'string', 'min:3|max:200'),
ValidatorAttribute('description', 'string', 'min:20|max:500'),
]
public function createArticle(#[ValidatorAttribute(validator: 'model:User')] int $user){
$data = $this->input()->
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;
}
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($this->input()->file('images', [])->getInputItems() as $image)
{
if($image->getMime() === 'image/jpeg')
{
$destinationFilname = sprintf('%s.%s', uniqid(), $image->getExtension());
$image->move(sprintf('/uploads/%s', $destinationFilename));
}
}
# Get all
$values = $this->input()->all();
# Only match specific keys
$values = $this->input()->all([
'company_name',
'user_id'
]);
if($this->input()->exists(['name', 'lastname'])) {
// Do stuff
}
/* Similar to code above */
if($this->input()->exists('name') && $this->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\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 NotFoundHttpException
*/
public function loadClass(string $class)
{
if (class_exists($class) === false) {
throw new NotFoundHttpException(sprintf('Class "%s" does not exist', $class), 404);
}
try {
return $this->container->get($class);
} catch (\Exception $e) {
throw new NotFoundHttpException($e->getMessage(), (int)$e->getCode(), $e->getPrevious());
}
}
/**
* Called when loading class method
* @param object $class
* @param string $method
* @param array $parameters
* @return object
*/
public function loadClassMethod($class, string $method, array $parameters)
{
try {
return $this->container->call([$class, $method], $parameters);
} catch (\Exception $e) {
throw new NotFoundHttpException($e->getMessage(), (int)$e->getCode(), $e->getPrevious());
}
}
/**
* Load closure
*
* @param Callable $closure
* @param array $parameters
* @return mixed
*/
public function loadClosure(callable $closure, array $parameters)
{
try {
return $this->container->call($closure, $parameters);
} catch (\Exception $e) {
throw new NotFoundHttpException($e->getMessage(), (int)$e->getCode(), $e->getPrevious());
}
}
}
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();
}
public function show($username) {
return sprintf('Username is: %s', $username);
}
[PASTE YOUR DEBUG-INFO HERE]
class ArticleController{
use RouterUtils;
#[Route(Route::POST, '/')]
public function createArticle(){
...
}
#[Route(Route::GET, '/{id}')]
public function getArticle(#[ValidatorAttribute] int $id){
...
}
}