Question

I am trying to delve into MVC with Front Controller Design.

I want to invoke my entire application by using one line, for example in index.php:

require_once(myclass.php);
$output = new myClass();

I would love to get rid of the require_once line, but I don't see how I could load my class without including it?

Anyway my main question would be how to load my various controllers and models and views etc using a one front end class. So far I have come up with:

class myClass
{
    private $name;
    public $root = $_SERVER['DOCUMENT_ROOT'];
    private $route = array("Controller" => "", "Model" => "", "View" => "", "Paremeters" => "");
    function __construct() 
    {   $uri = explode("/",$_SERVER['REQUEST_URI']);
        if(isset($uri[2])) {$this->route['Controller'] = $uri[2];}
        if(isset($uri[3])) {$this->route['Model'] = $uri[3];}
        if(isset($uri[4])) {$this->route['View'] = $uri[4];}
        if(isset($this->route['Controller'])) 
        {
            include($this->root."/".$this->route['Controller'].".php");
        }
    }

}

But it seems a bit convoluted and over the top. Also, once i've included the new class in the __construct, How am I supposed to load it?

Im sorry for the lack of knowledge, I have googled this a number of times and I keep coming up with the same pages that don't seem to expand my knowledge on the matter.

Was it helpful?

Solution 2

I'm surprised that in those two long and informative previous answers nobody bothered to actually answer your question in the simplest way.

You want the __autoload() function. You'll still have to define it somewhere in your code, but it can simply be added to a global header file and then you don't have to explicitly write an include for every class definition.

/* auto load model classes */
function __autoload($class_name) {
        $filename = 'class.' . strtolower($class_name) . '.php';
        $file = __SITE_PATH . '/_model/' . $filename;
        if( file_exists($file) == false ) {
                return false;
        }
        require($file);
}

OTHER TIPS

If your URLs are definitely going to be http://domain.com/[controller]/[action]/parameters, then your front controller could look like this:

<?php
class Application
{
    public function __construct()
    {
        $this->setupAutoloader();
        $this->route();
    }

    private function setupAutoloader()
    {
        // do your autoloading here
    }

    private function route()
    {
        $request = explode('/', trim($_SERVER['REQUEST_URI'], '/'));

        $controller = isset($request[0]) ? ucwords(array_shift($request)) . 'Controller' : 'HomeController';
        $action = isset($request[0]) ? array_shift($request) : 'index';
        $parameters = $request;

        $response = call_user_func_array(array($controller, $action), $parameters);
    }
}

From here, you can add your autoloader implementation, do whatever you want with your response, and call it from your index.php as follows:

<?php
require 'path/to/Application.php';

$application = new Application();

Unfortunately, you’re always going to have to include the very first file if it’s stored elsewhere in your file system, but as above from here you can then autoload other classes, such as libraries, controllers, models etc.

In order to load a class without manually include it you should take a look at spl_autoload_register that enables you to automatically load classes whenever required by the application.

As for the other question, well, it's all up to your design. If you want to load the common "controller" and "action" you should create a routable folder (this means the folder in which only controllers can stay) and place all the controller classes and then create a routable action space (the group of routable methods inside a controller class, usually is by defining the convention that actions methods are prefixed by action_). When you are done with that simply create your controllers like this:

class Blog {
    public function action_posts() { ... };
}

and manage it so that the URL /blog/posts/ will call this. (It just needs the same URI manipulation you have already proved to be good at). (Notice that the autoloader should handle the including of the actual class file by itself without requiring you to load all controller classes). Once you have the controller name and action you just need of something on the line of:

if (class_exists($controller)) {
    $app = new $controller;
    if (method_exists($app, $action)) {
        $app->$action(); // also take a look at call_user_func and call_user_func_array
    }
}

You can also allow parameters, but that is going to be quite difficult, in order to allow this kind of result:

class Blog {
    public function action_post($id) { ... };
}

and be called by /blog/post/14/ for example.

When dealing with URI also remember that you could have bad inputs and that you should handle them, but if you have created the correct routing space you are half way done already.

Finally if you want to have inspiration or for anything else, just take a look at CodeIgniter (which is one of the most easy to learn frameworks out there) or any other framework.

Hope it helped.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top