<?php
namespace App\Core;
use App\Helpers\Utils;
/**
* Class FrontController
* @package App\Core
*/
final class FrontController
{
/**
* @type object
*/
private $databaseHandler;
/**
* @type array Stores route paths to match server requests against.
*/
private $routes = [];
/**
* FrontController constructor.
*
* @param $databaseHandler
*/
public function __construct($databaseHandler)
{
$this->databaseHandler = $databaseHandler;
}
/**
* Adds a Route object to internal routes array.
*
* @param \App\Core\Route $route
*
* @return void
*/
public function addRoute(Route $route)
{
$this->routes[] = $route;
}
/**
* Retrieves the http method for current request.
*
* @return string
*/
private function processRequestMethod()
{
return $_SERVER['REQUEST_METHOD'];
}
/**
* Retrieves the uri path after the domain name and index.php. For example http://www.example.com/index.php/home
* would return index.php/home.
*
* @return void Uri path after the domain name.
*/
private function processRequestUri()
{
$uriPath = $_SERVER['PATH_INFO'];
// strip terminating slash for any uri path except for root '/'
if ($uriPath !== '/' && substr($uriPath, -1) === '/') {
$uriPath = substr($uriPath, 0, strlen($uriPath) - 1);
}
return $uriPath;
}
/**
* Matches a stored route with a uri request.
*
* @return void
*/
public function dispatchRoute()
{
$requestUriPath = $this->processRequestUri();
$requestHttpMethod = $this->processRequestMethod();
Utils::debug($this->routes);
Utils::debug($_SERVER);
// match the request uri and request method against a stored route
foreach ($this->routes as $route)
{
if ($requestUriPath === $route->path &&
$requestHttpMethod === $route->method
) {
$this->dispatch($route);
return;
}
}
//throw new \Exception('cannot match request against available routes');
// redirect to 404 page because the request URI did not match against a stored route
//require 'resources/views/404.php';
header('Location: http://localhost:8000/404');
}
/**
* Invokes the routing controller and the corresponding method and parameters (if provided)
* from the supplied route object.
*
* @param object $route
*
* @return void
*/
private function dispatch($route)
{
// does the route controller class exist
// @todo might be better to just use a try catch and instantiate the class instead of heavy file lookup
if (!$this->controllerExists($route->handler)) {
require 'resources/views/404.php';
return;
}
$controller = $route->handler;
$controller = new $controller($this->databaseHandler);
// does a route require a method to be invoked
if ($route->action) {
// ensure controller contains the action (i.e., the method) requested
if (!method_exists($controller, $route->action)) {
require 'resources/views/404.php';;
return;
}
// invoke the controller action (i.e., the method)
$controller->{$route->action}();
} else {
// attempt to invoke default index() method otherwise redirect to 404 page
method_exists($controller, 'index')
? $controller->index()
: require 'resources/views/404.php';;
}
}
/**
* Determines if a controller class file exists.
*
* @param string $controller
*
* @return bool
*/
private function controllerExists($controller)
{
return file_exists($controller . '.php') ? true : false;
}
}