We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Changing Volt expression tags

I recently discovered Phalcon and was blown away by how well designed the framework is - so much that I'm throwing away my well treasured self-built framework and ORM library and started to port a pretty large application to Phalcon. While doing so, I'm consulting the docs a lot and they're too nothing short of amazing. Still, not everything can be put there, so here I am with my first question :)

My application is going to use AngularJS quite heavily and it has the same markup as Volt for expressions - {{ expression }}

I know that I could change this in Angular, however I would prefer to do this in Volt instead, since I'll be using quite a few 3rd party Angular libraries and {{ }} is the standard. Of course, I could intercept the Volt compilation and force my own tags this way using a bunch of regexes, but perhaps there's a cleaner way to do this via configuration?

At the moment there is no way to change the markers of Volt in the volt layer.

You can however change it in AngularJS as you said. In one of my projects I did this:

var ngModule = angular.module('HHF', ['ngResource', 'ui'])
    .config(function($interpolateProvider) {
        $interpolateProvider.startSymbol('[[');
        $interpolateProvider.endSymbol(']]');
    })
):

so for angular I would use [[ data.results ]] and in volt I would use {{ expression }}

Sample here: https://github.com/niden/phalcon-angular-harryhogfootball/blob/master/public/js/utils.js

Thank you for the answer. I'm really not sure if this would work well with 3rd party Angular libraries like AngularUI Bootstrap.

I guess I'll explore my options to implement this via template compilation functions then.

I do this way In volt Class


$this->getCompiler()->addFunction('ng', function($input) {
  return '"{{".' . $input . '."}}"';
});

and in your volt templates

{{ng('Model.prop')}} 

will compile

{{Model.prop}}


18.4k
Accepted
answer

My approach to change the Volt expression format to [[ expression ]] - seems to work just fine

class LiveVolt extends \Phalcon\Mvc\View\Engine\Volt
{
    public function getCompiler()
    {
        if (empty($this->_compiler))
        {
            $this->_compiler = new LiveVoltCompiler($this->getView());
            $this->_compiler->setOptions($this->getOptions());
            $this->_compiler->setDI($this->getDI());
        }

        return $this->_compiler;
    }
}

class LiveVoltCompiler extends \Phalcon\Mvc\View\Engine\Volt\Compiler
{
    protected function _compileSource($source, $something = null)
    {
        $source = str_replace('{{', '<' . '?php $ng = <<<NG' . "\n" . '\x7B\x7B', $source);
        $source = str_replace('}}', '\x7D\x7D' . "\n" . 'NG;' . "\n" . ' echo $ng; ?' . '>', $source);

        $source = str_replace('[[', '{{', $source);
        $source = str_replace(']]', '}}', $source);

        return parent::_compileSource($source, $something);
    }
}


2.9k
edited Aug '14

Can you share to us where will we place your code @rinalds, thanks.



90

THANK YOU VERY MUCH!

My approach to change the Volt expression format to [[ expression ]] - seems to work just fine

class LiveVolt extends \Phalcon\Mvc\View\Engine\Volt
{
  public function getCompiler()
  {
      if (empty($this->_compiler))
      {
          $this->_compiler = new LiveVoltCompiler($this->getView());
          $this->_compiler->setOptions($this->getOptions());
          $this->_compiler->setDI($this->getDI());
      }

      return $this->_compiler;
  }
}

class LiveVoltCompiler extends \Phalcon\Mvc\View\Engine\Volt\Compiler
{
  protected function _compileSource($source, $something = null)
  {
      $source = str_replace('{{', '<' . '?php $ng = <<<NG' . "\n" . '\x7B\x7B', $source);
      $source = str_replace('}}', '\x7D\x7D' . "\n" . 'NG;' . "\n" . ' echo $ng; ?' . '>', $source);

      $source = str_replace('[[', '{{', $source);
      $source = str_replace(']]', '}}', $source);

      return parent::_compileSource($source, $something);
  }
}


90

Hi,

you need to change Legacy Volt engine to LiveVolt.

You could find in scafolded services.php:

/**

  • Setting up the view component */ $di->set('view', function () use ($config) {

    $view = new View();

    $view->setViewsDir($config->application->viewsDir);

    $view->registerEngines(array( '.volt' => function ($view, $di) use ($config) {

        $volt = new LiveVolt($view, $di);
    
        $volt->setOptions(array(
            'compiledPath' => $config->application->cacheDir,
            'compiledSeparator' => '_',
            'compileAlways' => true // TODO remove!! just in dev
        ));
    
        return $volt;
    },
    '.phtml' => 'Phalcon\Mvc\View\Engine\Php'

    ));

    return $view; }, true);

Can you share to us where will we place your code @rinalds, thanks.



171

@zo0m @CodeB100d

Let me describe how do I place the code.

Namespace:

My project name is PhalconNamecards, so the namecaspes start with PhalconNamecards.

This project has a module called "frontend", it is actually the only module for this small project, so the namecaspes usually, in fact, start with PhalconNamecards\Frontend.

folder structure

The folder structure of this small project is like below:


