These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace BotMan\BotMan; |
||
4 | |||
5 | use Closure; |
||
6 | use Illuminate\Support\Collection; |
||
7 | use BotMan\BotMan\Commands\Command; |
||
8 | use BotMan\BotMan\Messages\Matcher; |
||
9 | use BotMan\BotMan\Drivers\DriverManager; |
||
10 | use BotMan\BotMan\Traits\ProvidesStorage; |
||
11 | use BotMan\BotMan\Interfaces\UserInterface; |
||
12 | use BotMan\BotMan\Messages\Incoming\Answer; |
||
13 | use BotMan\BotMan\Traits\HandlesExceptions; |
||
14 | use BotMan\BotMan\Handlers\ExceptionHandler; |
||
15 | use BotMan\BotMan\Interfaces\CacheInterface; |
||
16 | use BotMan\BotMan\Messages\Attachments\File; |
||
17 | use BotMan\BotMan\Interfaces\DriverInterface; |
||
18 | use BotMan\BotMan\Messages\Attachments\Audio; |
||
19 | use BotMan\BotMan\Messages\Attachments\Image; |
||
20 | use BotMan\BotMan\Messages\Attachments\Video; |
||
21 | use BotMan\BotMan\Messages\Outgoing\Question; |
||
22 | use BotMan\BotMan\Interfaces\StorageInterface; |
||
23 | use BotMan\BotMan\Traits\HandlesConversations; |
||
24 | use Symfony\Component\HttpFoundation\Response; |
||
25 | use BotMan\BotMan\Commands\ConversationManager; |
||
26 | use BotMan\BotMan\Middleware\MiddlewareManager; |
||
27 | use BotMan\BotMan\Messages\Attachments\Location; |
||
28 | use BotMan\BotMan\Exceptions\Base\BotManException; |
||
29 | use BotMan\BotMan\Interfaces\DriverEventInterface; |
||
30 | use BotMan\BotMan\Messages\Incoming\IncomingMessage; |
||
31 | use BotMan\BotMan\Messages\Outgoing\OutgoingMessage; |
||
32 | use BotMan\BotMan\Interfaces\ExceptionHandlerInterface; |
||
33 | use BotMan\BotMan\Exceptions\Core\BadMethodCallException; |
||
34 | use BotMan\BotMan\Exceptions\Core\UnexpectedValueException; |
||
35 | use BotMan\BotMan\Messages\Conversations\InlineConversation; |
||
36 | |||
37 | /** |
||
38 | * Class BotMan. |
||
39 | */ |
||
40 | class BotMan |
||
41 | { |
||
42 | use ProvidesStorage, |
||
43 | HandlesConversations, |
||
44 | HandlesExceptions; |
||
45 | |||
46 | /** @var \Illuminate\Support\Collection */ |
||
47 | protected $event; |
||
48 | |||
49 | /** @var Command */ |
||
50 | protected $command; |
||
51 | |||
52 | /** @var IncomingMessage */ |
||
53 | protected $message; |
||
54 | |||
55 | /** @var OutgoingMessage|Question */ |
||
56 | protected $outgoingMessage; |
||
57 | |||
58 | /** @var string */ |
||
59 | protected $driverName; |
||
60 | |||
61 | /** @var array|null */ |
||
62 | protected $currentConversationData; |
||
63 | |||
64 | /** @var ExceptionHandlerInterface */ |
||
65 | protected $exceptionHandler; |
||
66 | |||
67 | /** |
||
68 | * IncomingMessage service events. |
||
69 | * @var array |
||
70 | */ |
||
71 | protected $events = []; |
||
72 | |||
73 | /** |
||
74 | * The fallback message to use, if no match |
||
75 | * could be heard. |
||
76 | * @var callable|null |
||
77 | */ |
||
78 | protected $fallbackMessage; |
||
79 | |||
80 | /** @var array */ |
||
81 | protected $groupAttributes = []; |
||
82 | |||
83 | /** @var array */ |
||
84 | protected $matches = []; |
||
85 | |||
86 | /** @var DriverInterface */ |
||
87 | protected $driver; |
||
88 | |||
89 | /** @var array */ |
||
90 | protected $config = []; |
||
91 | |||
92 | /** @var MiddlewareManager */ |
||
93 | public $middleware; |
||
94 | |||
95 | /** @var ConversationManager */ |
||
96 | protected $conversationManager; |
||
97 | |||
98 | /** @var CacheInterface */ |
||
99 | private $cache; |
||
100 | |||
101 | /** @var StorageInterface */ |
||
102 | protected $storage; |
||
103 | |||
104 | /** @var Matcher */ |
||
105 | protected $matcher; |
||
106 | |||
107 | /** @var bool */ |
||
108 | protected $loadedConversation = false; |
||
109 | |||
110 | /** @var bool */ |
||
111 | protected $firedDriverEvents = false; |
||
112 | |||
113 | /** @var bool */ |
||
114 | protected $runsOnSocket = false; |
||
115 | |||
116 | /** |
||
117 | * BotMan constructor. |
||
118 | * @param CacheInterface $cache |
||
119 | * @param DriverInterface $driver |
||
120 | * @param array $config |
||
121 | * @param StorageInterface $storage |
||
122 | */ |
||
123 | public function __construct(CacheInterface $cache, DriverInterface $driver, $config, StorageInterface $storage) |
||
124 | { |
||
125 | $this->cache = $cache; |
||
126 | $this->message = new IncomingMessage('', '', ''); |
||
127 | $this->driver = $driver; |
||
128 | $this->config = $config; |
||
129 | $this->storage = $storage; |
||
130 | $this->matcher = new Matcher(); |
||
131 | $this->middleware = new MiddlewareManager($this); |
||
132 | $this->conversationManager = new ConversationManager(); |
||
133 | $this->exceptionHandler = new ExceptionHandler(); |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * Set a fallback message to use if no listener matches. |
||
138 | * |
||
139 | * @param callable $callback |
||
140 | */ |
||
141 | public function fallback($callback) |
||
142 | { |
||
143 | $this->fallbackMessage = $callback; |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * @param string $name The Driver name or class |
||
148 | */ |
||
149 | public function loadDriver($name) |
||
150 | { |
||
151 | $this->driver = DriverManager::loadFromName($name, $this->config); |
||
152 | } |
||
153 | |||
154 | /** |
||
155 | * @param DriverInterface $driver |
||
156 | */ |
||
157 | public function setDriver(DriverInterface $driver) |
||
158 | { |
||
159 | $this->driver = $driver; |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * @return DriverInterface |
||
164 | */ |
||
165 | public function getDriver() |
||
166 | { |
||
167 | return $this->driver; |
||
168 | } |
||
169 | |||
170 | /** |
||
171 | * Retrieve the chat message. |
||
172 | * |
||
173 | * @return array |
||
174 | */ |
||
175 | public function getMessages() |
||
176 | { |
||
177 | return $this->getDriver()->getMessages(); |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Retrieve the chat message that are sent from bots. |
||
182 | * |
||
183 | * @return array |
||
184 | */ |
||
185 | public function getBotMessages() |
||
186 | { |
||
187 | return Collection::make($this->getDriver()->getMessages())->filter(function (IncomingMessage $message) { |
||
188 | return $message->isFromBot(); |
||
189 | })->toArray(); |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * @return Answer |
||
194 | */ |
||
195 | public function getConversationAnswer() |
||
196 | { |
||
197 | return $this->getDriver()->getConversationAnswer($this->message); |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * @param bool $running |
||
202 | * @return bool |
||
203 | */ |
||
204 | public function runsOnSocket($running = null) |
||
205 | { |
||
206 | if (is_bool($running)) { |
||
207 | $this->runsOnSocket = $running; |
||
208 | } |
||
209 | |||
210 | return $this->runsOnSocket; |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * @return UserInterface |
||
215 | */ |
||
216 | public function getUser() |
||
217 | { |
||
218 | if ($user = $this->cache->get('user_'.$this->driver->getName().'_'.$this->getMessage()->getSender())) { |
||
219 | return $user; |
||
220 | } |
||
221 | |||
222 | $user = $this->getDriver()->getUser($this->getMessage()); |
||
223 | $this->cache->put('user_'.$this->driver->getName().'_'.$user->getId(), $user, $this->config['user_cache_time'] ?? 30); |
||
224 | |||
225 | return $user; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * Get the parameter names for the route. |
||
230 | * |
||
231 | * @param $value |
||
232 | * @return array |
||
233 | */ |
||
234 | protected function compileParameterNames($value) |
||
235 | { |
||
236 | preg_match_all(Matcher::PARAM_NAME_REGEX, $value, $matches); |
||
237 | |||
238 | return array_map(function ($m) { |
||
239 | return trim($m, '?'); |
||
240 | }, $matches[1]); |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * @param string $pattern the pattern to listen for |
||
245 | * @param Closure|string $callback the callback to execute. Either a closure or a Class@method notation |
||
246 | * @param string $in the channel type to listen to (either direct message or public channel) |
||
247 | * @return Command |
||
248 | */ |
||
249 | public function hears($pattern, $callback, $in = null) |
||
250 | { |
||
251 | $command = new Command($pattern, $callback, $in); |
||
0 ignored issues
–
show
|
|||
252 | $command->applyGroupAttributes($this->groupAttributes); |
||
253 | |||
254 | $this->conversationManager->listenTo($command); |
||
255 | |||
256 | return $command; |
||
257 | } |
||
258 | |||
259 | /** |
||
260 | * Listen for messaging service events. |
||
261 | * |
||
262 | * @param string $name |
||
263 | * @param Closure|string $callback |
||
264 | */ |
||
265 | public function on($name, $callback) |
||
266 | { |
||
267 | $this->events[] = [ |
||
268 | 'name' => $name, |
||
269 | 'callback' => $this->getCallable($callback), |
||
270 | ]; |
||
271 | } |
||
272 | |||
273 | /** |
||
274 | * Listening for image files. |
||
275 | * |
||
276 | * @param $callback |
||
277 | * @return Command |
||
278 | */ |
||
279 | public function receivesImages($callback) |
||
280 | { |
||
281 | return $this->hears(Image::PATTERN, $callback); |
||
282 | } |
||
283 | |||
284 | /** |
||
285 | * Listening for image files. |
||
286 | * |
||
287 | * @param $callback |
||
288 | * @return Command |
||
289 | */ |
||
290 | public function receivesVideos($callback) |
||
291 | { |
||
292 | return $this->hears(Video::PATTERN, $callback); |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * Listening for audio files. |
||
297 | * |
||
298 | * @param $callback |
||
299 | * @return Command |
||
300 | */ |
||
301 | public function receivesAudio($callback) |
||
302 | { |
||
303 | return $this->hears(Audio::PATTERN, $callback); |
||
304 | } |
||
305 | |||
306 | /** |
||
307 | * Listening for location attachment. |
||
308 | * |
||
309 | * @param $callback |
||
310 | * @return Command |
||
311 | */ |
||
312 | public function receivesLocation($callback) |
||
313 | { |
||
314 | return $this->hears(Location::PATTERN, $callback); |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * Listening for files attachment. |
||
319 | * |
||
320 | * @param $callback |
||
321 | * @return Command |
||
322 | */ |
||
323 | public function receivesFiles($callback) |
||
324 | { |
||
325 | return $this->hears(File::PATTERN, $callback); |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * Create a command group with shared attributes. |
||
330 | * |
||
331 | * @param array $attributes |
||
332 | * @param \Closure $callback |
||
333 | */ |
||
334 | public function group(array $attributes, Closure $callback) |
||
335 | { |
||
336 | $previousGroupAttributes = $this->groupAttributes; |
||
337 | $this->groupAttributes = array_merge_recursive($previousGroupAttributes, $attributes); |
||
338 | |||
339 | call_user_func($callback, $this); |
||
340 | |||
341 | $this->groupAttributes = $previousGroupAttributes; |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * Fire potential driver event callbacks. |
||
346 | */ |
||
347 | protected function fireDriverEvents() |
||
348 | { |
||
349 | $driverEvent = $this->getDriver()->hasMatchingEvent(); |
||
350 | if ($driverEvent instanceof DriverEventInterface) { |
||
351 | $this->firedDriverEvents = true; |
||
352 | |||
353 | Collection::make($this->events)->filter(function ($event) use ($driverEvent) { |
||
354 | return $driverEvent->getName() === $event['name']; |
||
355 | })->each(function ($event) use ($driverEvent) { |
||
356 | /** |
||
357 | * Load the message, so driver events can reply. |
||
358 | */ |
||
359 | $messages = $this->getDriver()->getMessages(); |
||
360 | if (isset($messages[0])) { |
||
361 | $this->message = $messages[0]; |
||
362 | } |
||
363 | |||
364 | call_user_func_array($event['callback'], [$driverEvent->getPayload(), $this]); |
||
365 | }); |
||
366 | } |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * Try to match messages with the ones we should |
||
371 | * listen to. |
||
372 | */ |
||
373 | public function listen() |
||
374 | { |
||
375 | try { |
||
376 | $this->verifyServices(); |
||
377 | |||
378 | $this->fireDriverEvents(); |
||
379 | |||
380 | if ($this->firedDriverEvents === false) { |
||
381 | $this->loadActiveConversation(); |
||
382 | |||
383 | if ($this->loadedConversation === false) { |
||
384 | $this->callMatchingMessages(); |
||
385 | } |
||
386 | |||
387 | /* |
||
388 | * If the driver has a "messagesHandled" method, call it. |
||
389 | * This method can be used to trigger driver methods |
||
390 | * once the messages are handles. |
||
391 | */ |
||
392 | if (method_exists($this->getDriver(), 'messagesHandled')) { |
||
393 | $this->getDriver()->messagesHandled(); |
||
394 | } |
||
395 | } |
||
396 | |||
397 | $this->firedDriverEvents = false; |
||
398 | } catch (\Throwable $e) { |
||
399 | $this->exceptionHandler->handleException($e, $this); |
||
400 | } |
||
401 | } |
||
402 | |||
403 | /** |
||
404 | * Call matching message callbacks. |
||
405 | */ |
||
406 | protected function callMatchingMessages() |
||
407 | { |
||
408 | $matchingMessages = $this->conversationManager->getMatchingMessages($this->getMessages(), $this->middleware, $this->getConversationAnswer(), $this->getDriver()); |
||
409 | |||
410 | foreach ($matchingMessages as $matchingMessage) { |
||
411 | $this->command = $matchingMessage->getCommand(); |
||
412 | $callback = $this->command->getCallback(); |
||
413 | |||
414 | $callback = $this->getCallable($callback); |
||
415 | |||
416 | // Set the message first, so it's available for middlewares |
||
417 | $this->message = $matchingMessage->getMessage(); |
||
418 | |||
419 | $this->message = $this->middleware->applyMiddleware('heard', $matchingMessage->getMessage(), $this->command->getMiddleware()); |
||
420 | $parameterNames = $this->compileParameterNames($this->command->getPattern()); |
||
421 | |||
422 | $parameters = $matchingMessage->getMatches(); |
||
423 | if (count($parameterNames) !== count($parameters)) { |
||
424 | $parameters = array_merge( |
||
425 | //First, all named parameters (eg. function ($a, $b, $c)) |
||
426 | array_filter( |
||
427 | $parameters, |
||
428 | 'is_string', |
||
429 | ARRAY_FILTER_USE_KEY |
||
430 | ), |
||
431 | //Then, all other unsorted parameters (regex non named results) |
||
432 | array_filter( |
||
433 | $parameters, |
||
434 | 'is_integer', |
||
435 | ARRAY_FILTER_USE_KEY |
||
436 | ) |
||
437 | ); |
||
438 | } |
||
439 | |||
440 | $this->matches = $parameters; |
||
441 | array_unshift($parameters, $this); |
||
442 | |||
443 | $parameters = $this->conversationManager->addDataParameters($this->message, $parameters); |
||
444 | |||
445 | call_user_func_array($callback, $parameters); |
||
446 | } |
||
447 | |||
448 | if (empty($matchingMessages) && empty($this->getBotMessages()) && ! is_null($this->fallbackMessage)) { |
||
449 | $this->callFallbackMessage(); |
||
450 | } |
||
451 | } |
||
452 | |||
453 | /** |
||
454 | * Call the fallback method. |
||
455 | */ |
||
456 | protected function callFallbackMessage() |
||
457 | { |
||
458 | $this->message = $this->getMessages()[0]; |
||
459 | |||
460 | $this->fallbackMessage = $this->getCallable($this->fallbackMessage); |
||
461 | |||
462 | call_user_func($this->fallbackMessage, $this); |
||
463 | } |
||
464 | |||
465 | /** |
||
466 | * Verify service webhook URLs. |
||
467 | * |
||
468 | * @return null|Response |
||
469 | */ |
||
470 | protected function verifyServices() |
||
471 | { |
||
472 | return DriverManager::verifyServices($this->config); |
||
473 | } |
||
474 | |||
475 | /** |
||
476 | * @param string|Question $message |
||
477 | * @param string|array $recipients |
||
478 | * @param DriverInterface|null $driver |
||
479 | * @param array $additionalParameters |
||
480 | * @return Response |
||
481 | * @throws BotManException |
||
482 | */ |
||
483 | public function say($message, $recipients, $driver = null, $additionalParameters = []) |
||
484 | { |
||
485 | if ($driver === null && $this->driver === null) { |
||
486 | throw new BotManException('The current driver can\'t be NULL'); |
||
487 | } |
||
488 | |||
489 | $previousDriver = $this->driver; |
||
490 | $previousMessage = $this->message; |
||
491 | |||
492 | if ($driver instanceof DriverInterface) { |
||
493 | $this->setDriver($driver); |
||
494 | } elseif (is_string($driver)) { |
||
495 | $this->setDriver(DriverManager::loadFromName($driver, $this->config)); |
||
496 | } |
||
497 | |||
498 | $recipients = is_array($recipients) ? $recipients : [$recipients]; |
||
499 | |||
500 | foreach ($recipients as $recipient) { |
||
501 | $this->message = new IncomingMessage('', $recipient, ''); |
||
502 | $response = $this->reply($message, $additionalParameters); |
||
503 | } |
||
504 | |||
505 | $this->message = $previousMessage; |
||
506 | $this->driver = $previousDriver; |
||
507 | |||
508 | return $response; |
||
509 | } |
||
510 | |||
511 | /** |
||
512 | * @param string|Question $question |
||
513 | * @param array|Closure $next |
||
514 | * @param array $additionalParameters |
||
515 | * @param null|string $recipient |
||
516 | * @param null|string $driver |
||
517 | * @return Response |
||
518 | */ |
||
519 | public function ask($question, $next, $additionalParameters = [], $recipient = null, $driver = null) |
||
520 | { |
||
521 | if (! is_null($recipient) && ! is_null($driver)) { |
||
522 | if (is_string($driver)) { |
||
523 | $driver = DriverManager::loadFromName($driver, $this->config); |
||
524 | } |
||
525 | $this->message = new IncomingMessage('', $recipient, ''); |
||
526 | $this->setDriver($driver); |
||
527 | } |
||
528 | |||
529 | $response = $this->reply($question, $additionalParameters); |
||
530 | $this->storeConversation(new InlineConversation, $next, $question, $additionalParameters); |
||
531 | |||
532 | return $response; |
||
533 | } |
||
534 | |||
535 | /** |
||
536 | * @return $this |
||
537 | */ |
||
538 | public function types() |
||
539 | { |
||
540 | $this->getDriver()->types($this->message); |
||
541 | |||
542 | return $this; |
||
543 | } |
||
544 | |||
545 | /** |
||
546 | * @param int $seconds Number of seconds to wait |
||
547 | * @return $this |
||
548 | */ |
||
549 | public function typesAndWaits($seconds) |
||
550 | { |
||
551 | $this->getDriver()->types($this->message); |
||
552 | sleep($seconds); |
||
553 | |||
554 | return $this; |
||
555 | } |
||
556 | |||
557 | /** |
||
558 | * Low-level method to perform driver specific API requests. |
||
559 | * |
||
560 | * @param string $endpoint |
||
561 | * @param array $additionalParameters |
||
562 | * @return $this |
||
563 | * @throws BadMethodCallException |
||
564 | */ |
||
565 | public function sendRequest($endpoint, $additionalParameters = []) |
||
566 | { |
||
567 | $driver = $this->getDriver(); |
||
568 | if (method_exists($driver, 'sendRequest')) { |
||
569 | return $driver->sendRequest($endpoint, $additionalParameters, $this->message); |
||
570 | } else { |
||
571 | throw new BadMethodCallException('The driver '.$this->getDriver()->getName().' does not support low level requests.'); |
||
572 | } |
||
573 | } |
||
574 | |||
575 | /** |
||
576 | * @param string|Question $message |
||
577 | * @param array $additionalParameters |
||
578 | * @return mixed |
||
579 | */ |
||
580 | public function reply($message, $additionalParameters = []) |
||
581 | { |
||
582 | $this->outgoingMessage = is_string($message) ? OutgoingMessage::create($message) : $message; |
||
583 | |||
584 | return $this->sendPayload($this->getDriver()->buildServicePayload($this->outgoingMessage, $this->message, $additionalParameters)); |
||
585 | } |
||
586 | |||
587 | /** |
||
588 | * @param $payload |
||
589 | * @return mixed |
||
590 | */ |
||
591 | public function sendPayload($payload) |
||
592 | { |
||
593 | return $this->middleware->applyMiddleware('sending', $payload, [], function ($payload) { |
||
594 | $this->outgoingMessage = null; |
||
595 | |||
596 | return $this->getDriver()->sendPayload($payload); |
||
597 | }); |
||
598 | } |
||
599 | |||
600 | /** |
||
601 | * Return a random message. |
||
602 | * @param array $messages |
||
603 | * @return $this |
||
604 | */ |
||
605 | public function randomReply(array $messages) |
||
606 | { |
||
607 | return $this->reply($messages[array_rand($messages)]); |
||
608 | } |
||
609 | |||
610 | /** |
||
611 | * Make an action for an invokable controller. |
||
612 | * |
||
613 | * @param string $action |
||
614 | * @return string |
||
615 | * @throws UnexpectedValueException |
||
616 | */ |
||
617 | protected function makeInvokableAction($action) |
||
618 | { |
||
619 | if (! method_exists($action, '__invoke')) { |
||
620 | throw new UnexpectedValueException(sprintf( |
||
621 | 'Invalid hears action: [%s]', $action |
||
622 | )); |
||
623 | } |
||
624 | |||
625 | return $action.'@__invoke'; |
||
626 | } |
||
627 | |||
628 | /** |
||
629 | * @param $callback |
||
630 | * @return array|string|Closure |
||
631 | * @throws UnexpectedValueException |
||
632 | */ |
||
633 | protected function getCallable($callback) |
||
634 | { |
||
635 | if ($callback instanceof Closure) { |
||
636 | return $callback; |
||
637 | } |
||
638 | |||
639 | if (is_array($callback)) { |
||
640 | return $callback; |
||
641 | } |
||
642 | |||
643 | if (strpos($callback, '@') === false) { |
||
644 | $callback = $this->makeInvokableAction($callback); |
||
645 | } |
||
646 | |||
647 | list($class, $method) = explode('@', $callback); |
||
648 | |||
649 | return [new $class($this), $method]; |
||
650 | } |
||
651 | |||
652 | /** |
||
653 | * @return array |
||
654 | */ |
||
655 | public function getMatches() |
||
656 | { |
||
657 | return $this->matches; |
||
658 | } |
||
659 | |||
660 | /** |
||
661 | * @return IncomingMessage |
||
662 | */ |
||
663 | public function getMessage() |
||
664 | { |
||
665 | return $this->message; |
||
666 | } |
||
667 | |||
668 | /** |
||
669 | * @return OutgoingMessage|Question |
||
670 | */ |
||
671 | public function getOutgoingMessage() |
||
672 | { |
||
673 | return $this->outgoingMessage; |
||
674 | } |
||
675 | |||
676 | /** |
||
677 | * @param string $name |
||
678 | * @param array $arguments |
||
679 | * @return mixed |
||
680 | * @throws BadMethodCallException |
||
681 | */ |
||
682 | public function __call($name, $arguments) |
||
683 | { |
||
684 | if (method_exists($this->getDriver(), $name)) { |
||
685 | // Add the current message to the passed arguments |
||
686 | $arguments[] = $this->getMessage(); |
||
687 | $arguments[] = $this; |
||
688 | |||
689 | return call_user_func_array([$this->getDriver(), $name], $arguments); |
||
690 | } |
||
691 | |||
692 | throw new BadMethodCallException('Method ['.$name.'] does not exist.'); |
||
693 | } |
||
694 | |||
695 | /** |
||
696 | * Load driver on wakeup. |
||
697 | */ |
||
698 | public function __wakeup() |
||
699 | { |
||
700 | $this->driver = DriverManager::loadFromName($this->driverName, $this->config); |
||
701 | } |
||
702 | |||
703 | /** |
||
704 | * @return array |
||
705 | */ |
||
706 | public function __sleep() |
||
707 | { |
||
708 | $this->driverName = $this->driver->getName(); |
||
709 | |||
710 | return [ |
||
711 | 'event', |
||
712 | 'exceptionHandler', |
||
713 | 'driverName', |
||
714 | 'storage', |
||
715 | 'message', |
||
716 | 'cache', |
||
717 | 'matches', |
||
718 | 'matcher', |
||
719 | 'config', |
||
720 | 'middleware', |
||
721 | ]; |
||
722 | } |
||
723 | } |
||
724 |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.