In this section, we’ll go over the concept of variables and what you can do with them using our built in expression language.
As a side note, we’ve taken Symfony’s Expression Language and modified it to behave more like Java Expression Language.
Two major differences from Symfony’s original implementation are:
- If you reference a value that does not exist, instead of an error, you will get
null
. - We added several convenience shortucts for methods. Instead of having to write
$request->getPlatformId()
orrequest.getPlatformId()
, you can writerequest.platformId
.- When you access a property on an object, we check it in the following order:
property
,getProperty()
,isProperty()
,hasProperty()
.
- When you access a property on an object, we check it in the following order:
To start off, let’s go over the use cases for variables and expressions. With these, you can alter the response that is given to the user, you could alter the flow of your service based on some condition, set properties on the fly, etc.
To evaluate something, use the JUEL syntax: my_var
evaluated will be ${my_var}
. For example, in a Text Response Element you could place “Welcome to ${service_name}
!”, which would then be parsed into a greeting for the user.
Setting values
Note
One thing to be mindful of is types of data you set. If you do my_var = 1
, that 1 is not going to be a number, but rather a string. If you want to set data as a specific type, use my_var = ${1}
.
Service variables
If you recall a previous chapter, we’ve described the Variables tab in the editor. This is where you can set variables that will be available throughout the whole service. In here you’d want to set constants and configuration variables. Generally, things that will be set once and never change. Examples might include paths to a filesystem, maximum retry counts, some API keys, etc.
Runtime variables
As the name suggests, these variables are set and are available during the service’s runtime. The most basic way to set them, and the one you’ll be using most often, is with the Set Params element.
Some elements will provide what we refer to as “status variables”. During their runtime, these elements will gather data and make it available under a name that you will be able to specify. As an example, loop elements will make information about the current loop iteration available, such as the current index, the value being iterated over, flags to indicate whether the element is first or last, etc.
You don’t have to memorize all of these status variable fields, as each element that provides one will have its specific data listed in its help file.
Setting and getting complex values
Using the expression language you can access array fields with the square brackets notation, e.g. ${some_array['field']['subfield']}
. This will be important as some elements will result in complex nested data structures.
In addition to accessing data, you can also set nested data yourself. You can either set entire JSON objects yourself, like obj = ${{"prop": "value", "nested": { "a": 1 }}}
, or incrementally with the square brackets notation, such as some_arr["prop"]["nested"] = 1
.
To retrieve a complex value, use either period accessors OR square brackets. Mixing these will not work.
Either ${some.nested.property}
OR ${some["nested"]["property"]}
.
When accessing array fields with a numeric index, you have to use the square brackets notation. ${array[0]["prop"]}
will work, ${array.0.prop}
will not, and neither will ${array[0].prop}
.
System variables
There are some variables that are added into the overall context by the currently running component.
Service level variables
state
(string
) – Currently running block ID.previous_state
(string
) – The previously ran block ID.returning
(boolean
) – Whether or not the same block got ran twice in a row via the specialRead Block Again
element.first_call
(boolean
) – Whether or not this is the very first request in the session.request
(object
) – Has several different propertiesintentName
(string
) – The currently parsed intent name, if anyplatformData
(object
) – Platform data specific to the current platform the session is running on. More on that later.launchRequest
(boolean
) – Whether or not the incoming request is a launch request. Basically identical tofirst_call
.platformId
(string
) – The name of the platform the session is running on.- This list is not exhaustive. Check
\Convo\Core\Workflow\IIntentAwareRequest
for the rest of the available fields.
Block level variables
Some variables are specific to the currently running block. Currently we have:
failure_count
(number
) – The amount of times the user’s response could not be parsed properly. Starts at 0, and will reset to 0 the moment a request can be processed.result
(object
) – Present only during a process phase. Contains filled slot values which you can access withresult.yourSlotNameHere
.
Scopes
Data can be stored under different “persistence levels” or “durations”. There are currently 4 main ones:
Installation
– The “longest” lasting one. Data stored underInstallation
is stored for as long as the conversational skill remains installed on the user’s device. Should the user delete and/or reinstall the skill, this data is lost.User
– Second “longest” lasting scope. This data is stored until the user’s account is changed on their device.Session
– This scope lasts for as long as a session is active. After it ends, this data is reset.Request
– The shortest lasting scope, this scope lasts only for the duration of the current user <-> bot dialog turn. This is usually used by loop elements to provide the data of the current iteration.
Shadowing
If you’re not familiar with the term “shadowing” or “variable name shadowing”, it represents re-declaration of variables with the same name. In Convoworks, you may shadow a variable in various scopes, which are checked in order from most important to least important during expression extrapolation.
Let’s say you have a service level variable called my_name
, and it is set to Greg
. Later on, you set a variable on the Session
scope somewhere, with the same name of my_name
, but you set it to Bob
. Then you place a Text Response element and set its text property to “Hi, my name is ${my_name}
!” This will resolve to “Hi, my name is Bob!” because the Session
scope is more specific (important) than the service level scope.
In order from least important to most important, the scopes are: service variables, installation scope, session scope, request scope.
Additionally, variables can be set on Service
or on Component
level. Component
level will hide its parent Component
or Service
variables.