Sinisterly
PHP:MVC - Model View Controller | Controller Routing & Routers #2 - Printable Version

+- Sinisterly (https://sinister.li)
+-- Forum: Coding (https://sinister.li/Forum-Coding)
+--- Forum: PHP (https://sinister.li/Forum-PHP)
+--- Thread: PHP:MVC - Model View Controller | Controller Routing & Routers #2 (/Thread-PHP-MVC-Model-View-Controller-Controller-Routing-Routers-2)



PHP:MVC - Model View Controller | Controller Routing & Routers #2 - Keeper - 10-20-2013

Introduction:

In this part we'll get into the routing of the front controller. So let's go back to our front controller's class:

PHP Code:
<?php namespace KF; include_once 'Loader.php'; class App { private static $_instance=null; private $_config = null; /** * * @var \KF\FrontController */ private function __construct() { \KF\Loader::registerNamespace('KF', dirname(__FILE__).DIRECTORY_SEPARATOR); \KF\Loader::registerAutoLoad(); $this->_config = \KF\Config::getInstance(); } public function dispatch() { $a = new \KF\Routers\DefaultRouter(); $a->parse(); } public function setConfigFolder($path) { $this->_config->setConfigFolder($path); } public function getConfigFolder() { return $this->_configFolder; } public function run(){ if ($this->_config->getConfigFolder() == null) { $this->setConfigFolder('../config'); } $this->_frontController = \KF\FrontController::getInstance(); $this->_frontController->dispatch(); } /** * * @return \KF\App */ public static function getInstance(){ if (self::$_instance == null) { self::$_instance = new \KF\App(); } return self::$_instance; } }

What we need to do now is to start routing the routes that have been added. So we need to make a check whether the key of a route is positioned in the beginning of the URI:

PHP Code:
$routes = \KF\App:getInstance()->getConfig()->routes; if (is_array($routes) && count($routes) > 0) { foreach ($routes as $k => $v) { if (stripos($_uri, $k)===0) { $this->ns=$v; break; } } }

If that returns TRUE than we have the namespace we inquire where $v is the namespace itself. So we need to write that namespace somewhere. Let's make a property for it:

PHP Code:
private $ns=null; private $controller=null; private $method=null;

And since I just though right now, we need to extend the idea for the routes by differentiating the URL parameter from the controller. So back to our routes.php file we gonna add keys to the array so as to map them correspondingly.

PHP Code:
<?php $cnf['administration']['namespace']='Controllers\Admin'; $cnf['administration']['controllers']['index']='test'; $cnf['Administration']['namespace']['new']='create'; $cnf['*']['namespace']='Controllers'; return $cnf;

So now in this case, we should also modify the front controller to get that:

PHP Code:
$routes = \KF\App:getInstance()->getConfig()->routes; if (is_array($routes) && count($routes) > 0) { foreach ($routes as $k => $v) { if (stripos($_uri, $k)===0 && $v['namespace']) { $this->ns=$v['namespace']; break; } } }

Suppose we request the following URL after the modifications we've made so far:

Code:
kftest.localhost/index.php/administration

We'll get the correct namespace:

Code:
Controllers\Admin

Now let's get rid of that return function:

PHP Code:
echo $this->ns;

And replace it with the following:

PHP Code:
if ($this->ns == null && $routes['*']['namespace']) { $this->ns = $routes['*']['namespace']; } else if ($this->ns == null && !$routes['*']['namespace']) { throw new \Exception('Default route missing', 500); }

If a namespace is not found and the default router is existent (which in our case is ['*']) so then, the namespace itself would be equal to the default one. As simple as that. The other situation is when a router is not registered as well but as well as that, there is no default router for it to be compared/appended to, it throws an error.

Executing and echoing out the result like so sums up in the following:

PHP Code:
echo $this->ns;

Code:
Controllers

Which is the default one. Now let's see if the second check is valid. Let's request a URL address like that:

Code:
kftest.localhost/index.php/Infamous

We get the default one once more. Same would be if we register a new route. Suppose this one would be 'admin'.

PHP Code:
<?php $cnf['admin']['namespace']='Controllers\Admin'; $cnf['administration']['namespace']='Controllers\Admin'; $cnf['administration']['controllers']['index']='test'; $cnf['Administration']['namespace']['new']='create'; $cnf['*']['namespace']='Controllers'; return $cnf;

The result will be:

Code:
Controllers\Admin

Now what we need to do for the routing is take the controller and the corresponding method so that we may locate the file, make an instance for it and of course, call the method we need. So just to make a few points here. As you know, the priority of the namespaces changes depending on their line of the code. The first one gets the highest priority and so on. With the function stripos() we take the string that matches the namespace but what if that is 'administration' and we search for 'admin'? It will match 'admin' as it is contained in the first string and forget about the other part.

So we need to make the key to be equal to the length of the URI or there to be a '/' after it:

PHP Code:
$routes = \KF\App:getInstance()->getConfig()->routes; if (is_array($routes) && count($routes) > 0) { foreach ($routes as $k => $v) { if (stripos($_uri, $k)===0 && ($_uri==$k || stripos($_uri, $k . '/')===0) && $v['namespace']) { $this->ns=$v['namespace']; break; } } }

So in case we have only the packet 'administration':

Code:
kftest.localhost/index.php/administration

Then the key:

PHP Code:
$cnf['administration']['namespace']='Controllers\Admin';

Will correspond at 100% to the URI which assures us that we have located the correct packet. Now we need to get grab of the correct controller and method so that we may call them properly. We already did this in some of the first series, so let's add this to our front controller class:

PHP Code:
$_params = explode('/', $_uri); if ($_params[0]) { $this->controller = $_params[0]; if ($_params[1]) { $this->method=$_params[1]; } else { $this->method=$this->getDefaultMethod(); } } else { $this->controller = $this->getDefaultController(); $this->method = $this->getDefaultMethod(); }

We've developed the code previously as I said, so before you start asking why we're not elaborating into it now, refer to the previous series. Though I'll put it as plain as possible right now. Basically, we are exploding the URI. If the 0 parameter exists that's our controller in fact and the first parameter is the method. If there is no method, we grab the default one and if there is no controller we take the default controller and the default method as a whole.

Conclusion:

I'm overall trying to keep all of the tutorials from these series in a certain length so as to be easily accessible my the members and to be read with bigger interest and expectation for the next part. Thanks for reading!