Design patterns are guidelines for solving repetitive problems.

Quote from Wikipedia:

Software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design.

Types of Design Patterns

Front Controller

The front controller design pattern is listed in several pattern catalogs and related to the design of web applications. It is "a controller that handles all requests for a website", which is a useful structure for web application developers to achieve the flexibility and reuse without code redundancy.

Class diagram exemplifying the Front Controller pattern
Class diagram exemplifying the Front Controller pattern

Purpose

Use this for larger systems in which you know that you will need as much flexibility as possible in managing many different views and commands.

Implementation

<?php
class FrontController
{
    const DEFAULT_ACTION     = "index";
    const DEFAULT_CONTROLLER = "Index";
    const BASE_PATH = '';
    
    protected $controller    = self::DEFAULT_CONTROLLER;
    protected $action        = self::DEFAULT_ACTION;
    protected $params        = array();
    
    public function __construct(array $options = array()) {
        if (empty($options)) {
           $this->parseUri();
        }
        else {
            if (isset($options["controller"])) {
                $this->setController($options["controller"]);
            }
            if (isset($options["action"])) {
                $this->setAction($options["action"]);     
            }
            if (isset($options["params"])) {
                $this->setParams($options["params"]);
            }
        }
    }
    
    protected function parseUri() {
        $path = trim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), "/");
        if($path === self::BASE_PATH){
        	$this->setController($this->controller);
        	$this->setAction($this->action);
        }else{
			if(self::BASE_PATH != ''){
				$path = trim(str_replace(self::BASE_PATH, "", $path), "/");
			}
        	@list($controller, $action, $params) = explode("/", $path, 3);
        	if (isset($controller)){
        	    $this->setController($controller);
        	}
        	if (isset($action)){
        	    $this->setAction($action);
        	}
        	if (isset($params)){
        	    $this->setParams(explode("/", $params));
        	}
        } 
    }
    
    public function setController($controller) {
        $controller = ucfirst(strtolower($controller)) . "Controller";
        $controller = "Controller\\" . $controller;
        if (!class_exists($controller)) {
        	header("HTTP/1.0 404 Not Found");
        	echo "<h1>404 Not Found</h1>";
        	echo "Página não encontrada. Ir para <a href='/produtos'>Home</a>";
        	exit();
    	}
        $this->controller = $controller;
        return $this;
    }
    
    public function setAction($action) {
        $reflector = new \ReflectionClass($this->controller);
        if (!$reflector->hasMethod($action)) {
            header("HTTP/1.0 404 Not Found");
            echo "<h1>404 Not Found</h1>";
            echo "Página não encontrada. Ir para <a href='/produtos'>Home</a>";
            exit();
    	}
        $this->action = $action;
        return $this;
    }
    
    public function setParams(array $params) {
        $this->params = $params;
        return $this;
    }
    
    public function run() {
        call_user_func_array(array(new $this->controller, $this->action), $this->params);
    }
}

Application Controller

The application controller pattern is the pattern that permits the centralization of all view logic and promotes a unique process to define the flow of pages.

Purpose

Create a class to manage view logic and command selection.

Example

Here I’ll present a small, high-level sample of an Application Controller that manages a form compilation in multiple steps.

In Zend Framework, it can be thought of as homogeneous to Action Controllers (so that it can be easily put in an existing application’s infrastructure.) It usually does not take advantage of automated mechanisms like the ViewRenderer plugin to achieve a finer control. In fact, it does not map to a single domain action or a single view: the view is chosen on the fly and the domain model is seen through a Facade.

Implementation

<?php

class ApplicationController extends Zend_Controller_Action
{
    const LAST = 4;

    public function init()
    {
        // ... set up the various resources, like forms or domain entities
    }

    public function executeAction()
    {
        // other view variables...

        // keep partial compilations
        $this->session->merge($this->request->getPost());

        // this is our View change
        $step = $this->_request->getParam('step', 1);
        if ($step == self::LAST) { 
            return $this->render('final.phtml');
        } else {
            $this->view->form = $this->forms[$step];
        }

        // the script is always the same but the form rendered changes
        $this->render('appcontroller.phtml');
    }
}

Template View

In Template View, static HTML pages are defined and markers are used as placeholders within them for dynamic content on the page. When the page is requested, the markers are replaced with the dynamic content (ie, from a database or similar) by the underlying web server or framework.

Class diagram exemplifying the Template view pattern.
Class diagram exemplifying the Template view pattern.

Purpose

Create pages that manage display and user interface only, incorporating dynamic information into display markup with as little raw code as possible.

