LimeExpressionManager

Methods

A private constructor; prevents direct creation of object

__construct() 

Ensures there is only one instances of LEM. Note, if switch between surveys, have to clear this cache

singleton() : \LimeExpressionManager
static

Prevent users to clone the instance

__clone() 

Set the previewmode

SetPreviewMode(boolean|string $previewmode = false) : void
static

Arguments

$previewmode

boolean|string

'question', 'group', false

Tells Expression Manager that something has changed enough that needs to eliminate internal caching

SetDirtyFlag() : void
static

Set the SurveyId - really checks whether the survey you're about to work with is new, and if so, clears the LEM cache

SetSurveyId(integer|null $sid = NULL) 
static

Arguments

$sid

integer|null

Sets the language for Expression Manager. If the language has changed, then EM cache must be invalidated and refreshed

SetEMLanguage(string|null $lang = NULL) : void
static

Arguments

$lang

string|null

Do bulk-update/save of Condition to Relevance

UpgradeConditionsToRelevance(integer|null $surveyId = NULL, integer|null $qid = NULL) : array
static

Arguments

$surveyId

integer|null

  • if NULL, processes the entire database, otherwise just the specified survey

$qid

integer|null

  • if specified, just updates that one question

Response

array

of query strings

This reverses UpgradeConditionsToRelevance(). It removes Relevance for questions that have Condition

RevertUpgradeConditionsToRelevance(integer|null $surveyId = NULL, integer|null $qid = NULL) : int
static

Arguments

$surveyId

integer|null

$qid

integer|null

Response

int

Return array database name as key, LEM name as value

getLEMqcode2sgqa(integer $iSurveyId) : array
static
example

=> '38612X10X145')

Arguments

$iSurveyId

integer

Response

array

If $qid is set, returns the relevance equation generated from conditions (or NULL if there are no conditions for that $qid) If $qid is NULL, returns an array of relevance equations generated from Condition, keyed on the question ID

ConvertConditionsToRelevance(integer|null $surveyId = NULL, integer|null $qid = NULL) : array
static

Arguments

$surveyId

integer|null

$qid

integer|null

  • if passed, only generates relevance equation for that question - otherwise genereates for all questions with conditions

Response

array

of generated relevance strings, indexed by $qid

Return list of relevance equations generated from conditions

UnitTestConvertConditionsToRelevance(integer|null $surveyId = NULL, integer|null $qid = NULL) : array
static

Arguments

$surveyId

integer|null

$qid

integer|null

Response

array

of relevance equations, indexed by $qid

Process all question attributes that apply to EM (1) Sub-question-level relevance: e.g. array_filter, array_filter_exclude, relevance equations entered in SQ-mask (2) Validations: e.g. min/max number of answers; min/max/eq sum of answers

_CreateSubQLevelRelevanceAndValidationEqns(integer|null $onlyThisQseq = NULL) : void

Arguments

$onlyThisQseq

integer|null

  • only process these attributes for the specified question

Recursively find all questions that logically preceded the current array_filter or array_filter_exclude request Note, must support: (a) semicolon-separated list of $qroot codes for either array_filter or array_filter_exclude (b) mixed history of array_filter and array_filter_exclude values

_recursivelyFindAntecdentArrayFilters(string $qroot, array $aflist, array $afelist) : array

Arguments

$qroot

string

  • the question root variable name

$aflist

array

  • the list of array_filter $qroot codes

$afelist

array

  • the list of array_filter_exclude $qroot codes

Response

array

Create the arrays needed by ExpressionManager to process LimeSurvey strings.

setVariableAndTokenMappingsForExpressionManager(integer $surveyid, boolean|null $forceRefresh = false, boolean|null $anonymized = false, boolean $allOnOnePage = false) : boolean

The long part of this function should only be called once per page display (e.g. only if $fieldMap changes)

Arguments

$surveyid

integer

$forceRefresh

boolean|null

$anonymized

boolean|null

$allOnOnePage

boolean

  • if true (like for survey_format), uses certain optimizations

Response

boolean

  • true if $fieldmap had been re-created, so ExpressionManager variables need to be re-set

Return whether a sub-question is relevant

SubQuestionIsRelevant(string $sgqa) : boolean
static

Arguments

$sgqa

string

Response

boolean

Return whether question $qid is relevanct

QuestionIsRelevant(int $qid) : boolean
static

Arguments

$qid

int

Response

boolean

Returns true if the group is relevant and should be shown

GroupIsRelevant(int $gid) : boolean
static

Arguments

$gid

int

Response

boolean

Return whether group $gseq is relevant

GroupIsIrrelevantOrHidden(string $gseq) : boolean
static

Arguments

$gseq

string

Response

boolean

Check the relevance status of all questions on or before the current group.

ProcessAllNeededRelevance(string $onlyThisQseq = NULL) : void

This generates needed JavaScript for dynamic relevance, and sets flags about which questions and groups are relevant

Arguments

$onlyThisQseq

string

Translate all Expressions, Macros, registered variables, etc. in $string

ProcessString(string $string, integer $questionNum = NULL, array|null $replacementFields = array(), boolean $debug = false, integer $numRecursionLevels = 1, integer $whichPrettyPrintIteration = 1, boolean $noReplacements = false, boolean $timeit = true, boolean $staticReplacement = false) : string
static

Arguments

$string

string

  • the string to be replaced

$questionNum

integer

  • the $qid of question being replaced - needed for properly alignment of question-level relevance and tailoring

$replacementFields

array|null

  • optional replacement values

$debug

boolean

  • deprecated

$numRecursionLevels

integer

  • the number of times to recursively subtitute values in this string

$whichPrettyPrintIteration

integer

  • if want to pretty-print the source string, which recursion level should be pretty-printed

$noReplacements

boolean

  • true if we already know that no replacements are needed (e.g. there are no curly braces)

$timeit

boolean

$staticReplacement

boolean

  • return HTML string without the system to update by javascript

Response

string

  • the original $string with all replacements done.

Compute Relevance, processing $eqn to get a boolean value. If there are syntax errors, return false.

ProcessRelevance(string $eqn, string $questionNum = NULL, string $jsResultVar = NULL, string $type = NULL, int $hidden) : boolean
static

Arguments

$eqn

string

  • the relevance equation

$questionNum

string

  • needed to align question-level relevance and tailoring

$jsResultVar

string

  • this variable determines whether irrelevant questions are hidden

$type

string

  • question type

$hidden

int

  • whether question should always be hidden

Response

boolean

Compute Relevance, processing $eqn to get a boolean value. If there are syntax errors, return false.

_ProcessRelevance(string $eqn, string $questionNum = NULL, $gseq = NULL, string $jsResultVar = NULL, string $type = NULL, int $hidden) : boolean

Arguments

$eqn

string

  • the relevance equation

$questionNum

string

  • needed to align question-level relevance and tailoring

$gseq

$jsResultVar

string

  • this variable determines whether irrelevant questions are hidden

$type

string

  • question type

$hidden

int

  • whether question should always be hidden

Response

boolean

Create JavaScript needed to process sub-question-level relevance (e.g. for array_filter and _exclude)

_ProcessSubQRelevance(string $eqn, string $questionNum = NULL, string $rowdivid = NULL, string $type = NULL, string $qtype = NULL, string $sgqa = NULL, string $isExclusive = '', string $irrelevantAndExclusive = '') : boolean

Arguments

$eqn

string

  • the equation to parse

$questionNum

string

  • the question number - needed to align relavance and tailoring blocks

$rowdivid

string

  • the javascript ID that needs to be shown/hidden in order to control array_filter visibility

$type

string

  • the type of sub-question relevance (e.g. 'array_filter', 'array_filter_exclude')

$qtype

string

$sgqa

string

$isExclusive

string

$irrelevantAndExclusive

string

Response

boolean

_ProcessGroupRelevance

_ProcessGroupRelevance(int $groupSeq) : void

Arguments

$groupSeq

int

Used to show potential syntax errors of processing Relevance or Equations.

GetLastPrettyPrintExpression() : string
static

Response

string

Expand "self.suffix" and "that.qcode.suffix" into canonical list of variable names

GetAllVarNamesForQ(integer $qseq, string $varname) : string
static

Arguments

$qseq

integer

$varname

string

Response

string

Should be first function called on each page - sets/clears internally needed variables

StartProcessingPage(boolean $allOnOnePage = false, boolean $initializeVars = false) : void
static

Arguments

$allOnOnePage

boolean

  • true if StartProcessingGroup will be called multiple times on this page - does some optimizatinos

$initializeVars

boolean

  • if true, initializes the replacement variables to enable syntax highlighting on admin pages

Initialize a survey so can use EM to manage navigation

StartSurvey(int $surveyid, string $surveyMode = 'group', array $aSurveyOptions = NULL, bool $forceRefresh = false, int $debugLevel) 
static

Arguments

$surveyid

int

$surveyMode

string

$aSurveyOptions

array

$forceRefresh

bool

$debugLevel

int

NavigateBackwards

NavigateBackwards() : void
static

NavigateForwards

NavigateForwards(boolean $force = false) : array|null
static

Arguments

$force

boolean

  • if true, continue to go forward even if there are violations to the mandatory and/or validity rules

Response

array|null

  • lastMoveResult

Write values to database.

_UpdateValuesInDatabase(array|null $updatedValues, boolean $finished = false) : string

Arguments

$updatedValues

array|null

$finished

boolean

  • true if the survey needs to be finalized

Response

string

Get last move information, optionally clearing the substitution cache

GetLastMoveResult(boolean $clearSubstitutionInfo = false) : array|null
static

Arguments

$clearSubstitutionInfo

boolean

Response

array|null

Jump to a specific question or group sequence. If jumping forward, it re-validates everything in between

JumpTo(int $seq, boolean $preview = false, boolean $processPOST = true, boolean $force = false, boolean $changeLang = false) : array
static

Arguments

$seq

int

$preview

boolean

  • if true, then treat this group/question as relevant, even if it is not, so that it can be displayed

$processPOST

boolean

$force

boolean

  • if true, then skip validation of current group (e.g. will jump even if there are errors)

$changeLang

boolean

Response

array

Check the entire survey

_ValidateSurvey(boolean $force = false) : array

Arguments

$force

boolean

: force validation to true, even if there are error, used at survey start to fill EM

Response

array

with information on validated question

Check a group and all of the questions it contains

_ValidateGroup(integer $groupSeq, boolean $force = false) : \<array>

Arguments

$groupSeq

integer

  • the index-0 sequence number for this group

$force

boolean

: force validation to true, even if there are error

Response

\

  • detailed information about this group

For the current set of questions (whether in survey, gtoup, or question-by-question mode), assesses the following: (a) mandatory - if so, then all relevant sub-questions must be answered (e.g. pay attention to array_filter and array_filter_exclude) (b) always-hidden (c) relevance status - including sub-question-level relevance (d) answered - if $_SESSION[$LEM->sessid][sgqa]=='' or NULL, then it is not answered (e) validity - whether relevant questions pass their validity tests

_ValidateQuestion(integer $questionSeq, boolean $force = false) : \<array>

