Home arrow PHP arrow Page 2 - Using PHP Closures as View Helpers

Handing View Objects: Creating a View Class - PHP

In this first part of a two-part tutorial, I develop a basic template system that can parse any type of closure assigned as a property of its view object(s).

TABLE OF CONTENTS:
  1. Using PHP Closures as View Helpers
  2. Handing View Objects: Creating a View Class
By: Alejandro Gervasio
Rating: starstarstarstarstar / 0
January 24, 2012

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

In reality, building a class responsible for creating and handling view objects is a pretty straightforward process; there are many ways to accomplish this without much trouble. In this case, however, there's an additional challenge: as I explained before, the class must be able to parse all of the variables embedded into its associated template file, including closures.

So, is this somewhat difficult to achieve? Not really. The class below, which implements the previous "ViewInterface" interface, performs this task. Check it out: 

(MyApplication/View.php)

<?php

namespace MyApplication;

class View implements ViewInterface
{
    const DEFAULT_TEMPLATE_FILE = 'default_template.php';
    protected $_fields = array();
    protected $_templateFile;
   
    /**
     * Constructor
     */
    public function __construct(array $fields = array(), $templateFile = self::DEFAULT_TEMPLATE_FILE)
    {
        // optionally populate the view with an array of values
        if (!empty($fields)) {
            foreach ($fields as $field => $value) {
                $this->$field = $value;
            }
        }
        $this->setTemplateFile($templateFile);
    }
   
    /**
     * Set the view template file
     */
    public function setTemplateFile($templateFile)
    {
        if (!file_exists($templateFile) || !is_readable($templateFile)) {
            throw new InvalidArgumentException('The specified template file ' . $templateFile . ' is invalid.');
        }
        $this->_templateFile = $templateFile;
        return $this;
    }
   
    /**
     * Get the view template file
     */
    public function getTemplateFile()
    {
       return $this->_templateFile;
    }
   
    /**
     * Reset the template file to the default one
     */
    public function resetTemplateFile()
    {
        $this->_templateFile = self::DEFAULT_TEMPLATE_FILE;
        return $this;
    }
   
    /**
     * Assign a field to the view
     */
    public function set($name, $value)
    {
        return $this->__set($name, $value);
    }
   
    /**
     * Get the given field from the view
     */
    public function get($name)
    {
        return $this->__get($name);
    }
   
    /**
     * Check if the given field has been assigned to the view
     */
    public function exists($name)
    {
        return isset($this->_fields[$name]);
    }
   
    /**
     * Remove the given field from the view
     */
    public function remove($name)
    {
        if (isset($this->_fields[$name])) {
            unset($this->_fields[$name]);
        }
        return $this;
    }
      
    /**
     * Render the template file
     */
    public function render()
    {
        ob_start();
        include $this->_templateFile;
        return ob_get_clean();
    }
   
    /**
     * Assign the given field to the view via the '__set()' magic method
     */
    public function __set($name, $value)
    {
        $this->_fields[$name] = $value;
        return $this;
    }
   
    /**
     * Get the given field from the view via the '__get()' magic method
     */
    public function __get($name)
    {
        if (!isset($this->_fields[$name])) {
            throw new InvalidArgumentException('The specified view field ' . $name . ' does not exist.');
        }
        return (is_callable($this->_fields[$name]))
            ? $this->_fields[$name]($this)
            : $this->_fields[$name];   
    } 
}    

The above "View" class implements some simple mutators/getters, which allow you to assign, remove and retrieve fields by means of some PHP magic methods. On the other hand, its "render()" method does exactly what it name suggests: it renders the associated template by using a bit of output buffering.

Of course, if you're anything like me, you're wondering which part of the class actually parses any closures added to the corresponding template. Well, if you look closely at the "__get()" method, you'll realize that it first checks to see if the requested field is actually callable. If this is true, then it calls the closure (or any other callable function) and passes to it an instance of the view. This simple yet effective trick allows you to embed variables into a template file, including closures, which can be used as traditional view helpers. Got it? Good.

Naturally, the best way to see if the class can actually treat closures like helpers is by means of a concrete example. Below I created a basic HTML5 template; it contains some interspersed view fields. Have a look at it:
   
