« Zurück zu 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 Anhänge
124606 Angesehen
Durchschnitt (9 Stimmen)
Die durchschnittliche Bewertung ist 4.11111111111111 von max. 5 Sternen.
Kommentare
Antworten im Thread Autor Datum
I managed to do this. Create a class with a... Alex Brdar 27. November 2008 07:59
Since this is read at the end of setting the... Tor Iver Wilhelmsen 14. Mai 2009 05:50
I am facing one problem. I created the class... Arunjyoti Banik 16. März 2015 21:25
If I am not mistaken the... Edgar Vonk 28. September 2009 06:02
I am also facing the same problem..... Nitesh Kr Sahay 3. Juli 2013 08:07
This does not seem to work for a CMS template. ... Thomas Kellerer 27. November 2009 02:44
This is a great explanation. Thank you! jeff Leitman 18. März 2010 10:58
"1. You'll want to extend the ServicePreAction... Eric Dobbs 14. Juni 2010 13:07
You can put it under liferay-portal-ext in... Leon Fleysher 26. August 2010 00:17
Hi, Leon. I create my EXTServicePerAction... Blair Long 29. März 2011 01:12
Sorry for my bad english, If anybody know more... Blair Long 29. März 2011 01:49
See this example: Look at this example: public... Diego Andres Garcia 30. März 2011 12:07
Thank you, Diego! I create a new EXT... Blair Long 30. März 2011 22:29
And, If I re-name my custom class in existing... Blair Long 30. März 2011 22:49
I realize this page has been here for a long... Dana Oredson 13. März 2012 08:35
if you use 6.1 see... 凌 李 6. Mai 2013 01:49
My question is we do we need to iterate the... Adnan Yaqoob 30. Juli 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!
Gepostet am 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.
Gepostet am 14.05.09 05:50 als Antwort auf 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.
Gepostet am 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?
Gepostet am 27.11.09 02:44.
This is a great explanation. Thank you!
Gepostet am 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???
Gepostet am 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.
Gepostet am 26.08.10 00:17 als Antwort auf 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?
Gepostet am 29.03.11 01:12 als Antwort auf Leon Fleysher.
Sorry for my bad english, If anybody know more material about custom velocity variables, A thousand thanks !
Gepostet am 29.03.11 01:49 als Antwort auf 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
Gepostet am 30.03.11 12:07 als Antwort auf 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.
Gepostet am 30.03.11 22:29 als Antwort auf 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?
Gepostet am 30.03.11 22:49 als Antwort auf 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.
Gepostet am 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
Gepostet am 06.05.13 01:49.
I am also facing the same problem.....
Gepostet am 03.07.13 08:07 als Antwort auf 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??
Gepostet am 16.03.15 21:25 als Antwort auf 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
Gepostet am 30.07.15 08:52.