Archive for the 'CMS' Category

Page 2 of 3

PHP Bridge Pattern CMS

bridgeCMSA Flexible CMS

The previous post on the PHP Bridge Design pattern shows how a Bridge pattern has two connected but independent interfaces to make design flexibility for different online devices. This post explores how that same flexibility extends to making a Content Management System (CMS). Most of the Bridge participants in the design are unchanged or only slightly changed.

The major change in the Bridge design pattern actually makes it more in line with the original intention of the Bridge. The RefinedAbstraction participant (RefinedPage) no longer includes concrete content for the page. Instead, it provides the parameters for a client to add the content. This change adds flexibility and gives the developer more options than the original StandardPage class.

Two UIs and Multiple Clients

In order to make a decent CMS, you need to have at least two UIs:

  1. An Administrative UI for previewing and adding new content
  2. A User UI for viewing but not changing content

In creating the Administrative UI (HTML5/PHP/JavaScript), I had to use two PHP clients. One client is to preview the new data entered by the admin and the other client is to store the new data (after previewing and possibly editing it). Figure I provides a general overview of the UIs and the Clients that will use the Bridge pattern for a CMS:

Figure 1: User Interfaces and Clients

Figure 1: User Interfaces and Clients

The Administrative UI (BridgeCMSAdmin.html) uses the BridgeCMSAdminClient class for displaying different content and the StoreDataClient class for storing the information in a JSON file. An important condition to remember is that when using JSON files, you need to make their permissions available for reading and writing. (See the Memento II post and the special mini-post on setting permissions on Raspberry Pi systems.) Thus, the need for two clients; one for previewing new material and another for storing it in a JSON file. A lot of files are involved in this CMS; so take a look at the two different UIs and download the files for everything:
PlayPlayAdminDownload

To use the Administrator Module, follow these steps in the listed order:

  1. Type in Header data, select a graphic from the drop down menu, and then type in text for the body.
  2. Click a Desktop, Tablet or Phone radio button and then click Preview Page
  3. When you have everything the way you want it, First click Transfer to Storage and next click Store Data
  4. Now click the Play button and see the page you created.

In the admin UI, I used a drop down menu with only three selections for the graphic file since only three were set up. However, it would not be difficult to upload graphics and their file names. (See the post on uploading graphics using the Template Method.)

The UIs and their Clients

The main feature in creating a CMS is the Administrative UI. It calls two different clients for dealing with previews and persistent data storage. Unless you’re planning on a fairly long body text entry, the JSON file works fine. Look at the code below, and you can see that one of the issues is that the data that is entered for the preview must be transferred to a different form. It transferring the data is a simple task with a little JavaScript. The following script is all it takes:

?View Code JAVASCRIPT
function transferData(formNow)
{
    formNow.header.value = bridgeWork.header.value;
    formNow.graphic.value = bridgeWork.graphic.value;
    formNow.bodytext.value = bridgeWork.bodytext.value;
}

Stored in an external JS file, it was used only when the data was going to be stored; however, before storing it, it had to be transferred from the bridgeWork form to the dataStore form.

< !DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="cmsbridge.css"/>
    <script src="formXfer.js"> </script>
    <title>CMS Admin Bridge</title>
</head>
<body>
    <h2>Enter Update Data</h2>
    <form method="post" name="bridgeWork" action="BridgeCMSAdminClient.php">
        <input type="text" name="header"/>&nbsp;Header<br />
        <select name="graphic">
            <option>Select Travel Graphic</option>
            <option value="nephpAir.jpg">Air</option>
            <option value="nephpTrain.jpg">Train</option>
            <option value="nephpShip.jpg">Ship</option>
        </select>
        <br />
        Enter the text for the body below:<br />
        <textarea name="bodytext" cols="48" rows="12"></textarea><p></p>
        <h3>Preview New Data</h3>
        <input type="radio" name="device" value="Desktop"/>&nbsp;Desktop<br />
        <input type="radio" name="device" value="Tablet"/>&nbsp;Tablet<br />
        <input type="radio" name="device" value="Phone"/>&nbsp;Phone<p></p>
        <input type="submit" name="deliver" value="Preview Page"/>
    </form>
 
    <h3>Store New Data</h3>
    <form method="post" name="dataStore" action="StoreDataClient.php">
        <input type="hidden" name="header"/>
        <input type="hidden" name="graphic"/>
        <input type="hidden" name="bodytext"/>
        <button type="button" onclick="transferData(dataStore)">Transfer to Storage</button>
        <input type="submit" name="jsonstore" value="Store Data"/>
    </form>
 
</body>
</html>

Then using build-in PHP JSON json_encode() method, the data were placed into an array and stored in the JSON file. This was done using the StoreDataClient class:

< ?php
class StoreDataClient
{
    private static $dataStorage=array();
    private static $jsonFile="content.json";
    //Client stores data
    public static function store()
    {
        if (isset($_POST['jsonstore']))
        {   
            self::setStore();
        }
      file_put_contents(self::$jsonFile,json_encode(self::$dataStorage,JSON_UNESCAPED_UNICODE));
    }
 
    private static function setStore()
    {
        //Pushes data from HTML to array
        array_push(self::$dataStorage,$_POST['header'],$_POST['graphic'],$_POST['bodytext']);
    }
}
StoreDataClient::store();
?>

Just in case you’re wondering why a single PHP client class was not used for both preview and storage, it’s simple:

OOP Principle: Each class should have only a single responsibility.

We don’t want to cram classes; so each responsibility has its own class. (Click below to see the other client and the rest of the CMS.)
Continue reading ‘PHP Bridge Pattern CMS’

Share

PHP CMS Project Part V: The Factory Method

cms5A Simple Factory Method CMS

In deciding which design pattern to apply to this CMS, two came to mind. Because PHP is creating a Web page, creational patterns appeared to be the most appropriate. Both the Factory Method and the Abstract Factory were considered. The Factory Method is the simplest of the two and it can be expanded, and so I settled on it. The Abstract Factory would be more appropriate if the main goal was to select different Web page styles. This CMS is to update and use data from a MySQL table. Since a lot of files make up this CMS, it’s probably a good idea to download them first:
Download

To get started, take a look at Figure 1. In Part IV of this series you saw how to put data into and retrieve it from a database and use in a Web page. That is pretty much what has been done here except the request is through the Creator interface to insure loose coupling. The PageCreator implements the factoryMethod() method which creates a requested product specified by the Client. As a result the Client is only loosely bound to the concrete product it requests.

Figure 1: File Diagram for Factory Method CMS

Figure 1: File Diagram for Factory Method CMS

When the concrete creator object (PageCreator) passes the request for the concrete Product object (PageProduct1()), it does so through the deliverWeb() method—the method implemented through the Product interface.

Multiple Inheritance (Sort of)

Some languages like Java and Python support multiple inheritance. Strictly speaking, PHP does not, but you will find workarounds and you can combine inheritance and implementation in a single child class. In the declaration of the PageProduct1 class, you can see how this is done:

<?php
include_once('UniversalConnect.php');
include_once('Product.php');
include_once('ProductTools.php');
class PageProduct1 extends ProductTools implements Product
{
    function deliverWeb()
    {      
        $this->tableMaster="blogette";
        $this->hookup=UniversalConnect::doConnect();
        $this->loadContent();
        $this->content = array("css" => $this->css,
                         "title" => $this->title,
                         "header1" => $this->header1,
                         "header2" => $this->header2,
                         "body1" => $this->body1,
                         "body2" => $this->body2,
                         "image1" => $this->image1,
                         "image2" => $this->image2,
                         "caption1" => $this->caption1,
                         "caption2" => $this->caption2
                         );   
        return $this->content;
    }
 
    private function loadContent()
    {
        //Create Query Statement
	$this->sql ="SELECT * FROM $this->tableMaster WHERE id = 1";
 
	if ($result = $this->hookup->query($this->sql))
	{
	    while ($row = $result->fetch_assoc()) 
	    {
                $this->css = $row['css'];
                $this->title = $row['title'];
                $this->header1 = $row['header1'];
                $this->header2 = $row['header2'];
                $this->body1 = $row['body1'] . "<p />";
                $this->body2 = $row['body2'] . "<p />";
                $this->image1 = "images/" . $row['image1'];
                $this->image2 = "images/" . $row['image2'];
                $this->caption1 = $row['caption1'];
                $this->caption2 = $row['caption2'];
	    }
            $result->close();
	}
        $this->hookup->close(); 
    }
}
?>

The declaration line:

class PageProduct1 extends ProductTools implements Product

imbues PageProduct1 with both the properties of the ProductTools and the interface of the Product. By having the abstract class ProductTools provide the essential properties of a Product child, the properties need not be declared in the concrete product child classes and add some uniformity. At the same time the Product child implementations have the common Product interface. If you’re thinking that a single abstract class could have handled both the method and the properties, you’d be right. However, but having a separate class for properties, the same design could easily be adapted to include a whole new set of properties if need be.

You probably recognize PageProduct1 as the RetrieveBlog class from Part IV of the CMS series. About the only difference is that I created an abstract class ProductTools to store common product properties for use by any other product classes that the developer may care to add. It reduces clutter and makes it easier to make small changes. For example, one strategy considered is to create several different instances of PageProduct1, such as PageProduct2, PageProduct3 and so on. Each could simply identify a different table ID number to be called from the Client class. On the other hand, new data could be added simply by using an UPDATE SQL command to change the content of the record with an ID selected by the class.

Figure 2 shows an added page delivered as a concrete product upon a Client request, and as you can see, it looks just like the others in this series, but the content has changed:

Figure 2: Page created with Factory Method CMS

Figure 2: Page created with Factory Method CMS

The nature of the page has not changed, but the way in which it is requested has. The request is through the Creator interface; so next we’ll take a look at the concrete creator class and the new Client class.

Request to the Creator

