This commit is contained in:
Yuri Kuznetsov
2021-04-21 13:57:18 +03:00
parent de410bf75f
commit 50db978fa2
20 changed files with 257 additions and 114 deletions

View File

@@ -65,11 +65,10 @@ class FieldValidationManager
* @param Entity $entity An entity.
* @param ?StdClass $data Raw request payload data.
* @param ?Params $params Validation additional parameters.
*
* @throws BadRequest If data is not valid.
*/
public function process(Entity $entity, ?StdClass $data = null, ?Params $params = null) : void
public function process(Entity $entity, ?StdClass $data = null, ?Params $params = null): void
{
$dataIsSet = $data !== null;
@@ -105,7 +104,7 @@ class FieldValidationManager
/**
* Check a specific field for a specific validation type.
*/
public function check(Entity $entity, string $field, string $type, ?StdClass $data = null) : bool
public function check(Entity $entity, string $field, string $type, ?StdClass $data = null): bool
{
if (!$data) {
$data = $data ?? (object) [];
@@ -139,7 +138,7 @@ class FieldValidationManager
return true;
}
private function processField(Entity $entity, string $field, Params $params, StdClass $data) : void
private function processField(Entity $entity, string $field, Params $params, StdClass $data): void
{
$entityType = $entity->getEntityType();
@@ -168,8 +167,12 @@ class FieldValidationManager
}
private function processFieldCheck(
string $entityType, string $type, Entity $entity, string $field, $validationValue
) : bool {
string $entityType,
string $type,
Entity $entity,
string $field,
$validationValue
): bool {
$checker = $this->getFieldTypeChecker($entityType, $field);
@@ -187,8 +190,12 @@ class FieldValidationManager
}
private function processFieldRawCheck(
string $entityType, string $type, StdClass $data, string $field, $validationValue
) : bool {
string $entityType,
string $type,
StdClass $data,
string $field,
$validationValue
): bool {
$checker = $this->getFieldTypeChecker($entityType, $field);
@@ -205,7 +212,7 @@ class FieldValidationManager
return $checker->$methodName($data, $field, $validationValue);
}
private function getFieldTypeChecker(string $entityType, string $field) : ?object
private function getFieldTypeChecker(string $entityType, string $field): ?object
{
$key = $entityType . '_' . $field;
@@ -216,7 +223,7 @@ class FieldValidationManager
return $this->checkerCache[$key];
}
private function loadFieldTypeChecker(string $entityType, string $field) : void
private function loadFieldTypeChecker(string $entityType, string $field): void
{
$key = $entityType . '_' . $field;
@@ -229,7 +236,7 @@ class FieldValidationManager
$this->checkerCache[$key] = $this->factory->create($entityType, $field);
}
private function isFieldSetInData(string $entityType, string $field, StdClass $data) : bool
private function isFieldSetInData(string $entityType, string $field, StdClass $data): bool
{
$attributeList = $this->fieldUtil->getActualAttributeList($entityType, $field);

View File

@@ -44,7 +44,7 @@ class Params
*
* @return array<string>
*/
public function getSkipFieldList() : array
public function getSkipFieldList(): array
{
return $this->skipFieldList;
}
@@ -54,7 +54,7 @@ class Params
*
* @return array<string>
*/
public function getTypeSkipFieldList(string $type) : array
public function getTypeSkipFieldList(string $type): array
{
return $this->typeSkipFieldListData[$type] ?? [];
}
@@ -64,7 +64,7 @@ class Params
*
* @param array<string> $list
*/
public function withSkipFieldList(array $list) : self
public function withSkipFieldList(array $list): self
{
$obj = clone $this;
@@ -78,7 +78,7 @@ class Params
*
* @param array<string> $list
*/
public function withTypeSkipFieldList(string $type, array $list) : self
public function withTypeSkipFieldList(string $type, array $list): self
{
$obj = clone $this;
@@ -90,7 +90,7 @@ class Params
/**
* Create an empty instance.
*/
public static function fromNothing() : self
public static function fromNothing(): self
{
return new self();
}

View File

@@ -53,7 +53,7 @@ class ValidatorFactory
/**
* Whether can be created.
*/
public function isCreatable(string $entityType, string $field) : bool
public function isCreatable(string $entityType, string $field): bool
{
return (bool) $this->getClassName($entityType, $field);
}
@@ -63,7 +63,7 @@ class ValidatorFactory
*
* @throws RuntimeException
*/
public function create(string $entityType, string $field) : object
public function create(string $entityType, string $field): object
{
$className = $this->getClassName($entityType, $field);
@@ -74,7 +74,7 @@ class ValidatorFactory
return $this->injectableFactory->create($className);
}
private function getClassName(string $entityType, string $field) : ?string
private function getClassName(string $entityType, string $field): ?string
{
$key = $entityType . '_' . $field;
@@ -85,7 +85,7 @@ class ValidatorFactory
return $this->classNameCache[$key];
}
private function getClassNameNoCache(string $entityType, string $field) : ?string
private function getClassNameNoCache(string $entityType, string $field): ?string
{
$className1 = $this->metadata
->get(['entityDefs', $entityType, 'fields', $field, 'validatorClassName']);

View File

@@ -34,5 +34,5 @@ interface Attachment
/**
* Get a source ID.
*/
public function getSourceId() : string;
public function getSourceId(): string;
}

View File

@@ -46,7 +46,7 @@ class AttachmentEntityWrapper implements Attachment
$this->attachment = $attachment;
}
public function getSourceId() : string
public function getSourceId(): string
{
return $this->attachment->getSourceId();
}

View File

@@ -48,7 +48,7 @@ class Factory
$this->injectableFactory = $injectableFactory;
}
public function create(string $name) : Storage
public function create(string $name): Storage
{
$className = $this->metadata->get(['app', 'fileStorage', 'implementationClassNameMap', $name]);

View File

@@ -37,5 +37,5 @@ interface Local
/**
* Get a local file path.
*/
public function getLocalFilePath(Attachment $attachment) : string;
public function getLocalFilePath(Attachment $attachment): string;
}

View File

@@ -56,7 +56,7 @@ class Manager
/**
* Whether a file exists in a storage.
*/
public function exists(AttachmentEntity $attachment) : bool
public function exists(AttachmentEntity $attachment): bool
{
$implementation = $this->getImplementation($attachment);
@@ -66,7 +66,7 @@ class Manager
/**
* Get a file size.
*/
public function getSize(AttachmentEntity $attachment) : int
public function getSize(AttachmentEntity $attachment): int
{
$implementation = $this->getImplementation($attachment);
@@ -76,7 +76,7 @@ class Manager
/**
* Get file contents.
*/
public function getContents(AttachmentEntity $attachment) : string
public function getContents(AttachmentEntity $attachment): string
{
$implementation = $this->getImplementation($attachment);
@@ -86,7 +86,7 @@ class Manager
/**
* Get a file contents stream.
*/
public function getStream(AttachmentEntity $attachment) : StreamInterface
public function getStream(AttachmentEntity $attachment): StreamInterface
{
$implementation = $this->getImplementation($attachment);
@@ -96,7 +96,7 @@ class Manager
/**
* Store file contents represented as a stream.
*/
public function putStream(AttachmentEntity $attachment, StreamInterface $stream) : void
public function putStream(AttachmentEntity $attachment, StreamInterface $stream): void
{
$implementation = $this->getImplementation($attachment);
@@ -106,7 +106,7 @@ class Manager
/**
* Store file contents.
*/
public function putContents(AttachmentEntity $attachment, string $contents) : void
public function putContents(AttachmentEntity $attachment, string $contents): void
{
$implementation = $this->getImplementation($attachment);
@@ -118,7 +118,7 @@ class Manager
/**
* Remove a file.
*/
public function unlink(AttachmentEntity $attachment) : void
public function unlink(AttachmentEntity $attachment): void
{
$implementation = $this->getImplementation($attachment);
@@ -128,7 +128,7 @@ class Manager
/**
* Whether an attachment storage is local.
*/
public function isLocal(AttachmentEntity $attachment) : bool
public function isLocal(AttachmentEntity $attachment): bool
{
$implementation = $this->getImplementation($attachment);
@@ -138,7 +138,7 @@ class Manager
/**
* Get a local file path. If a file is not stored locally, a temporary file will be created.
*/
public function getLocalFilePath(AttachmentEntity $attachment) : string
public function getLocalFilePath(AttachmentEntity $attachment): string
{
$implementation = $this->getImplementation($attachment);
@@ -160,12 +160,12 @@ class Manager
return $path;
}
private static function wrapAttachmentEntity(AttachmentEntity $attachment) : AttachmentEntityWrapper
private static function wrapAttachmentEntity(AttachmentEntity $attachment): AttachmentEntityWrapper
{
return new AttachmentEntityWrapper($attachment);
}
private function getImplementation(AttachmentEntity $attachment) : Storage
private function getImplementation(AttachmentEntity $attachment): Storage
{
$storage = $attachment->getStorage();

View File

@@ -39,25 +39,25 @@ interface Storage
/**
* Get file contents as a stream.
*/
public function getStream(Attachment $attachment) : StreamInterface;
public function getStream(Attachment $attachment): StreamInterface;
/**
* Store file contents.
*/
public function putStream(Attachment $attachment, StreamInterface $stream) : void;
public function putStream(Attachment $attachment, StreamInterface $stream): void;
/**
* Whether a file exists.
*/
public function exists(Attachment $attachment) : bool;
public function exists(Attachment $attachment): bool;
/**
* Delete a file.
*/
public function unlink(Attachment $attachment) : void;
public function unlink(Attachment $attachment): void;
/**
* Get a file size.
*/
public function getSize(Attachment $attachment) : int;
public function getSize(Attachment $attachment): int;
}

View File

@@ -80,29 +80,29 @@ class AwsS3 implements Storage
$this->filesystem = new Filesystem($adapter);
}
public function unlink(Attachment $attachment) : void
public function unlink(Attachment $attachment): void
{
$this->filesystem->delete($attachment->getSourceId());
}
public function exists(Attachment $attachment) : bool
public function exists(Attachment $attachment): bool
{
return $this->filesystem->fileExists($attachment->getSourceId());
}
public function getSize(Attachment $attachment) : int
public function getSize(Attachment $attachment): int
{
return $this->filesystem->fileSize($attachment->getSourceId());
}
public function getStream(Attachment $attachment) : StreamInterface
public function getStream(Attachment $attachment): StreamInterface
{
$resource = $this->filesystem->readStream($attachment->getSourceId());
return new Stream($resource);
}
public function putStream(Attachment $attachment, StreamInterface $stream) : void
public function putStream(Attachment $attachment, StreamInterface $stream): void
{
// League\Flysystem does not support StreamInterface.
// Need to pass a resource.

View File

@@ -50,21 +50,21 @@ class EspoUploadDir implements Storage, Local
$this->fileManager = $fileManager;
}
public function unlink(Attachment $attachment) : void
public function unlink(Attachment $attachment): void
{
$this->fileManager->unlink(
$this->getFilePath($attachment)
);
}
public function exists(Attachment $attachment) : bool
public function exists(Attachment $attachment): bool
{
$filePath = $this->getFilePath($attachment);
return $this->fileManager->isFile($filePath);
}
public function getSize(Attachment $attachment) : int
public function getSize(Attachment $attachment): int
{
$filePath = $this->getFilePath($attachment);
@@ -75,7 +75,7 @@ class EspoUploadDir implements Storage, Local
return filesize($filePath);
}
public function getStream(Attachment $attachment) : StreamInterface
public function getStream(Attachment $attachment): StreamInterface
{
$filePath = $this->getFilePath($attachment);
@@ -88,7 +88,7 @@ class EspoUploadDir implements Storage, Local
return new Stream($resouce);
}
public function putStream(Attachment $attachment, StreamInterface $stream) : void
public function putStream(Attachment $attachment, StreamInterface $stream): void
{
$filePath = $this->getFilePath($attachment);
@@ -101,7 +101,7 @@ class EspoUploadDir implements Storage, Local
}
}
public function getLocalFilePath(Attachment $attachment) : string
public function getLocalFilePath(Attachment $attachment): string
{
return $this->getFilePath($attachment);
}

View File

@@ -46,9 +46,11 @@ class Argument implements Evaluatable
/**
* Get an argument type (function name).
*/
public function getType() : ?string
public function getType(): ?string
{
if (!is_object($this->data)) return null;
if (!is_object($this->data)) {
return null;
}
return $this->data->type ?? null;
}
@@ -56,7 +58,7 @@ class Argument implements Evaluatable
/**
* Get a nested argument list.
*/
public function getArgumentList() : ArgumentList
public function getArgumentList(): ArgumentList
{
if (!is_object($this->data)) {
throw new Error("Can't get an argument list from a scalar value item.");
@@ -64,9 +66,11 @@ class Argument implements Evaluatable
if (!property_exists($this->data, 'value')) {
$argumentList = new ArgumentList([]);
} else if (is_array($this->data->value)) {
}
else if (is_array($this->data->value)) {
$argumentList = new ArgumentList($this->data->value);
} else {
}
else {
$argumentList = new ArgumentList([$this->data->value]);
}
@@ -75,6 +79,8 @@ class Argument implements Evaluatable
/**
* Get RAW data.
*
* @return mixed
*/
public function getData()
{

View File

@@ -29,10 +29,17 @@
namespace Espo\Core\Formula;
use BadMethodCallException;
use OutOfBoundsException;
use Iterator;
use Countable;
use ArrayAccess;
use SeekableIterator;
/**
* A list of function arguments.
*/
class ArgumentList implements Evaluatable, \Iterator, \Countable, \ArrayAccess, \SeekableIterator
class ArgumentList implements Evaluatable, Iterator, Countable, ArrayAccess, SeekableIterator
{
protected $dataList;
@@ -46,25 +53,30 @@ class ArgumentList implements Evaluatable, \Iterator, \Countable, \ArrayAccess,
private function getLastValidKey()
{
$keys = array_keys($this->dataList);
$i = end($keys);
while ($i > 0) {
if (array_key_exists($i, $this->dataList)) {
break;
}
$i--;
}
return $i;
}
public function rewind()
{
$this->position = 0;
while (!$this->valid() && $this->position <= $this->getLastValidKey()) {
$this->position ++;
}
}
protected function getArgumentByIndex(int $index) : Argument
private function getArgumentByIndex(int $index): Argument
{
return new Argument($this->dataList[$index]);
}
@@ -110,12 +122,12 @@ class ArgumentList implements Evaluatable, \Iterator, \Countable, \ArrayAccess,
public function offsetSet($offset, $value)
{
throw new \BadMethodCallException('Setting is not allowed.');
throw new BadMethodCallException('Setting is not allowed.');
}
public function offsetUnset($offset)
{
throw new \BadMethodCallException('Unsetting is not allowed.');
throw new BadMethodCallException('Unsetting is not allowed.');
}
public function count() : int
@@ -126,8 +138,9 @@ class ArgumentList implements Evaluatable, \Iterator, \Countable, \ArrayAccess,
public function seek($offset)
{
$this->position = $offset;
if (!$this->valid()) {
throw new \OutOfBoundsException("Invalid seek offset ($offset).");
throw new OutOfBoundsException("Invalid seek offset ($offset).");
}
}
}

View File

@@ -38,34 +38,45 @@ class AttributeFetcher
{
private $relatedEntitiesCacheMap = [];
/**
* @return mixed
*/
public function fetch(Entity $entity, string $attribute, bool $getFetchedAttribute = false)
{
if (strpos($attribute, '.') !== false) {
$arr = explode('.', $attribute);
$key = $this->buildKey($entity, $arr[0]);
if (!array_key_exists($key, $this->relatedEntitiesCacheMap)) {
$this->relatedEntitiesCacheMap[$key] = $entity->get($arr[0]);
}
$relatedEntity = $this->relatedEntitiesCacheMap[$key];
if ($relatedEntity && ($relatedEntity instanceof Entity) && count($arr) > 0) {
return $this->fetch($relatedEntity, $arr[1]);
}
return null;
}
$methodName = 'get';
if ($getFetchedAttribute) {
$methodName = 'getFetched';
}
if ($entity->getAttributeParam($attribute, 'isParentName') && $methodName == 'get') {
$relationName = $entity->getAttributeParam($attribute, 'relation');
if ($parent = $entity->get($relationName)) {
return $parent->get('name');
}
} else if ($entity->getAttributeParam($attribute, 'isLinkMultipleIdList') && $methodName == 'get') {
}
else if ($entity->getAttributeParam($attribute, 'isLinkMultipleIdList') && $methodName == 'get') {
$relationName = $entity->getAttributeParam($attribute, 'relation');
if (!$entity->has($attribute)) {
$entity->loadLinkMultipleField($relationName);
}
@@ -74,12 +85,12 @@ class AttributeFetcher
return $entity->$methodName($attribute);
}
public function resetRuntimeCache()
public function resetRuntimeCache(): void
{
$this->relatedEntitiesCacheMap = [];
}
protected function buildKey(Entity $entity, string $link) : string
private function buildKey(Entity $entity, string $link): string
{
return spl_object_hash($entity) . '-' . $link;
}

View File

@@ -61,9 +61,13 @@ class Evaluator
$this->functionClassNameMap = $functionClassNameMap;
$this->parser = new Parser();
$this->parsedHash = [];
}
/**
* @return mixed
*/
public function process(string $expression, ?Entity $entity = null, ?StdClass $variables = null)
{
$this->processor = new Processor(
@@ -79,7 +83,7 @@ class Evaluator
return $result;
}
private function getParsedExpression(string $expression) : Argument
private function getParsedExpression(string $expression): Argument
{
if (!array_key_exists($expression, $this->parsedHash)) {
$this->parsedHash[$expression] = $this->parser->parse($expression);

View File

@@ -59,19 +59,23 @@ class FunctionFactory
$this->classNameMap = $classNameMap;
}
public function create(string $name, ?Entity $entity = null, ?StdClass $variables = null)
public function create(string $name, ?Entity $entity = null, ?StdClass $variables = null): object
{
if ($this->classNameMap && array_key_exists($name, $this->classNameMap)) {
$className = $this->classNameMap[$name];
} else {
}
else {
$arr = explode('\\', $name);
foreach ($arr as $i => $part) {
if ($i < count($arr) - 1) {
$part = $part . 'Group';
}
$arr[$i] = ucfirst($part);
}
$typeName = implode('\\', $arr);
$className = 'Espo\\Core\\Formula\\Functions\\' . $typeName . 'Type';
}
@@ -87,7 +91,10 @@ class FunctionFactory
'attributeFetcher' => $this->attributeFetcher,
]);
if (property_exists($className, 'hasAttributeFetcher') || method_exists($className, 'setAttributeFetcher')) {
if (
property_exists($className, 'hasAttributeFetcher') ||
method_exists($className, 'setAttributeFetcher')
) {
$object->setAttributeFetcher($this->attributeFetcher);
}

View File

@@ -59,12 +59,12 @@ abstract class BaseFunction
protected $log;
protected function getVariables() : StdClass
protected function getVariables(): StdClass
{
return $this->variables;
}
protected function getEntity() : Entity
protected function getEntity(): Entity
{
if (!$this->entity) {
throw new NotPassedEntity('function: ' . $this->name);
@@ -74,7 +74,11 @@ abstract class BaseFunction
}
public function __construct(
string $name, Processor $processor, ?Entity $entity = null, ?StdClass $variables = null, ?Log $log = null
string $name,
Processor $processor,
?Entity $entity = null,
?StdClass $variables = null,
?Log $log = null
) {
$this->name = $name;
$this->processor = $processor;

View File

@@ -52,6 +52,8 @@ class Manager
/**
* Executes a script and returns its result.
*
* @return mixed
*/
public function run(string $script, ?Entity $entity = null, ?StdClass $variables = null)
{

View File

@@ -38,7 +38,7 @@ use StdClass;
*/
class Parser
{
protected $priorityList = [
private $priorityList = [
['='],
['||'],
['&&'],
@@ -47,7 +47,7 @@ class Parser
['*', '/', '%'],
];
protected $operatorMap = [
private $operatorMap = [
'=' => 'assign',
'||' => 'logical\\or',
'&&' => 'logical\\and',
@@ -64,12 +64,12 @@ class Parser
'<=' => 'comparison\\lessThanOrEquals',
];
public function parse(string $expression) : StdClass
public function parse(string $expression): StdClass
{
return $this->split($expression);
}
protected function applyOperator(string $operator, string $firstPart, string $secondPart) : StdClass
private function applyOperator(string $operator, string $firstPart, string $secondPart): StdClass
{
if ($operator === '=') {
if (strlen($firstPart)) {
@@ -97,6 +97,7 @@ class Parser
]
];
}
throw new SyntaxError("Bad operator usage.");
}
@@ -111,9 +112,13 @@ class Parser
];
}
protected function processStrings(
string &$string, string &$modifiedString, ?array &$splitterIndexList = null, bool $intoOneLine = false
) {
private function processStrings(
string &$string,
string &$modifiedString,
?array &$splitterIndexList = null,
bool $intoOneLine = false
): bool {
$isString = false;
$isSingleQuote = false;
$isComment = false;
@@ -153,12 +158,13 @@ class Parser
if ($isString) {
if ($string[$i] === '(' || $string[$i] === ')') {
$modifiedString[$i] = '_';
} else if (!$isStringStart) {
}
else if (!$isStringStart) {
$modifiedString[$i] = ' ';
}
} else {
}
else {
if (!$isLineComment && !$isComment) {
if (!$isComment) {
if ($i && $string[$i] === '/' && $string[$i - 1] === '/') {
$isLineComment = true;
@@ -174,6 +180,7 @@ class Parser
if ($string[$i] === '(') {
$braceCounter++;
}
if ($string[$i] === ')') {
$braceCounter--;
}
@@ -184,6 +191,7 @@ class Parser
$splitterIndexList[] = $i;
}
}
if ($intoOneLine) {
if ($string[$i] === "\r" || $string[$i] === "\n" || $string[$i] === "\t") {
$string[$i] = ' ';
@@ -209,7 +217,7 @@ class Parser
return $isString;
}
protected function split(string $expression) : StdClass
private function split(string $expression): StdClass
{
$expression = trim($expression);
@@ -237,24 +245,34 @@ class Parser
if ($modifiedExpression[$i] === '(') {
$braceCounter++;
}
if ($modifiedExpression[$i] === ')') {
$braceCounter--;
}
if ($braceCounter === 0 && $i < strlen($modifiedExpression) - 1) {
$hasExcessBraces = false;
}
if ($braceCounter === 0) {
$expressionOutOfBraceList[] = true;
} else {
$expressionOutOfBraceList[] = false;
}
}
if ($braceCounter !== 0) {
throw new SyntaxError('Incorrect round brackets in expression ' . $expression . '.');
}
if (strlen($expression) > 1 && $expression[0] === '(' && $expression[strlen($expression) - 1] === ')' && $hasExcessBraces) {
if (
strlen($expression) > 1 &&
$expression[0] === '(' &&
$expression[strlen($expression) - 1] === ')' &&
$hasExcessBraces
) {
$expression = substr($expression, 1, strlen($expression) - 2);
return $this->split($expression);
}
@@ -262,14 +280,25 @@ class Parser
if ($expression[strlen($expression) - 1] !== ';') {
$splitterIndexList[] = strlen($expression);
}
$parsedPartList = [];
for ($i = 0; $i < count($splitterIndexList); $i++) {
if ($i > 0) {
$previousSplitterIndex = $splitterIndexList[$i - 1] + 1;
} else {
}
else {
$previousSplitterIndex = 0;
}
$part = trim(substr($expression, $previousSplitterIndex, $splitterIndexList[$i] - $previousSplitterIndex));
$part = trim(
substr(
$expression,
$previousSplitterIndex,
$splitterIndexList[$i] - $previousSplitterIndex
)
);
$parsedPartList[] = $this->parse($part);
}
return (object) [
@@ -281,44 +310,62 @@ class Parser
$firstOperator = null;
$minIndex = null;
if ($expression === '') return (object) [
'type' => 'value',
'value' => null,
];
if ($expression === '') {
return (object) [
'type' => 'value',
'value' => null,
];
}
foreach ($this->priorityList as $operationList) {
foreach ($operationList as $operator) {
$startFrom = 1;
while (true) {
$index = strpos($expression, $operator, $startFrom);
if ($index === false) break;
if ($expressionOutOfBraceList[$index]) break;
if ($index === false) {
break;
}
if ($expressionOutOfBraceList[$index]) {
break;
}
$startFrom = $index + 1;
}
if ($index !== false) {
$possibleRightOperator = null;
if (strlen($operator) === 1) {
if ($index < strlen($expression) - 1) {
$possibleRightOperator = trim($operator . $expression[$index + 1]);
}
}
if (
$possibleRightOperator &&
$possibleRightOperator != $operator &&
!empty($this->operatorMap[$possibleRightOperator])
) continue;
) {
continue;
}
$possibleLeftOperator = null;
if (strlen($operator) === 1) {
if ($index > 0) {
$possibleLeftOperator = trim($expression[$index - 1] . $operator);
}
}
if (
$possibleLeftOperator &&
$possibleLeftOperator != $operator &&
!empty($this->operatorMap[$possibleLeftOperator])
) continue;
) {
continue;
}
$firstPart = substr($expression, 0, $index);
$secondPart = substr($expression, $index + strlen($operator));
@@ -326,6 +373,7 @@ class Parser
$modifiedFirstPart = $modifiedSecondPart = '';
$isString = $this->processStrings($firstPart, $modifiedFirstPart);
$this->processStrings($secondPart, $modifiedSecondPart);
if (
@@ -337,14 +385,18 @@ class Parser
) {
if ($minIndex === null) {
$minIndex = $index;
$firstOperator = $operator;
} else if ($index < $minIndex) {
}
else if ($index < $minIndex) {
$minIndex = $index;
$firstOperator = $operator;
}
}
}
}
if ($firstOperator) {
break;
}
@@ -358,7 +410,8 @@ class Parser
$secondPart = trim($secondPart);
return $this->applyOperator($firstOperator, $firstPart, $secondPart);
} else {
}
else {
$expression = trim($expression);
if ($expression[0] === '!') {
@@ -420,22 +473,25 @@ class Parser
if ($expression === 'true') {
return (object) [
'type' => 'value',
'value' => true
'value' => true,
];
} else if ($expression === 'false') {
}
else if ($expression === 'false') {
return (object) [
'type' => 'value',
'value' => false
'value' => false,
];
} else if ($expression === 'null') {
}
else if ($expression === 'null') {
return (object) [
'type' => 'value',
'value' => null
'value' => null,
];
}
if ($expression[strlen($expression) - 1] === ')') {
$firstOpeningBraceIndex = strpos($expression, '(');
if ($firstOpeningBraceIndex > 0) {
$functionName = trim(substr($expression, 0, $firstOpeningBraceIndex));
$functionContent = substr($expression, $firstOpeningBraceIndex + 1, -1);
@@ -443,13 +499,14 @@ class Parser
$argumentList = $this->parseArgumentListFromFunctionContent($functionContent);
$argumentSplitedList = [];
foreach ($argumentList as $argument) {
$argumentSplitedList[] = $this->split($argument);
}
return (object) [
'type' => $functionName,
'value' => $argumentSplitedList
'value' => $argumentSplitedList,
];
}
}
@@ -461,21 +518,28 @@ class Parser
}
}
protected function stripComments(string &$expression, string &$modifiedExpression)
private function stripComments(string &$expression, string &$modifiedExpression): void
{
$commentIndexStart = null;
for ($i = 0; $i < strlen($modifiedExpression); $i++) {
if (is_null($commentIndexStart)) {
if ($modifiedExpression[$i] === '/' && $i < strlen($modifiedExpression) - 1 && $modifiedExpression[$i + 1] === '/') {
if (
$modifiedExpression[$i] === '/' &&
$i < strlen($modifiedExpression) - 1 &&
$modifiedExpression[$i + 1] === '/'
) {
$commentIndexStart = $i;
}
} else {
}
else {
if ($modifiedExpression[$i] === "\n" || $i === strlen($modifiedExpression) - 1) {
for ($j = $commentIndexStart; $j <= $i; $j++) {
$modifiedExpression[$j] = ' ';
$expression[$j] = ' ';
}
$commentIndexStart = null;
}
}
@@ -486,19 +550,22 @@ class Parser
if ($modifiedExpression[$i] === '/' && $modifiedExpression[$i + 1] === '*') {
$commentIndexStart = $i;
}
} else {
}
else {
if ($modifiedExpression[$i] === '*' && $modifiedExpression[$i + 1] === '/') {
for ($j = $commentIndexStart; $j <= $i + 1; $j++) {
$modifiedExpression[$j] = ' ';
$expression[$j] = ' ';
}
$commentIndexStart = null;
}
}
}
}
protected function parseArgumentListFromFunctionContent(string $functionContent) : array
private function parseArgumentListFromFunctionContent(string $functionContent): array
{
$functionContent = trim($functionContent);
@@ -511,21 +578,25 @@ class Parser
$commaIndexList = [];
$braceCounter = 0;
for ($i = 0; $i < strlen($functionContent); $i++) {
if ($functionContent[$i] === "'" && ($i === 0 || $functionContent[$i - 1] !== "\\")) {
if (!$isString) {
$isString = true;
$isSingleQuote = true;
} else {
}
else {
if ($isSingleQuote) {
$isString = false;
}
}
} else if ($functionContent[$i] === "\"" && ($i === 0 || $functionContent[$i - 1] !== "\\")) {
}
else if ($functionContent[$i] === "\"" && ($i === 0 || $functionContent[$i - 1] !== "\\")) {
if (!$isString) {
$isString = true;
$isSingleQuote = false;
} else {
}
else {
if (!$isSingleQuote) {
$isString = false;
}
@@ -535,7 +606,8 @@ class Parser
if (!$isString) {
if ($functionContent[$i] === '(') {
$braceCounter++;
} else if ($functionContent[$i] === ')') {
}
else if ($functionContent[$i] === ')') {
$braceCounter--;
}
}
@@ -548,13 +620,23 @@ class Parser
$commaIndexList[] = strlen($functionContent);
$argumentList = [];
for ($i = 0; $i < count($commaIndexList); $i++) {
if ($i > 0) {
$previousCommaIndex = $commaIndexList[$i - 1] + 1;
} else {
}
else {
$previousCommaIndex = 0;
}
$argument = trim(substr($functionContent, $previousCommaIndex, $commaIndexList[$i] - $previousCommaIndex));
$argument = trim(
substr(
$functionContent,
$previousCommaIndex,
$commaIndexList[$i] - $previousCommaIndex
)
);
$argumentList[] = $argument;
}

View File

@@ -57,7 +57,12 @@ class Processor
?Entity $entity = null,
?StdClass $variables = null
) {
$this->functionFactory = new FunctionFactory($this, $injectableFactory, $attributeFetcher, $functionClassNameMap);
$this->functionFactory = new FunctionFactory(
$this,
$injectableFactory,
$attributeFetcher,
$functionClassNameMap
);
$this->entity = $entity;
$this->variables = $variables ?? (object) [];
@@ -88,12 +93,14 @@ class Processor
return $function->process($item->getArgumentList());
}
private function processList(ArgumentList $args) : array
private function processList(ArgumentList $args): array
{
$list = [];
foreach ($args as $item) {
$list[] = $this->process($item);
}
return $list;
}
}