Completed
Push — master ( 1b605f...95b7c3 )
by Dan
06:00
created

PluginTrait::buildMethodMatchers()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 20
nc 5
nop 1
1
<?php
2
3
namespace Nopolabs\Yabot\Plugin;
4
5
use Exception;
6
use Nopolabs\Yabot\Helpers\ConfigTrait;
7
use Nopolabs\Yabot\Helpers\LogTrait;
8
use Nopolabs\Yabot\Message\Message;
9
use Throwable;
10
11
trait PluginTrait
12
{
13
    use LogTrait;
14
    use ConfigTrait;
15
16
    private $pluginId;
17
18
    /** @var PluginMatcher */
19
    private $pluginMatcher;
20
21
    /** @var MethodMatcher[] */
22
    private $methodMatchers;
23
24
    public function help(): string
25
    {
26
        return $this->get('help', 'no help available');
27
    }
28
29
    public function status(): string
30
    {
31
        return 'running';
32
    }
33
34
    public function init(string $pluginId, array $params)
35
    {
36
        $this->pluginId = $pluginId;
37
        $this->overrideConfig($params);
38
        $this->methodMatchers = $this->buildMethodMatchers($this->get('matchers'));
39
        $this->pluginMatcher = new PluginMatcher($pluginId, $this->getIsBot(), $this->getChannels(), $this->getUsers(), $this->getLog());
40
41
        $this->info("inited $pluginId config:", $this->getConfig());
42
    }
43
44
    public function replaceInPatterns($search, $replace, array $matchers): array
45
    {
46
        $replaced = [];
47
        foreach ($matchers as $name => $params) {
48
            $params['patterns'] = array_map(function ($pattern) use ($search, $replace) {
49
                return str_replace($search, $replace, $pattern);
50
            }, $params['patterns']);
51
            $replaced[$name] = $params;
52
        }
53
        return $replaced;
54
    }
55
56
    public function getPrefix(): string
57
    {
58
        return $this->get('prefix');
59
    }
60
61
    public function handle(Message $message)
62
    {
63
        if (!$this->pluginMatch($message)) {
64
            return;
65
        }
66
67
        if ($matched = $this->methodMatch($message)) {
68
            list($method, $matches) = $matched;
69
70
            $this->dispatch($method, $message, $matches);
71
        }
72
    }
73
74
    protected function pluginMatch(Message $message): bool
75
    {
76
        return $this->pluginMatcher->matches($message);
77
    }
78
79
    protected function methodMatch(Message $message): array
80
    {
81
        foreach ($this->methodMatchers as $methodMatcher) {
82
            if (($matches = $methodMatcher->matches($message)) === false) {
83
                continue;
84
            }
85
86
            $method = $methodMatcher->getMethod();
87
88
            $this->info("{$this->pluginId}:{$methodMatcher->getName()}:$method matched");
89
90
            return [$method, $matches];
91
        }
92
93
        return [];
94
    }
95
96
    protected function dispatch(string $method, Message $message, array $matches)
97
    {
98
        try {
99
            if (method_exists($this, $method)) {
100
                $this->$method($message, $matches);
101
            } else {
102
                $this->warning("{$this->pluginId} no method named: $method");
103
            }
104
        } catch (Exception $e) {
105
            $this->warning('Exception in ' . static::class . '::' . $method);
106
            $this->warning($e->getMessage());
107
            $this->warning($e->getTraceAsString());
108
        }
109
    }
110
111
    protected function overrideConfig(array $params)
112
    {
113
        $config = $this->canonicalConfig(array_merge($this->getConfig(), $params));
114
115
        $this->setConfig($config);
116
    }
117
118
    protected function setPluginId($pluginId)
119
    {
120
        $this->pluginId = $pluginId;
121
    }
122
123
    protected function getUsers()
124
    {
125
        return $this->get('users');
126
    }
127
128
    protected function getChannels()
129
    {
130
        return $this->get('channels');
131
    }
132
133
    /**
134
     * @return bool|null
135
     */
136
    protected function getIsBot()
137
    {
138
        return $this->get('isBot');
139
    }
140
141
    protected function getMatchers(): array
142
    {
143
        return $this->get('matchers');
144
    }
145
146
    protected function canonicalConfig(array $config): array
147
    {
148
        $config['prefix'] = $config['prefix'] ?? '';
149
        $config['isBot'] = $config['isBot'] ?? null;
150
        $config['channels'] = $config['channels'] ?? array_filter([$config['channel'] ?? null]);
151
        $config['users'] = $config['users'] ?? array_filter([$config['user'] ?? null]);
152
        $config['matchers'] = $this->canonicalMatchers($config['matchers'] ?? []);
153
154
        return $config;
155
    }
156
157
    protected function canonicalMatchers(array $matchers): array
158
    {
159
        $expanded = [];
160
161
        foreach ($matchers as $name => $params) {
162
            $params = is_array($params) ? $params : ['patterns' => [$params]];
163
            if (isset($params['pattern'])) {
164
                $params['patterns'] = [$params['pattern']];
165
                unset($params['pattern']);
166
            }
167
            $params['isBot'] = $params['isBot'] ?? null;
168
            $params['channels'] = $params['channels'] ?? array_filter([$params['channel'] ?? null]);
169
            $params['users'] = $params['users'] ?? array_filter([$params['user'] ?? null]);
170
            $params['method'] = $params['method'] ?? $name;
171
172
            if (!method_exists($this, $params['method'])) {
173
                $this->warning("{$this->pluginId} no method named: {$params['method']}");
174
            }
175
176
            $expanded[$name] = $params;
177
        }
178
179
        if (!$expanded) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $expanded 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...
180
            $this->warning("{$this->pluginId} has no matchers");
181
        }
182
183
        return $expanded;
184
    }
185
186
    protected function buildMethodMatchers(array $matchers) : array
187
    {
188
        $methodMatchers = [];
189
190
        foreach ($matchers as $name => $params) {
191
            $patterns = [];
192
            foreach ($params['patterns'] as $pattern) {
193
                try {
194
                    preg_match($pattern, '', $matches);
195
                    $patterns[] = $pattern;
196
                } catch (Throwable $e) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
197
                    $this->warning("$name.pattern='$pattern' " . $e->getMessage());
198
                }
199
            }
200
            $params['patterns'] = $patterns;
201
202
            $methodMatchers[] = new MethodMatcher(
203
                $name,
204
                $params['isBot'],
205
                $params['channels'],
206
                $params['users'],
207
                $params['patterns'],
208
                $params['method'],
209
                $this->getLog()
210
            );
211
        }
212
213
        return $methodMatchers;
214
    }
215
}