Completed
Push — master ( 9eb593...b26d1b )
by Dan
03:59
created

PluginTrait::getPluginMatcher()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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 getPriority(): int
57
    {
58
        return $this->get('priority');
59
    }
60
61
    public function getPrefix(): string
62
    {
63
        return $this->get('prefix');
64
    }
65
66
    public function handle(Message $message)
67
    {
68
        if (!$this->pluginMatch($message)) {
69
            return;
70
        }
71
72
        $this->methodMatch($message);
73
    }
74
75
    protected function pluginMatch(Message $message): bool
76
    {
77
        return $this->getPluginMatcher()->matches($message);
78
    }
79
80
    protected function getPluginMatcher() : PluginMatcher
81
    {
82
        return $this->pluginMatcher;
83
    }
84
85
    protected function methodMatch(Message $message)
86
    {
87
        foreach ($this->getMethodMatchers() as $methodMatcher) {
88
            /** @var MethodMatcher $methodMatcher */
89
            if ($matches = $methodMatcher->matches($message)) {
90
                $method = $methodMatcher->getMethod();
91
92
                $this->info("dispatching {$this->pluginId}:{$methodMatcher->getName()}:$method ".json_encode($matches));
93
94
                $this->dispatch($method, $message, $matches);
0 ignored issues
show
Bug introduced by
It seems like $matches defined by $methodMatcher->matches($message) on line 89 can also be of type boolean; however, Nopolabs\Yabot\Plugin\PluginTrait::dispatch() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
95
96
                if ($message->isHandled()) {
97
                    return;
98
                }
99
            }
100
        }
101
    }
102
103
    protected function getMethodMatchers() : array
104
    {
105
        return $this->methodMatchers;
106
    }
107
108
    protected function dispatch(string $method, Message $message, array $matches)
109
    {
110
        if (!method_exists($this, $method)) {
111
            $this->warning("{$this->pluginId} no method named: $method");
112
            return;
113
        }
114
115
        try {
116
117
            $this->$method($message, $matches);
118
119
        } catch (Throwable $throwable) {
120
            $errmsg = 'Exception in '.static::class.'::'.$method."\n"
121
                .$throwable->getMessage()."\n"
122
                .$throwable->getTraceAsString();
123
            $this->warning($errmsg);
124
        }
125
    }
126
127
    protected function overrideConfig(array $params)
128
    {
129
        $config = $this->canonicalConfig(array_merge($this->getConfig(), $params));
130
131
        $this->setConfig($config);
132
    }
133
134
    protected function setPluginId($pluginId)
135
    {
136
        $this->pluginId = $pluginId;
137
    }
138
139
    protected function getUsers()
140
    {
141
        return $this->get('users');
142
    }
143
144
    protected function getChannels()
145
    {
146
        return $this->get('channels');
147
    }
148
149
    /**
150
     * @return bool|null
151
     */
152
    protected function getIsBot()
153
    {
154
        return $this->get('isBot');
155
    }
156
157
    protected function getMatchers(): array
158
    {
159
        return $this->get('matchers');
160
    }
161
162
    protected function canonicalConfig(array $config): array
163
    {
164
        return [
165
            'priority' => $config['priority'] ?? PluginManager::DEFAULT_PRIORITY,
166
            'prefix' => ($config['prefix'] ?? '') ? $config['prefix'] : PluginManager::NO_PREFIX,
167
            'isBot' => $config['isBot'] ?? null,
168
            'channels' => $config['channels'] ?? array_filter([$config['channel'] ?? null]),
169
            'users' => $config['users'] ?? array_filter([$config['user'] ?? null]),
170
            'matchers' => $this->canonicalMatchers($config['matchers'] ?? []),
171
        ];
172
    }
173
174
    protected function canonicalMatchers(array $matchers): array
175
    {
176
        $expanded = [];
177
178
        foreach ($matchers as $name => $params) {
179
            $expanded[$name] = $this->canonicalMatcher($name, $params);
180
        }
181
182
        if (empty($expanded)) {
183
            $this->warning("{$this->pluginId} has no matchers");
184
        }
185
186
        return $expanded;
187
    }
188
189
    protected function canonicalMatcher(string $name, $params) : array
190
    {
191
        $params = is_array($params) ? $params : ['patterns' => [$params]];
192
193
        $method = $params['method'] ?? $name;
194
195
        if (!method_exists($this, $method)) {
196
            $this->warning("{$this->pluginId} no method named: $method");
197
        }
198
199
        return [
200
            'isBot' => $params['isBot'] ?? null,
201
            'channels' => $params['channels'] ?? array_filter([$params['channel'] ?? null]),
202
            'users' => $params['users'] ?? array_filter([$params['user'] ?? null]),
203
            'patterns' => $params['patterns'] ?? array_filter([$params['pattern'] ?? null]),
204
            'method' => $params['method'] ?? $name,
205
        ];
206
    }
207
208
    protected function buildMethodMatchers(array $matchers) : array
209
    {
210
        $methodMatchers = [];
211
212
        foreach ($matchers as $name => $params) {
213
            $methodMatchers[] = new MethodMatcher(
214
                $name,
215
                $params['isBot'],
216
                $params['channels'],
217
                $params['users'],
218
                $this->validPatterns($params['patterns'], $name),
219
                $params['method'],
220
                $this->getLog()
221
            );
222
        }
223
224
        return $methodMatchers;
225
    }
226
227
    protected function validPatterns(array $patterns, $name) : array
228
    {
229
        $valid = [];
230
        foreach ($patterns as $pattern) {
231
            if ($this->isValidRegExp($pattern, $name)) {
232
                $valid[] = $pattern;
233
            }
234
        }
235
        return $valid;
236
    }
237
238
    protected function isValidRegExp($pattern, $name) : bool
239
    {
240
        try {
241
            preg_match($pattern, '');
242
            return true;
243
        } catch (Throwable $e) {
244
            $this->warning("$name.pattern='$pattern' ".$e->getMessage());
245
            return false;
246
        }
247
    }
248
}