Implemented changes requested by FuzeWorks\Application
- Added Priorities to the routes array. Routes can now be saved with priorities, making higher priority routes load before lower priorities - Fixed bug where callable is not reset upon attempting routing a new route after another was not satisfied
This commit is contained in:
parent
be414aa2cd
commit
f49c5dd882
|
@ -156,7 +156,14 @@ class Router
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addRoute(string $route, $routeConfig = null, bool $prepend = true)
|
/**
|
||||||
|
* Add a route to the Router
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
* @param null $routeConfig
|
||||||
|
* @param int $priority
|
||||||
|
*/
|
||||||
|
public function addRoute(string $route, $routeConfig = null, int $priority = Priority::NORMAL)
|
||||||
{
|
{
|
||||||
// Set defaultCallable if no value provided
|
// Set defaultCallable if no value provided
|
||||||
if (is_null($routeConfig))
|
if (is_null($routeConfig))
|
||||||
|
@ -165,23 +172,27 @@ class Router
|
||||||
// Convert wildcards to Regex
|
// Convert wildcards to Regex
|
||||||
$route = str_replace([':any',':num'], ['[^/]+', '[0-9]+'], $route);
|
$route = str_replace([':any',':num'], ['[^/]+', '[0-9]+'], $route);
|
||||||
|
|
||||||
if ($prepend)
|
if (!isset($this->routes[$priority]))
|
||||||
$this->routes = [$route => $routeConfig] + $this->routes;
|
$this->routes[$priority] = [];
|
||||||
else
|
|
||||||
$this->routes[$route] = $routeConfig;
|
|
||||||
|
|
||||||
Logger::log('Route added at '.($prepend ? 'top' : 'bottom').': "'.$route.'"');
|
if (!isset($this->routes[$priority][$route]))
|
||||||
|
$this->routes[$priority][$route] = $routeConfig;
|
||||||
|
|
||||||
|
Logger::log('Route added with ' . Priority::getPriority($priority) . ": '" . $route."'");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a route from the array based on the given route.
|
* Removes a route from the array based on the given route.
|
||||||
*
|
*
|
||||||
* @param $route string The route to remove
|
* @param $route string The route to remove
|
||||||
|
* @param int $priority
|
||||||
*/
|
*/
|
||||||
public function removeRoute(string $route)
|
public function removeRoute(string $route, int $priority = Priority::NORMAL)
|
||||||
{
|
{
|
||||||
unset($this->routes[$route]);
|
if (!isset($this->routes[$priority][$route]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
unset($this->routes[$priority][$route]);
|
||||||
Logger::log('Route removed: '.$route);
|
Logger::log('Route removed: '.$route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,54 +205,60 @@ class Router
|
||||||
*/
|
*/
|
||||||
public function route(string $path)
|
public function route(string $path)
|
||||||
{
|
{
|
||||||
// Check all the provided custom paths
|
// Check all the provided custom paths, ordered by priority
|
||||||
foreach ($this->routes as $route => $routeConfig)
|
for ($i=Priority::getHighestPriority(); $i<=Priority::getLowestPriority(); $i++) {
|
||||||
{
|
if (!isset($this->routes[$i]))
|
||||||
// Match the path against the routes
|
|
||||||
if (!preg_match('#^'.$route.'$#', $path, $matches))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Save the matches
|
foreach ($this->routes[$i] as $route => $routeConfig)
|
||||||
Logger::log('Route matched: '.$route);
|
|
||||||
$this->matches = $matches;
|
|
||||||
$this->route = $route;
|
|
||||||
|
|
||||||
// Call callable if routeConfig is callable, so routeConfig can be replaced
|
|
||||||
// This is an example of 'Dynamic Rewrite'
|
|
||||||
// e.g: '.*$' => callable
|
|
||||||
if (is_callable($routeConfig))
|
|
||||||
$routeConfig = call_user_func_array($routeConfig, [$matches]);
|
|
||||||
|
|
||||||
// If routeConfig is an array, multiple things might be at hand
|
|
||||||
if (is_array($routeConfig))
|
|
||||||
{
|
{
|
||||||
// Replace defaultCallable if a custom callable is provided
|
// Match the path against the routes
|
||||||
// This is an example of 'Custom Callable'
|
if (!preg_match('#^'.$route.'$#', $path, $matches))
|
||||||
// e.g: '.*$' => ['callable' => [$object, 'method']]
|
continue;
|
||||||
if (isset($routeConfig['callable']) && is_callable($routeConfig['callable']))
|
|
||||||
$this->callable = $routeConfig['callable'];
|
|
||||||
|
|
||||||
// If the route provides a configuration, use that
|
// Save the matches
|
||||||
// This is an example of 'Static Rewrite'
|
Logger::log("Route matched: '" . $route . "' with " . Priority::getPriority($i));
|
||||||
// e.g: '.*$' => ['viewName' => 'custom', 'viewType' => 'cli', 'function' => 'index']
|
$this->matches = $matches;
|
||||||
else
|
$this->route = $route;
|
||||||
$this->matches = array_merge($this->matches, $routeConfig);
|
$this->callable = null;
|
||||||
|
|
||||||
|
// Call callable if routeConfig is callable, so routeConfig can be replaced
|
||||||
|
// This is an example of 'Dynamic Rewrite'
|
||||||
|
// e.g: '.*$' => callable
|
||||||
|
if (is_callable($routeConfig))
|
||||||
|
$routeConfig = call_user_func_array($routeConfig, [$matches]);
|
||||||
|
|
||||||
|
// If routeConfig is an array, multiple things might be at hand
|
||||||
|
if (is_array($routeConfig))
|
||||||
|
{
|
||||||
|
// Replace defaultCallable if a custom callable is provided
|
||||||
|
// This is an example of 'Custom Callable'
|
||||||
|
// e.g: '.*$' => ['callable' => [$object, 'method']]
|
||||||
|
if (isset($routeConfig['callable']) && is_callable($routeConfig['callable']))
|
||||||
|
$this->callable = $routeConfig['callable'];
|
||||||
|
|
||||||
|
// If the route provides a configuration, use that
|
||||||
|
// This is an example of 'Static Rewrite'
|
||||||
|
// e.g: '.*$' => ['viewName' => 'custom', 'viewType' => 'cli', 'function' => 'index']
|
||||||
|
else
|
||||||
|
$this->matches = array_merge($this->matches, $routeConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no custom callable is provided, use default
|
||||||
|
// This is an example of 'Default Callable'
|
||||||
|
if (is_null($this->callable))
|
||||||
|
$this->callable = [$this, 'defaultCallable'];
|
||||||
|
|
||||||
|
// Attempt and load callable. If false, continue
|
||||||
|
$output = $this->loadCallable($this->callable, $this->matches, $route);
|
||||||
|
if (is_bool($output) && $output === FALSE)
|
||||||
|
{
|
||||||
|
Logger::log('Callable not satisfied, skipping to next callable');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no custom callable is provided, use default
|
|
||||||
// This is an example of 'Default Callable'
|
|
||||||
if (is_null($this->callable))
|
|
||||||
$this->callable = [$this, 'defaultCallable'];
|
|
||||||
|
|
||||||
// Attempt and load callable. If false, continue
|
|
||||||
$output = $this->loadCallable($this->callable, $this->matches, $route);
|
|
||||||
if (is_bool($output) && $output === FALSE)
|
|
||||||
{
|
|
||||||
Logger::log('Callable not satisfied, skipping to next callable');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotFoundException("Could not load view. Router could not find matching route with satisfied callable.");
|
throw new NotFoundException("Could not load view. Router could not find matching route with satisfied callable.");
|
||||||
|
@ -387,12 +404,13 @@ class Router
|
||||||
/**
|
/**
|
||||||
* Returns an array with all the routes.
|
* Returns an array with all the routes.
|
||||||
*
|
*
|
||||||
|
* @param int $priority
|
||||||
* @return array
|
* @return array
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
*/
|
*/
|
||||||
public function getRoutes(): array
|
public function getRoutes(int $priority = Priority::NORMAL): array
|
||||||
{
|
{
|
||||||
return $this->routes;
|
return $this->routes[$priority];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -120,19 +120,14 @@ class RouterTest extends MVCRTestAbstract
|
||||||
$testAppendRouteFunction = [function () {
|
$testAppendRouteFunction = [function () {
|
||||||
}];
|
}];
|
||||||
$this->router->addRoute('testRoute', $testRouteFunction);
|
$this->router->addRoute('testRoute', $testRouteFunction);
|
||||||
$this->router->addRoute('testAppendRoute', $testAppendRouteFunction, false);
|
$this->router->addRoute('testAppendRoute', $testAppendRouteFunction, Priority::LOW);
|
||||||
|
|
||||||
// Test if the order is correct
|
// Test if the order is correct
|
||||||
$this->assertSame(
|
// First for Priority::NORMAL
|
||||||
['testRoute' => $testRouteFunction, 'testAppendRoute' => $testAppendRouteFunction],
|
$this->assertSame(['testRoute' => $testRouteFunction], $this->router->getRoutes(Priority::NORMAL));
|
||||||
$this->router->getRoutes()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test if the order is not incorrect
|
// Then for Priority::LOW
|
||||||
$this->assertNotSame(
|
$this->assertSame(['testAppendRoute' => $testAppendRouteFunction], $this->router->getRoutes(Priority::LOW));
|
||||||
['testAppendRoute' => $testAppendRouteFunction, 'testRoute' => $testRouteFunction],
|
|
||||||
$this->router->getRoutes()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue