ILIAS  release_8 Revision v8.19-1-g4e8f2f9140c
All Data Structures Namespaces Files Functions Variables Modules Pages
ilDclExpressionParser Class Reference

This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Learning e.V. More...

+ Collaboration diagram for ilDclExpressionParser:

Public Member Functions

 __construct (string $expression, ilDclBaseRecordModel $record, ilDclBaseFieldModel $field)
 
 parse ()
 Parse expression and return result. More...
 

Static Public Member Functions

static getOperators ()
 
static getFunctions ()
 

Data Fields

const N_DECIMALS = 1
 
const SCIENTIFIC_NOTATION_UPPER = 1000000000000
 
const SCIENTIFIC_NOTATION_LOWER = 0.000000001
 

Protected Member Functions

 formatScientific ($value)
 
 isMathToken (string $token)
 Check if a given token is a math expression. More...
 
 calculateFunctions (string $token)
 Execute any math functions inside a token. More...
 
 getFunctionArgs (int $index, array $data)
 Helper method to return the function and its arguments from a preg_replace_all $result array. More...
 
 substituteFieldValues (array $tokens)
 Given an array of tokens, replace each token that is a placeholder (e.g. More...
 
 parseMath (array $tokens)
 Parse a math expression. More...
 
 calculateFunction (string $function, array $args=array())
 Calculate a function with its arguments. More...
 
 calculate (string $operator, $left, $right)
 

Protected Attributes

ilDclBaseRecordModel $record
 
ilDclBaseFieldModel $field
 
string $expression
 

Static Protected Attributes

static array $operators
 
static array $cache_tokens = array()
 
static array $cache_fields = array()
 
static array $cache_math_tokens = array()
 
static array $cache_math_function_tokens = array()
 
static array $functions
 

Detailed Description

This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Learning e.V.

ILIAS is licensed with the GPL-3.0, see https://www.gnu.org/licenses/gpl-3.0.en.html You should have received a copy of said license along with the source code, too.

If this is not the case or you just want to try ILIAS, you'll find us at: https://www.ilias.de https://github.com/ILIAS-eLearning

Definition at line 19 of file class.ilDclExpressionParser.php.

Constructor & Destructor Documentation

◆ __construct()

ilDclExpressionParser::__construct ( string  $expression,
ilDclBaseRecordModel  $record,
ilDclBaseFieldModel  $field 
)

Definition at line 48 of file class.ilDclExpressionParser.php.

References $expression, $field, and $record.

49  {
50  $this->expression = $expression;
51  $this->record = $record;
52  $this->field = $field;
53  }

Member Function Documentation

◆ calculate()

ilDclExpressionParser::calculate ( string  $operator,
  $left,
  $right 
)
protected
Parameters
string$operator
float | int$left
float | int$right
Returns
float|int
Exceptions
ilException

Definition at line 355 of file class.ilDclExpressionParser.php.

Referenced by parseMath().

356  {
357  switch ($operator) {
358  case '+':
359  $result = $left + $right;
360  break;
361  case '-':
362  $result = $left - $right;
363  break;
364  case '*':
365  $result = $left * $right;
366  break;
367  case '/':
368  $result = ($right == 0) ? 0 : $left / $right;
369  break;
370  case '^':
371  $result = pow($left, $right);
372  break;
373  default:
374  throw new ilException("Unrecognized operator '$operator'");
375  }
376 
377  return $result;
378  }
+ Here is the caller graph for this function:

◆ calculateFunction()

ilDclExpressionParser::calculateFunction ( string  $function,
array  $args = array() 
)
protected

Calculate a function with its arguments.

Returns
float|int|number
Exceptions
ilException

Definition at line 330 of file class.ilDclExpressionParser.php.

Referenced by calculateFunctions().

331  {
332  switch ($function) {
333  case 'AVERAGE':
334  $count = count($args);
335 
336  return ($count) ? array_sum($args) / $count : 0;
337  case 'SUM':
338  return array_sum($args);
339  case 'MIN':
340  return min($args);
341  case 'MAX':
342  return max($args);
343  default:
344  throw new ilException("Unrecognized function '$function'");
345  }
346  }
+ Here is the caller graph for this function:

◆ calculateFunctions()

ilDclExpressionParser::calculateFunctions ( string  $token)
protected

Execute any math functions inside a token.

Definition at line 148 of file class.ilDclExpressionParser.php.

References $token, calculateFunction(), getFunctionArgs(), and substituteFieldValues().

Referenced by parse().

148  : string
149  {
150  if (isset(self::$cache_math_function_tokens[$this->field->getId()][$token])) {
151  $result = self::$cache_math_function_tokens[$this->field->getId()][$token];
152  if ($result === false) {
153  return $token;
154  }
155  } else {
156  $pattern = '#';
157  foreach (self::getFunctions() as $function) {
158  $pattern .= "($function)\\(([^)]*)\\)|";
159  }
160  if (!preg_match_all(rtrim($pattern, '|') . '#', $token, $result)) {
161  // No functions found inside token, just return token again
162  self::$cache_math_function_tokens[$this->field->getId()][$token] = false;
163 
164  return $token;
165  }
166  }
167  // Function found inside token, calculate!
168  foreach ($result[0] as $k => $to_replace) {
169  $function_args = $this->getFunctionArgs($k, $result);
170  $function = $function_args['function'];
171  $args = $this->substituteFieldValues($function_args['args']);
172  $token = str_replace($to_replace, $this->calculateFunction($function, $args), $token);
173  }
174 
175  return $token;
176  }
substituteFieldValues(array $tokens)
Given an array of tokens, replace each token that is a placeholder (e.g.
calculateFunction(string $function, array $args=array())
Calculate a function with its arguments.
getFunctionArgs(int $index, array $data)
Helper method to return the function and its arguments from a preg_replace_all $result array...
$token
Definition: xapitoken.php:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ formatScientific()

ilDclExpressionParser::formatScientific (   $value)
protected
Parameters
float | int$value
Returns
string|int

Definition at line 101 of file class.ilDclExpressionParser.php.

Referenced by parse().

102  {
103  if (abs($value) >= self::SCIENTIFIC_NOTATION_UPPER) {
104  return sprintf("%e", $value);
105  }
106  if (abs($value) <= self::SCIENTIFIC_NOTATION_LOWER && $value != 0) {
107  return sprintf("%e", $value);
108  }
109  return $value;
110  }
+ Here is the caller graph for this function:

◆ getFunctionArgs()

ilDclExpressionParser::getFunctionArgs ( int  $index,
array  $data 
)
protected

Helper method to return the function and its arguments from a preg_replace_all $result array.

Definition at line 181 of file class.ilDclExpressionParser.php.

References $i, and $index.

Referenced by calculateFunctions().

181  : array
182  {
183  $return = array(
184  'function' => '',
185  'args' => array(),
186  );
187  for ($i = 1; $i < count($data); $i++) {
188  $_data = $data[$i];
189  if ($_data[$index]) {
190  $function = $_data[$index];
191  $args = explode(';', $data[$i + 1][$index]);
192  $return['function'] = $function;
193  $return['args'] = $args;
194  break;
195  }
196  }
197 
198  return $return;
199  }
$index
Definition: metadata.php:145
$i
Definition: metadata.php:41
+ Here is the caller graph for this function:

◆ getFunctions()

static ilDclExpressionParser::getFunctions ( )
static

Definition at line 117 of file class.ilDclExpressionParser.php.

Referenced by ilDclFormulaFieldRepresentation\buildFieldCreationInput(), and ilDclTable\getFieldsForFormula().

117  : array
118  {
119  return self::$functions;
120  }
+ Here is the caller graph for this function:

◆ getOperators()

static ilDclExpressionParser::getOperators ( )
static

Definition at line 112 of file class.ilDclExpressionParser.php.

Referenced by ilDclFormulaFieldRepresentation\buildFieldCreationInput(), ilDclTable\getFieldsForFormula(), and ilDclTokenizer\getMathTokens().

112  : array
113  {
114  return self::$operators;
115  }
+ Here is the caller graph for this function:

◆ isMathToken()

ilDclExpressionParser::isMathToken ( string  $token)
protected

Check if a given token is a math expression.

Definition at line 125 of file class.ilDclExpressionParser.php.

References $functions, $operators, and $token.

Referenced by parse().

125  : bool
126  {
127  if (isset(self::$cache_math_tokens[$this->field->getId()][$token])) {
128  return self::$cache_math_tokens[$this->field->getId()][$token];
129  } else {
130  if (strpos($token, '"') === 0) {
131  return false;
132  }
133  $operators = array_keys(self::getOperators());
134  $functions = self::getFunctions();
135  $result = (bool) preg_match(
136  '#(\\' . implode("|\\", $operators) . '|' . implode('|', $functions) . ')#',
137  $token
138  );
139  self::$cache_math_tokens[$this->field->getId()][$token] = $result;
140 
141  return $result;
142  }
143  }
$token
Definition: xapitoken.php:70
+ Here is the caller graph for this function:

◆ parse()

ilDclExpressionParser::parse ( )

Parse expression and return result.

This method loops the tokens and checks if Token is of type string or math. Concatenates results to produce resulting string of parsed expression.

Exceptions
ilException

Definition at line 61 of file class.ilDclExpressionParser.php.

References $token, calculateFunctions(), formatScientific(), ilDclTokenizer\getMathTokens(), ilDclTokenizer\getTokens(), isMathToken(), parseMath(), and substituteFieldValues().

61  : string
62  {
63  if (isset(self::$cache_tokens[$this->field->getId()])) {
64  $tokens = self::$cache_tokens[$this->field->getId()];
65  } else {
66  $tokens = ilDclTokenizer::getTokens($this->expression);
67  self::$cache_tokens[$this->field->getId()] = $tokens;
68  }
69  $parsed = '';
70  foreach ($tokens as $token) {
71  if (empty($token)) {
72  continue;
73  }
74  if ($this->isMathToken($token)) {
75  $token = $this->calculateFunctions($token);
76  $math_tokens = ilDclTokenizer::getMathTokens($token);
77  $value = $this->parseMath($this->substituteFieldValues($math_tokens));
78 
79  $value = $this->formatScientific($value);
80 
81  $parsed .= $value;
82  } else {
83  // Token is a string, either a field placeholder [[Field name]] or a string starting with "
84  if (strpos($token, '"') === 0) {
85  $parsed .= strip_tags(trim($token, '"'));
86  } elseif (strpos($token, '[[') === 0) {
87  $parsed .= trim(strip_tags($this->substituteFieldValue($token)));
88  } else {
89  throw new ilException("Unrecognized string token: '$token'");
90  }
91  }
92  }
93 
94  return $parsed;
95  }
substituteFieldValues(array $tokens)
Given an array of tokens, replace each token that is a placeholder (e.g.
static getTokens(string $expression)
Split expression by & (ignore escaped &-symbols with backslash)
parseMath(array $tokens)
Parse a math expression.
$token
Definition: xapitoken.php:70
static getMathTokens(string $math_expression)
Generate tokens for a math expression.
calculateFunctions(string $token)
Execute any math functions inside a token.
isMathToken(string $token)
Check if a given token is a math expression.
+ Here is the call graph for this function:

◆ parseMath()

ilDclExpressionParser::parseMath ( array  $tokens)
protected

Parse a math expression.

Exceptions
Exception

Definition at line 254 of file class.ilDclExpressionParser.php.

References $operators, $token, and calculate().

Referenced by parse().

254  : ?string
255  {
256  $operators = self::$operators;
257  $precedence = 0;
258  $stack = new ilDclStack();
259  $precedences = new ilDclStack();
260  $in_bracket = false;
261  foreach ($tokens as $token) {
262  if (empty($token) or is_null($token)) {
263  $token = 0;
264  }
265  if (is_numeric($token) or $token === '(') {
266  $stack->push($token);
267  if ($token === '(') {
268  $in_bracket = true;
269  }
270  } elseif (in_array($token, array_keys($operators))) {
271  $new_precedence = $operators[$token]['precedence'];
272  if ($new_precedence > $precedence || $in_bracket) {
273  // Precedence of operator is higher, push operator on stack
274  $stack->push($token);
275  $precedences->push($new_precedence);
276  $precedence = $new_precedence;
277  } else {
278  // Precedence is equal or lower, calculate result on stack
279  while ($new_precedence <= $precedence && $stack->count() > 1) {
280  $right = (float) $stack->pop();
281  $operator = $stack->pop();
282  $left = (float) $stack->pop();
283  $result = $this->calculate($operator, $left, $right);
284  $stack->push($result);
285  $precedence = $precedences->pop();
286  }
287  $stack->push($token);
288  $precedence = $new_precedence;
289  $precedences->push($new_precedence);
290  }
291  } elseif ($token === ')') {
292  // Need to calculate stack back to opening bracket
293  $_tokens = array();
294  $elem = $stack->pop();
295  while ($elem !== '(' && !$stack->isEmpty()) {
296  $_tokens[] = $elem;
297  $elem = $stack->pop();
298  }
299  // Get result within brackets recursive and push to stack
300  $stack->push($this->parseMath(array_reverse($_tokens)));
301  $in_bracket = false;
302  } else {
303  throw new ilException("Unrecognized token '$token'");
304  }
305  // $stack->debug();
306  }
307  // If one element is left on stack, we are done. Otherwise calculate
308  if ($stack->count() == 1) {
309  $result = $stack->pop();
310 
311  return (ctype_digit((string) $result)) ? $result : number_format($result, self::N_DECIMALS, '.', "'");
312  } else {
313  while ($stack->count() >= 2) {
314  $right = $stack->pop();
315  $operator = $stack->pop();
316  $left = $stack->count() ? $stack->pop() : 0;
317  $stack->push($this->calculate($operator, $left, $right));
318  }
319  $result = $stack->pop();
320 
321  return $result;
322  }
323  }
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
parseMath(array $tokens)
Parse a math expression.
$token
Definition: xapitoken.php:70
calculate(string $operator, $left, $right)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ substituteFieldValues()

ilDclExpressionParser::substituteFieldValues ( array  $tokens)
protected

Given an array of tokens, replace each token that is a placeholder (e.g.

[[Field name]]) with it's value

Definition at line 204 of file class.ilDclExpressionParser.php.

References $DIC, $field, $lng, $token, ilDclBaseFieldModel\getId(), and ilDclCache\getTableCache().

Referenced by calculateFunctions(), and parse().

204  : array
205  {
206  $replaced = array();
207  foreach ($tokens as $token) {
208  if (strpos($token, '[[') === 0) {
209  $replaced[] = $this->substituteFieldValue($token);
210  } else {
211  $replaced[] = $token;
212  }
213  }
214 
215  return $replaced;
216  }
$token
Definition: xapitoken.php:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Field Documentation

◆ $cache_fields

array ilDclExpressionParser::$cache_fields = array()
staticprotected

Definition at line 37 of file class.ilDclExpressionParser.php.

◆ $cache_math_function_tokens

array ilDclExpressionParser::$cache_math_function_tokens = array()
staticprotected

Definition at line 39 of file class.ilDclExpressionParser.php.

◆ $cache_math_tokens

array ilDclExpressionParser::$cache_math_tokens = array()
staticprotected

Definition at line 38 of file class.ilDclExpressionParser.php.

◆ $cache_tokens

array ilDclExpressionParser::$cache_tokens = array()
staticprotected

Definition at line 36 of file class.ilDclExpressionParser.php.

◆ $expression

string ilDclExpressionParser::$expression
protected

Definition at line 27 of file class.ilDclExpressionParser.php.

Referenced by __construct().

◆ $field

ilDclBaseFieldModel ilDclExpressionParser::$field
protected

Definition at line 26 of file class.ilDclExpressionParser.php.

Referenced by __construct(), and substituteFieldValues().

◆ $functions

array ilDclExpressionParser::$functions
staticprotected
Initial value:
= array(
'SUM',
'AVERAGE',
'MIN',
'MAX',
)

Definition at line 41 of file class.ilDclExpressionParser.php.

Referenced by isMathToken().

◆ $operators

array ilDclExpressionParser::$operators
staticprotected
Initial value:
= array(
'+' => array('precedence' => 1),
'-' => array('precedence' => 1),
'*' => array('precedence' => 2),
'/' => array('precedence' => 2),
'^' => array('precedence' => 3),
)

Definition at line 29 of file class.ilDclExpressionParser.php.

Referenced by isMathToken(), and parseMath().

◆ $record

ilDclBaseRecordModel ilDclExpressionParser::$record
protected

Definition at line 25 of file class.ilDclExpressionParser.php.

Referenced by __construct().

◆ N_DECIMALS

const ilDclExpressionParser::N_DECIMALS = 1

Definition at line 21 of file class.ilDclExpressionParser.php.

◆ SCIENTIFIC_NOTATION_LOWER

const ilDclExpressionParser::SCIENTIFIC_NOTATION_LOWER = 0.000000001

Definition at line 23 of file class.ilDclExpressionParser.php.

◆ SCIENTIFIC_NOTATION_UPPER

const ilDclExpressionParser::SCIENTIFIC_NOTATION_UPPER = 1000000000000

Definition at line 22 of file class.ilDclExpressionParser.php.


The documentation for this class was generated from the following file: