Archive for the 'Static properties & methods' Category

Sandlight CMS IV: Dynamic Responsive Web PHPages

responsiveAt this point in the Sandlight CMS development process, two design patterns have been employed: 1) Chain of Responsibility as a device checker, and 2) Abstract Factory for making different parts for different devices. As usual, I’ve been posting the results so far on the Sandlight Productions, LLC website. The site itself is the example used in this series. This post is Part IV of the Sandlight CMS series, and if you have not been following the series you can review what has been done so far beginning with Part I.

At this stage, the project is ready to use the Abstract Factory to produce the needed parts and put them together into a page. However, before going ahead and have the factory build the parts I’d like to take an intermediate step and just build a dynamic responsive Web page.

The Dynamic Responsive Web PHPage

The easiest way to proceed is to begin with an HTML5 page, encapsulate the page into a PHP object (class) and add methods. The reason for this step is that the Web site, in addition to being responsive, needs to be dynamic. This means that it needs a way for the administrator to add changes, and in order for this to transpire, the dynamic portion of the page has to include variables in the place of static text, graphics and/or video. Figure 1 shows the general layout envisioned for the page:

Figure 1: Dynamic Responsive Web Page

Figure 1: Dynamic Responsive Web Page

Everything about the page must be responsive, but some parts are static and some are dynamic. In the two-column outline in Figure 1, the entire left column is static yet it must be responsive to different devices. In Parts I to III of this series, the pages have been responsive. The next step in making them both responsive and dynamic is to create parts of the page that will be dynamic since they are already set up to be responsive. Before continuing, click the Play button to see the progress so far and the Download button for all of the source code and accompanying files:
PlayDownload

Using PHP alone, creating a dynamic page is simple. Just place PHP variables where content goes. This is true for both the pages formatted by CSS3 and jQuery. Importantly, though, all of the Web pages should be encapsulated into PHP classes, using heredoc string variables as has been shown in previous installment of this series.

QR Code: The New Responsive Component

Quick Response Code (QR) is a new necessity for Web sites doing business on the Web and for just about every other kind of site that wants to increase its exposure. Basically, using a QR Code reader in a mobile device (phone or tablet) automatically brings up the link coded in the QR image (a square with some squiggly block images.) That beats trying to to thumb in a URL on a tiny phone keyboard. The following two can be downloaded free (at the time of this writing.):

sandlightqrcodeI’m pretty certain that other smart phones have QR readers; so if you have something other than an iOS or Android operating system on your mobile device, an Internet search for “QR Scanner” will probably be able to locate one for you.

sandlightOnce you have a QR scanner, you need a coded image, such as the one to your right. Go ahead and scan it to see what happens. It should take you to the Sandlight Productions, LLC home page build on this CMS (updated.) On it you will find several more QR codes for links to sites related to Sandlight. You can get the coded images online at different sites. One site allows you to include your logo and choice of colors is QRCode Monkey. The QR code image in green to your left with the Sandlight logo in the middle does exactly the same thing as the black one. So, if you’d like your QR Code images to keep your graphic designer happy, consider the visual options beyond the default. Figure 2 shows a page being scanned with an iPhone (left) and the linked page in the iPhone (right).

Figure 2: Scanned QR URL uploaded in mobile phone.

Figure 2: Scanned QR URL uploaded in mobile phone.

Adding QR codes to your site (or your client’s site) is very easy, and you should definitely include it in your dynamic responsive CMS. Let’s now see how the dynamic responsive two-column page is created:
Continue reading ‘Sandlight CMS IV: Dynamic Responsive Web PHPages’

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.

?View Code HTML
< !DOCTYPE html>


    
    
    CMS Admin Bridge


    

Enter Update Data

 Header

Enter the text for the body below:

Preview New Data

 Desktop
 Tablet
 Phone

 

Store New Data

 

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’

Static Connection Objects: Classes, Properties and Methods

connectReusable Connection Tools

Some years ago, Steve Krug wrote a book entitled, Don’t Make Me Think!. That sums up how I feel about MySQL connections with PHP. When I make a PHP-MySQL application, all I want to do is to call up a connection object and method, make my connection and go about using it as a mysqli object. I don’t want to have to think about it. I don’t want to have to re-write an error-handling sequence, and if I change the connection information, I want a single source where I can go and make changes without fear that the whole thing won’t blow sky-high. If you like, you can download the connection files along with a test class before continuing:
Download

The Big Boom Theory

A while back on this blog I posted a simple connection pattern. An interface stored connection information in the form of constants and an implemented class returned a connection object. The idea is to provide a simple and reusable application for MySQL connections.

In the book, I created a similar set of classes for making connections, but instead of using non-static variables I used static ones. The UniversalConnect class shows the use of static variables:


include_once('IConnectInfo.php');
class UniversalConnect implements IConnectInfo
{
        private static $server=IConnectInfo::HOST;
        private static $currentDB= IConnectInfo::DBNAME;
        private static $user= IConnectInfo::UNAME;
        private static $pass= IConnectInfo::PW;
        private static $hookup;
 
