Get up to 80 % extra points for free! More info:

Lesson 4 - Wiring controllers and views

In the previous lesson, Router, we created a router and ended the day with determining controller class names and parameters based on a URL address. In today's tutorial, we'll get the system partially working and display a simple article.

Views

Let's start with out with something easy. We'll prepare 2 views, wire them with controllers, and display an article.

Page layout

As you already know, each controller contains the "view that is to be rendered"'s name. The RouterController will display the view along with the page layout, which will consist of a header, navigation menu, footer among other things. However, it will not contain the main content, which will be added in later, by the internal (nested) controller.

You should all know at least a little bit of HTML and CSS at this point, however, I went ahead and prepared a simple layout template for you. Create a layout.phtml file in the "views" folder, and add the following code into it:

<!DOCTYPE html>
<html lang="en">
    <head>
        <base href="/localhost" />
        <meta charset="UTF-8" />
        <title><?= $title ?></title>
        <meta name="description" content="<?= $description ?>" />
        <link rel="stylesheet" href="style.css" type="text/css"/>
    </head>

    <body>
        <header>
            <h1>ICT.social MVC - Sample website</h1>
        </header>

        <nav>
            <ul>
                <li><a href="article/home">Home</a></li>
                <li><a href="article">Articles</a></li>
                <li><a href="contact">Contact</a></li>
            </ul>
        </nav>
        <br clear="both" />

        <article>

        </article>

        <footer>
            <p>Sample MVC tutorial from <a href="http://www.ict.social" target="_blank">ict.social</a> - The social network for programmers.</p>
        </footer>
    </body>
</html>

There are several things we'll touch base on, in regard to our source code. First of all, it's 99% HTML and clearly well formatted. It uses HTML 5 tags, which should go without saying nowadays.

The head includes a <base> tag, which sets the root folder on a website. This part is important for images, CSS files icons, and so on. Since we agreed on using pretty URLs with slashes, the browser could easily mistake them for subfolders. By setting the root folder, we explicitly state that we're located in the root. Remember that on the production server, you'd have to replace "localhost" with an absolute address like "http://www.do­main.com/". Theoretically, the "/" character shouldn't mess anything up, but a certain browser with a blue "e" does not support this feature.

Notice the PHP directives in the page head:

<title><?= $title ?></title>
<meta name="description" content="<?= $description ?>" />

We take a variable from a controller (from its $data array) and add it to the template. We don't insert HTML into PHP ever, but we may add a very small amount of PHP into HTML, without breaking the HTML structure. I'm sure you can tell that this:

<?= $variable ?>

is a shortened version of that:

<?php echo $variable; ?>

PHP has a lot of shorter syntax for templates to make it easier to manage them without any other means. I often mix the terms "template" and "view". I always mean the same thing, since our MVC essentially has every view as a phtml template.

The last interesting part is the article body, i.e. the part between the <article> tags. Notice how it's empty at the moment. We'll render the view based on the inner controller's data later on.

Error page

Next, we'll create an error page template. It'll be shown in case a user enters an invalid URL. The HTML code for the error.phtml file will be as follows:

<h1>Error 404</h1>
<p>The requested page was not found, please check the URL.</p>

Style

What sort of a website would it be without a bit of style? I've prepared this part for you as well. Create a style.css file in the root folder, and add the following content:

body {
    font-family: verdana;
    font-size: 14px;
    width: 900px;
    margin: 0 auto;
}

h1 {
    text-align: center;
    color: #444444;
    text-shadow: 3px 3px 3px #aaaaaa;
}

footer {
    font-size: 11px;
    text-align: center;
    padding-top: 20px;
}

article {
    text-shadow: 3px 3px 3px #aaaaaa;
}

nav ul {
    list-style-type: none;
}

nav li {
    float: left;
    margin-right: 15px;
}

nav a {
    background: #6FA4F8;
    color: white;
    padding: 5px 10px;
    border-radius: 10px;
    text-decoration: none;
    border: none;
    cursor: pointer;
}

