Skip to content

Handling placeholders

Rosario Carvello edited this page Jan 17, 2018 · 45 revisions

Introduction

Consider the common situation where you have to manage and show data dynamically on the web pages. You just learned that showing output is the main role of the View. This is still valid also when data to show are dynamical. For this purpose, in this paragraph, we expose a solution for handling dynamic web page by a using static Template, View, and Controller

Handling placeholders by using Template, View, and Controller

Suppose we have the following templates\home.html.tpl , the file just is shown on the previous page, in which we have placed the static placeholder {UserName}. Now we want to assign to it a value, eg. 'Mark' but the assignment must be dynamically provided at run-time.

<!DOCTYPE html>
<html>
  <head>
    <title>Site home page</title>
  </head>
  <body>
    <p>Welcome to the site Home Page</p>
    <br />
    <p>Welcome {UserName}</p>
  </body>
</html>

To do this job we procede by creating the following View class we call views\Home.php, which extends framework\View:

<?php
namespace views;
use framework\View;

/**
 * Class views\Home
 * Handles the treatment of the placeholder designed
 * into templates\home.html.tpl and provides the dynamic page.
 */
class Home extends View
{
    /* Contructor.
     * Override framework\View __construct() to 
     * use templates\home.html.tpl as design
     */
    public function __construct($tplName = null)
    {
        $tplName = "home";
        parent::__construct($tplName);
    }
    
    /* Custom method designed to manage the dynamic content 
     * of the placeholder {UserName}.
     *
     * @param string $name The name value to assign to {UserName}
     */
    public function setUserName($name)
    {
        // setVar is a method inherited from framework\View
        $this->setVar("UserName",$name);
    }
    
}

We are using the method setVar() provided by framework\View to replace a value to placeholder {UserName}.

Note that, unlike the instance of the abstract framework\View we used to show the static content in the previous example, we are now creating a custom class, views\Home.php, that extends framework\View. The reasons we make so are:

  • Unlike a template that cloth with a static behavior, one containing placeholders or even blocks, assumes a dynamic and specialized behavior. Consequently, it is better to manage it by creating a custom View and by using an instance of it to provide the expected dynamic content. A custom View should be appositely written anytime you need the treatment of the dynamism of Placeholders and Blocks coded into a Template. A View of this type should implement all the specific methods, like we have done in the example with the method setUserName($name), for handling all the necessary actions providing dynamism. On the other hand, the framework\View provides only abstract behaviors like showing a static design, for replacing a value to a placeholder, and for repeating n times the content of a block. It does not know anything about a custom logic necessary for providing dynamic page. We need to create a method for this purpose and is better than we code it inside a custom View. So when coding a method in this way we can consume all the (abstract) functionalities provided by its parent framework\View. Is what we have done with setUserName($name). You can see we used setVar() that is provided by the parent framework\View.

  • By implementing a custom View, we are respecting the SOC principle. Note that the custom views\Home view we used is the only entity enabled to manage the specialized behavior we expected to obtain from the placeholders or blocks of the custom templates\home.html.tpl template. On the other hand, if we had chosen to implement that behavior inside controllers\Home by using an instance of framework\View, probably we had coupled altogether different responsibilities and concerns inside the Controller.

Then, we modify the controller controllers\Home.php as follow to enable it to communicate with views\Home.php (pay attention to the comments):

namespace controllers;

use framework\Controller;
use views\Home as HomeView;

class Home extends Controller
{
    /**
     * Home constructor.
     * @override framework\Controller __construct()
     */
    public function __construct()
    {
        /**
         * A reference to the file: templates/home.html.tpl
         * @note Do not to specify the file extension ".html.tpl".
         */
        $tplName = "home";


        /**
         * Set the view with a new object of type framework\View. 
         * @note: We create the HomeView object by using the 
         *        template reference.
         */
        $this->view = new HomeView($tplName);

        /**
         *  To starting up the standard WebMVC behavior of acting
         *  cooperation between Controller and the View just
         *  invoke the parent constructor by passing the current view  
         */
        parent::__construct($this->view);
        
        /**
         * By default, the controller behavior will be 
         * that to greet a Guest user
         */
        $this->view->setUserName("Guest");

    }

    /**
     * Specifies the user for greeting
     * It wraps a call to $view->setUserName($name) 
     *
     * @param string $user User name value to be greet
     */    
    public function userToGreet($user) {
        $this->view->setUserName($user);
        $this->render();
    }
    
}

The following figure shows the WebMVC directory tree with files location:

WebMVC Files

Note we used 'Home' name for naming Controller, View, and 'home' for Template. We talked about this on the naming convention page page.

Finally, run the controller by typing the following address into your web browser:

http://localhost/home/user_to_greet/Mark

You should see the page:

Home web page

You can also run the controller without calling its userToGreet() method. Type:

http://localhost/home/

Now, you should see:

Home web page

Insight: General considerations

Although this example is very simple, there are still many feasible considerations to do:

What setVar() exactly does ?

The method setVar($placeholder, $value) provided by framework\View find a given placeholder in the active template and replace it with a given value. Bear in mind that:

  • If many occurrences of placeholders (like {UsenName}) are designed in a template, then they will be all replaced in one single setVar() call.
  • You must call a setVar() method after the view has been initialized in the controller.
  • You must not call twice the setVar() method by giving it, each time, the same placeholder.This because after the first time the placeholder will be replaced with a value, then, at the second call of setVar(), no placeholder will be found and an exception will be thrown.
  • It provides some useful actions. Follow the method reference extracted from framework\View source code:
    /**
     * Replaces all occurrences of the given placeholder with a given value.
     * If the placeholder is contained into a (previously opened) block
     * the replacement is made against the opened block.
     *
     * You can also specify if the given placeholder is enclosed in braces,
     * if you need to purify the given value against XSS and CHARSET for the given value
     *
     * @param string $placeholder  The placeholder to find
     * @param string $value        The value for replacing to founded placeholder
     * @param bool|true $useBraces If true (default) the placeholder name contain braces {}
     * @param bool $xssPurify      If true (default=false) purify the value against XSS
     * @param string $charset      Charset string for the give value. Default (UTF8) is the CHARSET 
     *                             constant value defined into config\application.config.php
     * 
     * @throws VariableNotFoundException.  If variable/placeholder was not found
     * @throws NotInitializedViewException If template was not loaded
     */
    public function setVar($placeholder, $value, $useBraces=true, $xssPurify=false, $charset = CHARSET)

What about the use of render()?

Although you can invoke the render() method from the Controller, in action this is a service implemented by the View for showing the GUI to the screen.
When you are writing a public method of a Controller, you need to manually invoke method render() anytime you want to output the GUI to the screen. Differently, you will not need to invoke it when you are writing a Controller constructor. The reason is that WebMVC, by default, when you are invoking a Controller without calling any of its methods, automatically executes render() for you. See the previous controller\Home source and you will find that we invoke render() inside userToGreet() but never in __construct();

Whats next

In the next page, we will introduce the dynamic Blocks handling for generating dynamic pages containing repeated sections

Clone this wiki locally