Passed
Push — master ( ff3cde...45279d )
by Brian
02:44
created

Ussd::save()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
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 3
    public function entry(string $expression): self
44
    {
45 3
        if ($this->newSession) {
46 3
            $this->store->put('_exp', $expression);
47
        }
48
49 3
        return $this;
50
    }
51
52 1
    public function save(array $options): self
53
    {
54 1
        foreach ($options as $key => $value) {
55 1
            $this->store->put($key, $value);
56
        }
57
58 1
        return $this;
59
    }
60
61 9
    public function handle(?string $userInput = ''): string
62
    {
63 9
        $answer = $this->getAnswer($userInput);
64
65 9
        if ($this->newSession) {
66 7
            $inquiry = $this->doParse();
67
68 5
            if (! $answer) {
69 3
                return $inquiry;
70
            }
71
        }
72
73 4
        $answers = explode('*', $answer);
74
75 4
        foreach ($answers as $answer) {
76 4
            $inquiry = $this->doParse($answer);
77
        }
78
79 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...
80
    }
81
82 9
    protected function doParse(?string $answer = ''): ?string
83
    {
84 9
        $this->doProcess($answer);
85
86 9
        $exp = $this->store->get('_exp');
87 9
        $node = $this->xpath->query($exp)->item(0);
88
89 9
        if (! $node) {
90 1
            $this->doBreak();
91
        }
92
93 9
        $inquiry = $this->doRender();
94
95 7
        if (! $inquiry) {
96 1
            return $this->doParse($answer);
97
        }
98
99 7
        return $inquiry;
100
    }
101
102 9
    protected function doProcess(?string $answer): void
103
    {
104 9
        $pre = $this->store->get('_pre');
105
106 9
        if (! $pre) {
107 8
            return;
108
        }
109
110 4
        $preNode = $this->xpath->query($pre)->item(0);
111
112 4
        $tagName = $this->resolveTagName($preNode);
113 4
        $tag = $this->instantiateTag($tagName, [$preNode, $this->store]);
114
115 4
        if (! $tag instanceof AnswerableTag) {
116 2
            return;
117
        }
118
119 2
        $tag->process($answer);
120
    }
121
122 1
    protected function doBreak(): void
123
    {
124 1
        $exp = $this->store->get('_exp');
125
126 1
        $breakpoints = (array) json_decode((string) $this->store->get('_breakpoints'), true);
127
128 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...
129
            throw new \Exception('Missing tag');
130
        }
131
132 1
        $breakpoint = array_shift($breakpoints);
133 1
        $this->store->put('_exp', $breakpoint[$exp]);
134 1
        $this->store->put('_breakpoints', json_encode($breakpoints));
135
    }
136
137 9
    protected function doRender(): ?string
138
    {
139 9
        $exp = $this->store->get('_exp');
140
141 9
        $node = $this->xpath->query($exp)->item(0);
142
143 9
        $tagName = $this->resolveTagName($node);
144 9
        $tag = $this->instantiateTag($tagName, [$node, $this->store]);
145 8
        $inquiry = $tag->handle();
146
147 7
        $exp = $this->store->get('_exp');
148 7
        $breakpoints = (array) json_decode((string) $this->store->get('_breakpoints'), true);
149
150 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...
151
            $breakpoint = array_shift($breakpoints);
152
            $this->store->put('_exp', $breakpoint[$exp]);
153
            $this->store->put('_breakpoints', json_encode($breakpoints));
154
        }
155
156 7
        return $inquiry;
157
    }
158
}
159