Compare commits
5 Commits
2a8fa3f397
...
e9fd8e153d
Author | SHA1 | Date |
---|---|---|
tracer | e9fd8e153d | |
tracer | f571d7548a | |
tracer | a55b14c71c | |
tracer | 87959d34b7 | |
tracer | 1ad567f337 |
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
class Route
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private string $name,
|
||||||
|
private string $route,
|
||||||
|
private string $regEx,
|
||||||
|
private array $parameters,
|
||||||
|
private Closure $callback
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// empty body
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
*/
|
||||||
|
public function setName(string $name): void
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRoute(): string
|
||||||
|
{
|
||||||
|
return $this->route;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $route
|
||||||
|
*/
|
||||||
|
public function setRoute(string $route): void
|
||||||
|
{
|
||||||
|
$this->route = $route;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRegEx(): string
|
||||||
|
{
|
||||||
|
return $this->regEx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $regEx
|
||||||
|
*/
|
||||||
|
public function setRegEx(string $regEx): void
|
||||||
|
{
|
||||||
|
$this->regEx = $regEx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getParameters(): array
|
||||||
|
{
|
||||||
|
return $this->parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $parameters
|
||||||
|
*/
|
||||||
|
public function setParameters(array $parameters): void
|
||||||
|
{
|
||||||
|
$this->parameters = $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Closure
|
||||||
|
*/
|
||||||
|
public function getCallback(): Closure
|
||||||
|
{
|
||||||
|
return $this->callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Closure $callback
|
||||||
|
*/
|
||||||
|
public function setCallback(Closure $callback): void
|
||||||
|
{
|
||||||
|
$this->callback = $callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,51 +3,61 @@
|
||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Entity\Route;
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A small router implementation for the address book demo.
|
||||||
|
* Currently it doesn't handle GET requests, as not needed.
|
||||||
|
* But if I reuse the code in my bind Api I'll enable GET as well.
|
||||||
|
*/
|
||||||
class Router
|
class Router
|
||||||
{
|
{
|
||||||
private array $uri;
|
|
||||||
private array $routes;
|
private array $routes;
|
||||||
|
|
||||||
public function __construct()
|
/*
|
||||||
|
* This method takes a route like /admin/users/{user} and creates a regex to match on call
|
||||||
|
*/
|
||||||
|
function addRoute(string $name, string $route, Closure $callback): void
|
||||||
{
|
{
|
||||||
$uri = parse_url(url: $_SERVER['REQUEST_URI'], component: PHP_URL_PATH);
|
// check for parameters
|
||||||
$this->uri = explode(separator: '/', string: $uri);
|
preg_match_all(pattern: "/(?<={).+?(?=})/", subject: $route, matches: $matches);
|
||||||
}
|
$parameters = $matches[0];
|
||||||
|
|
||||||
public function registerRoute(string $route, \Closure $callback): void
|
// create regex for route:
|
||||||
{
|
$regex = preg_replace(pattern: '/(?<={).+?(?=})/', replacement: '(.*?)', subject: $route);
|
||||||
$this->routes[$route] = $callback;
|
// code below is ugly, better match including the braces
|
||||||
}
|
$regex = str_replace(search: '{', replace: '', subject: $regex);
|
||||||
|
$regex = str_replace(search: '}', replace: '', subject: $regex);
|
||||||
|
|
||||||
private function matchRoute($url = '/users/tracer/posts/tracer', $method = 'GET')
|
$regex = '/^' . str_replace(search: "/", replace: '\\/', subject: $regex) . '$/i';
|
||||||
{
|
$route = new Route(name: $name, route: $route, regEx: $regex, parameters: $parameters, callback: $callback);
|
||||||
$reqUrl = $url;
|
|
||||||
|
$this->routes[] = $route;
|
||||||
$reqUrl = rtrim(string: $reqUrl, characters: "/");
|
|
||||||
|
|
||||||
foreach ($this->routes as $route => $closure) {
|
|
||||||
// convert urls like '/users/:uid/posts/:pid' to regular expression
|
|
||||||
// $pattern = "@^" . preg_replace('/\\\:[a-zA-Z0-9\_\-]+/', '([a-zA-Z0-9\-\_]+)', preg_quote($route['url'])) . "$@D";
|
|
||||||
$pattern = "@^" . preg_replace('\\/users/:[a-zA-Z0-9\_\-]+/', '([a-zA-Z0-9\-\_]+)', $route) . "$@D";
|
|
||||||
// echo $pattern."\n";
|
|
||||||
$params = [];
|
|
||||||
// check if the current request params the expression
|
|
||||||
$match = preg_match($pattern, $reqUrl, $params);
|
|
||||||
if ($match) {
|
|
||||||
// remove the first match
|
|
||||||
array_shift($params);
|
|
||||||
// call the callback with the matched positions as params
|
|
||||||
// return call_user_func_array($route['callback'], $params);
|
|
||||||
return [$route, $params];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check is there is a known route and executed the callback.
|
||||||
|
* Currently no 404 handling.
|
||||||
|
*/
|
||||||
public function handleRouting(): void
|
public function handleRouting(): void
|
||||||
{
|
{
|
||||||
$foo = $this->matchRoute();
|
$requestUri = $_SERVER['REQUEST_URI'];
|
||||||
var_dump($foo);
|
|
||||||
|
foreach ($this->routes as $route) {
|
||||||
|
if (preg_match(pattern: $route->getRegex(), subject: $requestUri, matches: $matches)) {
|
||||||
|
$parameters = [];
|
||||||
|
foreach ($route->getParameters() as $id => $parameter) {
|
||||||
|
$parameters[$parameter] = $matches[$id +1];
|
||||||
|
}
|
||||||
|
// PHP is mad about named parameters in call_user_func
|
||||||
|
// Uncaught Error: Unknown named parameter $args in …
|
||||||
|
// But PHPStorm seems happy without them. So what?
|
||||||
|
call_user_func($route->getCallback(), $parameters);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Throw a 404 result later …
|
||||||
|
die("Invalid route: $requestUri");
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,30 +11,8 @@ class Template
|
||||||
// empty body
|
// empty body
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public function render(string $templateName): void
|
public function render(string $templateName): void
|
||||||
{
|
{
|
||||||
$template = file_get_contents(filename: $this->templateDir . $templateName);
|
include $this->templateDir . $templateName;
|
||||||
|
|
||||||
// search for includes
|
|
||||||
preg_match_all(pattern: '/{% include ?\'?(.*?)\'? ?%}/i', subject: $template, matches: $matches, flags: PREG_SET_ORDER);
|
|
||||||
|
|
||||||
foreach ($matches as $value) {
|
|
||||||
$token = $value[0];
|
|
||||||
$include = $this->templateDir . $value[1];
|
|
||||||
if (file_exists(filename: $include)) {
|
|
||||||
$replacement = file_get_contents(filename: $include);
|
|
||||||
} else {
|
|
||||||
throw new Exception(message: "Missing included file: $include");
|
|
||||||
}
|
|
||||||
$template = str_replace(search: $token, replace: $replacement, subject: $template);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the original template code
|
|
||||||
$template = preg_replace(pattern: '/{% include ?\'?(.*?)\'? ?%}/i', replacement: '', subject: $template);
|
|
||||||
|
|
||||||
echo $template;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue