Stupidly Easy MVC in PHP or "We don't need no stinking framework!" (Part 2)

If you haven't read Part one, go do it! It provides the background for these classes.
In Part 1, I explain my base classes: MVC_Controller, MVC_View and MVC_Model. For my simple links application I extend the model class and the controller class. I did not need to extend the view for my purposes.

As I said before, the "action" variable is actually the name of the method you want to run. I listed the actions previously that I will need (planning ahead, what a concept) so it makes it easy to implement now:

See ListController code
First, I have to setup a few things in the constructor:

    function ListController() {
        parent::MVC_Controller();
        $this->model = new ListModel();
        $this->view->setTemplateDir("list");
        $this->doAction();
    }	

I call the parent method constructor. Then I create a new instance of the ListModel class. I set a directory for my templates for the view model (which was instantiated in the MVC_Controller class). Then I call doAction, which if this is the first time the page was accessed then there would be no "action" set. So, what happens when there is no action set? $this->defaultMethod() is called which I redefined here:

    function defaultMethod() {
        $this->displayLinks();
    }

Ok, now look at the displayLinks method:

    function displayLinks() {
        $linkData = $this->model->getLinks();
        $this->view->assign('linkData', $linkData);
        $this->view->display('displayLinks');
    }

How simple is that? I love this. I can have all my sql in one file, so it makes it so much easier to just sit and write all the sql I will need at once. The templates are in html (with smarty) so I can edit them in a nice editor like Dreamweaver, and no more printing out html with php.

See ListModel code
Lets look at the getLinks method:

    function getLinks() {
        $sql = "SELECT * FROM links";
        $this->result = $this->db->query($sql);
        return $this->fetchToArray();
    }

I use PearDB (but you can use anything, straight php mysql_* calls if you'd like) to get a result set, store in private variable then the fetchToArray method I defined in the parent class iterates over the result set and puts it into an array. Some might think this is "ok" to do in a view, but I'd rather keep as much logic out of the template as possible. Its bad enough that I have "if" statements in there!

See full template
Here's the body of displayLinks template:

<h3>List of Links</h3>
<form action="index.php" method="post">
<input type="hidden" name="action" value="showAddForm">
<input type="submit" value="Add a Link">
</form>
{section name="i" loop=$linkData }
<a href="{$linkData[i].link}">{$linkData[i].link}</a>
<p>{$linkData[i].description}</p>
<hr>
{/section}

This is just the ultimate simple template, you can always change it later to make it more pretty. Notice the form at the top, with the hidden variable "action" set to value "showAddForm" ? when you click that it will send "showAddForm" as the action to the controller and it will display the form to add a link.

Back to the controller, we see that method looks like this:

    function showAddForm() {
        $this->view->display('link_ae');
    }

I called my template "link_ae" to stand for "link add/edit" a convention picked up from DotProject.

Similarly, the showEditForm looks like:

    function showEditForm() {
        $this->view->assign("linkData",  $this->model->getLink() );
        $this->view->display('link_ae');
    }

See form template

Almost the same, but the edit form first gets the data and assigns it to the template.

The model is not just for looking up data. I wrote a method saveLink that will be used for either a new or existing record.

    function saveLink() {
        $link_id = $_POST['id'];
        if ($link_id == null) {
            $sql = "INSERT INTO links SET link=".$this->db->quote($_POST['link']).
                                        ", description=".$this->db->quote($_POST['description']);
        } else {
            $sql = "UPDATE links SET link=".$this->db->quote($_POST['link']).
                                    ", description=".$this->db->quote($_POST['description']) .
                                    " WHERE id=".$this->db->quote($_POST['id']);
        }
        $this->db->query($sql);
    }

I could do some checking to make sure the query was a success, returned a confirmation message to the controller which could then send it to a view to display the message.

Yeah. So what.
You might think, this is just a tiny app and you don't need to do all this for just storing a list of links in the database. Oh this is small I can just hack it. Yes, you could. But I bet it would take longer. What if The Powers That Be see this and go OH HEY! make it do this and that! and then they want to change how its displayed and you had hammered out all that HTML in print statements.
Separating things out, like model and view is extremely helpful even for working in a team. You can assign one person to do the model and write all the sql statements. Someone else can write the templates. In addition, it makes it easier when you change template solutions (or decide "I don't need no stinkin' template" and just use PHP) or DB abstraction etc.

I hope this helped you learn more about MVC even if you aren't using a bona fied framework.

Resouces:

Edited: Here's a link to my source files. This has add link and list all links features, no edit or delete. simple.zip

I agree

I did use a DAO, PearDB. But I think you are thinking of "ORM" object relation mapping (I think thats the right term?) to take the database result and turn it into an object which makes it easier to use. Rails has ActiveRecord. Pear has something called DB_DataObject, which I've used a little bit.

hmmm not sure

I'm not sure exactly what you mean. The third link, Plethora of php frameworks has quite a few list, maybe one of those has what you want.

List Index file

Looks like this:

include_once("ListController.class.php");

$c = new ListController();


The List controller calls the doAction from the parent class which calls the defaultMethod. If you want, I'll package all the file in a download for you.

Added a link

To download my sample app at the bottom of this blog entry. Enjoy.

Thanks

I will try to work on a follow up with some other examples. You havent been the first person to ask for some!

Great Summary! - but I cant access ur source files

I like it how u got down to the simple things.

Where are your source files so that
I can study them further.

Thanks.

Sorry about that. I updated

Sorry about that. I updated the link at the bottom of the article!