puiu91
5/11/2016 - 5:39 AM

fc.php

<?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;
    }
}