PhalconNamecards/
├── apps
│   └── frontend
│       ├── cache
│       ├── config
│       ├── controllers
│       ├── forms
│       ├── models
│       └── views
├── config
├── doc
├── logs
├── public
│   ├── css
│   ├── files
│   ├── img
│   ├── js
├── schemas
└── vendor
    ├── composer
    ├── phpoffice
    ├── react
    └── swiftmailer

Steps:

Step 1, Register a autoloader path/namespace

First we need to register a path for the custom libraries to autoload for later use in this project.

For example the file content in my case is as below:

File path: apps/frontend/config/loader.php

<?php
$loader = new \Phalcon\Loader();

//We're a registering a set of directories taken from the configuration file 
$loader->registerNamespaces(array(
    'PhalconNamecards\Frontend\Models' => $config->application->modelsDir,
    'PhalconNamecards\Frontend\Controllers' => $config->application->controllersDir,
    'PhalconNamecards\Frontend\Forms' => $config->application->formsDir,
    'PhalconNamecards\Frontend' => $config->application->libraryDir                    
    //Note this path is where we put our own libraries / classes.
    //and it's defined in the config.php with value of :   'libraryDir' => __DIR__ . '/../library/',
    //and the config.php is located as apps/frontend/config/config.php
));

$loader->register();

// Use composer autoloader to load vendor classes
require_once __DIR__ . '/../../../vendor/autoload.php';

So here the path "apps/library/" is registered as a location for the autoloader to search for. Any class found in that folder will need to have "PhalconNamecards\Frontend" as a prefix to be the very first part of its namespace.

Step 2, Create new folders and a new file

Create folders in the order of: apps/frontend/library, apps/frontend/library/View, apps/frontend/library/View/Engine, and then in the "Engine" folder.

Please note that the folder and file names are case-sensitive.

Now the folder structure is like below:

apps
└── frontend
    ├── cache
    │   ├── acl
    │   ├── metaData
    │   ├── swift
    │   └── volt
    ├── config
    ├── controllers
    ├── forms
    ├── library
    │   ├── Mail
    │   └── View
    │       └── Engine
    ├── models
    └── views
        ├── about
        ├── ......

Now create a file named "LiveVolt.php" under the newly created folder of "apps/frontend/library/View/Engine", then put the code from @rinalds into it, remember to change the namespace to be "PhalconNamecards\Frontend\View\Engine".

My LiveVolt.php content is below for your reference:

File path: apps/frontend/library/View/Engine/LiveVolt.php


<?php
namespace PhalconNamecards\Frontend\View\Engine;

class LiveVolt extends \Phalcon\Mvc\View\Engine\Volt
{
    public function getCompiler()
    {
        if (empty($this->_compiler))
        {
            $this->_compiler = new LiveVoltCompiler($this->getView());
            $this->_compiler->setOptions($this->getOptions());
            $this->_compiler->setDI($this->getDI());
        }

        return $this->_compiler;
    }
}

class LiveVoltCompiler extends \Phalcon\Mvc\View\Engine\Volt\Compiler
{
    protected function _compileSource($source, $something = null)
    {
        $source = str_replace('{{', '<' . '?php $ng = <<<NG' . "\n" . '\x7B\x7B', $source);
        $source = str_replace('}}', '\x7D\x7D' . "\n" . 'NG;' . "\n" . ' echo $ng; ?' . '>', $source);

        $source = str_replace('[[', '{{', $source);
        $source = str_replace(']]', '}}', $source);

        return parent::_compileSource($source, $something);
    }
}

Now we have this new volt engine ready to use.

Step 3, the final step: Use the new volt engihe.

So we need to change the default volt engine to our customized one.

That is, from Phalcon\Mvc\View\Engine\Volt to PhalconNamecards\Frontend\View\Engine\LiveVolt

The change will be done in the file where the view component, and generally also the $di are defined and set.

In my case it is the file of "service.php". Code sample as below:

File path: app/frontend/config/service.php

/**
 * Setting up the view component
 */
$di ['view'] = function () use ($config) {

    $view = new View();

    $view->setViewsDir($config->application->viewsDir);

    $view->registerEngines(array( 
        ".phtml" => 'Phalcon\Mvc\View\Engine\Php',
        '.volt' => function ($view, $di) use ($config) {

            //~ $volt = new Phalcon\Mvc\View\Engine\Volt($view, $di);
            $volt = new PhalconNamecards\Frontend\View\Engine\LiveVolt($view, $di);

            $volt->setOptions(array(
                'compiledPath' => $config->application->cacheDir . 'volt/',
                'compiledSeparator' => '_'
            ));

            return $volt;
        },
            ));

            return $view;
        };

Up to this step, we are done, now is the time to use [[ and ]] instead of {{ and }} in the volt templates.

Let me know for any questions. I am following this post.



771
edited Jan '15

my 2 cents: if u really really want to do as little changes as possible use this:

{{"{{connectedToChat ? username : 'Stranger'}}"}}

include angular expressions inside a volt output expression ...

take care



2.9k

Thanks @exool, very detailed.

I also tried @NikolaosDimopoulos solution using $interpolateProvider with the angular libraries and angular ui bootstrap and it worked well.

Thumbs up!