For you to get a more accurate idea of how the source files created so far fit into the whole framework’s schema, below I listed their respective definitions, starting with the “.htaccess” file. Here it is: (.htaccess file) # Turn on URL rewriting engine RewriteEngine On # Disable rewriting for existing files or directories RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # redirect all other requests to index.php RewriteRule ^.*$ index.php [PT,L] Then, the list continues with the definition of the front controller, which is as follows: (index.php) <?php // framework’s front controller // specify parameters for autoloading classes spl_autoload_register(NULL, FALSE); spl_autoload_extensions('.php'); spl_autoload_register(array('Autoloader', 'load')); // define custom ClassNotFoundException exception class class ClassNotFoundException extends Exception{} // define Autoloader class class Autoloader { // attempt to autoload a specified class public static function load($class) { if (class_exists($class, FALSE)) { return; } $file = $class . '.php'; if (!file_exists($file)) { eval('class ' . $class . '{}'); throw new Exception('File ' . $file . ' not found.'); } require_once($file); unset($file); if (!class_exists($class, FALSE)) { eval('class ' . $class . '{}'); throw new ClassNotFoundException('Class ' . $class . ' not found.'); } } } // handle request and dispatch it to the appropriate controller try{ Dispatcher::dispatch(); } catch (ClassNotFoundException $e){ echo $e->getMessage(); exit(); } catch (Exception $e){ echo $e->getMessage(); exit(); }// End front controller Still with me? Good. Now let's look at the following two files, which are the dispatcher and MySQL abstraction classes respectively: (Dispatcher.php) <?php class Dispatcher { // dispatch request to the appropriate controller/method public static function dispatch() { $url = explode('/', trim($_SERVER['REQUEST_URI'], '/')); array_shift($url); // get controller name $controller = !empty($url[0]) ? $url[0] . 'Controller' : 'DefaultController'; // get method name of controller $method = !empty($url[1]) ? $url[1] : 'index'; // get argument passed in to the method $arg = !empty($url[2]) ? $url[2] : NULL; // create controller instance and call the specified method $cont = new $controller; $cont->$method($arg); } }// End Dispatcher class (MySQL.php) <?php class MySQL { private $result = NULL; private $link = NULL; private static $instance = NULL; // return Singleton instance of MySQL class public static function getInstance(array $config = array()) { if (self::$instance === NULL) { self::$instance = new self($config); } return self::$instance; }
// constructor public function __construct(array $config = array()) { // grab connection parameters list($host, $user, $password, $database) = $config; if ((!$this->link = mysqli_connect($host, $user, $password, $database))) { throw new Exception('Error connecting to MySQL : ' . mysqli_connect_error()); } } // perform query public function query($query) { if (is_string($query) and !empty($query)) { if ((!$this->result = mysqli_query($this->link, $query))) { throw new Exception('Error performing query ' . $query . ' Message : ' . mysqli_error($this->link)); } } }
// fetch row from result set public function fetch() { if ((!$row = mysqli_fetch_object($this->result))) { mysqli_free_result($this->result); return FALSE; } return $row; } // get insertion ID public function getInsertID() { if ($this->result !== NULL) { return mysqli_insert_id($this->link); } return FALSE; }
// count rows in result set public function countRows() { if ($this->result !== NULL) { return mysqli_num_rows($this->result); } return 0; }
// close the database connection function __destruct() { is_resource($this->link) and mysqli_close($this->link); } }// End MySQL class Whew, that’s all the source code that comprises the framework for the moment. Due to the modular structure of the above classes, you shouldn’t have major problems understanding how they work and how they could be improved. If you're in an experimental mood, then I strongly encourage you to add your own enhancements and tweaks to the classes. It’ll be a fun and educational experience, trust me. Final thoughts In this third part of the series, I enhanced the functionality of this sample MVC framework even further by adding to it a class that takes care of interacting with MySQL in a simple manner. As I explained earlier, you’ll see the actual importance of this abstraction class when I show you the definition of the corresponding model, which will aggregate an instance of “MySQL” to handle the data layer very easily. However, before I get there it’s necessary to add more components to the framework to make it much more functional. That includes creating a class that performs basic sanitization on user-supplied data. That’s exactly what I’m going to do in the next tutorial, so now that you’ve been warned, you don’t have any excuses to miss it!
blog comments powered by Disqus |
|
|
|
|
|
|
|