Implementation

<?php
$this->headTitle($this->object);
$this->headTitle($this->methodName);
if ($this->result) {
    echo "<p>Result: $this->result</p>";
}
if ($this->form) {
    echo $this->form;
}

Page Controller

Page controller is an alternative to front controller in MVC model.

Purpose

Lighter weight but less flexible than Front Controller, Page Controller addresses the same need. Use this pattern to manage requests and handle view logic if you want fast results and your system is unlikely to grow substantially in complexity.

Example

Zend framework Page Controller example

Implementation

class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
        // assign a variable to the view, with the value coming from somewhere
        $this->view->variable1 = ...
        $this->render('viewName'); // executes views/scripts/viewName.php
    }
       
    public function bazAction()
    {
        // other action related to the former
    }
}

Transaction Script

Transaction Script (TS) is the simplest domain logic pattern we can find. It needs less work to implement than other domain logic patterns and therefore it's perfect fit for smaller applications that doesn't need big architecture behind them.

Purpose

When you want to get things done fast, with minimal up-front planning, fall back on procedural library code for your application logic. This pattern does not scale well.

Implementation

<?php
// we are forced to mock a request in production code:
$_GET['id'] = $someRow['id];
$_GET['orderField'] = 'name';
include 'list.php';
// or even capturing the response:
ob_start();
$_GET['id'] = $someRow['id];
$_GET['orderField'] = 'name';
include 'list.php';
$content = ob_get_content();
ob_end_clean();

Domain Model

At its worst business logic can be very complex. Rules and logic describe many different cases and slants of behavior, and it's this complexity that objects were designed to work with. A Domain Model creates a web of interconnected objects, where each object represents some meaningful individual, whether as large as a corporation or as small as a single line on an order form.

Purpose

At the opposite pole from Transaction Script, use this pattern to build object-based models of your business participants and processes.

Example

Webmail System.

Implementation

<?php
/**
 * Let's suppose we're developing a webmail application, and we 
 * want to create a Domain Model which encapsulates all the logic
 * of sending and receiving mails, creating them, forwarding, managing
 * replies and their visualization, and so on.
 * The most important class in this picture is an Entity which 
 * we'll give the name Email.
 */
class Email // does not extend anything
{
    /**
     * We probably want to introduce a class to manage addresses.
     * The modelling phase make decisions such as this, deciding on the issue of
     * primitive variable vs. wrapper class for object fields.
     * For now, we will leave them as simple strings. Subsequent
     * refactoring may introduce wrapper classes or interfaces.
     * @var string
     */
    private $_sender;
    private $_recipient;

    private $_subject;
    private $_text;
    
    /**
     * @return string
     */
    public function getSender()
    {
        return $this->_sender;
    }

    /**
     * Do we need setters and getters? Every field should be 
     * analyzed. If we can keep it private and inaccessible,
     * it's usually better.
     */
    public function setSender($sender)
    {
        $this->_sender = $sender;
    }

    /**
     * @return string
     */
    public function getRecipient()
    {
        return $this->_recipient;
    }

    public function setRecipient($recipient)
    {
        $this->_recipient = $recipient;
    }

    /**
     * @return string
     */
    public function getSubject()
    {
            return $this->_subject;
    }

    public function setSubject($subject)
    {
        $this->_subject = $subject;
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->_text;
    }

    public function setText($text)
    {
        $this->_text = $text;
    }

    public function __toString()
    {
        return $this->_subject . ' > ' . substr($this->_text, 0, 20) . '...';
    }

    public function reply()
    {
        $reply = new Email();
        $reply->setRecipient($this->_sender);
        $reply->setSender($this->_recipient);
        $reply->setSubject('Re: ' . $this->_subject);
        $reply->setText($this->_sender . " wrote:\n" . $this->_text);
        return $reply;
    }
}

/**
 * Interface for a service. This is part of the Domain Model,
 * implementations will be plugged in depending on the environment.
 */
interface EmailRepository
{
    /**
     * @return array
     * @TypeOf(Email)
     */
    public function getEmailsFor($recipient);
}

// client code
$mail = new Email();
$mail->setSender("alice@example.com");
$mail->setRecipient("bob@example.com");
$mail->setSubject('Hello');
$mail->setText('This is a test of an Email object, which is part of our Domain Model.');
echo $mail, "\n";
$reply = $mail->reply();
echo $reply, "\n";

Summary

In this post, we looked at the following enterprise patterns:

  • Front Controller
  • Application Controller
  • Template View
  • Page Controller
  • Transaction Script
  • Domain Model