(default_template.php)

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Using closures in PHP</title>
</head>
<body>
    <header>
        <h1>Header section</h1>
        <h2>Welcome! You're accessing this page from : <?php echo $this->clientIp;?></h2>
        <p><?php echo $this->header;?></p>
    </header>
    <section>
        <h2>Main section</h2>
        <p><?php echo $this->content;?></p>
    </section>
    <footer>
        <h2>Footer section</h2>
        <p><?php echo $this->footer;?></p>
    </footer>
</body>
</html>

While the structure of this template is pretty simple, it makes reference to a view field called "clientIp," which echoes to screen the IP address from which the user is accessing the web page. Since this data is essentially dynamic, it could be retrieved through a view helper.

Thanks to the functionality of the earlier "View" class, however, the same task can be performed by a closure, as shown below (as usual, the autoloader has been omitted for the sake of brevity):

<?php

use MyApplicationView;

// include the autoloader and create an instance of it
require_once __DIR__ . '/Autoloader.php';
$autoloader = new Autoloader;

// create a view object and assign some properties to it
$view = new View;
$view->header = 'This is the content of the header section';
$view->content = 'This is the content of the main section';
$view->footer = 'This is the content of the footer section';

$view->clientIp = function() {
    if (isset($_SERVER['HTTP_CLIENT_IP'])) {
        return $_SERVER['HTTP_CLIENT_IP'];
    }
    elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        return $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    else {
      return $_SERVER['REMOTE_ADDR'];
    }
};

// render the view template
echo $view->render();

As you can see from the above script, once a new view object has been spawned, it gets assigned some values to its "header," "content," "footer" and "clientIp" fields. Naturally, the most interesting aspect of this process is the use of a closure, which performs a basic check on some server variables to determine the actual IP address of the client.

Leaving apart the limited efficiency of the closure itself (it'll fail hard when the user is behind an anonymous proxy), the example shows how to encapsulate a specific task inside a closure, which can then be parsed by the view's "render()" method. Moreover, if you want to see the output generated by the previous script, the following screen capture will hopefully be quite illustrative: 

The script worked decently well. But, what's the point in using a closure to find out the IP of the client, when the same could be done through a method of a helper object? Since the task is fairly straightforward, a closure does the trick, even at the expense of sacrificing the advantages brought by Polymorphism. For more complex logic, an OO helper would unquestionably  be the right option.

However, there's a hidden benefit in using a closure as a view field: as you may have noticed, it gets called only when the view's template is parsed and rendered accordingly. This means that it's possible to use this approach to perform some expensive operations on request, such a lazy-loading data from a database.    

That's precisely the use case that I plan to cover in depth in the second part of this tutorial.  

Final Thoughts

In this first chapter of a two-part tutorial, I went through the development of a basic -- yet extendable -- template system, which could parse any type of closure assigned as a property of its view object(s). In the sample application that you just saw, I used this ability to determine the IP addresses of users accessing the application. This was pretty easy to accomplish.

As I explained before, however, it's dead simple to use this closure-based approach to perform more complex tasks. To give you proof of my claim, in the final installment, I'll be showing you how to lazy-load data from a simple text file and embed the corresponding contents into the previous template file. Best of all, I won't need to amend a single chunk of the entire system.

Don't miss the last part!

 

Selamlar beyler yeni escortunuz esra dan selamlar;18 yaşındayım lise menuzu öğrencisiyim. antalya’da yaşıyorum ama şehir önemli değil masraflar karşılandığı sürece istediğiniz yere gelirim. Boyum 1,70 kilom 49. Saç: siyah, göz: yeşil.Hakkımda : antalya bayan escortlarÇekici ve alımlıyım. Harika zaman geçirmek isteyen beyler ulaşsın. Çok ateşliyim ve sizinle birlikte olmak için bekliyorum. Eğer sizden hoşlandıysam fiyatta oynama yapabilirim fakat genel olarak fiyatım standarttır. Kondomsuz ilişkiye girmem bunun için ısrar ederseniz sizinle görüşmeyi keserim. Onun haricinde her şeye varım. Bir kadından bekleyebileceğiniz her şeyi yaparım. Sınırları zorlarım.Benimle zaman geçirirseniz sizi mutluluğun doruklarına çıkarırım. Unutulmayacak anılar yaşamak istiyorsanız durmayın bana ulaşın.Kaynak ve iletişim : http://antalyamasoz.com/konya-eskort-bayan-sibel/


 
 
>>> More PHP Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: