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.
		
		
		
		
		
			
		
			
				
					
					
						
							352 lines
						
					
					
						
							8.0 KiB
						
					
					
				
			
		
		
	
	
							352 lines
						
					
					
						
							8.0 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) { | 
						|
				// If route does not match the base url | 
						|
				if ($route[0] != $path) { | 
						|
					continue; | 
						|
				} | 
						|
 | 
						|
				// ["/example/my-page", "ExampleController", "action", "" : ["view", "title", "description"]], | 
						|
				self::addBasicRoute(['GET', 'POST'], $route); | 
						|
 | 
						|
				break; | 
						|
			} | 
						|
 | 
						|
			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, 'indexAction']); | 
						|
		self::addRoute(['GET'], [$route . '/create', $controller, 'createAction']); | 
						|
		self::addRoute(['POST'], [$route, $controller, 'storeAction']); | 
						|
		self::addRoute(['GET'], [$route . '/[i:id]', $controller, 'showAction', ['id']]); | 
						|
		self::addRoute(['GET'], [$route . '/[i:id]/edit', $controller, 'editAction', ['id']]); | 
						|
		self::addRoute(['PUT', 'PATCH'], [$route . '/[i:id]', $controller, 'updateAction', ['id']]); | 
						|
		self::addRoute(['DELETE'], [$route . '/[i:id]', $controller, 'destroyAction', ['id']]); | 
						|
	} | 
						|
 | 
						|
	//-------------------------------------// | 
						|
 | 
						|
	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)) { | 
						|
			return; | 
						|
		} | 
						|
 | 
						|
		$route      = $data[0] ?? ''; | 
						|
		$controller = $data[1] ?? ''; | 
						|
		$action     = $data[2] ?? ''; | 
						|
		$param      = $data[3] ?? []; | 
						|
		if ($route == '' || $controller == '' || $action == '') { | 
						|
			return; | 
						|
		} | 
						|
 | 
						|
		// Create Klein route | 
						|
		self::$router->respond($method, $route, function($request, $response, $service) | 
						|
			use($controller, $action, $param) { | 
						|
 | 
						|
			// Create new Controller object | 
						|
			$controller = '\App\Controllers\\' . $controller; | 
						|
			$controller = new $controller(self::$router); | 
						|
 | 
						|
			$stillValid = true; | 
						|
 | 
						|
			// If method does not exist in object | 
						|
			if (!method_exists($controller, $action)) { | 
						|
				$stillValid = false; | 
						|
			} | 
						|
 | 
						|
			// If no valid permissions | 
						|
			if ($controller->getAdminSection() && | 
						|
				$controller->getLoggedIn() == false) { | 
						|
				$stillValid = false; | 
						|
			} | 
						|
 | 
						|
			// Call Controller action | 
						|
			if ($stillValid) { | 
						|
 | 
						|
				// Loop through params | 
						|
				$params = []; | 
						|
				foreach ($param as $name) { | 
						|
					$params[] = $request->param($name); | 
						|
				} | 
						|
 | 
						|
				return $controller->{$action}(...$params); | 
						|
			} | 
						|
			else { | 
						|
				$controller->throw404(); | 
						|
			} | 
						|
		}); | 
						|
	} | 
						|
 | 
						|
	protected static function addBasicRoute(array $method = [], array $route = []): void | 
						|
	{ | 
						|
		if (!_exists($method) || !_exists($route)) { | 
						|
			return; | 
						|
		} | 
						|
 | 
						|
		// Create Klein route | 
						|
		self::$router->respond($method, $route[0], function() use($route) { | 
						|
 | 
						|
			// Create new Controller object | 
						|
			$controller = '\App\Controllers\\' . $route[1]; | 
						|
			$controller = new $controller(self::$router); | 
						|
 | 
						|
			// Complete action variable | 
						|
			if ($route[2] == '') { | 
						|
				$route[2] = 'indexAction'; | 
						|
			} | 
						|
			else { | 
						|
				$route[2] .= 'Action'; | 
						|
			} | 
						|
 | 
						|
			$stillValid = true; | 
						|
 | 
						|
			// If method does not exist in object | 
						|
			if (!method_exists($controller, $route[2])) { | 
						|
				$stillValid = false; | 
						|
			} | 
						|
 | 
						|
			// If no valid permissions | 
						|
			if ($controller->getAdminSection() && | 
						|
				$controller->getLoggedIn() == false) { | 
						|
				$stillValid = false; | 
						|
			} | 
						|
 | 
						|
			// Call Controller action | 
						|
			if ($stillValid) { | 
						|
				if (is_array($route[3])) { | 
						|
					return $controller->{$route[2]}( | 
						|
						$route[3][0] ?? '', | 
						|
						$route[3][1] ?? '', | 
						|
						$route[3][2] ?? '' | 
						|
					); | 
						|
				} | 
						|
				else if ($route[3] != '') { | 
						|
					return $controller->{$route[2]}($route[3]); | 
						|
				} | 
						|
				else { | 
						|
					return $controller->{$route[2]}(); | 
						|
				} | 
						|
			} | 
						|
			else { | 
						|
				$controller->throw404(); | 
						|
			} | 
						|
		}); | 
						|
	} | 
						|
 | 
						|
	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: | 
						|
 | 
						|
					$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(); | 
						|
 | 
						|
// @Todo | 
						|
// - combine addRoute and addBasicroute functionality
 | 
						|
 |