Arguments

$questionSeq

integer

  • the 0-index sequence number for this question

$force

boolean

: force validation to true, even if there are error, this allow to save in DB even with error

Response

\

of information about this question and its sub-questions

GetQuestionStatus

GetQuestionStatus($qid) 
static

Arguments

$qid

Get array of info needed to display the Group Index

GetGroupIndexInfo(string $gseq = NULL) : array
static

Arguments

$gseq

string

Response

array

Translate GID to 0-index Group Sequence number

GetGroupSeq(int $gid) : int
static

Arguments

$gid

int

Response

int

Get question sequence number from QID

GetQuestionSeq(int $qid) : int
static

Arguments

$qid

int

Response

int

Get array of info needed to display the Question Index

GetQuestionIndexInfo() : array
static

Response

array

Return entries needed to build the navigation index

GetStepIndexInfo(int|null $step = NULL) : array
static

Arguments

$step

int|null

  • if specified, return a single value, otherwise return entire array

Response

array

  • will be either question or group-level, depending upon $surveyMode

This should be called each time a new group is started, whether on same or different pages. Sets/Clears needed internal parameters.

StartProcessingGroup(int|null $gseq = NULL, boolean|null $anonymized = false, int|null $surveyid = NULL, boolean|null $forceRefresh = false) : void
static

Arguments

$gseq

int|null

  • the group sequence

$anonymized

boolean|null

  • whether anonymized

$surveyid

int|null

  • the surveyId

$forceRefresh

boolean|null

  • whether to force refresh of setting variable and token mappings (should be done rarely)

Should be called after each group finishes

FinishProcessingGroup(boolean|null $skipReprocessing = false) : void
static

Arguments

$skipReprocessing

boolean|null

Returns an array of string parts, splitting out expressions

SplitStringOnExpressions(string $src) : string
static

Arguments

$src

string

Response

string

Return a formatted table showing how much time each part of EM consumed

GetDebugTimingMessage() : string
static

Response

string

Should be called at end of each page

FinishProcessingPage() : void
static

GetRelevanceAndTailoringJavaScript

GetRelevanceAndTailoringJavaScript() 
static

setTempVars

setTempVars($vars) 
static

Arguments

$vars

Unit test strings containing expressions

UnitTestProcessStringContainingExpressions() 
static

Unit test Relevance using a simplified syntax to represent questions.

UnitTestRelevance() 
static

Set the 'this' variable as an alias for SGQA within the code.

SetThisAsAliasForSGQA(string $sgqa) : void
static

Arguments

$sgqa

string

ShowStackTrace

ShowStackTrace($msg = NULL, $args = NULL) 
static

Arguments

$msg

$args

gT

gT(string $string, $escapemode = 'html') 

Arguments

$string

string

$escapemode

ngT

ngT(string $sTextToTranslate, integer $number, $escapemode = 'html') 

Arguments

$sTextToTranslate

string

$number

integer

$escapemode

Returns true if the survey is using comma as the radix

usingCommaAsRadix() : boolean
static

Response

boolean

getConditionsForEM

getConditionsForEM($surveyid, $qid = NULL) 
static

Arguments

$surveyid

$qid

Deprecate obsolete question attributes.

UpgradeQuestionAttributes(boolean|null $changeDB = false, int|null $iSurveyID = NULL, int|null $onlythisqid = NULL) 
static

Arguments

$changeDB

boolean|null

  • if true, updates parameters and deletes old ones

$iSurveyID

int|null

  • if set, then only for that survey

$onlythisqid

int|null

  • if set, then only for this question ID

Return array of language-specific answer codes

getQuestionAttributesForEM(int|null $surveyid, int|null $qid, string|null $lang = '') : array

Arguments

$surveyid

int|null

$qid

int|null

$lang

string|null

Response

array

Return array of language-specific answer codes

getAnswerSetsForEM(int|null $surveyid = NULL, int|null $qid = NULL, string|null $lang = NULL) : array

Arguments

$surveyid

int|null

$qid

int|null

$lang

string|null

Response

array

Returns group info needed for indexes

getGroupInfoForEM(int $surveyid, string|null $lang = NULL) : array

Arguments

$surveyid

int

$lang

string|null

Response

array

Cleanse the $_POSTed data and update $_SESSION variables accordingly

ProcessCurrentResponses() 
static

isValidVariable

isValidVariable($varName) 
static

Arguments

$varName

GetVarAttribute

GetVarAttribute($name, string|null $attr, $default, integer $gseq, integer $qseq) 
static

Arguments

$name

$attr

string|null

$default

$gseq

integer

$qseq

integer

_GetVarAttribute

_GetVarAttribute($name, $attr, $default, integer $gseq, integer $qseq) 

Arguments

$name

$attr

$default

$gseq

integer

$qseq

integer

SetVariableValue

SetVariableValue(string $op, string $name, string $value) : int
static

Arguments

$op

string

$name

string

$value

string

Response

int

Create HTML view of the survey, showing everything that uses EM

ShowSurveyLogicFile(int $sid, int|null $gid = NULL, $qid = NULL, int|null $LEMdebugLevel, boolean|null $assessments = NULL) : array
static

Arguments

$sid

int

$gid

int|null

$qid

$LEMdebugLevel

int|null

$assessments

boolean|null

Response

array

TSV survey definition in format readable by TSVSurveyImport one line each per group, question, sub-question, and answer does not use SGQA naming at all.

TSVSurveyExport(int $sid) : array
static

Arguments

$sid

int

Response

array

Returns the survey ID of the EM singleton

getLEMsurveyId() : int
static

Response

int

This function loads the relevant data about tokens for a survey.

