Completed
Pull Request — master (#44)
by lan tian
02:25
created

Sms::content()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Toplan\PhpSms;
4
5
use SuperClosure\Serializer;
6
use Toplan\TaskBalance\Balancer;
7
8
/**
9
 * Class Sms
10
 */
11
class Sms
12
{
13
    /**
14
     * sms send task name
15
     */
16
    const TASK = 'PhpSms';
17
18
    /**
19
     * agents instance
20
     */
21
    protected static $agents = [];
22
23
    /**
24
     * agents`s name
25
     *
26
     * @var
27
     */
28
    protected static $agentsName = [];
29
30
    /**
31
     * agents`s config
32
     *
33
     * @var
34
     */
35
    protected static $agentsConfig = [];
36
37
    /**
38
     * whether to enable queue
39
     *
40
     * @var bool
41
     */
42
    protected static $enableQueue = false;
43
44
    /**
45
     * queue work
46
     *
47
     * @var \Closure
48
     */
49
    protected static $howToUseQueue = null;
50
51
    /**
52
     * sms already pushed to queue
53
     *
54
     * @var bool
55
     */
56
    protected $pushedToQueue = false;
57
58
    /**
59
     * hook handlers
60
     *
61
     * @var array
62
     */
63
    protected static $enableHooks = [
64
        'beforeRun',
65
        'beforeDriverRun',
66
        'afterDriverRun',
67
        'afterRun',
68
    ];
69
70
    /**
71
     * sms data
72
     *
73
     * @var array
74
     */
75
    protected $smsData = [
76
        'to'           => null,
77
        'templates'    => [],
78
        'content'      => '',
79
        'templateData' => [],
80
        'voiceCode'    => null,
81
    ];
82
83
    /**
84
     * first agent for send sms/voice verify
85
     *
86
     * @var string
87
     */
88
    protected $firstAgent = null;
89
90
    /**
91
     * a instance of class 'SuperClosure\Serializer'
92
     *
93
     * @var null
94 9
     */
95
    protected static $serializer = null;
96 9
97 9
    /**
98 9
     * store the static properties of Sms class when serialize a instance
99 9
     *
100
     * @var array
101
     */
102
    protected $_status_before_enqueue_ = [];
103
104
    /**
105
     * construct
106
     *
107
     * @param bool $autoBoot
108
     */
109 3
    public function __construct($autoBoot = true)
110
    {
111 3
        if ($autoBoot) {
112 3
            self::bootstrap();
113
        }
114 3
    }
115
116
    /**
117
     * create sms instance and set templates
118
     *
119
     * @param mixed $agentName
120
     * @param mixed $tempId
121
     *
122 3
     * @return Sms
123
     */
124
    public static function make($agentName = null, $tempId = null)
125
    {
126
        $sms = new self();
127
        if (is_array($agentName)) {
128
            $sms->template($agentName);
129
        } elseif ($agentName && is_string($agentName)) {
130
            if ($tempId === null) {
131
                $sms->content($agentName);
132 3
            } elseif (is_string("$tempId")) {
133
                $sms->template($agentName, $tempId);
134 3
            }
135 3
        }
136
137 3
        return $sms;
138
    }
139
140
    /**
141
     * send voice verify
142
     *
143
     * @param $code
144
     *
145
     * @return Sms
146
     */
147
    public static function voice($code)
148 3
    {
149
        $sms = new self();
150 3
        $sms->smsData['voiceCode'] = $code;
151 3
152
        return $sms;
153 3
    }
154 3
155 3
    /**
156 3
     * set how to use queue.
157 3
     *
158 3
     * @param $enable
159 3
     * @param $handler
160 3
     *
161
     * @return bool
162 3
     */
163
    public static function queue($enable = null, $handler = null)
164
    {
165
        if ($enable === null && $handler === null) {
166
            return self::$enableQueue;
167
        }
168
        if (is_callable($enable)) {
169
            $handler = $enable;
170
            $enable = true;
171
        }
172 6
        self::$enableQueue = (bool) $enable;
173
        if (is_callable($handler)) {
174 6
            self::$howToUseQueue = $handler;
0 ignored issues
show
Documentation Bug introduced by
It seems like $handler of type callable is incompatible with the declared type object<Closure> of property $howToUseQueue.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
175
        }
176 6
177
        return self::$enableQueue;
178
    }
179
180
    /**
181
     * set the mobile number
182
     *
183
     * @param $mobile
184
     *
185
     * @return $this
186 3
     */
187
    public function to($mobile)
188 3
    {
189
        $this->smsData['to'] = $mobile;
190 3
191
        return $this;
192
    }
193
194
    /**
195
     * set content for content sms
196
     *
197
     * @param $content
198
     *
199
     * @return $this
200
     */
201 3
    public function content($content)
202
    {
203 3
        $this->smsData['content'] = trim((string) $content);
204 3
205 3
        return $this;
206 3
    }
207 3
208 3
    /**
209
     * set template id for template sms
210
     *
211 3
     * @param $agentName
212 3
     * @param $tempId
213
     *
214 3
     * @return $this
215
     */
216
    public function template($agentName, $tempId = null)
217
    {
218
        if (is_array($agentName)) {
219
            foreach ($agentName as $k => $v) {
220
                $this->template($k, $v);
221
            }
222
        } elseif ($agentName && $tempId) {
223
            if (!isset($this->smsData['templates']) || !is_array($this->smsData['templates'])) {
224 3
                $this->smsData['templates'] = [];
225
            }
226 3
            $this->smsData['templates']["$agentName"] = $tempId;
227
        }
228 3
229
        return $this;
230
    }
231
232
    /**
233
     * set data for template sms
234
     *
235
     * @param array $data
236
     *
237
     * @return $this
238 3
     */
239
    public function data(array $data)
240 3
    {
241
        $this->smsData['templateData'] = $data;
242 3
243
        return $this;
244
    }
245
246
    /**
247
     * set the first agent
248
     *
249
     * @param $name
250
     *
251
     * @return $this
252 15
     */
253
    public function agent($name)
254 15
    {
255
        $this->firstAgent = (string) $name;
256
257
        return $this;
258 15
    }
259 12
260 12
    /**
261
     * start send
262
     *
263
     * @param bool $immediately
264
     *
265
     * @return mixed
266
     */
267 15
    public function send($immediately = false)
268 3
    {
269 3
        $this->validator();
270
271
        // if disable push to queue,
272
        // send the sms immediately.
273 15
        if (!self::$enableQueue) {
274 15
            $immediately = true;
275 15
        }
276 15
277 15
        // whatever 'PhpSms' whether to enable or disable push to queue,
278 15
        // if you are already pushed sms instance to queue,
279 3
        // you can recall the method `send()` in queue job without `true` parameter.
280
        //
281
        // So this mechanism in order to make you convenient use the method `send()` in queue system.
282 15
        if ($this->pushedToQueue) {
283
            $immediately = true;
284
        }
285
286
        // whether to send sms immediately,
287
        // or push it to queue.
288
        if ($immediately) {
289
            $result = Balancer::run(self::TASK, [
290
                'data'   => $this->getData(),
291
                'driver' => $this->firstAgent,
292 3
            ]);
293
        } else {
294 3
            $result = $this->push();
295
        }
296 3
297
        return $result;
298 3
    }
299
300
    /**
301
     * push sms send task to queue
302
     *
303
     * @throws \Exception | PhpSmsException
304
     *
305
     * @return mixed
306
     */
307
    protected function push()
308
    {
309
        if (is_callable(self::$howToUseQueue)) {
310
            try {
311
                $this->pushedToQueue = true;
312
313 33
                return call_user_func_array(self::$howToUseQueue, [$this, $this->smsData]);
314
            } catch (\Exception $e) {
315 33
                $this->pushedToQueue = false;
316
                throw $e;
317
            }
318
        } else {
319
            throw new PhpSmsException('Please define how to use queue by method `queue($enable, $handler)`');
320
        }
321 9
    }
322
323 9
    /**
324 9
     * get sms data
325 3
     *
326 3
     * @return array
327 3
     */
328 9
    public function getData()
329
    {
330
        return $this->smsData;
331
    }
332
333
    /**
334
     * bootstrap
335 18
     *
336
     * @param bool $force
337 18
     */
338 3
    public static function bootstrap($force = false)
339 3
    {
340
        if ((bool) $force) {
341 18
            Balancer::destroy(self::TASK);
342
        }
343
        $task = self::generatorTask();
344
        if (!count($task->drivers)) {
345
            self::configuration();
346
            self::createDrivers($task);
347 3
        }
348
    }
349 3
350 3
    /**
351 3
     * generator a sms send task
352 3
     *
353 3
     * @return object
354
     */
355
    public static function generatorTask()
356
    {
357
        if (!Balancer::hasTask(self::TASK)) {
358
            Balancer::task(self::TASK);
359
        }
360 3
361
        return Balancer::getTask(self::TASK);
362 3
    }
363 3
364 3
    /**
365 3
     * configuration
366 3
     */
367 3
    protected static function configuration()
368
    {
369
        $config = [];
370
        self::generatorAgentsName($config);
371
        self::generatorAgentsConfig($config);
372
        self::configValidator();
373
    }
374 3
375
    /**
376 3
     * generate enabled agents name
377 3
     *
378 3
     * @param array $config
379 3
     */
380 3
    protected static function generatorAgentsName(&$config)
381 3
    {
382 3
        if (empty(self::$agentsName)) {
383 3
            $config = $config ?: include __DIR__ . '/../config/phpsms.php';
384 3
            $enableAgents = isset($config['enable']) ? $config['enable'] : null;
385 3
            self::enable($enableAgents);
386 3
        }
387
    }
388
389
    /**
390
     * generator agents config
391
     *
392
     * @param array $config
393 3
     */
394
    protected static function generatorAgentsConfig(&$config)
395 3
    {
396
        $diff = array_diff_key(self::$agentsName, self::$agentsConfig);
397
        $diff = array_keys($diff);
398 3
        if (count($diff)) {
399
            $config = $config ?: include __DIR__ . '/../config/phpsms.php';
400
            $agentsConfig = isset($config['agents']) ? $config['agents'] : [];
401
            foreach ($diff as $name) {
402
                $agentConfig = isset($agentsConfig[$name]) ? $agentsConfig[$name] : [];
403
                self::agents($name, $agentConfig);
404
            }
405 15
        }
406
    }
407 3
408
    /**
409 3
     * config value validator
410
     *
411 3
     * @throws PhpSmsException
412
     */
413
    protected static function configValidator()
414
    {
415
        if (!count(self::$agentsName)) {
416
            throw new PhpSmsException('Please set at least one enable agent in config file(config/phpsms.php) or use method enable()');
417 3
        }
418 15
    }
419 15
420 15
    /**
421 15
     * create drivers for sms send task
422 15
     *
423 15
     * @param $task
424
     */
425
    protected static function createDrivers($task)
426 15
    {
427 15
        foreach (self::$agentsName as $name => $options) {
428
            //获取代理器配置
429 15
            $configData = self::getAgentConfigData($name);
430 15
            //解析代理器数组模式的调度配置
431 15
            if (is_array($options)) {
432 15
                $data = self::parseAgentArrayOptions($options);
433 15
                $configData = array_merge($configData, $data);
434
                $options = $data['driverOpts'];
435 15
            }
436 3
            //创建任务驱动器
437 3
            $task->driver("$name $options")->data($configData)
438 3
                 ->work(function ($driver) {
439
                     $configData = $driver->getDriverData();
440
                     $agent = self::getSmsAgent($driver->name, $configData);
441
                     $smsData = $driver->getTaskData();
442
                     extract($smsData);
443
                     if (isset($smsData['voiceCode']) && $smsData['voiceCode']) {
444
                         $agent->voiceVerify($to, $voiceCode);
445
                     } else {
446
                         $template = isset($templates[$driver->name]) ? $templates[$driver->name] : 0;
447
                         $agent->sendSms($template, $to, $templateData, $content);
448
                     }
449
                     $result = $agent->getResult();
450
                     if ($result['success']) {
451
                         $driver->success();
452
                     }
453
                     unset($result['success']);
454
455
                     return $result;
456
                 });
457
        }
458
    }
459
460
    /**
461
     * 解析可用代理器的数组模式的调度配置
462
     *
463
     * @param array $options
464
     *
465
     * @return array
466
     */
467
    protected static function parseAgentArrayOptions(array $options)
468
    {
469
        $agentClass = self::pullAgentOptionByName($options, 'agentClass');
470
        $sendSms = self::pullAgentOptionByName($options, 'sendSms');
471
        $voiceVerify = self::pullAgentOptionByName($options, 'voiceVerify');
472
        $backup = self::pullAgentOptionByName($options, 'backup');
473
        $driverOpts = implode(' ', array_values($options)) . " $backup";
474
475
        return compact('agentClass', 'sendSms', 'voiceVerify', 'driverOpts');
476
    }
477
478
    /**
479
     * 从调度配置中拉取指定数据
480
     *
481
     * @param array  $options
482
     * @param string $name
483
     *
484 3
     * @return null|string
485
     */
486 3
    protected static function pullAgentOptionByName(array &$options, $name)
487 3
    {
488
        $value = isset($options[$name]) ? $options[$name] : null;
489
        if ($name === 'backup') {
490
            $value = isset($options[$name]) ? ($options[$name] ? 'backup' : '') : '';
491
        }
492
        unset($options[$name]);
493
494
        return $value;
495
    }
496
497
    /**
498
     * get agent config data by name
499
     *
500
     * @param $name
501 18
     *
502
     * @return array
503 18
     */
504 3
    protected static function getAgentConfigData($name)
505 3
    {
506 3
        return isset(self::$agentsConfig[$name]) ?
507 3
               (array) self::$agentsConfig[$name] : [];
508
    }
509
510
    /**
511 3
     * get a sms agent instance,
512
     * if null, will create a new agent instance
513 3
     *
514 3
     * @param       $name
515
     * @param array $configData
516
     *
517
     * @throws PhpSmsException
518 3
     *
519
     * @return mixed
520 18
     */
521
    public static function getSmsAgent($name, array $configData)
522
    {
523
        if (!isset(self::$agents[$name])) {
524
            $configData['name'] = $name;
525
            $className = isset($configData['agentClass']) ? $configData['agentClass'] : ('Toplan\\PhpSms\\' . $name . 'Agent');
526
            if ((isset($configData['sendSms']) && is_callable($configData['sendSms'])) ||
527
                (isset($configData['voiceVerify']) && is_callable($configData['voiceVerify']))) {
528 18
                //创建寄生代理器
529
                $configData['agentClass'] = '';
530 18
                self::$agents[$name] = new ParasiticAgent($configData);
531
            } elseif (class_exists($className)) {
532
                //创建新代理器
533
                self::$agents[$name] = new $className($configData);
534 18
            } else {
535
                //无代理器可用
536
                throw new PhpSmsException("Do not support [$name] agent.");
537
            }
538
        }
539
540
        return self::$agents[$name];
541
    }
542
543 6
    /**
544
     * validate
545 6
     *
546 6
     * @throws PhpSmsException
547 6
     */
548 6
    protected function validator()
549 6
    {
550 3
        if (!$this->smsData['to']) {
551 6
            throw new PhpSmsException('Please set send sms(or voice verify) to who use `to()` method.');
552 3
        }
553 6
554 3
        return true;
555 3
    }
556 6
557
    /**
558
     * set enable agents
559
     *
560
     * @param      $agentName
561
     * @param null $options
562
     */
563
    public static function enable($agentName, $options = null)
564
    {
565
        if (is_array($agentName)) {
566 6
            foreach ($agentName as $name => $opt) {
567
                self::enable($name, $opt);
568 6
            }
569 3
        } elseif ($agentName && is_string($agentName) && $options !== null) {
570 3
            self::$agentsName["$agentName"] = is_array($options) ? $options : "$options";
571 3
        } elseif (is_int($agentName) && !is_array($options) && "$options") {
572 6
            self::$agentsName["$options"] = '1';
573 6
        } elseif ($agentName && $options === null) {
574
            self::$agentsName["$agentName"] = '1';
575
        }
576 6
    }
577 6
578 6
    /**
579
     * set config for available agents
580
     *
581
     * @param       $agentName
582
     * @param array $config
583
     *
584
     * @throws PhpSmsException
585 9
     */
586
    public static function agents($agentName, array $config = [])
587 9
    {
588
        if (is_array($agentName)) {
589
            foreach ($agentName as $name => $conf) {
590
                self::agents($name, $conf);
591
            }
592
        } elseif ($agentName && is_array($config)) {
593
            if (preg_match('/^[0-9]+$/', $agentName)) {
594
                throw new PhpSmsException("Agent name [$agentName] must be string, could not be a pure digital");
595 9
            }
596
            self::$agentsConfig["$agentName"] = $config;
597 9
        }
598
    }
599
600
    /**
601
     * get enable agents
602
     *
603 3
     * @return array
604
     */
605 3
    public static function getEnableAgents()
606 3
    {
607
        return self::$agentsName;
608
    }
609
610
    /**
611 3
     * get agents config info
612
     *
613 3
     * @return array
614 3
     */
615
    public static function getAgentsConfig()
616
    {
617
        return self::$agentsConfig;
618
    }
619
620
    /**
621
     * tear down enable agents
622
     */
623
    public static function cleanEnableAgents()
624 6
    {
625
        self::$agentsName = [];
626 6
    }
627 6
628 6
    /**
629 6
     * tear down agents config
630 6
     */
631 6
    public static function cleanAgentsConfig()
632 6
    {
633 6
        self::$agentsConfig = [];
634 6
    }
635 6
636 6
    /**
637
     * overload static method
638
     *
639 6
     * @param $name
640
     * @param $args
641
     *
642 6
     * @throws PhpSmsException
643
     */
644
    public static function __callStatic($name, $args)
645
    {
646
        $name = $name === 'beforeSend' ? 'beforeRun' : $name;
647
        $name = $name === 'afterSend' ? 'afterRun' : $name;
648
        $name = $name === 'beforeAgentSend' ? 'beforeDriverRun' : $name;
649
        $name = $name === 'afterAgentSend' ? 'afterDriverRun' : $name;
650
        if (in_array($name, self::$enableHooks)) {
651
            $handler = $args[0];
652
            $override = isset($args[1]) ? (bool) $args[1] : false;
653 3
            if (is_callable($handler)) {
654
                $task = self::generatorTask();
655
                $task->hook($name, $handler, $override);
656 3
            } else {
657 3
                throw new PhpSmsException("Please give method static $name() a callable parameter");
658
            }
659
        } else {
660 3
            throw new PhpSmsException("Do not find static method $name()");
661
        }
662
    }
663
664
    /**
665
     * overload method
666
     *
667
     * @param $name
668
     * @param $args
669
     *
670
     * @throws PhpSmsException
671
     * @throws \Exception
672
     */
673
    public function __call($name, $args)
674
    {
675
        try {
676
            $this->__callStatic($name, $args);
677
        } catch (\Exception $e) {
678
            throw $e;
679
        }
680
    }
681
682
    /**
683
     * serialize magic method
684
     * store current sms instance status
685
     *
686
     * @return array
687
     */
688
    public function __sleep()
689
    {
690
        $this->_status_before_enqueue_['enableAgents'] = self::serializeEnableAgents();
691
        $this->_status_before_enqueue_['agentsConfig'] = self::getAgentsConfig();
692
        $this->_status_before_enqueue_['handlers'] = self::serializeHandlers();
693
694
        return ['pushedToQueue', 'smsData', 'firstAgent', '_status_before_enqueue_'];
695
    }
696
697
    /**
698
     * unserialize magic method
699
     * note: the force bootstrap must before reinstall handlers!
700
     */
701
    public function __wakeup()
702
    {
703
        $status = $this->_status_before_enqueue_;
704
        self::$agentsName = self::unserializeEnableAgents($status['enableAgents']);
705
        self::$agentsConfig = $status['agentsConfig'];
706
        self::bootstrap(true);
707
        self::reinstallHandlers($status['handlers']);
708
    }
709
710
    /**
711
     * get a serializer
712
     *
713
     * @return Serializer
714
     */
715
    public static function getSerializer()
716
    {
717
        if (!self::$serializer) {
718
            self::$serializer = new Serializer();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \SuperClosure\Serializer() of type object<SuperClosure\Serializer> is incompatible with the declared type null of property $serializer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
719
        }
720
721
        return self::$serializer;
722
    }
723
724
    /**
725
     * serialize enable agents
726
     *
727
     * @return array
728
     */
729
    protected static function serializeEnableAgents()
730
    {
731
        $serializer = self::getSerializer();
732
        $enableAgents = self::getEnableAgents();
733
        foreach ($enableAgents as $name => &$options) {
734
            if (is_array($options)) {
735 View Code Duplication
                if (isset($options['sendSms']) && is_callable($options['sendSms'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
736
                    $options['sendSms'] = $serializer->serialize($options['sendSms']);
0 ignored issues
show
Documentation introduced by
$options['sendSms'] is of type callable, but the function expects a object<Closure>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
737
                }
738 View Code Duplication
                if (isset($options['voiceVerify']) && is_callable($options['voiceVerify'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
739
                    $options['voiceVerify'] = $serializer->serialize($options['voiceVerify']);
0 ignored issues
show
Documentation introduced by
$options['voiceVerify'] is of type callable, but the function expects a object<Closure>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
740
                }
741
            }
742
        }
743
744
        return $enableAgents;
745
    }
746
747
    /**
748
     * unserialize enable agents
749
     *
750
     * @param array $serialized
751
     *
752
     * @return mixed
753
     */
754
    protected static function unserializeEnableAgents(array $serialized)
755
    {
756
        $serializer = self::getSerializer();
757
        foreach ($serialized as $name => &$options) {
758
            if (is_array($options)) {
759
                if (isset($options['sendSms'])) {
760
                    $options['sendSms'] = $serializer->unserialize($options['sendSms']);
761
                }
762
                if (isset($options['voiceVerify'])) {
763
                    $options['voiceVerify'] = $serializer->unserialize($options['voiceVerify']);
0 ignored issues
show
Documentation introduced by
$options['voiceVerify'] is of type object<Closure>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
764
                }
765
            }
766
        }
767
768
        return $serialized;
769
    }
770
771
    /**
772
     * serialize these hooks` handlers:
773
     * 'beforeRun','beforeDriverRun','afterDriverRun','afterRun'
774
     *
775
     * @return array
776
     */
777
    protected static function serializeHandlers()
778
    {
779
        $hooks = [];
780
        $serializer = self::getSerializer();
781
        $task = self::generatorTask();
782
        foreach ($task->handlers as $hookName => $handlers) {
783
            foreach ($handlers as $handler) {
784
                $serialized = $serializer->serialize($handler);
785
                if (!isset($hooks[$hookName])) {
786
                    $hooks[$hookName] = [];
787
                }
788
                array_push($hooks[$hookName], $serialized);
789
            }
790
        }
791
792
        return $hooks;
793
    }
794
795
    /**
796
     * reinstall hooks` handlers by serialized handlers
797
     *
798
     * @param array $handlers
799
     */
800
    protected static function reinstallHandlers(array $handlers)
801
    {
802
        $serializer = self::getSerializer();
803
        foreach ($handlers as $hookName => $serializedHandlers) {
804
            foreach ($serializedHandlers as $index => $handler) {
805
                if (is_string($handler)) {
806
                    $handler = $serializer->unserialize($handler);
807
                }
808
                $override = $index === 0;
809
                self::$hookName($handler, $override);
810
            }
811
        }
812
    }
813
}
814