PHP:MVC - Model View Controller | FC & Routes #2

Keeper
11 years ago

0

Introduction:

First thing we gonna do is to unify the way that the routers are returning the information to the front controller so as to be unique and give us the opportunity for future changes and alongside that, with an ease. This case of returning data won’t be with objects or methods but with URI. The URI will be the string that the front controller will parse. So let’s contemplate a bit here:

kftest.localhost/administration/user/edit/22/desc  

Let’s say this is our URL address. We have the model administration with the controller user with the method edit and some parameters afterwards. So basically, all this is just a string which contains actually everything we need for the front controller. Actually, we have that extraction in our parse method of the controller’s class:

     public function parse() {  
          $_uri = substr(str_replace($_SERVER['SCRIPT_NAME'], "", $_SERVER["PHP_SELF"]), 1);  
...  

So from the whole request that is coming from the browser we just need to remove the domain name and, of course, evaluate the URL as string beforehand so as to manipulate it as such.

<?php  

namespace KF\Routers;  
class DefaultRouter {  
     private $controller=null;  
     private $method=null;  
     private $params=array();  
     public function parse() {  
          $_uri = substr(str_replace($_SERVER['SCRIPT_NAME'], "", $_SERVER["PHP_SELF"]), 1);  
          $controller = null;  
          $method = null;  
          $_params = explode('/', $_uri);  
          if ($_params[0]) {  
              $this->controller=ucfirst($_params[0]);  

               if ($_params[1]) {  
                   $this->method = $_params[1];  
                   unset($_params[0], $_params[1]);  
                   $this->params = array_values($_params);  
               }  
         }  
         public function getController() {  
                return $this->controller;  
         }  

         public function getMethod() {  
                return $this->method;  
         }  

         public function getGet() {  
                return $this->params;  
         }  
}  

In the previous tutorial we ended up with the following code for the router’s class. In our case we want to extract the URI which we explained and talked about above. Following that idea, the whole process can be quite shortened and we can end up with the following structure:

<?php  

namespace KF\Routers;  
class DefaultRouter {  

     public function getURI() {  
          return substr($_SERVER['PHP_SELF'], "", strlen($_SERVER(["SCRIPT_NAME"]) + 1);  
    }  

}  

It is always better and therefore recommended that you develop things in a simpler way. With just one line of code as of our method, we did a job that could include a lot more LOC. The previous code had the idea of obtaining, parsing and returning the corresponding data so every router should have parsed the data as well. Whereas now it’s idea is altered. So far we have just one default router but in the future series, every router will need to be able to unify the address so that the front controller may work with it.

Let’s create an interface in the Routers' folder:

<?php  
namespace KF\Routers;  

interface IRouter {  
     public function getURI();  
}  

Within this interface we need to specify its task. That from its side would mean the contract it needs to accept and here we say that every object that implements IRouter must have a public function. Here we don’t have a realization of the function. We just say that every class or object which implements IRouter should have that method.

<?php  

namespace KF\Routers;  
class DefaultRouter {  

     public function getURI() {  
          return substr($_SERVER['PHP_SELF'], "", strlen($_SERVER(["SCRIPT_NAME"]) + 1);  
    }  

}  

Now back to our default router we’ll make the implementation so as to work. If we don’t specify the method within the class, we’ll end up with this error which is self-explanatory:

Fatal error: Class KF\Routers\DefaultRouter contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (KF\Routers\IRouter::getURI)  

So by including the method, we enforce it to be implemented. As we’ve mentioned in the previous tutorials there are three main things we need to follow along the series. The first one was to terminate all dependencies between parameters and name of the file, second rule was more than one address to be able to match a controller and the third one was to use some sort of packets or something similar. Therefore, we need to describe (code) those rules somewhere. Best directory for that would be the config one obviously.

Make a new routes.php file so as to keep with the tutorial:

<?php  

$cnf['*']='Controller';  

That’s the router by default. Now let’s make a new controller with the namespace of Controllers and then say in routes that the controllers are in the namespace of Controllers, then things turn a lot easier for everything from now on.

<?php  

namespace Controllers;  
class Index {  

}  

So for example, if we get a request like:

kftest.localhost/administration  
<?php  

$cnf['administration']='Controllers\Admin';  

It will be searched for in that namespace for the administrators. Basically, seeking for a controller called administration and is located in the namespace Controllers. On the other side, if we get something like that in our URL as a request:

kftest.localhost/administration  

The controller will search for the class Users, not in Controllers but in Controllers/Admin. So that is why we structured it like so as we said before that it would be easier in the further development. Now we need to code a way in which the front controller can communicate with the routes.php file and extract certain data from within it. And we’ll start off with pointing where the namespace controllers is located.

app.php:

<?php  

$cnf['default_controller']='Index2';  
$cnf['default_method']='index2';  
$cnf['namespace']['Controllers']='/store/work/www/kftest/controllers/';  
return $cnf;  

Now if we execute it like so, we’ll get an error that registerNamespaces() is not located:

Fatal error: Call to undefined method KF\Loader::registerNamespaces() in ...  

So just implement it in the Loader.php file:

<?php  

namespace KF;  
final class Loader {  

  private static $namespaces = array();  

  private function __construct() {  

  }  

  public static function registerAutoLoad() {  
     spl_autoload_register(array("\KF\Loader", 'autoload'));  
  }  

  public static function autoload($class) {  
     echo $class;   
  }  

  public static function registerNamespace($namespace, $path) {  
       $namespace = trim($namespace);  
       if (strlen($namespace) > 0) {  
            if (!$path) {  
                 throw new \Exception('Invalid Path');  
            }  
            $_path = realpath($path);  
            if ($_path && is_dir($_path) && is_readable($_path)) {  
                self::$namespaces[$namespace] = $_path . DIRECTORY_SEPARATOR;  
            } else {  
                  throw new \Exception('Namespace directory read error:' . $path);  
            }  
    } else {  
         throw new exception \Exception('Invalid namespace:' . $namespace);  
    }  
}  

  public static function registerNamespaces($ar) {  
          if (is_array($ar)) {  
               foreach ($ar as $k => $v) {  
                    self::registerNamespace($k, $v);  
               } else {  
                  throw new \Exception('Invalid namespaces');  
               }  
   }  

We have explained this code before. Basically in two words, we’re just going over an array and per each iteration, it calls registerNamespaces().

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!

0replies
1voice
210views
You must be logged in to reply to this discussion. Login
1 of 1

This site only uses cookies that are essential for the functionality of this website. Cookies are not used for tracking or marketing purposes.

By using our site, you acknowledge that you have read and understand our Privacy Policy, and Terms of Service.

Dismiss