diff --git a/application/Espo/Core/Formula/Functions/ArrayAppendType.php b/application/Espo/Core/Formula/Functions/ArrayAppendType.php new file mode 100644 index 0000000000..92abef6f75 --- /dev/null +++ b/application/Espo/Core/Formula/Functions/ArrayAppendType.php @@ -0,0 +1,66 @@ +. + * + * 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 "EspoCRM" word. + ************************************************************************/ + +namespace Espo\Core\Formula\Functions; + +use Espo\Core\Formula\ArgumentList; +use Espo\Core\Formula\Exceptions\Error; + +/** + * @noinspection PhpUnused + */ +class ArrayAppendType extends BaseFunction +{ + public function process(ArgumentList $args) + { + if (count($args) < 2) { + $this->throwTooFewArguments(); + } + + $name = $this->evaluate($args[0]); + + if (!is_string($name)) { + $this->throwBadArgumentValue(1, 'string'); + } + + $value = $this->evaluate($args[1]); + + if (!property_exists($this->getVariables(), $name)) { + throw new Error("Cannot array-append to not existing variable."); + } + + $array =& $this->getVariables()->$name; + + if (!is_array($array)) { + throw new Error("Cannot array-append to non-array variable."); + } + + $array[] = $value; + } +} diff --git a/application/Espo/Core/Formula/Parser.php b/application/Espo/Core/Formula/Parser.php index 8ac1bda4f2..484e2f9f9d 100644 --- a/application/Espo/Core/Formula/Parser.php +++ b/application/Espo/Core/Formula/Parser.php @@ -108,10 +108,25 @@ class Parser if ($firstPart[0] == '$') { $variable = substr($firstPart, 1); + $isArrayAppend = false; + + if (str_ends_with($firstPart, '[]')) { + $variable = substr($firstPart, 1, -2); + + $isArrayAppend = true; + } + if ($variable === '' || !preg_match($this->variableNameRegExp, $variable)) { throw new SyntaxError("Bad variable name `$variable`."); } + if ($isArrayAppend) { + return new Node('arrayAppend', [ + new Value($variable), + $this->split($secondPart) + ]); + } + return new Node('assign', [ new Value($variable), $this->split($secondPart) diff --git a/tests/unit/Espo/Core/Formula/EvaluatorTest.php b/tests/unit/Espo/Core/Formula/EvaluatorTest.php index 5fdb2700cd..eec7b03832 100644 --- a/tests/unit/Espo/Core/Formula/EvaluatorTest.php +++ b/tests/unit/Espo/Core/Formula/EvaluatorTest.php @@ -1690,4 +1690,45 @@ class EvaluatorTest extends TestCase $this->assertEquals(null, $result); } + + public function testArrayAppend1(): void + { + $expression = " + \$test = list(); + \$test[] = 'a'; + array\\at(\$test, 0); + "; + + /** @noinspection PhpUnhandledExceptionInspection */ + $result = $this->evaluator->process($expression); + + $this->assertEquals('a', $result); + } + + public function testArrayAppendError1(): void + { + $expression = " + \$test[] = 'a'; + array\\at(\$test, 0); + "; + + $this->expectException(Error::class); + + /** @noinspection PhpUnhandledExceptionInspection */ + $this->evaluator->process($expression); + } + + public function testArrayAppendError2(): void + { + $expression = " + \$test = ''; + \$test[] = 'a'; + array\\at(\$test, 0); + "; + + $this->expectException(Error::class); + + /** @noinspection PhpUnhandledExceptionInspection */ + $this->evaluator->process($expression); + } }