loadTokenInformation(int $iSurveyId, string|null $sToken = null, boolean|null $bAnonymize = false) : void

If specific token is not given it loads empty values, this is used for question previewing and the like.

Arguments

$iSurveyId

int

$sToken

string|null

$bAnonymize

boolean|null

Add a flash message to state-key 'frontend{survey id}' The flash messages are templatereplaced in startpage.tstpl, {FLASHMESSAGE}

addFrontendFlashMessage(string $type, string $message, int $surveyid) : void
static

Arguments

$type

string

Yii type of flash: error, notice, 'success'

$message

string

$surveyid

int

Convert non-latin numerics in string to latin numerics Used for datepicker (Hindi, Arabic numbers)

convertNonLatinNumerics($str, $lang) : string
static

Arguments

$str

$lang

Response

string

Set currentQset. Used by unit-tests.

setCurrentQset(array $val) : void

Arguments

$val

array

Used for unit tests.

setKnownVars(mixed $val) : void

Arguments

$val

mixed

Used for unit tests.

setPageRelevanceInfo(mixed $info) : void

Arguments

$info

mixed

Properties

LimeExpressionManager is a singleton. $instance is its storage location.

instance : \LimeExpressionManager
static

Implements the recursive descent parser that processes expressions

em : \ExpressionManager
var

Type(s)

\ExpressionManager

groupRelevanceInfo

groupRelevanceInfo : array
var

Type(s)

array

The survey ID

sid : integer
var

Type(s)

integer

sum of LEM_DEBUG constants - use bitwise AND comparisons to identify which parts to use

debugLevel : int
var

Type(s)

int

sPreviewMode used for relevance equation force to 1 in preview mode Maybe we can set it public

sPreviewMode : string|boolean
var

Type(s)

string|boolean

Collection of variable attributes, indexed by SGQA code

knownVars : array

