You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
6.9 KiB
287 lines
6.9 KiB
<?php |
|
|
|
namespace App\Classes; |
|
|
|
use Klein\Klein; |
|
|
|
use App\Classes\Db; |
|
|
|
use App\Model\SectionModel; |
|
use App\Model\PageModel; |
|
|
|
class Router { |
|
|
|
protected static $router; |
|
protected static $routes = []; |
|
|
|
public static function _init(): void { |
|
self::$router = new Klein(); |
|
} |
|
|
|
//-------------------------------------// |
|
|
|
/** |
|
* Load all routes into the Klein object |
|
* |
|
* @return void |
|
*/ |
|
public static function fire(): void |
|
{ |
|
$path = parse_url($_SERVER['REQUEST_URI'])['path']; |
|
$check = str_replace('.', '', $path); |
|
|
|
// If it's a dynamic file or the file doesn't exist, go through the router. |
|
if ($path == $check || !file_exists(getcwd() . $path)) { |
|
|
|
Db::load(); |
|
self::setDefaultLayout(); |
|
self::loadConfigRoutes(); |
|
self::loadDbRoutes(); |
|
|
|
// Process basic routes |
|
foreach (self::$routes as $route) { |
|
// ["/example/my-page", "ExampleController", "action", "" : ["view", "title", "description"]], |
|
self::addRoute(['GET', 'POST'], $route); |
|
} |
|
|
|
self::createNavigation(); |
|
self::setHttpError(); |
|
|
|
self::$router->dispatch(); |
|
} |
|
} |
|
|
|
/** |
|
* Add CRUD routes |
|
* Example usage: Router::resource('/example', 'CrudController'); |
|
* |
|
* @param string $route The URL location |
|
* @param string $controller Controller to handle this route |
|
* |
|
* @return void |
|
*/ |
|
public static function resource(string $route, string $controller): void |
|
{ |
|
/* |
|
* HTTP Verb Part (URL) Action (Method) |
|
* |
|
* GET /route indexAction |
|
* GET /route/create createAction |
|
* POST /route storeAction |
|
* GET /route/{id} showAction |
|
* GET /route/{id}/edit editAction |
|
* PUT/PATCH /route/{id} updateAction |
|
* DELETE /route/{id} destroyAction |
|
*/ |
|
|
|
self::addRoute(['GET'], [$route, $controller, 'index']); |
|
self::addRoute(['GET'], [$route . '/create', $controller, 'create']); |
|
self::addRoute(['POST'], [$route, $controller, 'store']); |
|
self::addRoute(['GET'], [$route . '/[i:id]', $controller, 'show']); |
|
self::addRoute(['GET'], [$route . '/[i:id]/edit', $controller, 'edit']); |
|
self::addRoute(['PUT', 'PATCH'], [$route . '/[i:id]', $controller, 'update']); |
|
self::addRoute(['DELETE'], [$route . '/[i:id]', $controller, 'destroy']); |
|
} |
|
|
|
//-------------------------------------// |
|
|
|
protected static function setDefaultLayout(): void |
|
{ |
|
self::$router->respond(function ($request, $response, $service) { |
|
$service->layout('../app/views/layouts/default.php'); |
|
}); |
|
} |
|
|
|
protected static function loadConfigRoutes(): void |
|
{ |
|
if (file_exists('../route.php')) { |
|
self::$routes = require_once '../route.php'; |
|
} |
|
} |
|
|
|
/** |
|
* Add all pages in the Db to self::$routes |
|
* |
|
* @return void |
|
*/ |
|
protected static function loadDbRoutes(): void |
|
{ |
|
// Load all sections from Db |
|
$sections = SectionModel::selectAll('*', 'WHERE `active` = 1 ORDER BY `order` ASC'); |
|
|
|
// Return if no sections |
|
if (!_exists($sections)) { |
|
return; |
|
} |
|
|
|
// Load all pages from Db |
|
$pages = PageModel::selectAll('DISTINCT page.*', ' |
|
LEFT JOIN page_has_content ON page_has_content.page_id = page.id |
|
LEFT JOIN content ON content.id = page_has_content.content_id |
|
WHERE page.active = 1 AND content.active = 1 |
|
ORDER BY page.order ASC; |
|
'); |
|
|
|
// Return if no pages |
|
if (!_exists($pages)) { |
|
return; |
|
} |
|
|
|
// Select id column |
|
$section = array_column($sections, 'section', 'id'); |
|
|
|
// Loop through all pages |
|
foreach ($pages as $pageKey => $page) { |
|
// Skip if section isn't created / active |
|
if (!_exists($section, $page['section_id'])) { continue; } |
|
|
|
// url = /section/page |
|
$url = '/' . $section[$page['section_id']] . '/' . $page['page']; |
|
|
|
// Add route |
|
self::$routes[] = [$url, 'PageController', 'route', [$page['id']]]; |
|
} |
|
|
|
// Cache sections and pages |
|
Db::setSections($sections); |
|
Db::setPages($pages); |
|
} |
|
|
|
protected static function addRoute(array $method = [], array $data = []): void |
|
{ |
|
if (!_exists($method) || !_exists($data) || count($data) < 2) { |
|
return; |
|
} |
|
|
|
$route = $data[0] ?? null; |
|
$controller = $data[1] ?? null; |
|
$action = $data[2] ?? null; |
|
$parameters = $data[3] ?? []; |
|
|
|
if (!$route || !$controller || !is_array($parameters)) { |
|
return; |
|
} |
|
|
|
// Create Klein route |
|
self::$router->respond($method, $route, function($request, $response, $service) use($controller, $action, $parameters) { |
|
|
|
// Create new Controller object |
|
$controller = '\App\Controllers\\' . $controller; |
|
$controller = new $controller(self::$router); |
|
|
|
// Complete action variable |
|
if (!$action) { |
|
$action = 'indexAction'; |
|
} |
|
else { |
|
$action .= 'Action'; |
|
} |
|
|
|
// If method does not exist in object |
|
if (!method_exists($controller, $action)) { |
|
return $controller->throw404(); |
|
} |
|
|
|
// If no valid permissions |
|
if ($controller->getAdminSection() && !$controller->getLoggedIn()) { |
|
return $controller->throw404(); |
|
} |
|
|
|
// Get URL parameters |
|
$namedParameters = array_filter($request->paramsNamed()->all(), 'is_string', ARRAY_FILTER_USE_KEY); |
|
$namedParameters = array_values($namedParameters); |
|
|
|
// Append URL parameters to the hard-coded parameters |
|
array_push($parameters, ...$namedParameters); |
|
|
|
// Call Controller action |
|
return $controller->{$action}(...$parameters); |
|
}); |
|
} |
|
|
|
public static function createNavigation(): void |
|
{ |
|
// Pull from cache |
|
$sections = Db::getSections(); |
|
$pages = Db::getPages(); |
|
|
|
// [ |
|
// [ |
|
// 'section url', |
|
// 'title', |
|
// ['page url', 'title'], |
|
// ['page url', 'titleOfPage2'], |
|
// ], |
|
// [], |
|
// [], |
|
// ] |
|
|
|
$navigation = []; |
|
|
|
// Generate sections |
|
foreach ($sections as $section) { |
|
// Skip hidden sections |
|
if ($section['hide_navigation'] == '1') { |
|
continue; |
|
} |
|
|
|
// Add URL, title to ID |
|
$navigation[$section['id']] = [ |
|
$section['section'], $section['title'] |
|
]; |
|
} |
|
|
|
// Generate pages |
|
foreach ($pages as $page) { |
|
// Skip hidden sections |
|
if (!_exists($navigation, $page['section_id'])) { |
|
continue; |
|
} |
|
|
|
// Skip hidden pages |
|
if ($page['hide_navigation'] == '1') { |
|
continue; |
|
} |
|
|
|
// Add [URL, title] to ID |
|
$navigation[$page['section_id']][] = [ |
|
$page['page'], $page['title'] |
|
]; |
|
} |
|
|
|
self::$router->service()->navigation = $navigation; |
|
} |
|
|
|
//-------------------------------------// |
|
|
|
protected static function setHttpError(): void |
|
{ |
|
self::$router->onHttpError(function($code) { |
|
$service = self::$router->service(); |
|
|
|
switch ($code) { |
|
case 404: |
|
|
|
// @Todo: find out why this was needed and remove if possible |
|
$service->escape = function (?string $string) { |
|
return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8'); |
|
}; |
|
|
|
self::$router->response()->sendHeaders(true, true); |
|
$service->pageTitle = 'Error 404 (Not Found)'; |
|
$service->render('../app/views/errors/404.php'); |
|
break; |
|
} |
|
}); |
|
} |
|
|
|
//-------------------------------------// |
|
|
|
public static function getRoutes(): array |
|
{ |
|
return self::$routes; |
|
} |
|
|
|
} |
|
|
|
Router::_init();
|
|
|