Edit file File name : FormulaCalculator.php Content :<?php /** * * SugarCRM Community Edition is a customer relationship management program developed by * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. * * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. * Copyright (C) 2011 - 2017 SalesAgility Ltd. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License version 3 as published by the * Free Software Foundation with the addition of the following permission added * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License along with * this program; if not, see http://www.gnu.org/licenses or write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. * * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License version 3. * * In accordance with Section 7(b) of the GNU Affero General Public License version 3, * these Appropriate Legal Notices must retain the display of the "Powered by * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not * reasonably feasible for technical reasons, the Appropriate Legal Notices must * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". */ /** * Class FormulaNode */ class FormulaNode { public $text; public $level; public $parent; public $children = array(); public $evaluatedValue; public function __construct($text, $level, $parent = null) { $this->text = $text; $this->level = $level; $this->parent = $parent; } public function addChild($childNode) { $this->children [] = $childNode; } public function isLeaf() { return count($this->children) === 0; } } /** * Class FormulaCalculator */ class FormulaCalculator { const startTerminal = "{"; const endTerminal = "}"; const parameterSeparatorTerminal = ";"; const configuratorName = "SweeterCalc"; private $parameters; private $relationParameters; private $currentModule; private $creatorUserId; private $configurator; private $debugEnabled; private $debugFileName; /** * FormulaCalculator constructor. * * @param $parameters * @param $relationParameters * @param $currentModule * @param $creatorUserId */ public function __construct($parameters, $relationParameters, $currentModule, $creatorUserId) { $this->parameters = $parameters; $this->relationParameters = $relationParameters; $this->currentModule = $currentModule; $this->creatorUserId = $creatorUserId; require_once 'modules/Configurator/Configurator.php'; $this->configurator = new Configurator(); $this->configurator->loadConfig(); $this->debugEnabled = $this->configurator->config[FormulaCalculator::configuratorName]['DebugEnabled'] == 1; $this->debugFileName = isset($this->configurator->config[FormulaCalculator::configuratorName]['DebugFileName']) ? $this->configurator->config[FormulaCalculator::configuratorName]['DebugFileName'] : 'SweeterCalc.log'; } /** * @param $formula * * @return mixed|string * @throws Exception */ public function calculateFormula($formula) { try { $currentEncoding = mb_internal_encoding(); mb_internal_encoding("UTF-8"); $this->log("--------------------------------------------------------------------------------------------------------"); $this->log("Evaluating expression: '$formula'."); $rootNode = $this->createTree($formula); $evaluated = $this->evaluateTreeLevel($rootNode); $this->log("Expression evaluated, value is: '$evaluated'."); $this->log("--------------------------------------------------------------------------------------------------------"); mb_internal_encoding($currentEncoding); return $evaluated; } catch (Exception $e) { $this->log('Exception: ' . $e->getMessage()); throw $e; } } /** * @param $content */ private function log($content) { if (!$this->debugEnabled) { return; } $currentContent = file_exists($this->debugFileName) ? file_get_contents($this->debugFileName) : ""; file_put_contents($this->debugFileName, $currentContent . "[" . date("Y-m-d H:i:s") . "] " . $content . "\n"); } /** * @param $content * * @return FormulaNode */ private function createTree($content) { $rootNode = new FormulaNode($content, 0); $this->findLexicalElementsOnLevel($content, 0, $rootNode); return $rootNode; } /** * @param $content * @param $level * @param $node */ private function findLexicalElementsOnLevel($content, $level, &$node) { $characters = preg_split('//u', $content, -1, PREG_SPLIT_NO_EMPTY); $terminalLevel = 0; $hasChild = false; $currentText = ""; for ($i = 0; $i < count($characters); $i++) { $char = $characters[$i]; if ($terminalLevel > 0) { $currentText .= $char; } if ($char === FormulaCalculator::startTerminal) { if ($terminalLevel == 0) { $currentText .= $char; } $terminalLevel++; } elseif ($char === FormulaCalculator::endTerminal) { $terminalLevel--; if ($terminalLevel == 0) { $newLevel = $level + 1; $newNode = new FormulaNode($currentText, $newLevel, $node); $node->addChild($newNode); $this->findLexicalElementsOnLevel(mb_substr($currentText, 1, -1), $newLevel, $newNode); $currentText = ""; $hasChild = true; } } } } /** * @param $node * * @return int|mixed|string */ private function evaluateTreeLevel(&$node) { if ($node->isLeaf()) { $node->evaluatedValue = $this->evaluateNode($node->text); $this->log("Node value: " . $node->evaluatedValue); $node->evaluatedValue = $this->evaluateLeaf($node->evaluatedValue); $this->log("Evaluating leaf: " . $node->text); $this->log("Leaf value: " . $node->evaluatedValue); return $node->evaluatedValue; } $childItems = array(); foreach ($node->children as $child) { $childItems [] = array( 'value' => $child->text, 'evaluatedValue' => $this->evaluateTreeLevel($child), ); } if ($node->level > 0) { $node->evaluatedValue = $this->evaluateNode($node->text, $childItems); $this->log("Node value: " . $node->evaluatedValue); } else { $evaluatedValue = $node->text; foreach ($childItems as $childItem) { $pos = strpos($evaluatedValue, $childItem['value']); if ($pos !== false) { $this->log("Going to replace child value '" . $childItem['value'] . "' in expression: " . $evaluatedValue); $evaluatedValue = substr_replace($evaluatedValue, $childItem['evaluatedValue'], $pos, strlen($childItem['value'])); $this->log("Replaced child value '" . $childItem['evaluatedValue'] . "'. New expression: " . $evaluatedValue); } } $node->evaluatedValue = $evaluatedValue; } return $node->evaluatedValue; } /** * @param $text * @param array $childItems * * @return string */ private function evaluateNode($text, $childItems = array()) { if (count($childItems) == 0) { $this->log("Evaluating node: " . $text . " with no children."); } else { $this->log("Evaluating node: " . $text . " with children: "); $this->logVardump($childItems); } // Logical functions if (($params = $this->evaluateFunctionParams("equal", $text, $childItems)) != null) { return $params[0] == $params[1] ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("notEqual", $text, $childItems)) != null) { return $params[0] != $params[1] ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("greaterThan", $text, $childItems)) != null) { return $params[0] > $params[1] ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("greaterThanOrEqual", $text, $childItems)) != null) { return $params[0] >= $params[1] ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("lessThan", $text, $childItems)) != null) { return $params[0] < $params[1] ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("lessThanOrEqual", $text, $childItems)) != null) { return $params[0] <= $params[1] ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("empty", $text, $childItems)) != null) { return $params[0] == "" ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("notEmpty", $text, $childItems)) != null) { return $params[0] != "" ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("not", $text, $childItems)) != null) { return $params[0] == "0" ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("and", $text, $childItems)) != null) { return ($params[0] && $params[1]) ? "1" : "0"; } if (($params = $this->evaluateFunctionParams("or", $text, $childItems)) != null) { return ($params[0] || $params[1]) ? "1" : "0"; } // Control functions if (($params = $this->evaluateFunctionParams("ifThenElse", $text, $childItems)) != null) { return $params[0] ? $params[1] : $params[2]; } // String functions if (($params = $this->evaluateFunctionParams("substring", $text, $childItems)) != null) { // Workaround for PHP < 5.4.8 if (isset($params[2])) { return mb_substr($params[0], intval($params[1]), intval($params[2])); } else { return mb_substr($params[0], intval($params[1])); } } if (($params = $this->evaluateFunctionParams("length", $text, $childItems)) != null) { return mb_strlen($params[0]); } if (($params = $this->evaluateFunctionParams("replace", $text, $childItems)) != null) { return str_replace($params[0], $params[1], $params[2]); } if (($params = $this->evaluateFunctionParams("position", $text, $childItems)) != null) { $pos = mb_strpos($params[0], $params[1]); return ($pos == false) ? -1 : $pos; } if (($params = $this->evaluateFunctionParams("lowercase", $text, $childItems)) != null) { return mb_strtolower($params[0]); } if (($params = $this->evaluateFunctionParams("uppercase", $text, $childItems)) != null) { return mb_strtoupper($params[0]); } // Mathematical calculations if (($params = $this->evaluateFunctionParams("add", $text, $childItems)) != null) { return $this->parseFloat($params[0]) + $this->parseFloat($params[1]); } if (($params = $this->evaluateFunctionParams("subtract", $text, $childItems)) != null) { return $this->parseFloat($params[0]) - $this->parseFloat($params[1]); } if (($params = $this->evaluateFunctionParams("multiply", $text, $childItems)) != null) { return $this->parseFloat($params[0]) * $this->parseFloat($params[1]); } if (($params = $this->evaluateFunctionParams("divide", $text, $childItems)) != null) { return $this->parseFloat($params[0]) / $this->parseFloat($params[1]); } if (($params = $this->evaluateFunctionParams("power", $text, $childItems)) != null) { return pow($this->parseFloat($params[0]), $this->parseFloat($params[1])); } if (($params = $this->evaluateFunctionParams("squareRoot", $text, $childItems)) != null) { return sqrt($this->parseFloat($params[0])); } if (($params = $this->evaluateFunctionParams("absolute", $text, $childItems)) != null) { return abs($this->parseFloat($params[0])); } // Date functions if (($params = $this->evaluateFunctionParams("now", $text, $childItems)) != null) { return date($params[0]); } if (($params = $this->evaluateFunctionParams("yesterday", $text, $childItems)) != null) { return date($params[0], time() - 60 * 60 * 24); } if (($params = $this->evaluateFunctionParams("tomorrow", $text, $childItems)) != null) { return date($params[0], time() + 60 * 60 * 24); } if (($params = $this->evaluateFunctionParams("date", $text, $childItems)) != null) { return date($params[0], strtotime($params[1])); } if (($params = $this->evaluateFunctionParams("datediff", $text, $childItems)) != null) { $d1 = new DateTime($params[0]); $d2 = new DateTime($params[1]); $diff = $d1->diff($d2); switch ($params[2]) { case 'years': return $diff->y; case 'months': return $diff->y * 12 + $diff->m; case 'days': return $diff->days; case 'hours': return $diff->days * 24 + $diff->h; case 'minutes': return ($diff->days * 24 + $diff->h) * 60 + $diff->i; case 'seconds': return (($diff->days * 24 + $diff->h) * 60 + $diff->i) * 60 + $diff->s; default: return $diff->days; } } if (($params = $this->evaluateFunctionParams("addYears", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'Y'); } if (($params = $this->evaluateFunctionParams("addMonths", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'M'); } if (($params = $this->evaluateFunctionParams("addDays", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'D'); } if (($params = $this->evaluateFunctionParams("addHours", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'H', true); } if (($params = $this->evaluateFunctionParams("addMinutes", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'M', true); } if (($params = $this->evaluateFunctionParams("addSeconds", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'S', true); } if (($params = $this->evaluateFunctionParams("subtractYears", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'Y', false, false); } if (($params = $this->evaluateFunctionParams("subtractMonths", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'M', false, false); } if (($params = $this->evaluateFunctionParams("subtractDays", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'D', false, false); } if (($params = $this->evaluateFunctionParams("subtractHours", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'H', true, false); } if (($params = $this->evaluateFunctionParams("subtractMinutes", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'M', true, false); } if (($params = $this->evaluateFunctionParams("subtractSeconds", $text, $childItems)) != null) { return $this->modifyDate($params[0], $params[1], $params[2], 'S', true, false); } return $text; } /** * @param $obj */ private function logVardump($obj) { if (!$this->debugEnabled) { return; } ob_start(); var_dump($obj); $str = ob_get_contents(); ob_end_clean(); $this->log($str); } /** * @param $functionName * @param $text * @param $childItems * * @return array|null */ private function evaluateFunctionParams($functionName, $text, $childItems) { if (!preg_match("/^\s*\{\s*$functionName\s*\(/i", $text)) { return null; } $this->log("Matched funcion name: " . $functionName); $params = $this->getFunctionParameters($functionName, $text, $childItems); $this->log("Resolved parameters for function '$functionName': "); $this->logVardump($params); return $params; } /** * @param $functionName * @param $text * @param $childItems * * @return array */ private function getFunctionParameters($functionName, $text, $childItems) { $parameters = $this->getParameterArray($functionName, $text); $resolvedParameters = array(); foreach ($parameters as $parameter) { $this->log("Resolving parameter '$parameter'"); $found = false; foreach ($childItems as $childItem) { if ($parameter == $childItem['value']) { $this->log("Replacing parameter '$parameter' with value '" . $childItem['evaluatedValue'] . "'"); $resolvedParameters [] = $childItem['evaluatedValue']; $found = true; break; } } if (!$found) { $paramText = $parameter; $replaced = false; $this->log("Single expression parameter not found, trying to parse multi expression parameter..."); foreach ($childItems as $childItem) { if (mb_strpos($paramText, $childItem['value']) !== false) { $this->log("Found multi expression part '" . $childItem['value'] . "' in parameter '$paramText'"); $this->log("Replacing parameter part '" . $childItem['value'] . "' with value '" . $childItem['evaluatedValue'] . "'"); $paramText = str_replace($childItem['value'], $childItem['evaluatedValue'], $paramText); $replaced = true; $this->log("New parameter value '$paramText'"); } } if (!$replaced) { $this->log("Did not found any multi expression part."); } $resolvedParameters [] = $paramText; } } return $resolvedParameters; } /** * @param $functionName * @param $text * * @return array */ private function getParameterArray($functionName, $text) { $this->log("Extracting parameters for function '$functionName' ..."); $parameterText = $this->getParameterText($functionName, $text); $characters = preg_split('//u', $parameterText, -1, PREG_SPLIT_NO_EMPTY); $terminalLevel = 0; $params = array(); $currentParam = ""; for ($i = 0; $i < count($characters); $i++) { $char = $characters[$i]; if ($char === FormulaCalculator::startTerminal) { $terminalLevel++; $currentParam .= $char; } else { if ($char === FormulaCalculator::endTerminal) { $terminalLevel--; $currentParam .= $char; } else { if ($char === FormulaCalculator::parameterSeparatorTerminal) { if ($terminalLevel == 0) { $params [] = $currentParam; $currentParam = ""; } else { $currentParam .= $char; } } else { $currentParam .= $char; } } } } $params [] = $currentParam; $trimmed = array_map('trim', $params); $this->log("Extracted parameters:"); $this->logVardump($params); return $trimmed; } /** * @param $functionName * @param $text * * @return string */ private function getParameterText($functionName, $text) { $parameterText = preg_replace("/^\s*\{\s*" . $functionName . "\s*\(\s*/", "", $text, 1); $parameterText = preg_replace("/\s*\)\s*\}\s*$/", "", $parameterText, 1); return trim($parameterText); } /** * @param $value * * @return float */ private function parseFloat($value) { return floatval(str_replace(",", ".", $value)); } /** * @param $format * @param $datestring * @param $ammount * @param $type * @param bool $isTime * @param bool $isAdd * * @return string */ private function modifyDate($format, $datestring, $ammount, $type, $isTime = false, $isAdd = true) { $prefix = $isTime ? 'PT' : 'P'; $datetime = new DateTime($datestring); if ($isAdd) { $datetime->add(new DateInterval($prefix . $ammount . $type)); } else { $datetime->sub(new DateInterval($prefix . $ammount . $type)); } return $datetime->format($format); } /** * @param $leaf * * @return int|mixed|string */ private function evaluateLeaf($leaf) { $evaluated = $leaf; if (preg_match("/{P[0-9]+}/i", $leaf)) { for ($i = 0; $i < count($this->parameters); $i++) { $evaluated = str_replace("{P$i}", $this->parameters[$i], $evaluated); $evaluated = str_replace("{p$i}", $this->parameters[$i], $evaluated); } } else { if (preg_match("/{R[0-9]+}/i", $leaf)) { for ($i = 0; $i < count($this->relationParameters); $i++) { $evaluated = str_replace("{R$i}", $this->relationParameters[$i], $evaluated); $evaluated = str_replace("{r$i}", $this->relationParameters[$i], $evaluated); } } } $evaluated = $this->replaceGlobalVariables($evaluated); return $evaluated; } /** * @param $text * * @return int|string */ private function replaceGlobalVariables($text) { $evaluated = $text; $evaluated = $this->replaceGlobalVariable('GlobalCounter', $evaluated); $evaluated = $this->replaceGlobalVariable('GlobalCounterPerUser', $evaluated); $evaluated = $this->replaceGlobalVariable('GlobalCounterPerModule', $evaluated); $evaluated = $this->replaceGlobalVariable('GlobalCounterPerUserPerModule', $evaluated); $evaluated = $this->replaceGlobalVariable('DailyCounter', $evaluated); $evaluated = $this->replaceGlobalVariable('DailyCounterPerUser', $evaluated); $evaluated = $this->replaceGlobalVariable('DailyCounterPerModule', $evaluated); $evaluated = $this->replaceGlobalVariable('DailyCounterPerUserPerModule', $evaluated); return $evaluated; } /** * @param $globalVariableType * @param $text * * @return int|string */ private function replaceGlobalVariable($globalVariableType, $text) { if (preg_match("/^\{$globalVariableType\(/i", $text)) { $parameters = $this->getParameterArray($globalVariableType, $text); $currentValue = $this->getGlobalVariableConfig($globalVariableType, $parameters[0]); $newValue = $currentValue + 1; $this->setGlobalVariableConfig($globalVariableType, $parameters[0], $newValue); return isset($parameters[1]) ? $this->formatCounter($newValue, $parameters[1]) : $newValue; } return $text; } /** * @param $globalVariableType * @param $parameterText * * @return int */ private function getGlobalVariableConfig($globalVariableType, $parameterText) { switch ($globalVariableType) { case 'GlobalCounter': return $this->configurator->config[FormulaCalculator::configuratorName]['GlobalCounter'][$parameterText]; case 'GlobalCounterPerUser': return $this->configurator->config[FormulaCalculator::configuratorName]['GlobalCounterPerUser'][$this->creatorUserId][$parameterText]; case 'GlobalCounterPerModule': return $this->configurator->config[FormulaCalculator::configuratorName]['GlobalCounterPerModule'][$this->currentModule][$parameterText]; case 'GlobalCounterPerUserPerModule': return $this->configurator->config[FormulaCalculator::configuratorName]['GlobalCounterPerUserPerModule'][$this->creatorUserId][$this->currentModule][$parameterText]; case 'DailyCounter': if ($this->configurator->config[FormulaCalculator::configuratorName]['DailyCounter'][$parameterText]['date'] === date('Y-m-d') ) { return $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounter'][$parameterText]['value']; } else { return 0; } case 'DailyCounterPerUser': if ($this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUser'][$this->creatorUserId][$parameterText]['date'] === date('Y-m-d') ) { return $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUser'][$this->creatorUserId][$parameterText]['value']; } else { return 0; } case 'DailyCounterPerModule': if ($this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUser'][$this->currentModule][$parameterText]['date'] === date('Y-m-d') ) { return $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUser'][$this->currentModule][$parameterText]['value']; } else { return 0; } case 'DailyCounterPerUserPerModule': if ($this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUserPerModule'][$this->creatorUserId][$this->currentModule][$parameterText]['date'] === date('Y-m-d') ) { return $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUserPerModule'][$this->creatorUserId][$this->currentModule][$parameterText]['value']; } else { return 0; } } } /** * @param $globalVariableType * @param $parameterText * @param $value */ private function setGlobalVariableConfig($globalVariableType, $parameterText, $value) { switch ($globalVariableType) { case 'GlobalCounter': $this->configurator->config[FormulaCalculator::configuratorName]['GlobalCounter'][$parameterText] = $value; break; case 'GlobalCounterPerUser': $this->configurator->config[FormulaCalculator::configuratorName]['GlobalCounterPerUser'][$this->creatorUserId][$parameterText] = $value; break; case 'GlobalCounterPerModule': $this->configurator->config[FormulaCalculator::configuratorName]['GlobalCounterPerModule'][$this->currentModule][$parameterText] = $value; break; case 'GlobalCounterPerUserPerModule': $this->configurator->config[FormulaCalculator::configuratorName]['GlobalCounterPerUserPerModule'][$this->creatorUserId][$this->currentModule][$parameterText] = $value; break; case 'DailyCounter': $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounter'][$parameterText]['date'] = date('Y-m-d'); $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounter'][$parameterText]['value'] = $value; break; case 'DailyCounterPerUser': $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUser'][$this->creatorUserId][$parameterText]['date'] = date('Y-m-d'); $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUser'][$this->creatorUserId][$parameterText]['value'] = $value; break; case 'DailyCounterPerModule': $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUser'][$this->currentModule][$parameterText]['date'] = date('Y-m-d'); $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUser'][$this->currentModule][$parameterText]['value'] = $value; break; case 'DailyCounterPerUserPerModule': $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUserPerModule'][$this->creatorUserId][$this->currentModule][$parameterText]['date'] = date('Y-m-d'); $this->configurator->config[FormulaCalculator::configuratorName]['DailyCounterPerUserPerModule'][$this->creatorUserId][$this->currentModule][$parameterText]['value'] = $value; break; } $this->configurator->saveConfig(); } /** * @param $value * @param $digits * * @return string */ private function formatCounter($value, $digits) { return sprintf("%0" . $digits . "d", $value); } }Save