Actual variables are stored in this structure: $knownVars[$sgqa] = array( 'jsName_on' => // the name of the javascript variable if it is defined on the current page - often 'answerSGQA' 'jsName' => // the name of the javascript variable when referenced on different pages - usually 'javaSGQA' 'readWrite' => // 'Y' for yes, 'N' for no - currently not used 'hidden' => // 1 if the question attribute 'hidden' is true, otherwise 0 'question' => // the text of the question (or sub-question) 'qid' => // the numeric question id - e.g. the Q part of the SGQA name 'gid' => // the numeric group id - e.g. the G part of the SGQA name 'grelevance' => // the group level relevance string 'relevance' => // the question level relevance string 'qcode' => // the qcode-style variable name for this question (or sub-question) 'qseq' => // the 0-based index of the question within the survey 'gseq' => // the 0-based index of the group within the survey 'type' => // the single character type code for the question 'sgqa' => // the SGQA name for the variable 'ansList' => // ansArray converted to a JavaScript fragment - e.g. ",'answers':{ 'M':'Male','F':'Female'}" 'ansArray' => // PHP array of answer strings, keyed on the answer code = e.g. array['M']='Male'; 'scale_id' => // '0' for most answers. '1' for second scale within dual-scale questions 'rootVarName' => // the root code / name / title for the question, without any sub-question or answer-level suffix. This is from the title column in the questions table 'subqtext' => // the sub-question text 'rowdivid' => // the JavaScript ID of the row identifier for a question. This is used to show/hide entire question rows 'onlynum' => // 1 if only numbers are allowed for this variable. If so, then extra processing is needed to ensure that can use comma as a decimal separator );

Reserved variables (e.g. TOKEN:xxxx) are stored with this structure: $knownVars[$token] = array( 'code' => // the static value for the variable 'type' => // '' 'jsName_on' => // '' 'jsName' => // '' 'readWrite' => // 'N' - since these are always read-only variables );

var

Type(s)

array

maps qcode varname to SGQA code

qcode2sgqa : array
example

= '38612X10X145'

var

Type(s)

array

variables temporarily set for substitution purposes

tempVars : array

These are typically the LimeReplacement Fields passed in via templatereplace() Each has the following structure: array( 'code' => // the static value of the variable 'jsName_on' => // '' 'jsName' => // '' 'readWrite' => // 'N' );

var

Type(s)

array

Array of relevance information for each page (gseq), indexed by gseq.

pageRelevanceInfo : array

Within a page, it contains a sequential list of the results of each relevance equation processed array( 'qid' => // question id -- e.g. 154 'gseq' => // 0-based group sequence -- e.g. 2 'eqn' => // the raw relevance equation parsed -- e.g. "!is_empty(p2_sex)" 'result' => // the Boolean result of parsing that equation in the current context -- e.g. 0 'numJsVars' => // the number of dynamic JavaScript variables used in that equation -- e.g. 1 'relevancejs' => // the actual JavaScript to insert for that relevance equation -- e.g. "LEMif(LEManyNA('p2_sex'),'',( ! LEMempty(LEMval('p2_sex') )))" 'relevanceVars' => // a pipe-delimited list of JavaScript variables upon which that equation depends -- e.g. "java38612X12X153" 'jsResultVar' => // the JavaScript variable in which that result will be stored -- e.g. "java38612X12X154" 'type' => // the single character type of the question -- e.g. 'S' 'hidden' => // 1 if the question should always be hidden 'hasErrors' => // 1 if there were parsing errors processing that relevance equation

var

Type(s)

array

pageTailorInfo

pageTailorInfo : array
var

Type(s)

array

internally set to true (1) for survey.php so get group-specific logging but keep javascript variable namings consistent on the page.

allOnOnePage : boolean
var

Type(s)

boolean

survey mode. One of 'survey', 'group', or 'question'

surveyMode : string
var

Type(s)

string

a set of global survey options passed from LimeSurvey

surveyOptions : array

For example, array( 'rooturl' => // URL prefix needed to be able to click on a syntax-highlighted variable name and have it open the needed editting window 'hyperlinkSyntaxHighlighting' => // true if should be able to click on variables to edit them 'active' => // 0 for inactive, 1 for active survey 'allowsave' => // 0 for do not allow save; 1 for allow save 'anonymized' => // 1 for anonymous 'assessments' => // 1 for use assessments 'datestamp' => // 1 for use date stamps 'ipaddr' => // 1 for capture IP address 'radix' => // '.' for use period as decimal separator; ',' for use comma as decimal separator 'savetimings' => // "Y" if should save survey timings 'startlanguage' => // the starting language -- e.g. 'en' 'surveyls_dateformat' => // the index of the language specific date format -- e.g. 1 'tablename' => // the name of the table storing the survey data, if active -- e.g. lime_survey_38612 'target' => // the path for uploading files -- e.g. '/temp/files/' 'timeadjust' => // the time offset -- e.g. 0 'tempdir' => // the temporary directory for uploading files -- e.g. '/temp/' );

var

Type(s)

array

array of mappings of Question # (qid) to pipe-delimited list of SGQA codes used within it

qid2code : array
example

= "38612X11X150|38612X11X150other"

var

Type(s)

array

array of mappings of JavaScript Variable names to Question number (qid)

jsVar2qid : array
example

= '161'

var

Type(s)

array

maps name of the variable to the SGQ name (without the A suffix)

qcode2sgq : array
example

= "38612X10X147"

= "26626X37X705sq1#1"

var

Type(s)

array

array of mappings of knownVar aliases to the JavaScript variable names.

alias2varName : array

This maps both the SGQA and qcode alias names to the same 2 dimensional array

example

= array( 'jsName' => // the JavaScript variable name used by EM -- e.g. "java38612X11X147" 'jsPart' => // the JavaScript fragment used in EM's ____ array -- e.g. "'p1_sex':'java38612X11X147'" );

= array( 'jsName' => "java26626X37X705sq1#1" 'jsPart' => "'afDS_sq1_1':'java26626X37X705sq1#1'" );

var

Type(s)

array

JavaScript array of mappings of canonical JavaScript variable name to key attributes.

varNameAttr : array

These fragments are used to create the JavaScript varNameAttr array.

example

= "'java38612X11X147':{ 'jsName':'java38612X11X147','jsName_on':'java38612X11X147','sgqa':'38612X11X147','qid':147,'gid':11,'type':'G','default':'','rowdivid':'','onlynum':'','gseq':1,'answers':{ 'M':'Male','F':'Female'}}"

= "'java26626X37X705sq1#1':{ 'jsName':'java26626X37X705sq1#1','jsName_on':'java26626X37X705sq1#1','sgqa':'26626X37X705sq1#1','qid':705,'gid':37,'type':'1','default':'','rowdivid':'26626X37X705sq1','onlynum':'','gseq':1,'answers':{ '0~1':'1|Low','0~2':'2|Medium','0~3':'3|High','1~1':'1|Never','1~2':'2|Sometimes','1~3':'3|Always'}}"

var

Type(s)

array

array of enumerated answer lists indexed by qid These use a tilde syntax to indicate which scale the answer is part of.

qans : array
example

= "4|Child" // this means that code 4 in scale 0 has a coded value of 4 and a display value of 'Child'

[705]): ['1~2'] = '2|Sometimes' // this means that the second scale for this question uses the coded value of 2 to represent 'Sometimes'

TODO - add example from survey using assessments

var

Type(s)

array

map of gid to 0-based sequence number of groups

groupId2groupSeq : array
example

= 0 // means that the first group (gseq=0) has gid=10

var

Type(s)

array

map question # to an incremental count of question order across the whole survey

questionId2questionSeq : array
example

= 13 // means that that 14th question in the survey has qid=157

var

Type(s)

array

map question # to the group it is within, using an incremental count of group order

questionId2groupSeq : array
example

= 2 // means that qid 157 is in the 3rd page of questions (gseq = 2)

var

Type(s)

array

array of info about each Group, indexed by GroupSeq

groupSeqInfo : array
example

= array( 'qstart' => 9 // the first qseq within that group 'qend' => 13 //the last qseq within that group );

var

Type(s)

array

tracks which groups have at least one relevant, non-hidden question

gseq2relevanceStatus : array
example

= 0 // means that the third group (gseq==2) is currently irrelevant

var

Type(s)

array

maps question # to the validation equation(s) for that question.

qid2validationEqn : array

These are grouped by qid then validation type, such as 'value_range', and 'num_answers'

example

= array( 'eqn' => array( 'value_range' = "((is_empty(26626X34X703.NAOK) || 26626X34X703.NAOK >= (0)) and (is_empty(26626X34X703.NAOK) || 26626X34X703.NAOK <= (5)))" ), 'tips' => array( 'value_range' = "Each answer must be between {fixnum(0)} and {fixnum(5)}" ), 'subqValidEqns' = array( [] = array( 'subqValidSelector' => '' // 'subqValidEqn' => "(is_empty(26626X34X703.NAOK) || 26626X34X703.NAOK >= (0)) && (is_empty(26626X34X703.NAOK) || 26626X34X703.NAOK <= (5))" ), 'sumEqn' => '' // the equation to compute the current sum of the responses 'sumRemainingEqn' => '' // the equation to how much is left (for the question attribute that lets you specify the exact value of the sum of the answers) );

var

Type(s)

array

keeps relevance in proper sequence so can minimize relevance processing to see what should be see on page and in indexes Array is indexed on qseq

questionSeq2relevance : array
example

= array( 'relevance' => "!is_empty(num)" // the question-level relevance equation 'grelevance' => "" // the group-level relevance equation 'qid' => "699" // the question id 'qseq' => 3 // the 0-index question sequence 'gseq' => 0 // the 0-index group sequence 'jsResultVar_on' => 'answer26626X34X699' // the javascript variable holding the input value 'jsResultVar' => 'java26226X34X699' // the javascript variable (often hidden) holding the value to be submitted 'type' => 'N' // the one character question type 'hidden' => 0 // 1 if it should be always_hidden 'gid' => "34" // group id 'mandatory' => 'N' // 'Y' if mandatory 'eqn' => "" // TODO ?? 'help' => "" // the help text 'qtext' => "Enter a larger number than {num}" // the question text 'code' => 'afDS_sq5_1' // the full variable name 'other' => 'N' // whether the question supports the 'other' option - 'Y' if true 'rowdivid' => '2626X37X705sq5' // the javascript id for the row - in this case, the 5th sub-question 'aid' => 'sq5' // the answer id 'sqid' => '791' // the sub-question's qid (only populated for some question types) );

var

Type(s)

array

current Group sequence (0-based index)

currentGroupSeq : integer
example
var

Type(s)

integer

for Question-by-Question mode, the 0-based index

currentQuestionSeq : integer
example
var

Type(s)

integer

used in Question-by-Question mode

currentQID : integer
var

Type(s)

integer

set of the current set of questions to be displayed, indexed by QID - at least one must be relevant

currentQset : array|null

The array has N entries, where N is the number if qids in the Qset. Each has the following contents:

example

= array( 'info' => array() // this is an exact copy of $questionSeq2relevance[$qseq] -- TODO - remove redundancy 'relevant' => 1 // 1 if the question is currently relevant 'hidden' => 0 // 1 if the question is always hidden 'relEqn' => '' // the relevance equation -- TODO - how different from ['info']['relevance']? 'sgqa' => // pipe-separated list of SGQA codes for this question -- e.g. "26626X37X705sq1#0|26626X37X705sq1#1|26626X37X705sq2#0|26626X37X705sq2#1|26626X37X705sq3#0|26626X37X705sq3#1|26626X37X705sq4#0|26626X37X705sq4#1|26626X37X705sq5#0|26626X37X705sq5#1" 'unansweredSQs' => // pipe-separated list of currently unanswered SGQA codes for this question -- e.g. "26626X37X705sq1#0|26626X37X705sq1#1|26626X37X705sq3#0|26626X37X705sq3#1|26626X37X705sq5#0|26626X37X705sq5#1" 'valid' => 0 // 1 if the current answers pass all of the validation criteria for the question 'validEqn' => // the auto-generated validation criteria, based upon advanced question attributes -- e.g. "((count(if(count(26626X37X705sq1#0.NAOK,26626X37X705sq1#1.NAOK)==2,1,''), if(count(26626X37X705sq2#0.NAOK,26626X37X705sq2#1.NAOK)==2,1,''), if(count(26626X37X705sq3#0.NAOK,26626X37X705sq3#1.NAOK)==2,1,''), if(count(26626X37X705sq4#0.NAOK,26626X37X705sq4#1.NAOK)==2,1,''), if(count(26626X37X705sq5#0.NAOK,26626X37X705sq5#1.NAOK)==2,1,'')) >= (minSelect)) and (count(if(count(26626X37X705sq1#0.NAOK,26626X37X705sq1#1.NAOK)==2,1,''), if(count(26626X37X705sq2#0.NAOK,26626X37X705sq2#1.NAOK)==2,1,''), if(count(26626X37X705sq3#0.NAOK,26626X37X705sq3#1.NAOK)==2,1,''), if(count(26626X37X705sq4#0.NAOK,26626X37X705sq4#1.NAOK)==2,1,''), if(count(26626X37X705sq5#0.NAOK,26626X37X705sq5#1.NAOK)==2,1,'')) <= (maxSelect)))" 'prettyValidEqn' => // syntax-highlighted version of validEqn, only showing syntax errors 'validTip' => // html fragment to insert for the validation tip -- e.g. "

Please select between 1 and 3 answer(s)

" 'prettyValidTip' => // version of validTip that can be parsed by EM to create dynmamic validation -- e.g. "

Please select between {fixnum(minSelect)} and {fixnum(maxSelect)} answer(s)

" 'validJS' => // JavaScript fragment that can perform validation. This is the result of parsing validEqn -- e.g. "LEMif(LEManyNA('minSelect', 'maxSelect'),'',(((LEMcount(LEMif(LEMcount(LEMval('26626X37X705sq1#0.NAOK') , LEMval('26626X37X705sq1#1.NAOK') ) == 2, 1, ''), LEMif(LEMcount(LEMval('26626X37X705sq2#0.NAOK') , LEMval('26626X37X705sq2#1.NAOK') ) == 2, 1, ''), LEMif(LEMcount(LEMval('26626X37X705sq3#0.NAOK') , LEMval('26626X37X705sq3#1.NAOK') ) == 2, 1, ''), LEMif(LEMcount(LEMval('26626X37X705sq4#0.NAOK') , LEMval('26626X37X705sq4#1.NAOK') ) == 2, 1, ''), LEMif(LEMcount(LEMval('26626X37X705sq5#0.NAOK') , LEMval('26626X37X705sq5#1.NAOK') ) == 2, 1, '')) >= (LEMval('minSelect') )) && (LEMcount(LEMif(LEMcount(LEMval('26626X37X705sq1#0.NAOK') , LEMval('26626X37X705sq1#1.NAOK') ) == 2, 1, ''), LEMif(LEMcount(LEMval('26626X37X705sq2#0.NAOK') , LEMval('26626X37X705sq2#1.NAOK') ) == 2, 1, ''), LEMif(LEMcount(LEMval('26626X37X705sq3#0.NAOK') , LEMval('26626X37X705sq3#1.NAOK') ) == 2, 1, ''), LEMif(LEMcount(LEMval('26626X37X705sq4#0.NAOK') , LEMval('26626X37X705sq4#1.NAOK') ) == 2, 1, ''), LEMif(LEMcount(LEMval('26626X37X705sq5#0.NAOK') , LEMval('26626X37X705sq5#1.NAOK') ) == 2, 1, '')) <= (LEMval('maxSelect') )))))" 'invalidSQs' => // current list of subquestions that fail validation criteria -- e.g. "26626X37X705sq1#0|26626X37X705sq1#1|26626X37X705sq2#0|26626X37X705sq2#1|26626X37X705sq3#0|26626X37X705sq3#1|26626X37X705sq4#0|26626X37X705sq4#1|26626X37X705sq5#0|26626X37X705sq5#1" 'relevantSQs' => // current list of subquestions that are relevant -- e.g. "26626X37X705sq1#0|26626X37X705sq1#1|26626X37X705sq2#0|26626X37X705sq2#1|26626X37X705sq3#0|26626X37X705sq3#1|26626X37X705sq4#0|26626X37X705sq4#1|26626X37X705sq5#0|26626X37X705sq5#1" 'irrelevantSQs' => // current list of subquestions that are irrelevant -- e.g. "26626X37X705sq2#0|26626X37X705sq2#1|26626X37X705sq4#0|26626X37X705sq4#1" 'subQrelEqn' => // TODO - ?? 'mandViolation' => 0 // 1 if the question is mandatory and fails the mandatory criteria 'anyUnanswered' => 1 // 1 if any parts of the question are unanswered 'mandTip' => '' // message to display if the question fails mandatory criteria 'message' => '' // TODO ?? 'updatedValues' => // array of values that should be updated for this question, as [$sgqa] = $value 'sumEqn' => '' // 'sumRemainingEqn' => '' // );

var

Type(s)

array|null

last result of NavigateForwards, NavigateBackwards, or JumpTo Array of status information about last movement, whether at question, group, or survey level

lastMoveResult : array|null
example

array( 'finished' => 0 // 1 if the survey has been completed and needs to be finalized 'message' => '' // any error message that needs to be displayed 'seq' => 1 // the sequence count, using gseq, or qseq units if in 'group' or 'question' mode, respectively 'mandViolation' => 0 // whether there was any violation of mandatory constraints in the last movement 'valid' => 0 // 1 if the last movement passed all validation constraints. 0 if there were any validation errors 'unansweredSQs' => // pipe-separated list of any sub-questions that were not answered 'invalidSQs' => // pipe-separated list of any sub-questions that failed validation constraints );

var

Type(s)

array|null

array of information needed to generate navigation index in question-by-question mode One entry for each question, indexed by qseq

indexQseq : array
example

= array( 'qid' => "700" // the question id 'qtext' => 'How old are you?' // the question text 'qcode' => 'age' // the variable name 'qhelp' => '' // the help text 'anyUnanswered' => 0 // 1 if there are any sub-questions answered. Used for index display 'anyErrors' => 0 // 1 if there are any errors among the sub-questions. Could be used for index display 'show' => 1 // 1 if there are any relevant, non-hidden sub-questions. Only if so, then display the index entry 'gseq' => 0 // the group sequence 'gtext' => // text description for the group 'gname' => 'G1' // the group title 'gid' => "34" // the group id 'mandViolation' => 0 // 1 if the question as a whole fails the mandatory criteria 'valid' => 1 // 0 if any part of the question fails validation criteria. );

var

Type(s)

array

array of information needed to generate navigation index in group-by-group mode One entry for each group, indexed by gseq

indexGseq : array
example

= array( 'gtext' => // the description for the group 'gname' => 'G1' // the group title 'gid' => '34' // the group id 'anyUnanswered' => 0 // 1 if any questions within the group are unanswered 'anyErrors' => 0 // 1 if any of the questions within the group fail either validity or mandatory constraints 'valid' => 1 // 1 if at least question in the group is relevant and non-hidden 'mandViolation' => 0 // 1 if at least one relevant, non-hidden question in the group fails mandatory constraints 'show' => 1 // 1 if there is at least one relevant, non-hidden question within the group );

var

Type(s)

array

array of group sequence number to static info One entry per group, indexed on gseq

gseq2info : array
example

= array( 'group_order' => 0 // gseq 'gid' => "34" // group id 'group_name' => 'G2' // the group title 'description' => // the description of the group (e.g. gtitle) 'grelevance' => '' // the group-level relevance );

var

Type(s)

array

the maximum groupSeq reached - this is needed for Index

maxGroupSeq : int
var

Type(s)

int

the maximum Question reached sequencly ordered, used to show error to the user if we stop before this step with indexed survey.

maxQuestionSeq : integer

In question by question mode : $maxQuestionSeq==$SESSION['survey'.surveyid]['maxstep'], use it ?

var

Type(s)

integer

mapping of questions to information about their subquestions.

q2subqInfo : array

One entry per question, indexed on qid

example

= array( 'qid' => 702 // the question id 'qseq' => 6 // the question sequence 'gseq' => 0 // the group sequence 'sgqa' => '26626X34X702' // the root of the SGQA code (reallly just the SGQ) 'varName' => 'afSrcFilter_sq1' // the full qcode variable name - note, if there are sub-questions, don't use this one. 'type' => 'M' // the one-letter question type 'fieldname' => '26626X34X702sq1' // the fieldname (used as JavaScript variable name, and also as database column name 'rootVarName' => 'afDS' // the root variable name 'preg' => '/[A-Z]+/' // regular expression validation equation, if any 'subqs' => array() of sub-questions, where each contains: 'rowdivid' => '26626X34X702sq1' // the javascript id identifying the question row (so array_filter can hide rows) 'varName' => 'afSrcFilter_sq1' // the full variable name for the sub-question 'jsVarName_on' => 'java26626X34X702sq1' // the JavaScript variable name if the variable is defined on the current page 'jsVarName' => 'java26626X34X702sq1' // the JavaScript variable name to use if the variable is defined on a different page 'csuffix' => 'sq1' // the SGQ suffix to use for a fieldname 'sqsuffix' => '_sq1' // the suffix to use for a qcode variable name );

var

Type(s)

array

array of advanced question attributes for each question Indexed by qid; available for all quetions

qattr : array
example

= array( 'array_filter_exclude' => 'afSrcFilter' 'exclude_all_others' => 'sq5' 'max_answers' => '3' 'min_answers' => '1' 'other_replace_text' => '{afSrcFilter_other}' );

var

Type(s)

array

list of needed sub-question relevance (e.g. array_filter) Indexed by qid then sgqa; only generated for current group of questions

subQrelInfo : array
example

= array( 'qid' => '708' // the question id 'eqn' => "((26626X34X702sq2 != ''))" // the auto-generated sub-question-level relevance equation 'prettyPrintEqn' => '' // only generated if there errors - shows syntax highlighting of them 'result' => 0 // result of processing the sub-question-level relevance equation in the current context 'numJsVars' => 1 // the number of on-page javascript variables in 'eqn' 'relevancejs' => // the generated javascript from 'eqn' -- e.g. "LEMif(LEManyNA('26626X34X702sq2'),'',(((LEMval('26626X34X702sq2') != ""))))" 'relevanceVars' => "java26626X34X702sq2" // the pipe-separated list of on-page javascript variables in 'eqn' 'rowdivid' => "26626X37X708sq2" // the javascript id of the question row (so can apply array_filter) 'type' => 'array_filter' // semicolon delimited list of types of subquestion relevance filters applied 'qtype' => 'A' // the single character question type 'sgqa' => "26626X37X708" // the SGQ portion of the fieldname 'hasErrors' => 0 // 1 if there are any parse errors in the sub-question validation equations );

var

Type(s)

array

array of Group-level relevance status Indexed by gseq; only shows groups that have been visited

gRelInfo : array
example

= array( 'gseq' => 1 // group sequence 'eqn' => '' // the group-level relevance 'result' => 1 // result of processing the group-level relevance 'numJsVars' => 0 // the number of on-page javascript variables in the group-level relevance equation 'relevancejs' => '' // the javascript version of the relevance equation 'relevanceVars' => '' // the pipe-delimited list of on-page javascript variable names used within the group-level relevance equation 'prettyPrint' => '' // a pretty-print version of the group-level relevance equation, only if there are errors );

var

Type(s)

array

Array of timing information to debug how long it takes for portions of LEM to run.

runtimeTimings : array

Array of timing information (in seconds) for EM to help with debugging

example

= array( [0]="LimeExpressionManager::NavigateForwards" [1]=1.7079849243164 );

var

Type(s)

array

True (1) if calling LimeExpressionManager functions between StartSurvey and FinishProcessingPage Used (mostly deprecated) to detect calls to LEM which happen outside of the normal processing scope

initialized : boolean
var

Type(s)

boolean

True (1) if have already processed the relevance equations (so don't need to do it again)

processedRelevance : boolean
var

Type(s)

boolean

Message generated to show debug timing values, if debugLevel includes LEM_DEBUG_TIMING

debugTimingMsg : string
var

Type(s)

string

temporary variable to reduce need to parse same equation multiple times. Used for relevance and validation Array, indexed on equation, providing the following information:

ParseResultCache : array
example

= array( 'result' => 1 // result of processing the equation in the current scope 'prettyPrint' => '' // syntax-highlighted version of equation if there are any errors 'hasErrors' => 0 // 1 if there are any syntax errors );

var

Type(s)

array

array of 2nd scale answer lists for types ':' and ';' -- needed for convenient print of logic file Indexed on qid; available for all questions

multiflexiAnswers : array
example

= array( '1~1' => '1|Never', '1~2' => '2|Sometimes', '1~3' => '3|Always' );

var

Type(s)

array

used to specify whether to generate equations using SGQA codes or qcodes Default is to convert all qcode naming to sgqa naming when generating javascript, as that provides the greatest backwards compatibility TSV export of survey structure sets this to false so as to force use of qcode naming

sgqaNaming : Boolean
var

Type(s)

Boolean

Number of groups in survey (number of possible pages to display)

numGroups : integer
var

Type(s)

integer

Numer of questions in survey (counting display-only ones?)

numQuestions : integer
var

Type(s)

integer

String identifier for the active session

sessid : string
var

Type(s)

string

Linked list of array filters

qrootVarName2arrayFilter : array
var

Type(s)

array

Array, keyed on qid, to JavaScript and list of variables needed to implement exclude_all_others_auto

qid2exclusiveAuto : array
var

Type(s)

array

Array of values to be updated

updatedValues : array
var

Type(s)

array