It seems like you are using an ad blocker. To enhance your experience and support our website, please consider:

  1. Signing in to disable ads on our site. Our users don't see ads
  2. Or, Sign up if you don't have an account yet
  3. Or, disable your adblocker by doing this:
    • Click on the adblocker icon in your browser's toolbar.
    • Select "Pause on this site" or a similar option for lancecourse.com.

PHP Frameworking - Templating (Part 4)

By Matej Sima

Welcome to PHP Frameworking tutorial part 4, after a while we're back to our series of PHP enlightment. Today we'll learn about templating our application views. This tutorial is part of series which can be found here, to understand what's going on you'll most likely need to read previous parts as well.

What is templating?

Templating enables us to manipulate our views in a more sophisticated and eye-charming manner. Example below will demonstrate a regular PHP way to display a variable, and code below it will replace the traditional way with the way of templating engine (which we will apply).

myView.php:

Hello, my name is <?=$name?>

myView.php (with templating applied):

Hello, my name is {{name}}

In previous parts of the series we've build a View and ViewLoader classes, which enabled us to load our views in objected-way.

<?php

//example usage of our view class $view = new lancecourse\core\view\View( lancecourse\core\view\ViewLoader('/views/') );

$view->display('myView.php');

?>

Let's implement templating

First of all, let's get rid of .php extension on our ->display() calls. To do that we need to edit our ViewLoader, especially the load method.

core/view/ViewLoader.php(#load):

public function load($viewName){

    $path = $this->path.$viewName.'.php';

    if( file_exists($path) ){

        return file_get_contents($path);

    }
    throw new Exception("View does not exist: ".$viewName);
}

After applying changes above, we do not have to include .php after our view name anymore, when loading it via ->display method of our View class.

<?php

$view->display('myView.php'); //chages to: $view->display('myView');

?>

Now let's implement templating functionality which will get rid of <?=$var?> in our templates.

We will be creating lancecourse\core\view\Templating class, which will have two methods (for now), one to parse our view, and the other one to help with this complex task, parse() method will be used for external access to the class, rest of the methods implemented could be marked as private.

First method ->replaceVariables($view, $variables), will replace all occurences of {{variableName}} by variableName value from array of passed variables when displaying the view.

Before we do anything else, we have to edit our View class to support templating, and variable-to-view passing:

core/view/View.php:

class View{

public function __construct($viewLoader, $engine){

    $this->viewLoader = $viewLoader;

    $this->engine = $engine;

}

public function display($viewName, $variables = []){

    echo $this->engine->parse(

        $this->viewLoader->load($viewName),

        $variables
    );
}
}

As we have our View class ready, we can proceed with creating Templating class.

core/view/Templating.php:

<?php

namespace lancecourse\core\view;

class Templating{

public function replaceVariables(&$view, $variables){

    $view = preg_replace_callback('/(\\{)(\\{)((?:[a-zA-Z]*))(\\})(\\})/',
    function($match) use($variables){
        return $variables[$match[3]];
    }, $view);

}

public function parse($view, $variables){

    $this->replaceVariables($view, $variables);

    return $view;
}
}

?>

We are passing content of our view by refferece to our parsing methods, as it may contain a lot of data, we do not want to copy it each time we pass it to a method.

Now let's inject our Templating class into the View class as prepared earlier.

controllers/BaseController.php:

public function __construct(){

$this->view = new \lancecourse\core\view\View(

    new \lancecourse\core\view\ViewLoader(BASEPATH.'/views/'),

    new \lancecourse\core\view\Templating()
);

}

Time to use our new Templating in a view:

controllers/IndexController.php:

public function index(){ $this->view->display('hello', [ 'name' => 'John' ]); }

views/hello.php:

Hello from {{name}}

That's it, you now have the simpliest form of templating.

Advanced templating - view helpers

View helpers are functions to use inside your views, to process variables or display some advanced stuff you may need.

views/hello.php:

Result is {{sum -> 4,10}}

Example above will display result of 14, if we implement a proper sum helper. Let's add a helper parsing into our Templating class:

core/view/Templating.php:

public function __construct($helpers){ $this->helpers = $helpers; }

public function applyHelpers(&$view){

 $view = preg_replace_callback('/(\{)(\{)((?:[a-zA-Z0-9_,\->\(\)\s]*))(\})(\})/', function($match){ 

 $helperWithParams = explode('->', $match[3]); 

 $helper = trim($helperWithParams[0]); 

 $params = explode(',', trim($helperWithParams[1])); 

 return call_user_func_array($this->helpers[$helper], $params); }, $view); }

//also update the parsing function public function parse($view, $variables){

$this->replaceVariables($view, $variables);
$this->applyHelpers($view);

return $view;
}

Constructor now takes an array of helpers in form of:

<?php

[ 'helperName' = function(){} ]

Let's pass some helpers to our View instance:

controllers/BaseController.php:

public function __construct(){

$helpers = [
    'sum' => function($x, $y){
        return $x+$y;
    }
];

$this->view = new \lancecourse\core\view\View(

    new \lancecourse\core\view\ViewLoader(BASEPATH.'/views/'),

    new \lancecourse\core\view\Templating($helpers)
);

}

That's it, now you may use the sum helper as shown in example view before.

Last updated 2024-01-11 UTC