Completed
Pull Request — master (#470)
by Claus
06:03
created

MathViewHelper::matches()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
namespace TYPO3Fluid\Fluid\ViewHelpers\Expression;
4
5
/*
6
 * This file belongs to the package "TYPO3 Fluid".
7
 * See LICENSE.txt that was shipped with this package.
8
 */
9
10
use TYPO3Fluid\Fluid\Component\ExpressionComponentInterface;
11
use TYPO3Fluid\Fluid\Core\Parser\Exception;
12
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
13
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
14
15
/**
16
 * Math Expression ViewHelper, seconds as expression type
17
 */
18
class MathViewHelper extends AbstractViewHelper implements ExpressionComponentInterface
19
{
20
    protected $parts = [];
21
22
    /**
23
     * Possible operators, sorted by likely frequency of use to make
24
     * the strpos() check work as fast as possible for the most common
25
     * use cases.
26
     *
27
     * @var string
28
     */
29
    protected static $operators = '+-*/%^';
30
31
    public function __construct(iterable $parts = [])
32
    {
33
        $this->parts = $parts;
34
    }
35
36
    protected function initializeArguments()
37
    {
38
        $this->registerArgument('a', 'mixed', 'Numeric first value to calculate', true);
39
        $this->registerArgument('b', 'mixed', 'Numeric first value to calculate', true);
40
        $this->registerArgument('operator', 'string', 'Operator to use, e.g. +, -, %', true);
41
    }
42
43
    public static function matches(array $parts): bool
44
    {
45
        return isset($parts[2]) && strpos(static::$operators, $parts[1]) !== false;
46
    }
47
48
    public function evaluate(RenderingContextInterface $renderingContext)
49
    {
50
        $arguments = $this->getArguments()->setRenderingContext($renderingContext)->getArrayCopy();
51
        $parts = empty($this->parts) ? [$arguments['a'], $arguments['operator'], $arguments['b']] : $this->parts;
52
        $variable = array_shift($parts);
53
        $result = $renderingContext->getVariableProvider()->get($variable) ?? $variable;
54
        $operator = null;
55
        $operators = str_split(static::$operators);
56
        foreach ($parts as $part) {
57
            if (in_array($part, $operators, true)) {
58
                $operator = $part;
59
            } else {
60
                $part = $renderingContext->getVariableProvider()->get($part) ?? $part;
61
62
                if (!is_string($operator)) {
63
                    throw new Exception(
64
                        sprintf(
65
                            'Invalid operator type (%s) given, it must be a valid string, e.g. "+" or "-"!',
66
                            gettype($operator)
67
                        ),
68
                        1561121432
69
                    );
70
                }
71
72
                $result = self::evaluateOperation($result, $operator, $part);
73
            }
74
        }
75
        return $result + 0;
76
    }
77
78
    /**
79
     * @param integer|float $left
80
     * @param string $operator
81
     * @param integer|float $right
82
     * @return integer|float
83
     */
84
    protected static function evaluateOperation($left, string $operator, $right)
85
    {
86
        if (!is_numeric($left)) {
87
            $left = 0;
88
        }
89
        if (!is_numeric($right)) {
90
            $right = 0;
91
        }
92
        if ($operator === '%') {
93
            return $left % $right;
94
        } elseif ($operator === '-') {
95
            return $left - $right;
96
        } elseif ($operator === '+') {
97
            return $left + $right;
98
        } elseif ($operator === '*') {
99
            return $left * $right;
100
        } elseif ($operator === '/') {
101
            return (integer) $right !== 0 ? $left / $right : 0;
102
        } elseif ($operator === '^') {
103
            return pow($left, $right);
104
        }
105
        return 0;
106
    }
107
}
108