PHP CMS Project Part II: Separating Tasks

cms2Separation of Content from Form

In Part I of A PHP CMS Project, you saw how a Web page could be placed in a variable using PHP’s HEREDOC operator. Once in HEREDOC, different parts of the page could be filled with content delivered through variables. Using a simple CSS format, it was possible to have the general layout of a Web page and updates through through a private methods in the same class.

This next step further separates the Web page structure from the data that it uses for content. Essentially, this steps makes the HEREDOC Web page a separate class and calls for content from another class. At this point, there’s no design pattern involved; just a little OOP. In fact everything is the same except the content. (Later on in this series you will see which design patterns would be useful.) Figure 1 shows what the new page looks like:

Figure 1: Content from an external source

Figure 1: Content from an external source

As you can see in Figure 1, the content on the page has changed, but the format is the same. The big difference is that all of the data were sent through an external object. You can test the page and download the source code by clicking the following buttons:
PlayDownload

Once you have downloaded the classes, you can see similarities and differences in the classes now and those in Part I. The first new class to examine is Content. Simply stated, this is the class that stores the data for the Web page. It has a single method, getContent() and no constructor function. As a rule of thumb, if I don’t need a specific constructor function (one using __construct), I don’t include one.

<?php
//Content.php
include_once('PageMaster.php');
class Content extends PageMaster
{
    public function getContent()
    {      
        $this->content = array("css" => "heredoc.css",
                         "title" => "Here's Doc!",
                         "header1" => "New York State of Mind",
                         "header2" => "The Travel Page",
                         "body1" => "<p>Let's go have some fun. This is what I did on my summer vacation. ",
                         "body2" => " There much to see in NYC. Tall buildings, yellow cabs and lots of people.</p>",
                         "image1" => "images/mermaid.png",
                         "image2" => "images/plane.png",
                         "caption1" => "<br /> New York has the best mermaids.<br /> ",
                         "caption2" => "<br /> Off to New York City.<br /> ");   
        return $this->content;
    }
}
?>

Now that the content is in a different class, it’s easier to change the content without having to change the DocHere class. Of course the idea is to leave the DocHere class alone and just change the content through the use of variables. However, instead of scalar variables, you can use a compound variable—an array in this case. So now, all of the content has moved from a set of variables in the same class as the HEREDOC Web page to an array in an external class.

Before looking at the updated DocHere class, you will find a small but significant change. Figure 2 shows the difference in how a variable is inserted into a HEREDOC document and how an array element from an external class is inserted into the same HTML tag:

Figure 2: Inserting variables and imported array elements.

Figure 2: Inserting variables and imported array elements.

Note that the same element names (or key names) are used as were for the variable names. (e.g., $this->header1 is now $this->hd[“header1”].) So now, the HTML page is in a single variable ($this->document), and all of the content for that page is in a single array ($this->hd).

To “catch” the data from the Content object, the DocHere class uses the $content variable ($this->content) it inherits from the abstract class PageMaster. Next, the $hd variable (short for ‘html data’) calls the getContent() method from the Content class. The getContent() method delivers the array with the data used in the HTML page.

<?php
//DocHere.php
include_once('PageMaster.php');
include_once('Content.php');
 
class DocHere extends PageMaster
{
    function __construct()
    {
        $this->content=new Content();
        $this->hd = $this->content->getContent();
        $this->document = <<<CMSTEMPLATE
        <!DOCTYPE html>
        <html>
        <head>
        <link rel="stylesheet" type="text/css" href={$this->hd["css"]}>
        <meta charset="UTF-8">
        <title>{$this->hd["title"]}</title>
        </head>
        <body>
        <header>
            <h1>{$this->hd["header1"]}</h1>
        </header>
            <article>
                <header>
                <h2>{$this->hd["header2"]}</h2>
                </header>
                {$this->hd["body1"]}
                {$this->hd["body2"]}
                <section class="doRight" >
                    <img src={$this->hd["image1"]}>
                    <caption ><span class="pixcaption">{$this->hd["caption1"]}</span> </caption>
                </section>
                <section class="doLeft">
                    <img src={$this->hd["image2"]}>
                    <caption><span class="pixcaption">{$this->hd["caption2"]}</span> </caption>
                </section>
            </article>
        </body>
        </html>
 
CMSTEMPLATE;
    echo $this->document;
    }   
}
?>

The business logic if pretty well taken care of in the DocHere and Content classes. So you may well ask, What’s up with the abstract class, PageMaster?

Adding an Abstract Class

