Learn how to create a twig extension in symfony, create queries and use custom methods in your views.

How to create a twig extension in symfony and create queries with twig

Twig is a template engine for the PHP programming language. Its syntax originates from Jinja and Django templates. It's an open source product licensed under a BSD License and maintained by Fabien Potencier. Symfony2 PHP framework comes with a bundled support for Twig as its default template engine.

Use twig is really easy and comfortable to use, however if you come from a php rendering way (symfony 1 or plain php) you'll find many inconvenients, for example not all the methods that php uses come by default with twig and for those who creates queries in the views (yes, everybody know that is a bad practice, however this could save your life more than once if you're in hurries).

Fortunately, is really easy to create custom methods and include them to our project, let's get started !

To create custom functions and filters, we need to create a folder that will contain our class inside our container bundle, for example :

ourcodeworldBundle > Inside ourcodeworldBundle there are more bundles, so we will create a folder called Extensions in that bundle, then the path of our folder will be :ourcodeworldBundle/Extensions

Now we will create a class that will contain our service (it will receive as parameters in the contructor, doctrine) and we will call the class (and the file) TwigExtensions.php for example, change the name if you want.

<?php
// The namespace according to the bundle and the path
namespace ourcodeworld\Extensions;

use Symfony\Bridge\Doctrine\RegistryInterface;

// The Name of your class
class TwigExtensions extends \Twig_Extension
{
    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('replaceNonAlphaNumerics', array($this, 'replaceNonAlphaNumerics')),
            // add more if you want like this new \Twig_SimpleFilter('replaceNonAlphaNumerics', array($this, 'replaceNonAlphaNumerics')),
        );
    }
    
    public function getFunctions()
    {
        return array(
            new \Twig_SimpleFunction('is_mobile', array($this, 'is_mobile')),
            // add more like this if you want new \Twig_SimpleFunction('is_mobile', array($this, 'is_mobile')),
        );
    }
    
    protected $doctrine;

    public function __construct(RegistryInterface $doctrine)
    {
        // if you want to do queries execute : $this->doctrine->getManager();
        $this->doctrine = $doctrine;
    }
    
    public function replaceNonAlphaNumerics($cadena,$replacer = "-"){
        return preg_replace("/[^A-Za-z0-9 ]/", $replacer, $cadena);
    } 
    
    /**
     * Verificar si el dispositivo es un mobil desde php
     * @return boolean
     */
    public function is_mobile(){
        $useragent = $_SERVER['HTTP_USER_AGENT'];
        if(preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i',$useragent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i',substr($useragent,0,4))){
            return true;
        }
        
        return false;
    }
    
    public function getName()
    {
        return 'TwigExtensions';
    }
}

The class contains 2 functions (1 twig function and 1 twig filter), the filter will replace all non alphanumerics chars in a string and the function will return true or false according to the device (if is mobile or not). Then you need to register the extensions in the settings.yml file (located in /app/config/services.yml), and we are going to register our service like this :

# Learn more about services, parameters and containers at
# http://symfony.com/doc/current/book/service_container.html
parameters:
#    parameter_name: value

services:
#    service_name:
#        class: AppBundle\Directory\ClassName
#        arguments: ["@another_service_name", "plain_value", "%parameter_name%"]

    twig.extension:
# the namespace with the name of our class and we pass the doctrine service
        class: ourcodeworld\Extensions\TwigExtensions
        arguments: 
            doctrine : '@doctrine'
        tags:
          -  { name: twig.extension }

Now we will be able to use our functions and filters in twig in the views (do not forget to clear the cache) :

{%if is_mobile() == true%}
  we have a mobile device here
{%else%}
  it seems a pc
{%endif%}

and the filters

{{"my löäü string"|replaceNonAlphaNumerics}}

Senior Software Engineer at Software Medico. Interested in programming since he was 14 years old, Carlos is a self-taught programmer and founder and author of most of the articles at Our Code World.

Sponsors