Building a View

From GeeklogWiki
Revision as of 00:33, 31 October 2009 by LWC (talk | contribs) (Why Flexy?: Fixed English)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Building a View

Views are the visual components shown to your users. They often display information from one or more models. It is important to note that your views are to contain no business logic. It just displays a page to a user. The Geeklog 2 Framework has consciously chose to use Flexy for a variety of reasons but know now that you can very quickly retrofit any of what you see to use any other templating engine (such as Smarty).

Why Flexy?

One of the more annoying questions I get from PHP developers is why Flexy? Why Flexy? Why Flexy? First, keep in mind the Geeklog 2 Framework has been around in various forms since 2003 and back then one of the more annoying things about other template engines out there is their blatant desire to allow rendering of HTML and JavaScript by default. Flexy, rightfully so, hates these things and will always escape them unless you explicitly tell it to allow them. After that, Flexy is full of the sorts of features you'd like to see from a modern PHP template eninge. Things like compiling of templates, support for control structures (IF's, FOR loops, etc), object-oriented design and out-of-the-box multilingual support via PEAR::Translation2.

Are there other good alternatives out there? Absolutely, and let me remind you that just because the Geeklog 2 Framework uses Flexy that doesn't mean you couldn't retrofit your projects to use another engine. That's the beauty of object-oriented code.

Your First View

OK, enough talk...let's see an MVCnPHP view first hand. Every view is comprised of two parts. The first part is the MVCnPHP view which is responsible for pulling all data needed to be displayed on the page. The second part is the Flexy template. Let's first build the Flexy template by creating a page called Home.thtml. Note that Geeklog 2 Coding Standards require that all HTML templates use the .thtml extension.

<html>
    <head>
        <title>{pageTitle}</title>
    </head>
    <body>
    <p>
    This is a page created using the Geeklog 2 Framework.  You are viewing this page on {getDateTime()}.
    </p>
    </body>
</html>

As you would expect from a PHP template engine, the template file itself is mostly HTML. The template above excercises a couple tasks such as showing data in a variable and calling a method. Those familir with other template engines might notice the variable and method call noted by {} above. In the TITLE tag, there is the pageTitle variable and in the body there is a method call to getDateTime(). Where does that variable and method exist? On the MVCnPHP view!

/**
 * MVCnPHP Abstract BaseView object
 */
require 'Geeklog/MVCnPHP/BaseView.php';

/**
 * PEAR::HTML_Template_Flexy
 */
require 'Flexy.php';

class SAMPLE_HomeView extend MVCnPHP_BaseView  {   
    /**
     * Handle to instance of a flexy object
     *
     * @access protected
     * @var object
     */
     protected $flexyHandle = null;

    /**
     * Page title
     * @var string
     * @access protected
     */
    protected $pageTitle = null;

    /**
     * Constructor
     *
     * @access public
     */
    public function __construct()
    {
        $this->pageTitle = 'Your first MVCnPHP View';
        $this->initializeFlexy();
    }

    /**
     * Instantiates Flexy
     *
     * @access protected
     *
     */
    protected function initializeFlexy()
    {
        $options = array(
            'templateDir'   => '/path/to/templates',
            'compileDir'    => '/path/to/templates/compiled_templates',
            'forceCompile'  => 0,
            'debug'         => 0,
            'locale'        => 'en'       
        );
        
        $this->flexyHandle = new FARMS_HTML_Template_Flexy($options);
    }

    /**
     * Gets current date and time
     *
     * @access public
     * @return string Current date and time
     *
     */
    public function getDateTime()
    {
        return strftime('%D %T');
    }

    /**
     * Shows the page.
     *
     * @access public
     */
    public function getView() {
        
        $this->setPageTitle('Your first MVCnPHP View');
    	$this->flexyHandle->compile('Home.thtml');
        $this->flexyHandle->outputObject($this);       
    }
}

So how does all the above work? Let's run down the notable bits of code. First of all, if you go back and look at the Flexy template we created, we had a variable called pageTitle. It is no mistake that on our MVCnPHP view we have a public class member called pageTitle. Similarly, the Flexy template had a call to a method getDateTime() which can be seen above as a public method on our MVCnPHP view. The magic to all this is in the getView() method:

$this->flexyHandle->compile('Home.thtml');
$this->flexyHandle->outputObject($this);       

The first line above compiles our Flexy template Home.thtml into executable PHP code. It's worth noting that Flexy is smart enough to only compile the template if the template hasn't be compiled yet or if the template itself has changed since the last compile. This works exactly like JSP's in the Java world.

The outputObject() call tell Flexy to now run the compiled template and that it should use our MVCnPHP view ($this) as the class that holds all the data and methods needed to render the page.

Now you may be wondering how the getView() method even gets called. That is done by the MVCnPHP Controller and it knows how to call our view based on it's configuration file.

Note on Namespacing

PHP5 has no notion of namespaces. Thus if you have a class called User and you are trying to integrate your code with third party code that also has a class called User then you will be in trouble because of the name conflict. Your only option is ensure the class names are entirely different. The Geeklog 2 Framework, uses the PEAR approach to solving this by qualifying each class name with a prefix. That prefix is typically the package name you'd like to give the class had you had namespace support. If you agree this is all messy, feel free to follow the history of attempts made at getting namespace support in PHP5 here. In the meantime, if you notice class names with prefixs like SAMPLE_ or GEEKLOG_ or MVCnPHP_ you know why.