The real “un-coupler” participant in the Factory Method design pattern is the Creator and its implementations. In this instance, the single concrete class passes on the request from the Client for a Product. In the following listing are both the Creator abstract class and its child class, PageCreator: (Note: Product type hinting is used so that additional concrete product implementations may be called through the same interface. This is an example of the design pattern principle of program to the interface (Product) and not the implementation (PageProduct1).

<?php
//Creator.php
abstract class Creator
{
	protected $webProduct;
	abstract public function factoryMethod(Product $pageNow);
}
?>
 
?php
//ConcreteCreator.php
include_once('Creator.php');
 
class PageCreator extends Creator
{
	public function factoryMethod(Product $pageNow)
	{
		$this->webProduct=new $pageNow();
		return($this->webProduct->deliverWeb());
	}
}
?>

At this point, you may wonder where the content of the $pageNow parameter comes from. In this case, and all along in this series actually, the Web page has been the client. It is requesting content for the HEREDOC page. So, we might as well put it where it belongs—in the Client class as shown:

<?php
include_once('PageProduct1.php');
include_once('PageCreator.php');
 
class Client
{
    private $content;
    private $document;
    private $hd;
 
    function __construct()
    {
        $this->content=new PageCreator();
        $this->hd = $this->content->factoryMethod(new PageProduct1());
        $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"><br />{$this->hd["caption1"]}</span> </caption>
                </section>
                <section class="doLeft">
                    <img src={$this->hd["image2"]}>
                    <caption><span class="pixcaption"><br />{$this->hd["caption2"]}</span> </caption>
                </section>
            </article>
        </body>
        </html>
 
CMSTEMPLATE;
    echo $this->document;
    }
}
$worker = new Client();
?>

The two lines in the Client that show it to be part of a Factory Method design pattern are:

$this->content=new PageCreator();
$this->hd = $this->content->factoryMethod(new PageProduct1());

The Client makes the request through the PageCreator class and then invokes the factoryMethod() to specify the product, PageProduct1. Now suppose later that you want to make more products—implementations of the Product interface. Because the request in the Creator specifies through type hinting is for the Product and not any specific implementation of the Product interface, it can handle any Product implementation.

You may want to review other implementations of the Factory Method on this blog for a review in understanding how everything works together. However, it comes down to Request -> Creator -> Product.

The CMS Co-Stars

In wrapping up this series on creating a CMS using a design pattern in PHP, you will find a folder full of some of the tools you’ll need for creating and maintaining the system in a folder named “Administrative.” At some point soon, I hope to implement it for the http://www.sandlight.com site, and I’d be very interested in what others have done or ideas for making it better. In the meantime enjoy exploring its possibilities.

Share

PHP Graphic CMS Class with Template Method

uploadLoad Up the Graphic Files

In Part IV of the Content Management System (CMS) series, I noted that I wanted to have a separate post on uploading graphics to a web server. This post addresses the issues involved in getting graphics in place on a web server that will be included in a Web page, whether you’re using a CMS or not. In the case of selecting a graphic from your desktop and uploading it to a server, most of the important work is done by HTML. So, we’ll start with the HTML assuming that HTML5 is in use. Be advised at the outset that you will need to do a little system administration to set your file privileges in the folders where you will store the graphic files. In the development process, I used a local host, a different computer on my LAN, and two different web servers at remote locations.

Choosing a File to Upload

HTML5 (and possibly earlier versions) has some very nice built-in form attributes that make selecting a graphic file from your computer to place in an “uploadable” state quite easy. All you need are a couple of lines of HTML. Within a form container, the line:

<input type=”file” name=”file” id=”file”>

generates the following button when you load the code into a browser:

In the <form> tag, you will need to include an enctype assignment:

<form action=”target.php” method=”post” enctype=”multipart/form-data”>

That’s about it, and you’re all set to select a file that can be accessed through the PHP superglobal variable $_FILES.

The following HTML code generates the CSS first the then HTML portion of the little graphic CMS:

@charset "UTF-8";
/* CSS Document */
/* upload.css */
body
{
    font-family: Verdana, helvetica, arial, futura, sans-serif;
    color:#991C00;
    background-color:#FFFCDB; 
}
 
h1
{
    font-family: "Arial Black", futura, sans-serif;
    color:#E09A25;
    background-color:#262B30;
    text-align: center;
}
< !doctype html>
<html>
    <head>
        <meta charset="UTF-8"/>
            <link type="text/css" rel="stylesheet" href="upload.css"/>
        <title>Catalog Files</title>
    </head>
<body>
    <h1>Graphic File Loader</h1>
    <form action="triggerUpload.php" method="post" enctype="multipart/form-data">
    Click the 'Choose File' button to browse your local drive for files to upload:<br />
        <input type="file" name="file" id="file"/><p></p>
    Once you have chosen a file, click the 'Load Graphic File' button to upload the file to your web server:<br />
        <input type="submit" name="submit" value="Load Graphic File"/>
    </form>
</body>
</html>

I added separation between the Choose File button and Load Graphic File submit button so that the HTML and PHP portions are more clearly defined. Figure 1 shows the initial web page for the upload:

Figure 1: Selecting and calling PHP Script

Figure 1: Selecting and calling PHP Script

Since the goal of having a CMS is to make updates simple, this initial example does not have any whistles and bells (e.g., folder selection), and it does nothing more than to prepare a selected file for upload to a server.

A Little PHP

On the PHP side of the equation, you have only two code elements:

  1. $_FILES: Superglobal array with selected file information in elements
  2. move_uploaded_file(): Stores uploaded file (in $_FILES) to in specified server location.

Creating a class, using the minimum code and no error, type or size checking, is quite simple. To keep it even simpler, the following trigger script instantiates the Upload class:

< ?php
//triggerUpload.php
include_once("Upload.php");
$worker = new Upload();
?>

After testing the initial Upload class, we’ll see how it can be enhanced. First, though, take a look at the code:

< ?php
//Upload.php
class Upload
{
    private $fileNow;
    public function __construct()
{
        if ($_FILES)
        {
            $this->fileNow=$_FILES["file"]["name"];
 
            //The following line does all the work
            move_uploaded_file($_FILES["file"]["tmp_name"],"images/$this->fileNow");
 
            echo $this->fileNow . " has been uploaded to the images folder:";
        }
    }
}
?>

That simple class does everything you need to upload and store a file in a folder named “images” in the directory where the script is launched. It’s pretty basic, but you should be able to see exactly what is required to upload a file to a web server without having to use an FTP client.

Template Method for Details

Note: Before you get started on this section, download all of the files that are involved:
Download

As you saw, the Upload class is quite easy. However, you will want to make sure that not just any file type is loaded and you’ll want to make sure that you don’t have giant files loaded that may fill up your disk space. (You also want to protect against maliciously uploaded files.) The $_FILES array has information to use for checking type and size. Using the $_FILES array information we can boil the process down to three steps:

  1. checkSize(); See how big it is and compare to a maximum allowable size.
  2. checkType(); Add a set of acceptable file types used with a Web page and check to see if the file type is acceptable.
  3. uploadFile(); If the file type and size are okay, upload the file.

Click below to continue:
Continue reading ‘PHP Graphic CMS Class with Template Method’

Share

PHP CMS Project Part IV: La Petite Blog

cms4Bring in the MySql

At this stage there is still no design pattern in the project. You will see that re-use is starting to creep in, and we’re getting to the point where some decisions can be made about what design pattern would best fit this project. In Part V, you will see how a design pattern pulls everything together and why one is helpful to PHP programming.

In Part III of this series, you saw how external data from text files can be placed into an array and used by the DocHere class to populate a web page. In this installment, the same process shows how this can be done using data from a MySql database.

From Data Input to Web Page Display

The whole point of a CMS is to make updating a web site or blog easy. For the time being, I’m going to treat the web page example as a little blog–La Petite Blog. Figures 1 and 2 show how the data are to be entered and the end result pulled out of a database and displayed in the web page.

Figure 1: HTML form to send data to MySql database

Figure 1: HTML form to send data to MySql database

Figure 1 shows that the same categories of data used throughout the project are still in use. Even the CSS file is the same. The form is a simple HTML5 one. (Click View Code to see listing.)

< !doctype html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="heredoc.css"/>
    <meta charset="UTF-8"/>
    <title>Blogette Data Entry</title>
</head>
<body>
<h1>La Petite Blog</h1>
<h2>&nbsp;Enter data to update your blogette</h2>
<div>
    <form name = "content" action="InsertBlog.php" method="post">
        <input type="text" name="css" value="heredoc.css"/>&nbsp;CSS file
        <input type="text" name="title" />&nbsp;Title
        <input type="text" name="header1" />&nbsp;Header 1
        <input type="text" name="header2" />&nbsp;Header 2
        <textarea rows="5" cols="80" name="body1" >&nbsp;Add body text here</textarea>
        <textarea rows="5" cols="80" name="body2" >&nbsp;Add body text here</textarea>
        <input type="text" name="image1" />&nbsp;Image 1 file name
        <input type="text" name="image2"/>&nbsp;Image 2 file name
        <input type="text" name="caption1" />&nbsp;Caption for Image 1
        <input type="text" name="caption2"/>&nbsp;Caption for Image 2
        <input type="submit" value="Store data"/>
    </form>
</div>
</body>
</html>

The “entry” for the system is the class RetrieveBlog. It is almost identical to the Content class in Part III, and it generates the required results as shown in Figure 2.

Figure 2: Page content from database.

Figure 2: Page content from database.

Getting from the HTML5 data input to the PHP-generated web page takes a bit of doing, and so to get started, download the necessary files:
Download

From Data Input to Web View

The whole point of a CMS is to regularly update a web page easily. By the end of this stage, the only thing you’ll need with an FTP client for is to upload graphics. (Uploading graphic files from a web page using PHP is handled up an upcoming post apart from this series.) For now, though, you will be able to update all text in a web page as well as graphics are have already been placed in an image folder. Here’s what we’ll need:

  1. An HTML form for data entry (see above)
  2. A PHP class to create a MySQL Table to store data
  3. A PHP class to take the data from the HTML form and store it in the MySQL table
  4. A PHP class to retrieve the data from the and make it available to the web page

We’ll start with the table.
Continue reading ‘PHP CMS Project Part IV: La Petite Blog’

Share

PHP CMS Project Part III: Going External

cms3Solve Once; Use Often

One of the goals, indeed the purpose, of most OOP is to solve a programming problem one time and then re-use it. The idea of re-using code is not so much cutting and pasting code as it is to have a good solution and use the same solution for similar problems. In a larger context, that’s exactly what design patterns do. So far in this CMS series, we have not had to add much to the original DocHere class or to the CSS file. In this step, the only class you will need to change is the Content class developed in in Part II of the PHP CMS Series.

The sample page content has been changed, but all of the new data are from external sources (not unlike the graphics and CSS.) Figure 1 shows the new data in the old page:

Figure 1: All of the data are from external sources of both the PHP files and Web page.

Figure 1: All of the data are from external sources of both the PHP files and Web page.

As you can see, everything in the page is in the original style and arrangement. That’s the way it’s supposed to be. All that’s going on is changing data to an existing Web page. The difference in this step is that all of the data are stored in text or graphic files external to the Web page and PHP objects. Everything in this installment is identical to the classes in Part II. All you will need to do is to make some changes in the Content class. The class still uses the same associative array to pass data to the Web page; however, instead of getting its data from literals in the Content class, it gets content from external text files.

Getting Content from the Outside

Before looking into more complex (and robust) ways of adding and/or changing content in a Web page, consider how simple it is using humble text files. Figure 2 shows how the data from an external source becomes the value in a key-value pair in an associative array:

Figure 2: Substituting external text file data for literal value in associative array.

Figure 2: Substituting external text file data for literal value in associative array.

So all that needs to be done with the Content class is to make changes so that it now picks up the data for the Web page from external sources. Actually, every time the Content class has loaded a graphic, it got the data from an external file—a URL. So, all this does is the same thing you’ve done with graphics but with text data.

<?php
include_once('PageMaster.php');
class Content extends PageMaster
{
    private $title;
    private $header1;
    private $header2;
    private $body1;
    private $body2;
    private $caption1;
    private $caption2;
 
    public function getContent()
    {      
        $this->loadContent();
        $this->content = array("css" => "heredoc.css",
                         "title" => $this->title,
                         "header1" => $this->header1,
                         "header2" => $this->header2,
                         "body1" => $this->body1,
                         "body2" => $this->body2,
                         "image1" => "images/bobbed.png",
                         "image2" => "images/daraculaCar.png",
                         "caption1" => $this->caption1,
                         "caption2" => $this->caption2,
                         );   
        return $this->content;
    }
 
    private function loadContent()
    {
        $this->title = file_get_contents('text/title.txt');
        $this->header1 = file_get_contents('text/header1.txt');
        $this->header2 = file_get_contents('text/header2.txt');
        $this->body1 = file_get_contents('text/body1.txt');
        $this->body2 = file_get_contents('text/body2.txt');
        $this->caption1 = file_get_contents('text/caption1.txt');
        $this->caption2 = file_get_contents('text/caption2.txt');
    }
}
?>

All of the content for the page must be placed in text files with the appropriate names. Simply writing what you want to appear in the Web page will do the trick. You can use HTML tags in the text files as well, but remember that all you want is to add content; not structure. Using the image in Figure 1, you should be able to determine what goes in each text file.

As you can see very little had to be done to change the Content class so that it works with external data instead of literals assigned to associative array elements. Eventually, this project will lead to using a database, but for now, each step is one at a time.

Adding a Class for Loading Data

It would be pretty easy to make a LoadContent class from the loadContent() method. Then there would be an object to have the data ready for content use by the Web page and a separate one to load the data used for content. In Part IV, the CMS looks at a separate data loading class and what advantages it would have.

Share