Passed
Branch master (89ed0c)
by Brian
03:20
created

Parser   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Test Coverage

Coverage 93.1%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 56
c 1
b 0
f 0
dl 0
loc 121
ccs 54
cts 58
cp 0.931
rs 10
wmc 17

7 Methods

Rating   Name   Duplication   Size   Complexity  
A renderNext() 0 22 3
A parse() 0 19 3
A __construct() 0 8 1
A prepareCache() 0 16 3
A setBreakpoint() 0 15 3
A createTag() 0 7 2
A processResponse() 0 15 2
1
<?php
2
3
namespace Bmatovu\Ussd;
4
5
use Bmatovu\Ussd\Contracts\Tag;
6
use Illuminate\Contracts\Cache\Repository as CacheContract;
7
use Illuminate\Support\Facades\Log;
8
use Illuminate\Support\Str;
9
10
class Parser
11
{
12
    protected \DOMXPath $xpath;
13
    protected CacheContract $cache;
14
    protected string $prefix;
15
    protected int $ttl;
16
17 5
    public function __construct(\DOMXPath $xpath, string $exp, CacheContract $cache, string $prefix, string $session_id, ?int $ttl = null)
18
    {
19 5
        $this->xpath = $xpath;
20 5
        $this->cache = $cache;
21 5
        $this->prefix = $prefix;
22 5
        $this->ttl = $ttl;
23
24 5
        $this->prepareCache($session_id, $exp);
25
    }
26
27 5
    public function parse(?string $answer): string
28
    {
29 5
        $this->processResponse($answer);
30
31 5
        $exp = $this->cache->get("{$this->prefix}_exp");
32
33 5
        $node = $this->xpath->query($exp)->item(0);
34
35 5
        if (! $node) {
36 1
            $this->setBreakpoint();
37
        }
38
39 5
        $output = $this->renderNext();
40
41 3
        if (! $output) {
42 1
            return $this->parse($answer);
43
        }
44
45 3
        return $output;
46
    }
47
48 5
    protected function prepareCache(string $session_id, string $exp)
49
    {
50 5
        $preSessionId = $this->cache->get("{$this->prefix}_session_id");
51
52 5
        if ($preSessionId === $session_id) {
53 2
            return;
54
        }
55
56 3
        if ('' !== $preSessionId) {
57
            // $this->cache->tag($this->prefix)->flush();
58
        }
59
60 3
        $this->cache->put("{$this->prefix}_session_id", $session_id, $this->ttl);
61 3
        $this->cache->put("{$this->prefix}_pre", '', $this->ttl);
62 3
        $this->cache->put("{$this->prefix}_exp", $exp, $this->ttl);
63 3
        $this->cache->put("{$this->prefix}_breakpoints", '[]', $this->ttl);
64
    }
65
66 5
    protected function processResponse(?string $answer): void
67
    {
68 5
        $pre = $this->cache->get("{$this->prefix}_pre");
69
70 5
        if (! $pre) {
71 4
            return;
72
        }
73
74 2
        $preNode = $this->xpath->query($pre)->item(0);
75
76
        // Log::debug("Process  -->", ['tag' => $preNode->tagName, 'pre' => $pre]);
77
78 2
        $tagName = Str::studly($preNode->tagName);
79 2
        $tag = $this->createTag(__NAMESPACE__."\\Tags\\{$tagName}Tag", [$preNode, $this->cache, $this->prefix, $this->ttl]);
80 2
        $tag->process($answer);
81
    }
82
83 1
    protected function setBreakpoint(): void
84
    {
85
        // Log::debug("Error    -->", ['tag' => '', 'exp' => $exp]);
86
87 1
        $exp = $this->cache->get("{$this->prefix}_exp");
88
89 1
        $breakpoints = (array) json_decode((string) $this->cache->get("{$this->prefix}_breakpoints"), true);
90
91 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...
92
            throw new \Exception('Missing tag');
93
        }
94
95 1
        $breakpoint = array_shift($breakpoints);
96 1
        $this->cache->put("{$this->prefix}_exp", $breakpoint[$exp], $this->ttl);
97 1
        $this->cache->put("{$this->prefix}_breakpoints", json_encode($breakpoints), $this->ttl);
98
    }
99
100 5
    protected function renderNext(): ?string
101
    {
102
        // Log::debug("Handle   -->", ['tag' => $node->tagName, 'exp' => $exp]);
103
104 5
        $exp = $this->cache->get("{$this->prefix}_exp");
105
106 5
        $node = $this->xpath->query($exp)->item(0);
107
108 5
        $tagName = Str::studly($node->tagName);
109 5
        $tag = $this->createTag(__NAMESPACE__."\\Tags\\{$tagName}Tag", [$node, $this->cache, $this->prefix, $this->ttl]);
110 4
        $output = $tag->handle();
111
112 3
        $exp = $this->cache->get("{$this->prefix}_exp");
113 3
        $breakpoints = (array) json_decode((string) $this->cache->get("{$this->prefix}_breakpoints"), true);
114
115 3
        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...
116
            $breakpoint = array_shift($breakpoints);
117
            $this->cache->put("{$this->prefix}_exp", $breakpoint[$exp], $this->ttl);
118
            $this->cache->put("{$this->prefix}_breakpoints", json_encode($breakpoints), $this->ttl);
119
        }
120
121 3
        return $output;
122
    }
123
124 5
    protected function createTag(string $fqcn, array $args = []): Tag
125
    {
126 5
        if (! class_exists($fqcn)) {
127 1
            throw new \Exception("Missing class: {$fqcn}");
128
        }
129
130 4
        return \call_user_func_array([new \ReflectionClass($fqcn), 'newInstance'], $args);
131
    }
132
}
133