Passed
Push — master ( b228e7...ac4a28 )
by Brian
03:12
created

Ussd::doProcess()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 18
ccs 10
cts 10
cp 1
rs 9.9666
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3
1
<?php
2
3
namespace Bmatovu\Ussd;
4
5
use Bmatovu\Ussd\Contracts\AnswerableTag;
6
use Bmatovu\Ussd\Traits\Utilities;
7
use Illuminate\Container\Container;
8
use Illuminate\Contracts\Config\Repository as ConfigRepository;
9
10
class Ussd
11
{
12
    use Utilities;
0 ignored issues
show
introduced by
The trait Bmatovu\Ussd\Traits\Utilities requires some properties which are not provided by Bmatovu\Ussd\Ussd: $tagName, $attributes, $nodeValue
Loading history...
13
14
    protected \DOMXPath $xpath;
15
    protected string $sessionId;
16
    protected Store $store;
17
    protected bool $newSession = false;
18
19
    /**
20
     * @param \DOMXPath|string $menu
21
     */
22 9
    public function __construct($menu, string $sessionId)
23
    {
24 9
        $this->xpath = $menu instanceof \DOMXPath ? $menu : $this->fileToXpath($menu);
25
26 9
        $config = Container::getInstance()->make(ConfigRepository::class);
27 9
        $store = $config->get('ussd.cache.store', 'file');
28 9
        $ttl = $config->get('ussd.cache.ttl', 120);
29 9
        $this->store = new Store($store, $ttl, $sessionId);
30
31 9
        if ($this->sessionExists($sessionId)) {
32 2
            return;
33
        }
34
35 7
        $this->newSession = true;
36 7
        $this->store->put('_session_id', $sessionId);
37 7
        $this->store->put('_answer', '');
38 7
        $this->store->put('_pre', '');
39 7
        $this->store->put('_exp', '/menu/*[1]');
40 7
        $this->store->put('_breakpoints', '[]');
41
    }
42
43
    /**
44
     * @param \DOMXPath|string $menu
45
     */
46 7
    public static function make($menu, string $sessionId): self
47
    {
48 7
        return new static($menu, $sessionId);
49
    }
50
51 1
    public static function new(...$args): self
52
    {
53 1
        return new static(...$args);
54
    }
55
56 3
    public function entry(string $expression): self
57
    {
58 3
        if ($this->newSession) {
59 3
            $this->store->put('_exp', $expression);
60
        }
61
62 3
        return $this;
63
    }
64
65 1
    public function save(array $options): self
66
    {
67 1
        foreach ($options as $key => $value) {
68 1
            $this->store->put($key, $value);
69
        }
70
71 1
        return $this;
72
    }
73
74 9
    public function handle(?string $userInput = ''): string
75
    {
76 9
        $answer = $this->getAnswer($userInput);
77
78 9
        if ($this->newSession) {
79 7
            $inquiry = $this->doParse();
80
81 5
            if (!$answer) {
82 3
                return $inquiry;
83
            }
84
        }
85
86 4
        $answers = explode('*', $answer);
87
88 4
        foreach ($answers as $answer) {
89 4
            $inquiry = $this->doParse($answer);
90
        }
91
92 3
        return $inquiry;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $inquiry does not seem to be defined for all execution paths leading up to this point.
Loading history...
93
    }
94
95 9
    protected function doParse(?string $answer = ''): ?string
96
    {
97 9
        $this->doProcess($answer);
98
99 9
        $exp = $this->store->get('_exp');
100 9
        $node = $this->xpath->query($exp)->item(0);
101
102 9
        if (!$node) {
103 1
            $this->doBreak();
104
        }
105
106 9
        $inquiry = $this->doRender();
107
108 7
        if (!$inquiry) {
109 1
            return $this->doParse($answer);
110
        }
111
112 7
        return $inquiry;
113
    }
114
115 9
    protected function doProcess(?string $answer): void
116
    {
117 9
        $pre = $this->store->get('_pre');
118
119 9
        if (!$pre) {
120 8
            return;
121
        }
122
123 4
        $preNode = $this->xpath->query($pre)->item(0);
124
125 4
        $tagName = $this->resolveTagName($preNode);
126 4
        $tag = $this->instantiateTag($tagName, [$preNode, $this->store]);
127
128 4
        if (!$tag instanceof AnswerableTag) {
129 2
            return;
130
        }
131
132 2
        $tag->process($answer);
133
    }
134
135 1
    protected function doBreak(): void
136
    {
137 1
        $exp = $this->store->get('_exp');
138
139 1
        $breakpoints = (array) json_decode((string) $this->store->get('_breakpoints'), true);
140
141 1
        if (!$breakpoints || !isset($breakpoints[0][$exp])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $breakpoints of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
142
            throw new \Exception('Missing tag');
143
        }
144
145 1
        $breakpoint = array_shift($breakpoints);
146 1
        $this->store->put('_exp', $breakpoint[$exp]);
147 1
        $this->store->put('_breakpoints', json_encode($breakpoints));
148
    }
149
150 9
    protected function doRender(): ?string
151
    {
152 9
        $exp = $this->store->get('_exp');
153
154 9
        $node = $this->xpath->query($exp)->item(0);
155
156 9
        $tagName = $this->resolveTagName($node);
157 9
        $tag = $this->instantiateTag($tagName, [$node, $this->store]);
158 8
        $inquiry = $tag->handle();
159
160 7
        $exp = $this->store->get('_exp');
161 7
        $breakpoints = (array) json_decode((string) $this->store->get('_breakpoints'), true);
162
163 7
        if ($breakpoints && isset($breakpoints[0][$exp])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $breakpoints of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
164
            $breakpoint = array_shift($breakpoints);
165
            $this->store->put('_exp', $breakpoint[$exp]);
166
            $this->store->put('_breakpoints', json_encode($breakpoints));
167
        }
168
169 7
        return $inquiry;
170
    }
171
}
172