Completed
Pull Request — master (#470)
by Claus
01:34
created

MathViewHelper   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 88
rs 10
c 0
b 0
f 0
wmc 20
lcom 1
cbo 4

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A initializeArguments() 0 6 1
A matches() 0 4 2
A evaluate() 0 18 4
B evaluateOperation() 0 18 8
A resolveToNumericValue() 0 13 4
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\Rendering\RenderingContextInterface;
12
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
13
14
/**
15
 * Math Expression ViewHelper, seconds as expression type
16
 */
17
class MathViewHelper extends AbstractViewHelper implements ExpressionComponentInterface
18
{
19
    protected $parts = [];
20
21
    /**
22
     * Possible operators, sorted by likely frequency of use to make
23
     * the strpos() check work as fast as possible for the most common
24
     * use cases.
25
     *
26
     * @var string
27
     */
28
    protected static $operators = '+-*/%^';
29
30
    public function __construct(iterable $parts = [])
31
    {
32
        $this->parts = $parts;
33
    }
34
35
    protected function initializeArguments()
36
    {
37
        $this->registerArgument('a', 'mixed', 'Numeric first value to calculate', true);
38
        $this->registerArgument('b', 'mixed', 'Numeric first value to calculate', true);
39
        $this->registerArgument('operator', 'string', 'Operator to use, e.g. +, -, %', true);
40
    }
41
42
    public static function matches(array $parts): bool
43
    {
44
        return isset($parts[2]) && strpos(static::$operators, $parts[1]) !== false;
45
    }
46
47
    public function evaluate(RenderingContextInterface $renderingContext)
48
    {
49
        $arguments = $this->getArguments()->setRenderingContext($renderingContext)->getArrayCopy();
50
        $parts = empty($this->parts) ? [$arguments['a'], $arguments['operator'], $arguments['b']] : $this->parts;
51
        $variable = array_shift($parts);
52
        $result = $this->resolveToNumericValue($variable, $renderingContext);
53
        $operator = null;
54
        $operators = str_split(static::$operators);
55
        foreach ($parts as $part) {
56
            if (in_array($part, $operators, true)) {
57
                $operator = $part;
58
            } else {
59
                $part = $this->resolveToNumericValue($part, $renderingContext);
60
                $result = $this->evaluateOperation($result, $operator, $part);
61
            }
62
        }
63
        return $result + 0;
64
    }
65
66
    /**
67
     * @param integer|float $left
68
     * @param string $operator
69
     * @param integer|float $right
70
     * @return integer|float
71
     */
72
    protected function evaluateOperation($left, string $operator, $right)
73
    {
74
        switch ($operator) {
75
            case '%':
76
                return $left % $right;
77
            case '-':
78
                return $left - $right;
79
            case '*':
80
                return $left * $right;
81
            case '^':
82
                return pow($left, $right);
83
            case '/':
84
                return (integer) $right !== 0 ? $left / $right : 0;
85
            case '+':
86
            default:
87
                return $left + $right;
88
        }
89
    }
90
91
    protected function resolveToNumericValue($value, RenderingContextInterface $renderingContext)
92
    {
93
        if (is_object($value)) {
94
            if (!method_exists($value, '__toString')) {
95
                return 0;
96
            }
97
            $value = (string) $value;
98
        }
99
        if (!is_numeric($value)) {
100
            $value = $renderingContext->getVariableProvider()->get((string) $value);
101
        }
102
        return $value + 0;
103
    }
104
}
105