Completed
Push — master ( df1a77...53322f )
by Dmitry
03:46
created

FormulaEngine::getContext()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
ccs 4
cts 4
cp 1
cc 2
eloc 4
nc 2
nop 0
crap 2
1
<?php
2
/**
3
 * PHP Billing Library
4
 *
5
 * @link      https://github.com/hiqdev/php-billing
6
 * @package   php-billing
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2017-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\php\billing\formula;
12
13
use hiqdev\php\billing\charge\ChargeModifier;
14
use hiqdev\php\billing\charge\modifiers\Discount;
15
use hiqdev\php\billing\charge\modifiers\Leasing;
16
use Hoa\Ruler\Context;
17
use Hoa\Ruler\Model;
18
use Hoa\Ruler\Ruler;
19
use Hoa\Visitor\Visit;
20
21
/**
22
 * @author Andrii Vasyliev <[email protected]>
23
 */
24
class FormulaEngine
25
{
26
    /**
27
     * @var Ruler
28
     */
29
    protected $ruler;
30
31
    /**
32
     * @var Visit|Asserter
33
     */
34
    protected $asserter;
35
36
    /**
37
     * @var Context
38
     */
39
    protected $context;
40
41
    /**
42
     * @var ChargeModifier
43
     */
44
    protected $discount;
45
46
    /**
47
     * @var ChargeModifier
48
     */
49
    protected $leasing;
50
51 14
    public function __construct()
52
    {
53 14
        if (!class_exists(Context::class)) {
54
            throw new \Exception('to use formula engine install `hoa/ruler`');
55
        }
56 14
    }
57
58
    /**
59
     * @param string $formula
60
     * @return ChargeModifier
61
     */
62 6
    public function build(string $formula): ChargeModifier
63
    {
64
        try {
65 6
            $model = $this->interpret($formula);
66 5
            $result = $this->getRuler()->assert($model, $this->getContext());
67 1
        } catch (FormulaEngineException $e) {
68 1
            throw $e;
69
        } catch (\Hoa\Ruler\Exception\Asserter $e) {
70
            throw FormulaRuntimeError::fromException($e, $formula);
71
        } catch (\Exception $exception) {
72
            throw FormulaRuntimeError::create($formula, 'Formula run failed');
73
        }
74
75 5
        if (!$result instanceof ChargeModifier) {
76 1
            throw FormulaRuntimeError::create($formula, 'Formula run returned unexpected result');
77
        }
78
79 4
        return $result;
80
    }
81
82
    /**
83
     * @param string $formula
84
     * @return Model\Model
85
     * @throws
86
     */
87 6
    public function interpret(string $formula): Model\Model
88
    {
89
        try {
90 6
            return $this->getRuler()->interpret($this->normalize($formula));
91 1
        } catch (\Hoa\Compiler\Exception\Exception $exception) {
92 1
            throw FormulaSyntaxError::fromException($exception, $formula);
93
        } catch (\Hoa\Ruler\Exception\Interpreter $exception) {
94
            throw FormulaSyntaxError::fromException($exception, $formula);
95
        } catch (\Throwable $exception) {
96
            throw FormulaSyntaxError::create($formula);
0 ignored issues
show
Bug introduced by
The call to create() misses a required argument $message.

This check looks for function calls that miss required arguments.

Loading history...
97
        }
98
    }
99
100 14
    public function normalize(string $formula): string
101
    {
102
        return implode(' AND ', array_filter(array_map(function ($value) {
103 14
            $value = trim($value);
104 14
            if (strlen($value) === 0) {
105 5
                return null;
106
            }
107
108 10
            return $value;
109 14
        }, explode("\n", $formula))));
110
    }
111
112
    /**
113
     * Validates $formula
114
     *
115
     * @param string $formula
116
     * @return null|string `null` when formula has no errors or string error message
117
     */
118 4
    public function validate(string $formula): ?string
119
    {
120
        try {
121 4
            $this->build($formula);
122
            return null;
123 2
        } catch (FormulaEngineException $e) {
124 2
            return $e->getMessage();
125 2
        }
126
    }
127
128
    public function getRuler(): Ruler
129 6
    {
130
        if ($this->ruler === null) {
131 6
            $this->ruler = new Ruler();
132 6
            $this->ruler->setAsserter($this->getAsserter());
133 6
        }
134
135
        return $this->ruler;
136 6
    }
137
138
    public function getAsserter(): Visit
139 6
    {
140
        if ($this->asserter === null) {
141 6
            $this->asserter = new Asserter();
142 6
        }
143
144
        return $this->asserter;
145 6
    }
146
147
    public function getContext(): Context
148 5
    {
149
        if ($this->context === null) {
150 5
            $this->context = $this->buildContext();
151 5
        }
152
153
        return $this->context;
154 5
    }
155
156
    protected function buildContext(): Context
157 5
    {
158
        $context = new Context();
159 5
        $context['discount'] = $this->getDiscount();
160 5
        $context['leasing'] = $this->getLeasing();
161 5
162
        return $context;
163 5
    }
164
165
    public function getDiscount(): ChargeModifier
166 5
    {
167
        if ($this->discount === null) {
168 5
            $this->discount = new Discount();
169 5
        }
170
171
        return $this->discount;
172 5
    }
173
174
    public function getLeasing(): ChargeModifier
175 5
    {
176
        if ($this->leasing === null) {
177 5
            $this->leasing = new Leasing();
178 5
        }
179
180
        return $this->leasing;
181 5
    }
182
}
183