At this state of development, the abstract class, PageMaster is nothing more than a placeholder for an abstract class or interface we may need later in the development process. The three variables (or more correctly properties) of the abstract class can be inherited using protected visibility.

<?php
//PageMaster.php
abstract Class PageMaster
{
    protected $content; 
    protected $hd;
    protected $document;
}
?>

One OOP principle that you may be able to extract from this is the use of polymorphism. The $content object is used in both implemented classes. In the Content class, the $content property is an array, while that same property name in the DocHere class is an instance of the Content object. It’s not the best example of polymorphism, but it’s a start. (You can see more typical and useful examples of polymorphism in abstract methods—with properties the polymorphism is almost the same as the difference between the same local variable name used in different functions.) Further, keep in mind that that actual array from the Content object is stored in the $hd array; not the $content object in the DocHere class. It is passed to $hd using the following:

$this->hd = $this-content->getContent())

So for now, don’t worry about the PageMaster abstract class. However, in future development, of both the abstract class and the CMS project, you may find it quite important.

Why The Baby Steps?

Some readers may wonder why this example is taking its sweet time working up to both a CMS and design pattern in PHP. In reference to the book (PHP Design Patterns, some readers have complained that it is too difficult to understand. Despite the fact that it was written for advanced PHP developers, there’s no getting around the fact that design patterns are hard to learn. (Even the authors of the original Design Patterns book say that design design patterns and OOP are hard to comprehend, and their audience consists of C++ and Java developers!) With a plethora of bad examples of design patterns in PHP that are easy to understand on the internet, I thought working slowly through the logic of some examples on this blog may come up with both a good design pattern example and make it both practical and comprehensible. Any reader feedback on this topic will be quite helpful and welcomed.

Share

Copyright © 2013 William Sanders. All Rights Reserved.

5 Responses to “PHP CMS Project Part II: Separating Tasks”


  • Victor Saldarriaga

    It’s not that your book and blog present the concepts in a difficult way, the issue, and from my point of view is that (and I assume this) most of us are used to work by separating our code, for example, a simple blog may have this structure:
    blog
    ->admin
    ->css
    ->includes
    ->users
    ->views
    helper.php
    index.php

    The logic resides in controllers, these controllers send information to a helper function View and this function generates the page html code, example:

    function view($path, $data)
    {
    if ( $data ) {
    extract($data);
    }

    $path = $path .’.view.php’;
    include $_SERVER[‘DOCUMENT_ROOT’] . ‘/views/layout.php’;
    }

    The layout looks like this:

    And the controller just sends the variables through $data array like this:

    $data = array(
    ‘pageTitle’ => ‘Joke Listing’,
    ‘pagination’ => $displayPagination,
    ‘id’ => $row[‘id’],
    ‘text’ => $row[‘joketext’],
    ‘name’ => $row[‘author’],
    ’email’ => $row[’email’],
    );
    view(‘posts’, $data);

    So in that way I don’t put any presentation code on my controllers and the presentation layer just receives the information to display and generates the view according to this. I can’t connect the dots and replicate this using OOP …if you make a small example shedding light on this, that would be great. Hope I’m not asking much…thanks!

  • Victor Saldarriaga

    Seems the layout code didn’t make it :), I just made a gist:
    https://gist.github.com/vsalda/6078669

  • Victor Saldarriaga

    Hi Bill
    I converted the helper function into a helper class. I added it to the Factory Pattern example “One Factory and Multiple Products” (page 90 from the book).
    You can check it here: https://github.com/vsalda/afactory_multipleproducts
    I’d appreciate any corrections…thanks in advance!

  • Hi Victor,

    A View class (or multi-class module) is usually part of an MVC pattern/framework and not part of a Factory Method; you don’t want to confuse the two. They have a very different logic, and a lot of the design pattern PHP programming assumptions that are made have their origins in MVC, and it can prove to be a rut. Try to break that habit or you’ll be stuck with MVC no matter what design pattern you try to move away with. (Keep in mind that MVC is 1979 and the patterns used here all have their origin in the 1995 GoF Design Pattern work.)

    However, I REALLY like what you did with the View class though. (Call it VictorsHelper class next time!) It’s modular and it is loosely bound. Great stuff!!

    Cheers,
    Bill

  • Victor Saldarriaga

    Hi Bill, yes, I’m trying to put my mind in “OOP” mode. When it’s about generating content, I’m “lazy” and I always go the DRY route…that’s why I tried to make that “View” class…and thanks!

Leave a Reply