« Voltar para Templating Languages

Custom Velocity Variables

Introduction #

If you ever wanted to create more custom Velocity Variables that would be available for your theme to reference it's as easy as setting an attribute in ServicePreAction.java!

Background #

If you look at the template code inside a typical Liferay theme, you will see many velocity variables being referenced. For example inside of the Classic theme's dock.vm, there is a line of code:

 <h2 class="user-greeting">
  <span>$user_greeting</span>
 <h2>

$user_greeting fetches the "Welcome Joe Bloggs" sign you'll see when you log in as test@liferay.com Where did $user_greeting come from? Look inside init.vm, and you'll that it's set here:

 #set ($user_greeting = $user.getGreeting())

It gets the User object ($user) and retrieves the 'greeting' (.getGreeting()) from the database. Where is the User object set as a velocity variable? The magic happens inside of VelocityVariables.java:

 vc.put("user", themeDisplay.getUser());

'vc' is an instance of VelocityContext, and all we are doing here is getting the user object (themeDisplay.getUser()) and assigning it the key of "user". This translates to the ability to using $user as the User object.

Custom Velocity Variables #

  1. First see what variables are already available.
    1. Some commonly used ones that are already available include $user, $company, $layout, and $themeDisplay. You probably don't want to create a new one for getting a user's screen name, because you can just do $user.getScreenName().
  2. ServicePreAction.java
    1. You'll want to extend the ServicePreAction class first and reference it in portal-ext.properties:
 servlet.service.events.pre=com.liferay.portal.events.ServicePreAction,your.custom.EXTServicePreAction

Inside your extended ServicePreAction class, create a Map object with the key and value of the vm variables you want to insert, and then set that into the attribute under the key WebKeys.VM_VARIABLES.

Finally, the WebKeys.VM_VARIABLES gets picked up in VelocityVariables.java:

 // Insert custom vm variables
 Map vmVariables = (Map)req.getAttribute(WebKeys.VM_VARIABLES);
 if (vmVariables != null) {
   Iterator itr = vmVariables.entrySet().iterator();
   while (itr.hasNext()) {
    Map.Entry entry = (Map.Entry)itr.next();
    String key = (String)entry.getKey();
    Object value = entry.getValue();
    if (Validator.isNotNull(key)) {
      vc.put(key, value);
    }
   }
 }
0 Anexos
124626 Visualizações
Média (9 Votos)
A média da avaliação é 4.11111111111111 estrelas de 5.
Comentários
Respostas do tópico Autor Data
I managed to do this. Create a class with a... Alex Brdar 27 de Novembro de 2008 07:59
Since this is read at the end of setting the... Tor Iver Wilhelmsen 14 de Maio de 2009 05:50
I am facing one problem. I created the class... Arunjyoti Banik 16 de Março de 2015 21:25
If I am not mistaken the... Edgar Vonk 28 de Setembro de 2009 06:02
I am also facing the same problem..... Nitesh Kr Sahay 3 de Julho de 2013 08:07
This does not seem to work for a CMS template. ... Thomas Kellerer 27 de Novembro de 2009 02:44
This is a great explanation. Thank you! jeff Leitman 18 de Março de 2010 10:58
"1. You'll want to extend the ServicePreAction... Eric Dobbs 14 de Junho de 2010 13:07
You can put it under liferay-portal-ext in... Leon Fleysher 26 de Agosto de 2010 00:17
Hi, Leon. I create my EXTServicePerAction... Blair Long 29 de Março de 2011 01:12
Sorry for my bad english, If anybody know more... Blair Long 29 de Março de 2011 01:49
See this example: Look at this example: public... Diego Andres Garcia 30 de Março de 2011 12:07
Thank you, Diego! I create a new EXT... Blair Long 30 de Março de 2011 22:29
And, If I re-name my custom class in existing... Blair Long 30 de Março de 2011 22:49
I realize this page has been here for a long... Dana Oredson 13 de Março de 2012 08:35
if you use 6.1 see... 凌 李 6 de Maio de 2013 01:49
My question is we do we need to iterate the... Adnan Yaqoob 30 de Julho de 2015 08:52

I managed to do this. Create a class with a no-arg constructor that extends com.liferay.portal.kernel.events.Action:
<pre>
public class EXTServicePreAction extends Action {
public void run(HttpServletRequest req, HttpServletResponse res)
throws ActionException {
Map<String, Object> vmVariables = new HashMap<String, Object>();
// Setup some variables
vmVariables.put("extendedVariable", "test");
req.setAttribute(WebKeys.VM_VARIABLES, vmVariables);
}
}
</pre>

Now you can define this in portal-ext.properties, you still need ServicePreAction included first:
<pre>
servlet.service.events.pre=com.liferay.portal.events.ServicePreAction­,your.custom.EXTServicePreAction
<pre>

