1 | <?php |
||
2 | |||
3 | namespace Bmatovu\Ussd; |
||
4 | |||
5 | use Bmatovu\Ussd\Contracts\AnswerableTag; |
||
6 | use Bmatovu\Ussd\Support\Util; |
||
7 | use Bmatovu\Ussd\Traits\Utilities; |
||
8 | use Illuminate\Container\Container; |
||
9 | use Illuminate\Contracts\Config\Repository as ConfigRepository; |
||
10 | use Illuminate\Support\Facades\App; |
||
11 | |||
12 | class Ussd |
||
13 | { |
||
14 | use Utilities; |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
15 | |||
16 | protected \DOMXPath $xpath; |
||
17 | protected string $sessionId; |
||
18 | protected Store $store; |
||
19 | protected bool $newSession = false; |
||
20 | |||
21 | /** |
||
22 | * @param \DOMXPath|string $menu |
||
23 | */ |
||
24 | 9 | public function __construct($menu, string $sessionId) |
|
25 | { |
||
26 | 9 | $this->xpath = $menu instanceof \DOMXPath ? $menu : $this->fileToXpath($menu); |
|
27 | |||
28 | 9 | $config = Container::getInstance()->make(ConfigRepository::class); |
|
29 | 9 | $store = $config->get('ussd.cache.store', 'file'); |
|
30 | 9 | $ttl = $config->get('ussd.cache.ttl', 120); |
|
31 | 9 | $this->store = new Store($store, $ttl, $sessionId); |
|
32 | |||
33 | 9 | App::setLocale($this->store->get('locale', 'en')); |
|
34 | |||
35 | 9 | if ($this->sessionExists($sessionId)) { |
|
36 | 2 | return; |
|
37 | } |
||
38 | |||
39 | 7 | $this->newSession = true; |
|
40 | 7 | $this->store->put('_session_id', $sessionId); |
|
41 | 7 | $this->store->put('_answer', ''); |
|
42 | 7 | $this->store->put('_pre', ''); |
|
43 | 7 | $this->store->put('_exp', '/menu/*[1]'); |
|
44 | 7 | $this->store->put('_breakpoints', '[]'); |
|
45 | } |
||
46 | |||
47 | /** |
||
48 | * @param \DOMXPath|string $menu |
||
49 | */ |
||
50 | 7 | public static function make($menu, string $sessionId): self |
|
51 | { |
||
52 | 7 | return new static($menu, $sessionId); |
|
53 | } |
||
54 | |||
55 | 1 | public static function new(...$args): self |
|
56 | { |
||
57 | 1 | return new static(...$args); |
|
58 | } |
||
59 | |||
60 | 3 | public function entry(string $expression): self |
|
61 | { |
||
62 | 3 | if ($this->newSession) { |
|
63 | 3 | $this->store->put('_exp', $expression); |
|
64 | } |
||
65 | |||
66 | 3 | return $this; |
|
67 | } |
||
68 | |||
69 | 1 | public function save(array $options): self |
|
70 | { |
||
71 | 1 | foreach ($options as $key => $value) { |
|
72 | 1 | $this->store->put($key, $value); |
|
73 | } |
||
74 | |||
75 | 1 | return $this; |
|
76 | } |
||
77 | |||
78 | 9 | public function handle(?string $userInput = ''): string |
|
79 | { |
||
80 | 9 | $answer = $this->getAnswer($userInput); |
|
81 | |||
82 | 9 | if ($this->newSession) { |
|
83 | 7 | $inquiry = $this->doParse(); |
|
84 | |||
85 | 5 | if (! $answer) { |
|
86 | 3 | return $inquiry; |
|
87 | } |
||
88 | } |
||
89 | |||
90 | 4 | $answers = explode('*', $answer); |
|
91 | |||
92 | 4 | foreach ($answers as $answer) { |
|
93 | 4 | $inquiry = $this->doParse($answer); |
|
94 | } |
||
95 | |||
96 | 3 | return $inquiry; |
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
97 | } |
||
98 | |||
99 | 9 | protected function doParse(?string $answer = ''): ?string |
|
100 | { |
||
101 | 9 | $this->doProcess($answer); |
|
102 | |||
103 | 9 | $exp = $this->store->get('_exp'); |
|
104 | 9 | $node = $this->xpath->query($exp)->item(0); |
|
105 | |||
106 | 9 | if (! $node) { |
|
107 | 1 | $this->doBreak(); |
|
108 | } |
||
109 | |||
110 | 9 | $inquiry = $this->doRender(); |
|
111 | |||
112 | 7 | if (! $inquiry) { |
|
113 | 1 | return $this->doParse($answer); |
|
114 | } |
||
115 | |||
116 | 7 | return $inquiry; |
|
117 | } |
||
118 | |||
119 | 9 | protected function doProcess(?string $answer): void |
|
120 | { |
||
121 | 9 | $pre = $this->store->get('_pre'); |
|
122 | |||
123 | 9 | if (! $pre) { |
|
124 | 8 | return; |
|
125 | } |
||
126 | |||
127 | 4 | $preNode = $this->xpath->query($pre)->item(0); |
|
128 | |||
129 | 4 | $tagName = $this->resolveTagName($preNode); |
|
130 | 4 | $tag = $this->instantiateTag($tagName, [$preNode, $this->store]); |
|
131 | |||
132 | 4 | if (! $tag instanceof AnswerableTag) { |
|
133 | 2 | return; |
|
134 | } |
||
135 | |||
136 | 2 | $tag->process($answer); |
|
137 | } |
||
138 | |||
139 | 1 | protected function doBreak(): void |
|
140 | { |
||
141 | 1 | $exp = $this->store->get('_exp'); |
|
142 | |||
143 | 1 | $breakpoints = (array) json_decode((string) $this->store->get('_breakpoints'), true); |
|
144 | |||
145 | 1 | if (! $breakpoints || ! isset($breakpoints[0][$exp])) { |
|
0 ignored issues
–
show
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 ![]() |
|||
146 | throw new \Exception(Util::hydrate($this->store, trans('MissingTag'))); |
||
147 | } |
||
148 | |||
149 | 1 | $breakpoint = array_shift($breakpoints); |
|
150 | 1 | $this->store->put('_exp', $breakpoint[$exp]); |
|
151 | 1 | $this->store->put('_breakpoints', json_encode($breakpoints)); |
|
152 | } |
||
153 | |||
154 | 9 | protected function doRender(): ?string |
|
155 | { |
||
156 | 9 | $exp = $this->store->get('_exp'); |
|
157 | |||
158 | 9 | $node = $this->xpath->query($exp)->item(0); |
|
159 | |||
160 | 9 | $tagName = $this->resolveTagName($node); |
|
161 | 9 | $tag = $this->instantiateTag($tagName, [$node, $this->store]); |
|
162 | 8 | $inquiry = $tag->handle(); |
|
163 | |||
164 | 7 | $exp = $this->store->get('_exp'); |
|
165 | 7 | $breakpoints = (array) json_decode((string) $this->store->get('_breakpoints'), true); |
|
166 | |||
167 | 7 | if ($breakpoints && isset($breakpoints[0][$exp])) { |
|
0 ignored issues
–
show
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 ![]() |
|||
168 | $breakpoint = array_shift($breakpoints); |
||
169 | $this->store->put('_exp', $breakpoint[$exp]); |
||
170 | $this->store->put('_breakpoints', json_encode($breakpoints)); |
||
171 | } |
||
172 | |||
173 | 7 | return $inquiry; |
|
174 | } |
||
175 | } |
||
176 |