        public function doConnect()
        {
                self::$hookup=mysqli_connect(self::$server, self::$user, self::$pass, self::$currentDB);
                if(self::$hookup)
                {
                        echo "Successful connection to MySQL:
"
; } elseif (mysqli_connect_error(self::$hookup)) { echo('Here is why it failed: ' . mysqli_connect_error()); } return self::$hookup; } } ?>

To create an instance of the mysqli object in a static environment, the following line (13) is employed:

13 $this->hookup=UniversalConnect::doConnect();

The property, $this->hookup is a private one in the constructer function of the using class. In tests on two of three hosts, the results showed the following:

Successful connection to MySQL:
Old table proxyLog has been dropped.
Table proxyLog has been created successfully.

However, in the third host, using PHP 5.4, the same code generated the following error:

Strict Standards: Non-static method UniversalConnect::doConnect() should not be called statically, assuming $this from incompatible context in D:\ABC\XYZ\jblow\PHPdp\tablework\CreateTable.php on line 13 Successful connection to MySQL:
Old table proxyLog has been dropped.
Table proxyLog has been created successfully.

Testing it on a fourth server, I got the expected results. But I still could not find what the problem was.

Static for All

The problem turned out to be minor (don’t they always) and was solved simply by making the method that returns the msqli connection static. This required both the doConnect method to be declared static in the interface and in the UniversalConnect class. The following listing shows how the repair was made so that on hosting services with Strict Standards, you won’t run into problems. (It’s also a better overall practice.)


//Filename: IConnectInfo.php
//Substitute your connect info
interface IConnectInfo
{
        const HOST ="localhost";
        const UNAME ="phpDesign";
        const PW ="phpPatterns";
        const DBNAME = "phpBase";
 
        public static function doConnect();
}
?>
 

//Filename: UniversalConnect.php
//ini_set("display_errors","1");
//ERROR_REPORTING(E_ALL);
include_once('IConnectInfo.php');
 
class UniversalConnect implements IConnectInfo
{
        private static $server=IConnectInfo::HOST;
        private static $currentDB= IConnectInfo::DBNAME;
        private static $user= IConnectInfo::UNAME;
        private static $pass= IConnectInfo::PW;
        private static $hookup;
 
        public static function doConnect()
        {
                self::$hookup=mysqli_connect(self::$server, self::$user, self::$pass, self::$currentDB);
                if(self::$hookup)
                {
                        echo "Successful connection to MySQL:
"
; } elseif (mysqli_connect_error(self::$hookup)) { echo('Here is why it failed: ' . mysqli_connect_error()); } return self::$hookup; } } ?>   //The following file is an example of how to use a static method //without instantiating the class of which the method is a part //Any file where you need a MySQL connection works the same. //ini_set("display_errors","1"); //ERROR_REPORTING(E_ALL); include_once('UniversalConnect.php'); class CreateTable { private $tableMaster; private $hookup;   public function __construct() { $this->tableMaster="sandTable";   //Single line to create mysqli object $this->hookup=UniversalConnect::doConnect();   $drop = "DROP TABLE IF EXISTS $this->tableMaster";   if($this->hookup->query($drop) === true) { printf("Old table %s has been dropped.
"
,$this->tableMaster); }   $sql = "CREATE TABLE $this->tableMaster (id SERIAL, uname NVARCHAR(15), pw NVARCHAR(10), PRIMARY KEY (id))";   if($this->hookup->query($sql) === true) { printf("Table $this->tableMaster has been created successfully.
"
); } $this->hookup->close(); } } $worker=new CreateTable(); ?>

The first two files are the interface and implementation for the UniversalConnect object, and the third file is just a sample of what you might use it for.

Keep Host Aware

I’ve had to work with a lot of different hosting services and configurations over which I have little or no control. Currently, I regularly use five different hosts, four of which are run by sysadmins who have levels of skill varying from novice to the-best-there-is (student sysadmins often change our PHP.ini files in the learning process.) The only host I can really control all the time is my host on my LAN. I can change the php.ini file so that I have the desired level of security, standards and access. Because of these variations I often use the following two lines:

ini_set("display_errors","1");
ERROR_REPORTING(E_ALL);

In this way, I don’t have to worry about the skill level of the sysadmin (and I do have to worry!). If I find something I do or don’t like about the php.ini configuration, I can always reset them myself or ask the sysadmin at a later date to make the fix. In the meantime, though, until I’m sure about how the php.ini file is configured, I’m going to include lines that make sure I get full error reporting.

After my experience with the static properties and method, I’m changing my error reporting to:

ERROR_REPORTING( E_ALL | E_STRICT );

In working with design patterns and OOP, you need all the feedback you can get. Of course, the best plan is to set your php.ini file so you have your error reporting set the way you want, but if you don’t have full control over configurations, you need a backup plan.