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();
 | 
						|
 |