PHP:MVC - Model View Controller | App #2 & Loader3

Keeper
11 years ago

0

Introduction:

Now that we are done with the Application class, Loader and Config mechanisms, we can proceed to the building of our front controller. The front controller is what initiates our whole framework. It’s the very beginning of the system. So let’s see how we will structure and code it.

<?php  

namespace KF;  

class FrontController {  

     private static $_instance = null;  

     private function __construct() {  

     }  

     public function dispatch() {  

     }  

    /**  
     *  
     * [@return](/profile/return) \KF\FrontController  
     */  

     public static function getInstance() {  
         if (self::$_instance == null) {  
             self::$_instance = new \KF\FrontController();  
         }  
         return self::$_instance;  
     }  
}  

We need one public method which we’ll call dispatch() and upon calling it, the controller needs to find which router to use then make an instance for it and the other process is within the router. First we need one private property which will hold the controller and a method in the run class of our App.file.

<?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 setConfigFolder($path) {  
         $this->_config->setConfigFolder($path);  
  }  

  public function getConfigFolder() {  
         return $this->_configFolder;  
   }  

  public function run(){  
    echo 'Devoted to Antagonism and Infamous';  
  }  
  /**  
  *  
  *  [@return](/profile/return) \KF\App  
  */  

  public static function getInstance(){  
    if (self::$_instance == null) {  
    self::$_instance = new \KF\App();  
    }  
    return self::$_instance;  
  }  
}   

And now we need to make an instance in run():

<?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 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](/profile/return) \KF\App  
  */  

  public static function getInstance(){  
    if (self::$_instance == null) {  
    self::$_instance = new \KF\App();  
    }  
    return self::$_instance;  
  }  
}   

There a lot of things around that but for now, we just make an instance for it and call dispatch(). We need to have that implementation of the front controller in the run class because if it’s in the construction we’ll have some trouble in the future. Everything will be explained further in the series. The dispatch() method will determine which controller to use. Imagine we have some cron job on our server that calls the system from command line. We won’t even have HTTP protocol then. So here is the perfect place to explain about the routers. Each one of them is responsible for a certain matter. One for JSON requests, one for command line requests and so on.

<?php  

namespace KF\Routers;  
class DefaultRouter {  

     public function parse() {  
          echo 'FrontController Class Works';  
     }  
}  

Just to make sure it all works, let’s hardcore the Front controller file a bit:

<?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](/profile/return) \KF\App  
  */  

  public static function getInstance(){  
    if (self::$_instance == null) {  
    self::$_instance = new \KF\App();  
    }  
    return self::$_instance;  
  }  
}   

We end up with the output:

FrontController Class Works  

Now let’s get into the actual implementation of the front controller. The code is basically gonna analyze the following link:

http://example.com/user/edit/22/blabla  

And from it to extract controller, method and the corresponding parameters. Now to the way we could achieve this. Let’s just echo the $_SERVER environment variable for reference:

echo '<pre>'.print_r($_SERVER, true).'</pre>';  

Resulting in:

Array  
(  
    [HTTP_HOST] => localhost  
    [HTTP_CONNECTION] => keep-alive  
    [HTTP_CACHE_CONTROL] => max-age=0  
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8  
    [HTTP_USER_AGENT] => Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36  
    [HTTP_ACCEPT_ENCODING] => gzip,deflate,sdch  
    [HTTP_ACCEPT_LANGUAGE] => en-US,en;q=0.8  
    [SERVER_SIGNATURE] =>   
    [SERVER_SOFTWARE] => Apache/2.2.22 (Win64) PHP/5.3.13  
    [SERVER_NAME] => localhost  
    [SERVER_ADDR] => ::1  
    [SERVER_PORT] => 80  
    [REMOTE_ADDR] => ::1  
    [DOCUMENT_ROOT] => C:/wamp/www/  
    [SERVER_ADMIN] => admin@localhost  
    [SCRIPT_FILENAME] => C:/wamp/www/keeper.php  
    [REMOTE_PORT] => 53691  
    [GATEWAY_INTERFACE] => CGI/1.1  
    [SERVER_PROTOCOL] => HTTP/1.1  
    [REQUEST_METHOD] => GET  
    [QUERY_STRING] =>   
    [REQUEST_URI] => /keeper.php/admin/index/dashboard  
    [SCRIPT_NAME] => /keeper.php  
    [PHP_SELF] => /keeper.php/admin/index/dashboard  
    [REQUEST_TIME] => 1369562323  
)  

Now we can extract that address from REQUEST_URI with a simple str_replace function. However, note that under IIS, PHP_SELF is not returned, therefore stick to REQUEST_URI. Either ways they both do the same job.

<?php  

namespace KF\Routers;  
class DefaultRouter {  

     public function parse() {  
          echo '<pre>'.print_r($_SERVER, true).'</pre>';  
          $_uri = str_replace($_SERVER['SCRIPT_NAME'], "", $_SERVER["PHP_SELF"]);  
          echo $_uri;  
     }  
}  

Which returns the address that we actually want:

/admin/index/dashboard  

Now we can even get rid of the first forward slash or actually the first character which alternatively will always be /:

<?php  

namespace KF\Routers;  
class DefaultRouter {  

     public function parse() {  
          echo '<pre>'.print_r($_SERVER, true).'</pre>';  
          $_uri = substr(str_replace($_SERVER['SCRIPT_NAME'], "", $_SERVER["PHP_SELF"]), 1);  
          echo $_uri;  
     }  
}  

And we get the following:

admin/index/dashboard  

Now let’s see the implementation in a more sophisticated example:

<?php  

namespace KF\Routers;  
class DefaultRouter {  

     public function parse() {  
          $_uri = substr(str_replace($_SERVER['SCRIPT_NAME'], "", $_SERVER["PHP_SELF"]), 1);  
          $controller = null;  
          $method = null;  
          $_params = explode('/', $_uri);  
          if ($_params[0]) {  
              controller=ucfirst($_params[0]);  

               if ($_params[1]) {  
                   $method = $_params[1];  
                   unset($_params[0], $_params[1]);  
               } else {  
                    $method = 'index';  
               }  
          } else {  
                 $controller = 'index';  
                 $method = 'index';  
     }  
}  

We take the address with the first variable and with explode we transform the string to an array in which the first element (admin) will be the controller, index and id - parameters. So if there is no controller defined, we define one with the default value of index and the $_GET parameters are for sure not there. Now we’ll make one public function which will return the according controller.

<?php  

namespace KF\Routers;  
class DefaultRouter {  

     public function parse() {  
          $_uri = substr(str_replace($_SERVER['SCRIPT_NAME'], "", $_SERVER["PHP_SELF"]), 1);  
          $controller = null;  
          $method = null;  
          $_params = explode('/', $_uri);  
          if ($_params[0]) {  
              controller=ucfirst($_params[0]);  

               if ($_params[1]) {  
                   $method = $_params[1];  
                   unset($_params[0], $_params[1]);  
               } else {  
                    $method = 'index';  
               }  
          } else {  
                 $controller = 'index';  
                 $method = 'index';  
     }  
            echo $controller . '<br />' . $method;  
}  
         public function getController() {  

         }  
}  

Now let’s make the $controller variable from local a property for the class. Same for the method and parameters which will be initialized as arrays.

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

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