I want to stay true to the MVC model...

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
kilbad
Forum Commoner
Posts: 28
Joined: Wed Apr 02, 2008 3:51 pm

I want to stay true to the MVC model...

Post by kilbad »

I have been working on some simple MVC classes, and everything works how I want it to. However, I want to do things the right way, and feel like currently my displayView method should be my View class, and my View class should be a template class? Am I right?

My question is, although this may be a matter of semantics, should I rename/restructure anything in these classes to stay true to the MVC model, and to make sure I am appropriately separating my business and presentation logic?

Code: Select all

 
<?php
 
class FrontController extends ActionController {
 
    //Declaring variable(s)
    private static $instance;
    protected $controller;
 
    private function __construct(){}
 
    //Starting new instance of this class with a singleton pattern
    public static function getInstance() {
        if(!self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
 
    public function dispatch($throwExceptions = false) {
 
        /*  
            Checking for the GET variables $module and $action, and, if present,
            will strip them down with a regular expression function with a white
            list of allowed characters, removing anything that is not a letter,
            number, underscore or hyphen.
        */
        $regex  = '/[^-_A-z0-9]++/';
        $module = isset($_GET['module']) ? preg_replace($regex, '', $_GET['module']) : 'home';
        $action = isset($_GET['action']) ? preg_replace($regex, '', $_GET['action']) : 'frontpage';
 
        /*
            Generating Actions class filename (example: HomeActions) and path to
            that class (example: home/HomeActions.php5), checking if $file is a
            valid file, and then, if so, requiring that file.
        */
        $class = ucfirst($module) . 'Actions';
        $file  = $this->pageDir . '/' . $module . '/' . $class . '.php5';
 
        if (!is_file($file)) {
            throw new FrontControllerException('Page not found!');
        }
 
        require_once $file;
 
        /*  
            Creating a new instance of the Actions class (example: $controller
            = new HomeActions();), and passing page directory variable to the
            ActionController class.
        */
        $controller = new $class();
        $controller->setPageDir($this->pageDir);
 
        try {
            //Using the setModule method in the ActionController class
            $controller->setModule($module);
 
            /*
                The ActionController dispatchAction method Checks if the method
                exists, then runs the displayView function in the
                ActionController class.
            */    
            $controller->dispatchAction($action);
        }
        catch(Exception $e) {
 
            /*
                An exception has occurred, and an error message will be
                displayed if $throwExceptions is set to TRUE.
            */
            if($throwExceptions) {
                echo $e; //Full exception echoed
            } else {
                echo $e->errorMessage(); //Simple error messaged echoed
            }
        }
    }
}
 
abstract class ActionController {
 
    //Declaring variable(s)
    protected $pageDir;
    protected $module;
    protected $viewData = array();
 
    public function setPageDir($pageDir){
        $this->pageDir = $pageDir;
    }
 
    public function setModule($module) {
        $this->module = $module;
    }
 
    public function getModule() {
        return $this->module;
    }
 
    //Placing a value in the $viewData array at the key position
    public function setVar($key, $value) {
        $this->viewData[$key] = $value;
    }
 
    //Returns a value from the $viewData array located at the key position
    public function getVar($key) {
        if (array_key_exists($key, $this->viewData)) {
            return $this->viewData[$key];
        }
    }
 
    public function getViewData($viewData) {
        $this->viewData = $viewData;
    }
 
    /*
        Checking for actionMethod in the Actions class (example: doFrontpage()
        within home/HomeActions.php5) with the method_exists function and, if
        present, the actionMethod and displayView functions are executed.
    */  
    public function dispatchAction($action) {
        $actionMethod = 'do' . ucfirst($action);
        if (!method_exists($this, $actionMethod)) {
            throw new FrontControllerException('Page not found!');
        }
        $this->$actionMethod();
        $this->displayView($action);
    }
 
    public function displayView($action) {
        if (!is_file($this->pageDir . '/' . $this->getModule() . '/' . $action . 'View.php5')) {
            throw new FrontControllerException('Page not found!');
        }
 
        //Setting $this->actionView to the path of the action View file
        $this->actionView = $this->pageDir . '/' . $this->getModule() . '/' . $action . 'View.php5';
 
        /*
            Creating a new instance of the View class and passing the $pageDir,
            $viewData, and actionView variables
        */  
        $view = new View();
        $view->setPageDir($this->pageDir);
        $view->getViewData($this->viewData);
        $view->setVar('actionView',$this->actionView);
        $view->render();
    }
}
 
class View extends ActionController {
 
    public function render() {
 
        //Including default template settings
        require_once $this->pageDir . '/defaultTplSettings.php5';
 
        /*
            Merging the default template variables with variables provided in
            the $this->viewData array, taken from the Actions class, giving
            priority to those provided by the action class, then extracting the
            array with the extract() function, which creates a variable for
            every array value, and the name of the value (the variable name) is
            the key's value.
        */
        $templateSettings = array_merge($defaultTemplateSettings, $this->viewData);
        extract($templateSettings, EXTR_OVERWRITE);
 
        //Including template file within which the action View file is included
        require_once $this->pageDir . '/default.tpl';
    }
}
 
class FrontControllerException extends Exception {
    public function errorMessage() {
        //Error message
        return $this->getMessage();
    }
}
 
?>
 
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: I want to stay true to the MVC model...

Post by Christopher »

It is difficult to say whether you are staying true to MVC because you have not included the most important part -- the Model. And because it is difficult to know what "staying true to MVC" means. ;)

The main thing that strikes me looking at your code is that everything is and ActionController. I certainly understand why you did that. There is a lot of common functionality needed in PHP in Models, Views and Controllers. And where to put dispatch (Action or Front) is an ongoing question. The problem with these discussions is that the dive very, deep very quickly. Perhaps you can let us know a little more about you thinking.
(#10850)
kilbad
Forum Commoner
Posts: 28
Joined: Wed Apr 02, 2008 3:51 pm

Re: I want to stay true to the MVC model...

Post by kilbad »

I am still very new to PHP, and wanted to learn object oriented PHP, so I decided to try to make a very simple MVC to run my personal website on. However, while I felt like I was getting close to a finished project, I read this blog entry and started thinking, "have I just been toying around with a pseudo-MVC model this whole time? Am I keeping my business and presentation logic separate enough?" etc.

Therefore, I guess, my overall question would be, while still keeping my MVC very simple, what changes do I need to make to complete it properly? My biggest goals here are to (1) learn and, as a consequence, (2) code it well/the right way.

However, any feedback is greatly appreciated!
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: I want to stay true to the MVC model...

Post by Christopher »

You point to an article that shows how dangerous a little knowledge can be. That guy is marketing a framework as if it is the only way things can be done. And if you have ever tried to use Agavi, you will know how untrue his ideas are on many levels.

The most important thing you can do is to always separate your Models from the rest of your code. After that, you would probably be better off following general PHP best practices that trying to get a clean implementation of Controllers and Views. They are very difficult to get right for the general case. You will code yourself into a corner more often that out of one. ;)

Just following current best practices will give you more benefits for the time spent.
(#10850)
kilbad
Forum Commoner
Posts: 28
Joined: Wed Apr 02, 2008 3:51 pm

Re: I want to stay true to the MVC model...

Post by kilbad »

Thank you very much for your reply! So in response to your post, that
arborint wrote:...the most important thing you can do is to always separate your Models from the rest of your code.... Just following current best practices will give you more benefits for the time spent.
...do you have any specific feedback for my classes above?

Thanks again for all your help!
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: I want to stay true to the MVC model...

Post by Christopher »

I gave my one comment. The most important thing going forward is that your Model classes have no dependencies on any of the code above.
(#10850)
Post Reply