And that's it, the Velocity theme templates can now see the variables!
Postado em 27/11/08 07:59.
Since this is read at the end of setting the variables you can also use this to override the preexisting variables. E.g. we have some custom page types where we want to have "Add Application" available, and added an action listener like this which set "show_add_content" based on permissions instead of permissions plus "portlet" and whatever else it uses hardcoded.
Postado em 14/05/09 05:50 em resposta a Alex Brdar.
If I am not mistaken the servlet.service.events.pre is triggered for _every_ HTTP request in Liferay? Is this true? When I load a page (with just one portlet on it) I see that my custom action is invoked around 10 times..

Since I invoke quite heavy business logic in my action (calling a remote EJemoticon I am looking for another solution. Is there another event I can couple my custom action to?

One solution I can think of could be: create a custom post login action, do the business logic there, set the result in the session, and then from my servlet.service.events.pre action retrieve this result from the session and place it in the Velocity variables in the request.
Postado em 28/09/09 06:02.
This does not seem to work for a CMS template.
I can see the variable in the request attributes and I can retrieve something, but calling a method on it doesn't work:

#set ($vars = $request.get('attributes').get('VM_VARIABLES'))
#set ($myHelper = $vars.get('myHelper'))

If I show $vars.toString() it display a "toString" of the map, including the key "myHelper", but when trying to call a method on $myHelper it does not work.

What am I missing?
Postado em 27/11/09 02:44.
This is a great explanation. Thank you!
Postado em 18/03/10 10:58.
"1. You'll want to extend the ServicePreAction class first and reference it in portal-ext.properties"

Where do I create the package for this class???
Postado em 14/06/10 13:07.
You can put it under liferay-portal-ext in whatever package you want -- just write the same package name in portal-ext.properties when referencing your ServicePreAction. I'd also recommend to change the name of your extended class.
Postado em 26/08/10 00:17 em resposta a Eric Dobbs.
Hi, Leon.
I create my EXTServicePerAction extends ServicePreAction and override "run" method. Is it right?
My code below:
public class CustomVelocityVariableAction extends ServicePreAction{
public void run(HttpServletRequest request, HttpServletResponse response)
throws ActionException {
super.run(request, response);
Map vmVariables = (Map)request.getAttribute(WebKeys.VM_VARIABLES);
if (vmVariables != null) {
vmVariables.put("my_vm_var", "my_vm_var");
}

}
}


Which portal-ext.properties file I need to change?
"webapps\ROOT\WEB-INF\classes" or EXT plugins project?
Postado em 29/03/11 01:12 em resposta a Leon Fleysher.
Sorry for my bad english, If anybody know more material about custom velocity variables, A thousand thanks !
Postado em 29/03/11 01:49 em resposta a Blair Long.
See this example:
Look at this example:
public void run(HttpServletRequest request, HttpServletResponse response)throws ActionException {
Map<String, Object> variablesVM= new HashMap<String, Object>();
variablesVM.put("test", "test");
request.setAttribute(WebKeys.VM_VARIABLES, variablesVM);
}

Change the properties in EXT project and deploy it.

In the .VM you can use the var:
$test

...good luck
Postado em 30/03/11 12:07 em resposta a Blair Long.
Thank you, Diego!
I create a new EXT project and follow your example. It's ok.
But I can't apply it in existing EXT project, Because portal-ext.properties file doesn't copy to %Tomcat%webapps\ROOT\WEB-INF\classes this folder.
I see that just deploy project first will copy this file.
Postado em 30/03/11 22:29 em resposta a Diego Andres Garcia.
And, If I re-name my custom class in existing EXT project, then change portal-ext.properties suitably, Copy this file to tomcat manually. When re-start tomcat, It occured "ClassNotFoundException". This mean my custom class didn't deploy successfully.
Does this issue cause some difference between Community Edition and Enterprise Edition?
Postado em 30/03/11 22:49 em resposta a Blair Long.
I realize this page has been here for a long time, but if your theme depends on these velocity variables, isn't it better to use the theme's init_custom.vm?

Then you can pick up your theme and deploy it on a separate site that doesn't have the service pre action defined and your theme should still work.
Postado em 13/03/12 08:35.
if you use 6.1 see this:http://www.opensourceforlife.com/2012/06/custom-velocity-variable-in-lifera­y-61.html
Postado em 06/05/13 01:49.
I am also facing the same problem.....
Postado em 03/07/13 08:07 em resposta a Edgar Vonk.
I am facing one problem. I created the class inside a hook project and referenced it as said in portal-ext.properties. When I am restarting the server, console messages are throwing ClassNotFoundException (Unable to load ServicePreActionExtended with the portal class loader or the current context class loader).

But when I am placing the same code in portal.properties of the hook it is throwing ClassNotFoundException for the original ServicePreAction class.
Cant figure out where I am wrong .............. Can you give a suggestion??
Postado em 16/03/15 21:25 em resposta a Alex Brdar.
My question is we do we need to iterate the vmVariables unless we need to locate some existing variable.
Why can't we simple put a new entry after getting the map from request
Postado em 30/07/15 08:52.