Working with CSS Styles and the Stage Pattern in PHP 5

The stage pattern lets you build classes that can modify their behaviors according to the variations of a given programming context. If you want to learn more about it, then you should start reading this article now! Welcome to the final installment of the series that began with "Implementing the stage pattern in PHP 5." Made up of two articles, this series walks you through the application of this useful pattern, and complements the corresponding theory with illustrative code samples.

Introduction

Stepping back quickly to the preceding tutorial of the series, you’ll recall that I introduced the key concepts of the stage pattern. I also provided you with some friendly hands-on examples, aimed at demonstrating, at least basically, the functionality of this rather unusual pattern.

Speaking more specifically, in that tutorial I developed a couple of straightforward PHP classes. The first one was tasked with displaying regular DIVs on a simple web page, while the second one was capable of modifying the values assigned to the "overflow" CSS property corresponding to all these DIVs. These classes demonstrated how a particular class can change its behavior in response to the modifications introduced into its context.

Obviously, the example described above is a concise implementation of the logic followed by the stage pattern, which hopefully will help you understand more easily how it this pattern works. However, to be frank, I think that the more code samples you see covering the pattern in question, the more you’ll learn about it. Therefore, in this final article of the series I’m going to provide you with another practical example of how the stage pattern works.

Essentially, what I plan to demonstrate here is how this pattern can be used to build different versions of a given web document on the fly, either for display on a typical computer monitor, or for printing. There will be a target class, responsible for defining a few CSS styles used by the pertinent web document. There will also be a contextual class to determine which of these styles will be attached to the web page in question.

Now that you know the purpose of this last tutorial of the series, let’s continue learning how to implement the stage pattern with PHP 5. Let’s get started now!

{mospagebreak title=Building a target class}

As I said in the beginning of this article, my demonstration of how to implement the stage pattern with PHP 5 will consist mainly of creating a simple mechanism that generates dynamically two different versions of a given web document. The first one will be best suited for use with conventional computer monitors, and the second one will be simply a "printer-friendly" format of the document in question.

Of course, as you might have guessed, selecting the proper CSS styles that fit a particular web page format will be a task performed by two concrete classes, in this case called "CSSNormal" and "CSSPrint" respectively.

The signatures corresponding to these two concrete classes are shown below, including the pertinent definition of their parent. Having said that, the classes look like this:

// define abstract ‘CSS’ class
abstract class CSS{
   protected $font;
   protected $color;
   protected $background;
   abstract public function __construct
($font,$color,$background);
   abstract public function getFont();
   abstract public function getColor();
   abstract public function getBackground();          
}

// define concrete ‘CSSNormal’ class
class CSSNormal extends CSS{
   public function __construct($font,$color,$background){
     if($font!=’Arial’&&$font!=’Tahoma’&&$font!=’Verdana’){
       throw new Exception(‘Invalid value for font property.’);
     }
     if(!preg_match("/^#[0-9a-f][0-9a-f][0-9a-f]$/",$color)){
       throw new Exception(‘Invalid value for foreground color
property.’);
     }
     if(!preg_match("/^#[0-9a-f][0-9a-f][0-9a-f]$/",$background)){
       throw new Exception(‘Invalid value for background color
property.’);
     }
     $this->font=$font;
     $this->color=$color;
     $this->background=$background;                      
   }
   public function getFont(){
     return $this->font;
   }
   public function getColor(){
     return $this->color;
   }
   public function getBackground(){
     return $this->background;
   }
}

// define concrete ‘CSSPrint’ class
class CSSPrint extends CSS{
   public function __construct($font,$color,$background){
     if($font!=’Arial’){
       throw new Exception(‘Invalid value for font property.’);
     }
     if($color!=’#000′){
       throw new Exception(‘Invalid value for foreground color
property.’);
     }
     if($background!=’#fff’){
       throw new Exception(‘Invalid value for background color
property.’);
     }
     $this->font=$font;
     $this->color=$color;
     $this->background=$background;                      
   }
   public function getFont(){
     return $this->font;
   }
   public function getColor(){
     return $this->color;
   }
   public function getBackground(){
     return $this->background;
   }
}

As you can see, the concrete classes listed above are very easy to grasp. Basically, their primary task is to create a CSS style that suits the requirements of a particular web page format.

In the first case, the "CSSNormal" class is tasked with building a CSS style that’s best suited for use with computer screens, while the second class, called "CSSPrint," is obviously responsible for creating a set of styles for use with printers.

So far, so good. At this point I have built two simple classes that are capable of generating diverse CSS styles for applying to a specific web document. However, at this moment I’m sure you’re asking the following question: how does the stage pattern fit into this schema? I’m glad you asked!

Having at our disposal the two classes previously defined, I’m going to create a contextual class. It will be able to change its behavior in order to select a specific CSS style according to the format requirements of a given web page. In doing so, I’ll be implementing the model demanded by the stage pattern.

Naturally, this brand new contextual class will be defined in the following section, therefore click on the link that appears below and keep reading.

{mospagebreak title=Defining a basic contextual class}

As I expressed in the section you just read, to complete the programmatic model imposed by the stage pattern, it’s necessary to build a contextual class capable of selecting the appropriate CSS style that fits the requirements of a specific web document.

