Completed
Push — master ( 021f1e...bdc39b )
by Marcel
01:57
created

BotMan::getCallable()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 6
nop 1
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 Psr\Container\ContainerInterface;
10
use BotMan\BotMan\Drivers\DriverManager;
11
use BotMan\BotMan\Traits\ProvidesStorage;
12
use BotMan\BotMan\Interfaces\UserInterface;
13
use BotMan\BotMan\Messages\Incoming\Answer;
14
use BotMan\BotMan\Traits\HandlesExceptions;
15
use BotMan\BotMan\Handlers\ExceptionHandler;
16
use BotMan\BotMan\Interfaces\CacheInterface;
17
use BotMan\BotMan\Messages\Attachments\File;
18
use BotMan\BotMan\Interfaces\DriverInterface;
19
use BotMan\BotMan\Messages\Attachments\Audio;
20
use BotMan\BotMan\Messages\Attachments\Image;
21
use BotMan\BotMan\Messages\Attachments\Video;
22
use BotMan\BotMan\Messages\Outgoing\Question;
23
use Psr\Container\NotFoundExceptionInterface;
24
use BotMan\BotMan\Interfaces\StorageInterface;
25
use BotMan\BotMan\Traits\HandlesConversations;
26
use Symfony\Component\HttpFoundation\Response;
27
use BotMan\BotMan\Commands\ConversationManager;
28
use BotMan\BotMan\Middleware\MiddlewareManager;
29
use BotMan\BotMan\Messages\Attachments\Location;
30
use BotMan\BotMan\Exceptions\Base\BotManException;
31
use BotMan\BotMan\Interfaces\DriverEventInterface;
32
use BotMan\BotMan\Messages\Incoming\IncomingMessage;
33
use BotMan\BotMan\Messages\Outgoing\OutgoingMessage;
34
use BotMan\BotMan\Interfaces\ExceptionHandlerInterface;
35
use BotMan\BotMan\Exceptions\Core\BadMethodCallException;
36
use BotMan\BotMan\Exceptions\Core\UnexpectedValueException;
37
use BotMan\BotMan\Messages\Conversations\InlineConversation;
38
39
/**
40
 * Class BotMan.
41
 */
