We use expression language to work with variables, arrays, functions, objects, and operators in the Convoworks Editor.
For that purpose, we made adjustments to the Symphony Expression Language component to behave more like the Java Expression Language.
Differences from the base Symphony implementation:
- you can reference a nonexisting value (resolves to null)
- you can reference object methods in short way: e.g. $request->getPlatformId() can be written as request.platformId, $request->isLaunchRequest() can be written as request.launchRequest
To evaluate an expression, we use the JUEL syntax. For example, you have a variable called service_name, and to output the value in the Text response element, you have to use this syntax: ${service_name}.
Or, you want to evaluate this comparison in the IF element: result.value > 5
Setting variables
You can use variables to mix static text with dynamic values when outputting display or speech, to test and adjust workflow (IF) or to dynamically set component properties.
The variable values are by default strings. So, when you’re setting them, if you want to define the value type as anything other than a string, you have to evaluate it.
Look at the following examples:
- my_var = 1 – this will be interpreted as a string
- my_var = ${1} – this will be treated as an integer.
There are two things to consider whenever you’re creating a variable: whether it’ll be a runtime or service variable.
Service variables
Service variables are created on the Variables page and can be used in the Editor just like other variable types. The differences are that they are available everywhere in the service – which means all service components can access them – and they cannot be updated during runtime, however, they can be shadowed.
You can use them for setting service constants/config like the service name, URLs to data sources, base paths, numeric constants like max number of players, etc.
Runtime variables
Runtime variables are set during the service execution. To set a runtime variable place the Set parameter element in one of the service blocks and enter the name-value in the element’s Properties field.
Some elements will also inject their own runtime variables. For example, a LOOP element will inject a counter, an HTTP client element will inject response information, etc. In most of those cases, you can specify the injected variable’s name.
When setting the variable, some elements let you choose its scope.
Setting variable scope
Scopes define for how long a particular variable is available. There are three scope types:
- Installation – available until the user removes and installs the app again. These values are available through multiple sessions.
- Session – available only during a single session. The next time the service is started it has to be reinitialized.
- Request – available only during a single request. It’s mainly used by components, e.g Loop element for its current item info.
When you define two or more variables with the same name but different scopes, variable shadowing will occur. In other words, one variable will shadow (hide) the other/s. Each variable type has a defined priority, and the lower priority variable/s will always be hidden by the higher priority one.
Starting from the lowest to highest priority:
- Service variables
- Installation scope
- Session scope
- Request scope
There’s a third type of variables which are built-in, and available on either the block or service level.
System variables
System variables are the third types of variables available in ConvoWorks. They are built-in and are injected into the evaluation context by running components (service, block). But you can access them just like any other variable.
PHP Predefined Variables
You can access built in PHP predefined variables. This is how you would get value from the post variable ${_POST[‘my_var’]}.
This way you can access: _SERVER, _REQUEST, _POST, _GET, _COOKIE, _SESSION, _FILES and _ENV
Service-level
- state – string, block_id of the currently executing block
- previous_state – string, previously executed block’s block_id
- returning – boolean, true if the same block is executed multiple times in a roll – e.g. we called GOTO to the same state that it is now (within the process part of the block)
- first_call – boolean, set to true only on the first request in the ongoing session
- request – the current request object. Few interesting properties to mention: request.intentName, request.platformData, request.launchRequest, request.platformId. There’s also the request.isCrossSessionCapable which enables you to check if the service could save values from previous sessions. This is useful in the case of Google Assistant services because you don’t have the ability to store variables for the duration of the service installation if the user’s voice isn’t matched to the device. For more and, concrete implementations check the \Convo\Core\Workflow\IIntentAwareRequest
Block-level
- failure_count – available only in the process phase and block fallback flow. Indicates how many times the fallback flow was triggered (no processor matched). Starts at 0.
- result – available only in the process phase. You use it to access the current filter result stored in filter slots. To access slot values use result.slotName or result[‘slotName’] syntax.
Setting arrays and multidimensional arrays
Some of our components return complex data structures like arrays and multidimensional arrays that you can then use in your workflow. Expression language allows us to access those values. E.g. to access sub-array: ${someArray[‘field’][‘subfield’]}.
But you can also define arrays yourself either as service variables or using the Set parameter element. In both cases, you define key-value pairs.
Below, you can see two different notations using square and curly brackets which you can use to create associative arrays:
As you can see, using curly brackets, you can add multiple values at once while using square bracket notation, only one at a time.
Indexed arrays example:
Notice that we don’t use curly brackets notation when creating indexed arrays.
Here’s an example of creating and assigning values to a multidimensional array:
You can also use existing variables for setting index number or setting array values:
Important note: Do not mix JUEL notation with the square brackets notation. For example, if you have an array of user objects, do not do use this syntax:
- ${users[1].name}
Instead, write out the expression using only square brackets, like this:
- ${users[1][“name”]}
Working with functions
You can also use different functions to manipulate data in the expressions. You can view the list of all PHP and custom functions available to you here: Functions
Here’s a simple example with PHP’s is_numeric function and the IF element:
We’re using the NOT operator and is_numeric function to evaluate whether the slot result isn’t a number.
Here’s another example, this time with two custom functions, ordinal and human_concat in the Text response element:
The Status variable of the Trivia Scores element provides player names, their rank, and scores. We’re using it here to output the rank and names of the players with the same score. The ordinal function converts the cardinal rank number into an ordinal number, while the human_concat function converts an array of names into a sentence with the ‘and’ conjunction at the end.