To perform this simple task, below I defined the brand new "CSSContext" class. It is responsible for returning the correct CSS object to client code in response to the format demands of a given web page.

Now that I have explained how this contextual class is going to work, please pay attention to its respective signature: 

// define ‘CSSContext’ class
class CSSContext{
   private $pageFormat=NULL;
   public function __construct(){}
   public function setPageFormat($pageFormat){
     if($pageFormat!=’normal’&&$pageFormat!=’print’){
       throw new Exception(‘Invalid value for web page
format.’); 
     }
     $this->pageFormat=$pageFormat;
   }
   public function getCSS(){
     if($this->pageFormat==’normal’){
       return new CSSNormal(‘Verdana’,'#f00′,’#eee’);
     }
     else{
       return new CSSPrint(‘Arial’,'#000′,’#fff’);
     }
   }
}

As I said before, the above class has been provided with the capacity to create a specific CSS object in accordance with the format requirements of a particular web document. As you can see, this task is performed by its "getCSS()" method, which returns to calling code either a CSS object suitable for use with computer monitors, or another one for use with printers.

All right, at this stage I have defined a contextual class that controls what type of CSS object must be used according to the specifications of a given web document. However, there’s a missing piece in this scenario, since I need to create a mechanism that generates the web document in question.

In response to this requirement, below I included the definition of a brand new class. It’s called "WebPage," and it is tasked with creating web pages on the fly, using a specific CSS object passed as an input parameter to the corresponding constructor.

The signature for the aforementioned class is as follows:

// define ‘WebPage’ class
class WebPage{
   private $title=’Testing State pattern’;
   private $html=NULL;
   private $css=NULL;
   public function __construct(CSS $css){
     $this->css=$css;
   }
   public function makeHeader(){
     $this->html=’<html><head><title>’.$this-
>title.’</title></head>’;
   }
   public function makeBody(){
     $this->html.=’<body><div style="font: bold 12px ‘.$this-
>css->getFont().’;color :’.$this->css->getColor().’;background:
‘.$this->css->getBackground().’;">This is the default content
used to test the state pattern.</div>’;
   }
   public function makeFooter(){
     $this->html.=’</body></html>’;
   }
   public function getHTML(){
     return $this->html;
   }
}

Now that you have seen the definition for the above "WebPage" class, I’m pretty certain that you’ll see more clearly how the stage pattern is implemented in this case. Let me explain the situation briefly: on one hand, there’s a contextual class that selects the proper CSS object to be used when generating a web document, while on the other hand there’s another class that changes its behavior — notice the implementation of the "makeBody()" method – to fit the requirements of a particular page format.

Okay, at this point you hopefully understand how the stage pattern is used here. However, I think that you’ll grasp the way that this pattern works even more easily if I set up a concrete example where all the previous classes are put to work in conjunction.

In the following section I’m going to develop a short script that will help to demonstrate the functionality of the stage pattern. Keep reading, please.

{mospagebreak title=Completing the implementation of the stage pattern}

Indeed, the best way to understand how the stage pattern works with this specific implementation is by creating a functional example that demonstrates how a given web document can use different CSS styles according to specific format requirements.

In this case, the following sample pair of scripts show how an instance of the contextual "CSScontext" class is capable of modifying the behavior of a specific "WebPage" object to generate two different versions of the same web document.

Now that I have explained how the pertinent example is going to work, please examine the corresponding source code, which looks like this: 

// example displaying a normal web page
try{
   // create new ‘CSSContext’ object 
   $cssContext=new CSSContext();
   // set CSS styles to work with a normal web page format
   $cssContext->setPageFormat(‘normal’);
   // create new ‘WebPage’ object
   $webPage=new WebPage($cssContext->getCSS());
   $webPage->makeHeader();
   $webPage->makeBody();
   $webPage->makeFooter();
   // display web page using normal format
   echo $webPage->getHTML();
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

// example displaying a printer-friendly web page
try{
   // create new ‘CSSContext’ object 
   $cssContext=new CSSContext();
   // set CSS styles to work with a printer-friendly web page
format
   $cssContext->setPageFormat(‘print’);
   $webPage=new WebPage($cssContext->getCSS());
   $webPage->makeHeader();
   $webPage->makeBody();
   $webPage->makeFooter();
   // display web page using printer-friendly format
   echo $webPage->getHTML();
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

As shown above, the stage pattern is implemented here to change the behavior of a "WebPage" object so it can display distinct versions of the same web document. As you can see in the two previous scripts, the first time the web page is rendered, a "normal" CSS style is used, while in the second case, the page in question is displayed with a "printer-friendly" format.

At this point, I believe that the previous code samples should give you an accurate idea of how to implement the stage pattern in a concrete situation. However, as with many other design patterns, I suggest you create your own testing examples to acquire a better grounding in how it this pattern functions.

Final thoughts

Unfortunately, we’ve come to the end of this journey. In these two tutorials, I introduced the basic concepts of the stage pattern, and also showed you a couple of functional examples where it can be applied with minor hassles.

As you hopefully learned, if you ever need to build a class that changes the way it works according to the modifications introduced into its context, the stage pattern can provide a good method for solving this issue.

See you in the next PHP tutorial!

Google+ Comments

Google+ Comments