nav a:hover {
    background: #2976f8;
    color: #EEEEEE;
    text-decoration: none;
}

There is nothing interesting here aside from a few CSS 3 properties.

Rendering views

Our views are done and the controllers are done. Now, let's make the application functional at last.

Move back to the RouterController and remove the test outputs in the process() method that we added last time. If no controller is specified (the first URL parameter is empty or missing), we'll redirect the user to the home article. Despite the fact that it doesn't exist yet, we can use its URL.

public function process($params)
{
    $parsedUrl = $this->parseUrl($params[0]);

    if (empty($parsedUrl[0]))
        $this->redirect('article/home');
    // The controller is the 1st URL parameter
    $controllerClass = $this->dashesToCamel(array_shift($parsedUrl)) . 'Controller';

If the script continues, that means we've got a controller's class name, after which we'll check whether the file really exists. If it does, we;ll create an instance of said class. Otherwise, we'll redirect the user to the error page.

if (file_exists('controllers/' . $controllerClass . '.php'))
    $this->controller = new $controllerClass;
else
    $this->redirect('error');

We now have an instance of the inner (nested) controller exactly where we want it to be. Now we'll call the process() method on the inner controller and let it execute its inner logic. For example, it could be looking for an article in the database. To be more accurate, the inner controller's process() method will call the appropriate model's logic, but all of this will be dealt with later on.

$this->controller->process($parsedUrl);

The last thing we have to do now is set the router's view, which is the website layout's template.

Let's create a few variables for the template. We already know that we used the $title and $description variables in there. We also know that we pass variables to the view as the $this->data[] array's keys. When it comes to template variables, we'll add the inner controller's title and description. The code will be the following:

$this->data['title'] = $this->controller->head['title'];
$this->data['description'] = $this->controller->head['description'];

We still have to set the view, which we'll do simply by setting the template's filename to the $view property:

// Sets the main template
$this->view = 'layout';

The RouterController is done!

ErrorController

Now, let's create a controller for an actual web page. This controller will be for the error page. Create an ErrorController.php file in the "controllers" folder with the following contents:

class ErrorController extends Controller
{
    public function process($params)
    {
    // HTTP header
    header("HTTP/1.0 404 Not Found");
    // HTML header
    $this->head['title'] = 'Error 404';
    // Sets the template
    $this->view = 'error';
    }
}

The controller sends a header to the browser to inform it that it's on an error page. Aside from that, it doesn't do anything other than setting the title and the template.

We're done! That was fast, wasn't it? We'll add next couple of system parts in the same way.

Wiring up

Time to wrap it all up! Go ahead and call the renderView() method on the router in index.php, right after calling its process() method. Here, we can clearly see how the logic and output are separated into two individual tasks.

$router->renderView();

When we enter a URL address, we'll be redirected to the error page, where the router will call the ErrorController. Here, we see that router worked and rendered the template for us:

ICT.social MVC framework in PHP – Rendering the layout - Simple Object-Oriented CMS in PHP (MVC)

The inner controller's template (ErrorController) has not been rendered, let's make it right. We'll insert this template in the empty spot in the <article> tag in the layout.phtml template. Since the template is currently being processed by the RouterController accessing the inner controller as an instance property is fairly straightforward. We won't insert things like this in views, but we pretty much have to in layouts:

<?php $this->controller->renderView();

The result:

ICT.social MVC framework v PHP – Rendering the view - Simple Object-Oriented CMS in PHP (MVC)

Finally, we have something functional. Even though it's just an error page :) In the next lesson, Contact form, we'll add a simple contact form into our system.


 

Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.

Download

By downloading the following file, you agree to the license terms

Downloaded 465x (9.91 kB)
Application includes source codes in language PHP

 

Previous article
Router
All articles in this section
Simple Object-Oriented CMS in PHP (MVC)
Skip article
(not recommended)
Contact form
Article has been written for you by David Capka Hartinger
Avatar
User rating:
8 votes
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn university David learned IT at the Unicorn University - a prestigious college providing education on IT and economics.
Activities