jasonsnider/tinker-mvc

View on GitHub
core/Tinker/src/Mvc/Dispatcher.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php
/**
 * Dispatcher
 */
namespace Tinker\Mvc;

/**
 * Dispatcher converts a request into a controller action. It uses Router's
 * mapped request to locate and load the correct controller from the correct
 * plugin. If found the requested action is called on the controller. A
 * controller action is in the form of Object::method() where the method MUST
 * be public.
 */
class Dispatcher
{
    /**
     * Loader
     *
     * @var object
     */
    protected $Loader;

    /**
     * Router
     *
     * @var object
     */
    protected $Router;

    /**
     * Theme
     *
     * @var object
     */
    protected $Theme;

    /**
     * View
     *
     * @var object
     */
    protected $view;

    /**
     * Gather plugins, controllers and actions
     * Given the URI /example/main/index/p1/p2/p3/p4:1
     * We would be passing 4 GET parameters (where p4 is a named key to value
     * pair and p1 - p3 would be assigned numeric keys) into the index action of
     * the main controller of the example plugin.
     *
     * The name of the plugin should also be that plugins namespace.
     *
     * We will predefine 3 possible paths for autoloading:
     * 1. Core, the core path will look for a Plugins directory in the core
     *
     * library, this will mostly be used for building examples.
     * 2. Main, This will check the main plugin path.
     *
     * 3. App, This will check the Plugin path inside App. This directory will
     * ship empty by default. I'm assuming this is where you will build your
     * application.
     *
     * An autoloader will figure out which path to pull from.
     * Finally we will istanitate the classes based on the PSR-4 autoloading
     * statndards. This might look something like:
     *
     * $class = '\\Example\\Controller\\MainController';
     * $controller = new $class();
     * $controller->index();
     *
     * Sample URI /tinker_plugin/tinker_plugin/execute/e1/e2/e3/e4:1
     *
     * @param object $loader
     * @param object $router
     * @param object $theme
     * @param object $view
     * @param boolean $render (set to false for unit testing)
     * @return void
     */
    public function __construct($loader, $router, $theme, $view, $render = true) {

        $this->Loader = $loader;
        $this->Router = $router;
        $this->Theme = $theme;
        $this->View = $view;

        $plugin = $this->Router->getPlugin(true);
        $model = $this->Router->getPlugin(true);
        $controller = $this->Router->getController(true) . 'Controller';
        $action = $this->Router->getAction();

        //Autoload all plugins
        $this->Loader->addNamespace(
            $plugin,
            'plugin' . DS . $plugin . DS . 'src'
        );

        $this->Loader->addNamespace(
            $plugin,
            APP . DS . 'plugin' . DS . $plugin . DS . 'src'
        );

        $this->Loader->addNamespace(
            'App',
            APP . DS . 'src'
        );

        if($render){
            if (!empty($this->Router->checkAsset($loader))):
                $this->Router->fetchAsset($this->Router->checkAsset($loader));
            else:
                //Load the MVC stack, if a specific plugin has not been defined as
                //a container MVC conventions will be used to load the MVC stack
                if (\Tinker\Di\IoCRegistry::registered($controller)) {
                    $controller = \Tinker\Di\IoCRegistry::resolve($controller);
                } else {
                    $class = "\\{$plugin}\\Controller\\{$controller}";
                    $model = "\\{$plugin}\\Model\\{$model}";

                    $controller = new $class($this->Theme, $this->View);
                    $controller->inject(new $model());
                }

                $controller->{$action}();
            endif;
        }

    }

}