42
class BotMan
43
{
44
    use ProvidesStorage,
45
        HandlesConversations,
46
        HandlesExceptions;
47
48
    /** @var \Illuminate\Support\Collection */
49
    protected $event;
50
51
    /** @var Command */
52
    protected $command;
53
54
    /** @var IncomingMessage */
55
    protected $message;
56
57
    /** @var OutgoingMessage|Question */
58
    protected $outgoingMessage;
59
60
    /** @var string */
61
    protected $driverName;
62
63
    /** @var array|null */
64
    protected $currentConversationData;
65
66
    /** @var ExceptionHandlerInterface */
67
    protected $exceptionHandler;
68
69
    /**
70
     * IncomingMessage service events.
71
     * @var array
72
     */
73
    protected $events = [];
74
75
    /**
76
     * The fallback message to use, if no match
77
     * could be heard.
78
     * @var callable|null
79
     */
80
    protected $fallbackMessage;
81
82
    /** @var array */
83
    protected $groupAttributes = [];
84
85
    /** @var array */
86
    protected $matches = [];
87
88
    /** @var DriverInterface */
89
    protected $driver;
90
91
    /** @var array */
92
    protected $config = [];
93
94
    /** @var MiddlewareManager */
95
    public $middleware;
96
97
    /** @var ConversationManager */
98
    protected $conversationManager;
99
100
    /** @var CacheInterface */
101
    private $cache;
102
103
    /** @var ContainerInterface */
104
    protected $container;
105
106
    /** @var StorageInterface */
107
    protected $storage;
108
109
    /** @var Matcher */
110
    protected $matcher;
111
112
    /** @var bool */
113
    protected $loadedConversation = false;
114
115
    /** @var bool */
116
    protected $firedDriverEvents = false;
117
118
    /** @var bool */
119
    protected $runsOnSocket = false;
120
121
    /**
122
     * BotMan constructor.
123
     * @param CacheInterface $cache
124
     * @param DriverInterface $driver
125
     * @param array $config
126
     * @param StorageInterface $storage
127
     */
128
    public function __construct(CacheInterface $cache, DriverInterface $driver, $config, StorageInterface $storage)
129
    {
130
        $this->cache = $cache;
131
        $this->message = new IncomingMessage('', '', '');
132
        $this->driver = $driver;
133
        $this->config = $config;
134
        $this->storage = $storage;
135
        $this->matcher = new Matcher();
136
        $this->middleware = new MiddlewareManager($this);
137
        $this->conversationManager = new ConversationManager();
138
        $this->exceptionHandler = new ExceptionHandler();
139
    }
140
141
    /**
142
     * Set a fallback message to use if no listener matches.
143
     *
144
     * @param callable $callback
145
     */
146
    public function fallback($callback)
147
    {
148
        $this->fallbackMessage = $callback;
149
    }
150
151
    /**
152
     * @param string $name The Driver name or class
153
     */
154
    public function loadDriver($name)
155
    {
156
        $this->driver = DriverManager::loadFromName($name, $this->config);
157
    }
158
159
    /**
160
     * @param DriverInterface $driver
161
     */
162
    public function setDriver(DriverInterface $driver)
163
    {
164
        $this->driver = $driver;
165
    }
166
167
    /**
168
     * @return DriverInterface
169
     */
170
    public function getDriver()
171
    {
172
        return $this->driver;
173
    }
174
175
    /**
176
     * @param ContainerInterface $container
177
     */
178
    public function setContainer(ContainerInterface $container)
179
    {
180
        $this->container = $container;
181
    }
182
183
    /**
184
     * Retrieve the chat message.
185
     *
186
     * @return array
187
     */
188
    public function getMessages()
189
    {
190
        return $this->getDriver()->getMessages();
191
    }
192
193
    /**
194
     * Retrieve the chat message that are sent from bots.
195
     *
196
     * @return array
197
     */
198
    public function getBotMessages()
199
    {
200
        return Collection::make($this->getDriver()->getMessages())->filter(function (IncomingMessage $message) {
201
            return $message->isFromBot();
202
        })->toArray();
203
    }
204
205
    /**
206
     * @return Answer
207
     */
208
    public function getConversationAnswer()
209
    {
210
        return $this->getDriver()->getConversationAnswer($this->message);
211
    }
212
213
    /**
214
     * @param bool $running
215
     * @return bool
216
     */
217
    public function runsOnSocket($running = null)
218
    {
219
        if (is_bool($running)) {
220
            $this->runsOnSocket = $running;
221
        }
222
223
        return $this->runsOnSocket;
224
    }
225
226
    /**
227
     * @return UserInterface
228
     */
229
    public function getUser()
230
    {
231
        if ($user = $this->cache->get('user_'.$this->driver->getName().'_'.$this->getMessage()->getSender())) {
232
            return $user;
233
        }
234
235
        $user = $this->getDriver()->getUser($this->getMessage());
236
        $this->cache->put('user_'.$this->driver->getName().'_'.$user->getId(), $user, $this->config['user_cache_time'] ?? 30);
237
238
        return $user;
239
    }
240
241
    /**
242
     * Get the parameter names for the route.
243
     *
244
     * @param $value
245
     * @return array
246
     */
247
    protected function compileParameterNames($value)
248
    {
249
        preg_match_all(Matcher::PARAM_NAME_REGEX, $value, $matches);
250
251
        return array_map(function ($m) {
252
            return trim($m, '?');
253
        }, $matches[1]);
254
    }
255
256
    /**
257
     * @param string $pattern the pattern to listen for
258
     * @param Closure|string $callback the callback to execute. Either a closure or a Class@method notation
259
     * @param string $in the channel type to listen to (either direct message or public channel)
260
     * @return Command
261
     */
262
    public function hears($pattern, $callback, $in = null)
263
    {
264
        $command = new Command($pattern, $callback, $in);
0 ignored issues
show
Bug introduced by
It seems like $callback defined by parameter $callback on line 262 can also be of type object<Closure>; however, BotMan\BotMan\Commands\Command::__construct() does only seem to accept object<BotMan\BotMan\Closure>|string, maybe add an additional type check?

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.

Loading history...
Bug introduced by
It seems like $in defined by parameter $in on line 262 can also be of type string; however, BotMan\BotMan\Commands\Command::__construct() does only seem to accept array|null, maybe add an additional type check?

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.

Loading history...
265
        $command->applyGroupAttributes($this->groupAttributes);
266
267
        $this->conversationManager->listenTo($command);
268
269
        return $command;
270
    }
271
272
    /**
273
     * Listen for messaging service events.
274
     *
275
     * @param string $name
276
     * @param Closure|string $callback
277
     */
278
    public function on($name, $callback)
279
    {
280
        $this->events[] = [
281
            'name' => $name,
282
            'callback' => $this->getCallable($callback),
283
        ];
284
    }
285
286
    /**
287
     * Listening for image files.
288
     *
289
     * @param $callback
290
     * @return Command
291
     */
292
    public function receivesImages($callback)
293
    {
294
        return $this->hears(Image::PATTERN, $callback);
295
    }
296
297
    /**
298
     * Listening for image files.
299
     *
300
     * @param $callback
301
     * @return Command
302
     */
303
    public function receivesVideos($callback)
304
    {
305
        return $this->hears(Video::PATTERN, $callback);
306
    }
307
308
    /**
309
     * Listening for audio files.
310
     *
311
     * @param $callback
312
     * @return Command
313
     */
314
    public function receivesAudio($callback)
315
    {
316
        return $this->hears(Audio::PATTERN, $callback);
317
    }
318
319
    /**
320
     * Listening for location attachment.
321
     *
322
     * @param $callback
323
     * @return Command
324
     */
325
    public function receivesLocation($callback)
326
    {
327
        return $this->hears(Location::PATTERN, $callback);
328
    }
329
330
    /**
331
     * Listening for files attachment.
332
     *
333
     * @param $callback
334
     * @return Command
335
     */
336
    public function receivesFiles($callback)
337
    {
338
        return $this->hears(File::PATTERN, $callback);
339
    }
340
341
    /**
342
     * Create a command group with shared attributes.
343
     *
344
     * @param  array $attributes
345
     * @param  \Closure $callback
346
     */
347
    public function group(array $attributes, Closure $callback)
348
    {
349
        $previousGroupAttributes = $this->groupAttributes;
350
        $this->groupAttributes = array_merge_recursive($previousGroupAttributes, $attributes);
351
352
        call_user_func($callback, $this);
353
354
        $this->groupAttributes = $previousGroupAttributes;
355
    }
356
357
    /**
358
     * Fire potential driver event callbacks.
359
     */
360
    protected function fireDriverEvents()
361
    {
362
        $driverEvent = $this->getDriver()->hasMatchingEvent();
363
        if ($driverEvent instanceof DriverEventInterface) {
364
            $this->firedDriverEvents = true;
365
366
            Collection::make($this->events)->filter(function ($event) use ($driverEvent) {
367
                return $driverEvent->getName() === $event['name'];
368
            })->each(function ($event) use ($driverEvent) {
369
                /**
370
                 * Load the message, so driver events can reply.
371
                 */
372
                $messages = $this->getDriver()->getMessages();
373
                if (isset($messages[0])) {
374
                    $this->message = $messages[0];
375
                }
376
377
                call_user_func_array($event['callback'], [$driverEvent->getPayload(), $this]);
378
            });
379
        }
380
    }
381
382
    /**
383
     * Try to match messages with the ones we should
384
     * listen to.
385
     */
386
    public function listen()
387
    {
388
        try {
389
            $this->verifyServices();
390
391
            $this->fireDriverEvents();
392
393
            if ($this->firedDriverEvents === false) {
394
                $this->loadActiveConversation();
395
396
                if ($this->loadedConversation === false) {
397
                    $this->callMatchingMessages();
398
                }
399
400
                /*
401
                 * If the driver has a  "messagesHandled" method, call it.
402
                 * This method can be used to trigger driver methods
403
                 * once the messages are handles.
404
                 */
405
                if (method_exists($this->getDriver(), 'messagesHandled')) {
406
                    $this->getDriver()->messagesHandled();
0 ignored issues
show
Bug introduced by
The method messagesHandled() does not seem to exist on object<BotMan\BotMan\Interfaces\DriverInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
407
                }
408
            }
409
410
            $this->firedDriverEvents = false;
411
            $this->message = new IncomingMessage('', '', '');
412
        } catch (\Throwable $e) {
413
            $this->exceptionHandler->handleException($e, $this);
414
        }
415
    }
416
417
    /**
418
     * Call matching message callbacks.
419
     */
420
    protected function callMatchingMessages()
421
    {
422
        $matchingMessages = $this->conversationManager->getMatchingMessages($this->getMessages(), $this->middleware, $this->getConversationAnswer(), $this->getDriver());
423
424
        foreach ($matchingMessages as $matchingMessage) {
425
            $this->command = $matchingMessage->getCommand();
426
            $callback = $this->command->getCallback();
427
428
            $callback = $this->getCallable($callback);
429
430
            // Set the message first, so it's available for middlewares
431
            $this->message = $matchingMessage->getMessage();
432
433
            $this->message = $this->middleware->applyMiddleware('heard', $matchingMessage->getMessage(), $this->command->getMiddleware());
434
            $parameterNames = $this->compileParameterNames($this->command->getPattern());
435
436
            $parameters = $matchingMessage->getMatches();
437
            if (count($parameterNames) !== count($parameters)) {
438
                $parameters = array_merge(
439
                    //First, all named parameters (eg. function ($a, $b, $c))
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
440
                    array_filter(
441
                        $parameters,
442
                        'is_string',
443
                        ARRAY_FILTER_USE_KEY
444
                    ),
445
                    //Then, all other unsorted parameters (regex non named results)
446
                    array_filter(
447
                        $parameters,
448
                        'is_integer',
449
                        ARRAY_FILTER_USE_KEY
450
                    )
451
                );
452
            }
453
454
            $this->matches = $parameters;
455
            array_unshift($parameters, $this);
456
457
            $parameters = $this->conversationManager->addDataParameters($this->message, $parameters);
458
459
            call_user_func_array($callback, $parameters);
460
        }
461
462
        if (empty($matchingMessages) && empty($this->getBotMessages()) && ! is_null($this->fallbackMessage)) {
463
            $this->callFallbackMessage();
464
        }
465
    }
466
467
    /**
468
     * Call the fallback method.
469
     */
470
    protected function callFallbackMessage()
471
    {
472
        $this->message = $this->getMessages()[0];
473
474
        $this->fallbackMessage = $this->getCallable($this->fallbackMessage);
475
476
        call_user_func($this->fallbackMessage, $this);
477
    }
478
479
    /**
480
     * Verify service webhook URLs.
481
     *
482
     * @return null|Response
483
     */
484
    protected function verifyServices()
485
    {
486
        return DriverManager::verifyServices($this->config);
487
    }
488
489
    /**
490
     * @param string|Question $message
491
     * @param string|array $recipients
492
     * @param DriverInterface|null $driver
493
     * @param array $additionalParameters
494
     * @return Response
495
     * @throws BotManException
496
     */
497
    public function say($message, $recipients, $driver = null, $additionalParameters = [])
498
    {
499
        if ($driver === null && $this->driver === null) {
500
            throw new BotManException('The current driver can\'t be NULL');
501
        }
502
503
        $previousDriver = $this->driver;
504
        $previousMessage = $this->message;
505
506
        if ($driver instanceof DriverInterface) {
507
            $this->setDriver($driver);
508
        } elseif (is_string($driver)) {
509
            $this->setDriver(DriverManager::loadFromName($driver, $this->config));
510
        }
511
512
        $recipients = is_array($recipients) ? $recipients : [$recipients];
513
514
        foreach ($recipients as $recipient) {
515
            $this->message = new IncomingMessage('', $recipient, '');
516
            $response = $this->reply($message, $additionalParameters);
517
        }
518
519
        $this->message = $previousMessage;
520
        $this->driver = $previousDriver;
521
522
        return $response;
0 ignored issues
show
Bug introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
523
    }
524
525
    /**
526
     * @param string|Question $question
527
     * @param array|Closure $next
528
     * @param array $additionalParameters
529
     * @param null|string $recipient
530
     * @param null|string $driver
531
     * @return Response
532
     */
533
    public function ask($question, $next, $additionalParameters = [], $recipient = null, $driver = null)
534
    {
535
        if (! is_null($recipient) && ! is_null($driver)) {
536
            if (is_string($driver)) {
537
                $driver = DriverManager::loadFromName($driver, $this->config);
538
            }
539
            $this->message = new IncomingMessage('', $recipient, '');
540
            $this->setDriver($driver);
541
        }
542
543
        $response = $this->reply($question, $additionalParameters);
544
        $this->storeConversation(new InlineConversation, $next, $question, $additionalParameters);
545
546
        return $response;
547
    }
548
549
    /**
550
     * @return $this
551
     */
552
    public function types()
553
    {
554
        $this->getDriver()->types($this->message);
555
556
        return $this;
557
    }
558
559
    /**
560
     * @param int $seconds Number of seconds to wait
561
     * @return $this
562
     */
563
    public function typesAndWaits($seconds)
564
    {
565
        $this->getDriver()->types($this->message);
566
        sleep($seconds);
567
568
        return $this;
569
    }
570
571
    /**
572
     * Low-level method to perform driver specific API requests.
573
     *
574
     * @param string $endpoint
575
     * @param array $additionalParameters
576
     * @return $this
577
     * @throws BadMethodCallException
578
     */
579
    public function sendRequest($endpoint, $additionalParameters = [])
580
    {
581
        $driver = $this->getDriver();
582
        if (method_exists($driver, 'sendRequest')) {
583
            return $driver->sendRequest($endpoint, $additionalParameters, $this->message);
584
        } else {
585
            throw new BadMethodCallException('The driver '.$this->getDriver()->getName().' does not support low level requests.');
586
        }
587
    }
588
589
    /**
590
     * @param string|Question $message
591
     * @param array $additionalParameters
592
     * @return mixed
593
     */
594
    public function reply($message, $additionalParameters = [])
595
    {
596
        $this->outgoingMessage = is_string($message) ? OutgoingMessage::create($message) : $message;
597
598
        return $this->sendPayload($this->getDriver()->buildServicePayload($this->outgoingMessage, $this->message, $additionalParameters));
0 ignored issues
show
Bug introduced by
It seems like $this->outgoingMessage can also be of type object<BotMan\BotMan\Mes...tgoing\OutgoingMessage>; however, BotMan\BotMan\Interfaces...::buildServicePayload() does only seem to accept string|object<BotMan\Bot...ages\Outgoing\Question>, 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...
599
    }
600
601
    /**
602
     * @param $payload
603
     * @return mixed
604
     */
605
    public function sendPayload($payload)
606
    {
607
        return $this->middleware->applyMiddleware('sending', $payload, [], function ($payload) {
608
            $this->outgoingMessage = null;
609
610
            return $this->getDriver()->sendPayload($payload);
611
        });
612
    }
613
614
    /**
615
     * Return a random message.
616
     * @param array $messages
617
     * @return $this
618
     */
619
    public function randomReply(array $messages)
620
    {
621
        return $this->reply($messages[array_rand($messages)]);
622
    }
623
624
    /**
625
     * Make an action for an invokable controller.
626
     *
627
     * @param string $action
628
     * @return string
629
     * @throws UnexpectedValueException
630
     */
631
    protected function makeInvokableAction($action)
632
    {
633
        if (! method_exists($action, '__invoke')) {
634
            throw new UnexpectedValueException(sprintf(
635
                'Invalid hears action: [%s]', $action
636
            ));
637
        }
638
639
        return $action.'@__invoke';
640
    }
641
642
    /**
643
     * @param $callback
644
     * @return array|string|Closure
645
     * @throws UnexpectedValueException
646
     * @throws NotFoundExceptionInterface
647
     */
648
    protected function getCallable($callback)
649
    {
650
        if ($callback instanceof Closure) {
651
            return $callback;
652
        }
653
654
        if (is_array($callback)) {
655
            return $callback;
656
        }
657
658
        if (strpos($callback, '@') === false) {
659
            $callback = $this->makeInvokableAction($callback);
660
        }
661
662
        list($class, $method) = explode('@', $callback);
663
664
        $command = $this->container ? $this->container->get($class) : new $class($this);
665
666
        return [$command, $method];
667
    }
668
669
    /**
670
     * @return array
671
     */
672
    public function getMatches()
673
    {
674
        return $this->matches;
675
    }
676
677
    /**
678
     * @return IncomingMessage
679
     */
680
    public function getMessage()
681
    {
682
        return $this->message;
683
    }
684
685
    /**
686
     * @return OutgoingMessage|Question
687
     */
688
    public function getOutgoingMessage()
689
    {
690
        return $this->outgoingMessage;
691
    }
692
693
    /**
694
     * @param string $name
695
     * @param array $arguments
696
     * @return mixed
697
     * @throws BadMethodCallException
698
     */
699
    public function __call($name, $arguments)
700
    {
701
        if (method_exists($this->getDriver(), $name)) {
702
            // Add the current message to the passed arguments
703
            $arguments[] = $this->getMessage();
704
            $arguments[] = $this;
705
706
            return call_user_func_array([$this->getDriver(), $name], $arguments);
707
        }
708
709
        throw new BadMethodCallException('Method ['.$name.'] does not exist.');
710
    }
711
712
    /**
713
     * Load driver on wakeup.
714
     */
715
    public function __wakeup()
716
    {
717
        $this->driver = DriverManager::loadFromName($this->driverName, $this->config);
718
    }
719
720
    /**
721
     * @return array
722
     */
723
    public function __sleep()
724
    {
725
        $this->driverName = $this->driver->getName();
726
727
        return [
728
            'event',
729
            'exceptionHandler',
730
            'driverName',
731
            'storage',
732
            'message',
733
            'cache',
734
            'matches',
735
            'matcher',
736
            'config',
737
            'middleware',
738
        ];
739
    }
740
}
741