Completed
Pull Request — master (#54)
by lan tian
02:40
created

Sms::generatorAgentsConfig()   B

Complexity

Conditions 6
Paths 13

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 13
ccs 12
cts 12
cp 1
rs 8.8571
cc 6
eloc 9
nc 13
nop 1
crap 6

1 Method

Rating   Name   Duplication   Size   Complexity  
A Sms::cleanEnableAgents() 0 5 1
1
<?php
2
3
namespace Toplan\PhpSms;
4
5
use SuperClosure\Serializer;
6
use Toplan\TaskBalance\Balancer;
7
use Toplan\TaskBalance\Task;
8
9
/**
10
 * Class Sms
11
 *
12
 *
13
 * @author toplan<[email protected]>
14
 */
15
class Sms
16
{
17
    /**
18
     * Send task`s name.
19
     *
20
     * @var string
21
     */
22
    const TASK = 'PhpSms';
23
24
    /**
25
     * SMS agents(service providers),
26
     * they are instances of class [Toplan\PhpSms\Agent].
27
     *
28
     * @var array
29
     */
30
    protected static $agents = [];
31
32
    /**
33
     * The enabled agents` name.
34
     *
35
     * @var array
36
     */
37
    protected static $agentsName = [];
38
39
    /**
40
     * The enabled agents` config info.
41
     *
42
     * @var array
43
     */
44
    protected static $agentsConfig = [];
45
46
    /**
47
     * Whether to use queue.
48
     *
49
     * @var bool
50
     */
51
    protected static $enableQueue = false;
52
53
    /**
54
     * How to push to queue.
55
     *
56
     * @var \Closure
57
     */
58
    protected static $howToUseQueue = null;
59
60
    /**
61
     * The enable hooks for balance task.
62
     *
63
     * @var array
64
     */
65
    protected static $enableHooks = [
66
        'beforeRun',
67
        'beforeDriverRun',
68
        'afterDriverRun',
69
        'afterRun',
70
    ];
71
72
    /**
73
     * An instance of class [SuperClosure\Serializer]
74
     *
75
     * @var Serializer
76
     */
77
    protected static $serializer = null;
78
79
    /**
80
     * SMS(or voice verify) data container.
81
     *
82
     * @var array
83
     */
84
    protected $smsData = [
85
        'to'           => null,
86
        'templates'    => [],
87
        'content'      => null,
88
        'templateData' => [],
89
        'voiceCode'    => null,
90
    ];
91
92
    /**
93
     * The name of first agent.
94
     *
95
     * @var string|null
96
     */
97
    protected $firstAgent = null;
98
99
    /**
100
     * Whether the current instance has already pushed to queue.
101
     *
102
     * @var bool
103
     */
104
    protected $pushedToQueue = false;
105
106
    /**
107
     * Status container,
108
     * store config data before serialize a instance(before enqueue).
109
     *
110
     * @var array
111
     */
112
    protected $_status_before_enqueue_ = [];
113
114
    /**
115
     * Constructor
116
     *
117
     * @param bool $autoBoot
118
     */
119 6
    public function __construct($autoBoot = true)
120
    {
121 6
        if ($autoBoot) {
122 3
            self::bootstrap();
123 3
        }
124 6
    }
125
126
    /**
127
     * Boot balanced send task.
128
     */
129 6
    public static function bootstrap()
130
    {
131 6
        $task = self::getTask();
132
133
        //注意这里判断Task实例有没有drivers,不能用empty,因为其不能检查语句,
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
134
        //而恰巧Task实例获取drivers是通过魔术方法获取的.
135 6
        if (!count($task->drivers)) {
136 3
            self::configuration();
137 3
            self::createDrivers($task);
138 3
        }
139 6
    }
140
141
    /**
142
     * Get or generate a balanced task instance for send SMS/voice verify.
143
     *
144
     * @return Task
145
     */
146 15
    public static function getTask()
147
    {
148 15
        if (!Balancer::hasTask(self::TASK)) {
149 3
            Balancer::task(self::TASK);
150 3
        }
151
152 15
        return Balancer::getTask(self::TASK);
153
    }
154
155
    /**
156
     * Configuration.
157
     */
158 6
    protected static function configuration()
159
    {
160 6
        $config = [];
161 6
        if (empty(self::$agentsName)) {
162 3
            self::initEnableAgents($config);
163 3
        }
164 6
        $diff = array_diff_key(self::$agentsName, self::$agentsConfig);
165 6
        self::initAgentsConfig(array_keys($diff), $config);
166 6
        self::validateConfig();
167 6
    }
168
169
    /**
170
     * Try to read and set enable agents` name from config file.
171
     *
172
     * @param array $config
173
     */
174 3
    protected static function initEnableAgents(array &$config)
175
    {
176 3
        $config = empty($config) ? include __DIR__ . '/../config/phpsms.php' : $config;
177 3
        $enableAgents = isset($config['enable']) ? $config['enable'] : [];
178 3
        self::enable($enableAgents);
179 3
    }
180
181
    /**
182
     * Try to read and set enabled agents` config from config file.
183
     *
184
     * @param array $agents
185
     * @param array $config
186
     */
187 6
    protected static function initAgentsConfig(array $agents, array &$config)
188
    {
189 6
        if (empty($agents)) {
190 3
            return;
191
        }
192 3
        $config = empty($config) ? include __DIR__ . '/../config/phpsms.php' : $config;
193 3
        $agentsConfig = isset($config['agents']) ? $config['agents'] : [];
194 3
        foreach ($agents as $name) {
195 3
            $agentConfig = isset($agentsConfig[$name]) ? $agentsConfig[$name] : [];
196 3
            self::agents($name, $agentConfig);
197 3
        }
198 3
    }
199
200
    /**
201
     * validate configuration.
202
     *
203
     * @throws PhpSmsException
204
     */
205 6
    protected static function validateConfig()
206
    {
207 6
        if (!count(self::$agentsName)) {
208
            throw new PhpSmsException('Please configure at least one agent');
209
        }
210 6
    }
211
212
    /**
213
     * Create drivers of the balanced task.
214
     *
215
     * @param Task $task
216
     */
217 18
    protected static function createDrivers(Task $task)
218
    {
219 3
        foreach (self::$agentsName as $name => $options) {
220
            //获取代理器配置
221 3
            $configData = self::getAgentConfigData($name);
222
            //解析代理器数组模式的调度配置
223 3
            if (is_array($options)) {
224 3
                $data = self::parseAgentArrayOptions($options);
225 3
                $configData = array_merge($configData, $data);
226 3
                $options = $data['driverOpts'];
227 3
            }
228
            //创建任务驱动器
229 3
            $task->driver("$name $options")->data($configData)
230 18
                 ->work(function ($driver) {
231 18
                     $configData = $driver->getDriverData();
232 18
                     $agent = self::getSmsAgent($driver->name, $configData);
233 18
                     $smsData = $driver->getTaskData();
234 18
                     extract($smsData);
235 18
                     if (isset($smsData['voiceCode']) && $smsData['voiceCode']) {
236
                         $agent->voiceVerify($to, $voiceCode);
237
                     } else {
238 18
                         $template = isset($templates[$driver->name]) ? $templates[$driver->name] : 0;
239 18
                         $agent->sendSms($template, $to, $templateData, $content);
240
                     }
241 18
                     $result = $agent->result();
242 18
                     if ($result['success']) {
243 18
                         $driver->success();
244 18
                     }
245 18
                     unset($result['success']);
246
247 18
                     return $result;
248 3
                 });
249 3
        }
250 3
    }
251
252
    /**
253
     * Parse the enabled agents` scheduling config data.
254
     * 解析可用代理器的数组模式的调度配置
255
     *
256
     * @param array $options
257
     *
258
     * @return array
259
     */
260 3
    protected static function parseAgentArrayOptions(array $options)
261
    {
262 3
        $agentClass = self::pullAgentOptionByName($options, 'agentClass');
263 3
        $sendSms = self::pullAgentOptionByName($options, 'sendSms');
264 3
        $voiceVerify = self::pullAgentOptionByName($options, 'voiceVerify');
265 3
        $backup = self::pullAgentOptionByName($options, 'backup') ? 'backup' : '';
266 3
        $driverOpts = implode(' ', array_values($options)) . " $backup";
267
268 3
        return compact('agentClass', 'sendSms', 'voiceVerify', 'driverOpts');
269
    }
270
271
    /**
272
     * Pull the character option data from the scheduling config.
273
     *
274
     * @param array  $options
275
     * @param string $name
276
     *
277
     * @return mixed
278
     */
279 3
    protected static function pullAgentOptionByName(array &$options, $name)
280
    {
281 3
        if (!isset($options[$name])) {
282 3
            return;
283
        }
284 3
        $value = $options[$name];
285 3
        unset($options[$name]);
286
287 3
        return $value;
288
    }
289
290
    /**
291
     * Get agent config data by name.
292
     *
293
     * @param string $name
294
     *
295
     * @return array
296
     */
297 3
    protected static function getAgentConfigData($name)
298
    {
299 3
        return isset(self::$agentsConfig[$name]) ? self::$agentsConfig[$name] : [];
300
    }
301
302
    /**
303
     * Get a sms agent instance by agent name,
304
     * if null, will try to create a new agent instance.
305
     *
306
     * @param string $name
307
     * @param array  $configData
308
     *
309
     * @throws PhpSmsException
310
     *
311
     * @return mixed
312
     */
313 21
    public static function getSmsAgent($name, array $configData)
314
    {
315 21
        if (!isset(self::$agents[$name])) {
316 6
            $configData['name'] = $name;
317 6
            $className = isset($configData['agentClass']) ? $configData['agentClass'] : ('Toplan\\PhpSms\\' . $name . 'Agent');
318 6
            if ((isset($configData['sendSms']) && is_callable($configData['sendSms'])) ||
319 6
                (isset($configData['voiceVerify']) && is_callable($configData['voiceVerify']))) {
320
                //创建寄生代理器
321 3
                $configData['agentClass'] = '';
322 3
                self::$agents[$name] = new ParasiticAgent($configData);
323 6
            } elseif (class_exists($className)) {
324
                //创建新代理器
325 3
                self::$agents[$name] = new $className($configData);
326 3
            } else {
327
                //无代理器可用
328
                throw new PhpSmsException("Do not support [$name] agent.");
329
            }
330 6
        }
331
332 21
        return self::$agents[$name];
333
    }
334
335
    /**
336
     * Set enable agents.
337
     *
338
     * @param mixed $agentName
339
     * @param mixed $options
340
     */
341 6
    public static function enable($agentName, $options = null)
342
    {
343 6
        if (is_array($agentName)) {
344 6
            foreach ($agentName as $name => $opt) {
345 6
                self::enable($name, $opt);
346 6
            }
347 6
        } elseif ($agentName && is_string($agentName) && $options !== null) {
348 3
            self::$agentsName["$agentName"] = is_array($options) ? $options : "$options";
349 6
        } elseif (is_int($agentName) && !is_array($options) && "$options") {
350 3
            self::$agentsName["$options"] = '1';
351 6
        } elseif ($agentName && $options === null) {
352 3
            self::$agentsName["$agentName"] = '1';
353 3
        }
354 6
    }
355
356
    /**
357
     * Set config info by agent name.
358
     *
359
     * @param array|string $agentName
360
     * @param array        $config
361
     *
362
     * @throws PhpSmsException
363
     */
364 6
    public static function agents($agentName, array $config = [])
365
    {
366 6
        if (is_array($agentName)) {
367 3
            foreach ($agentName as $name => $conf) {
368 3
                self::agents($name, $conf);
369 3
            }
370 6
        } elseif ($agentName && is_array($config)) {
371 6
            if (preg_match('/^[0-9]+$/', $agentName)) {
372
                throw new PhpSmsException("Agent name [$agentName] must be string, could not be a pure digital");
373
            }
374 6
            self::$agentsConfig["$agentName"] = $config;
375 6
        }
376 6
    }
377
378
    /**
379
     * Get the enabled agents` name.
380
     *
381
     * @return array
382
     */
383 12
    public static function getEnableAgents()
384
    {
385 12
        return self::$agentsName;
386
    }
387
388
    /**
389
     * Get the enabled agents` config info.
390
     *
391
     * @return array
392
     */
393 12
    public static function getAgentsConfig()
394
    {
395 12
        return self::$agentsConfig;
396
    }
397
398
    /**
399
     * Tear down enable agents and prepare to create and start a new balance task,
400
     * so before do it must destroy old task instance.
401
     */
402 6
    public static function cleanEnableAgents()
403
    {
404 6
        Balancer::destroy(self::TASK);
405 6
        self::$agentsName = [];
406 6
    }
407
408
    /**
409
     * Tear down agents config and prepare to create and start a new balance task,
410
     * so before do it must destroy old task instance.
411
     */
412 3
    public static function cleanAgentsConfig()
413
    {
414 3
        Balancer::destroy(self::TASK);
415 3
        self::$agentsConfig = [];
416 3
    }
417
418
    /**
419
     * Create a sms instance which send SMS,
420
     * and set SMS templates or content.
421
     *
422
     * @param mixed $agentName
423
     * @param mixed $tempId
424
     *
425
     * @return Sms
426
     */
427
    public static function make($agentName = null, $tempId = null)
428
    {
429
        $sms = new self();
430
        if (is_array($agentName)) {
431
            $sms->template($agentName);
432
        } elseif ($agentName && is_string($agentName)) {
433
            if ($tempId === null) {
434
                $sms->content($agentName);
435
            } elseif (is_string("$tempId")) {
436
                $sms->template($agentName, $tempId);
437
            }
438
        }
439
440
        return $sms;
441
    }
442
443
    /**
444
     * Create a sms instance which send voice verify,
445
     * and set verify code.
446
     *
447
     * @param string|int $code
448
     *
449
     * @return Sms
450
     */
451 3
    public static function voice($code)
452
    {
453 3
        $sms = new self();
454 3
        $sms->smsData['voiceCode'] = $code;
455
456 3
        return $sms;
457
    }
458
459
    /**
460
     * Set whether to use queue, and define how to use queue.
461
     *
462
     * @param mixed $enable
463
     * @param mixed $handler
464
     *
465
     * @return bool
466
     */
467 3
    public static function queue($enable = null, $handler = null)
468
    {
469 3
        if ($enable === null && $handler === null) {
470 3
            return self::$enableQueue;
471
        }
472 3
        if (is_callable($enable)) {
473 3
            $handler = $enable;
474 3
            $enable = true;
475 3
        }
476 3
        self::$enableQueue = (bool) $enable;
477 3
        if (is_callable($handler)) {
478 3
            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...
479 3
        }
480
481 3
        return self::$enableQueue;
482
    }
483
484
    /**
485
     * Set the receiver`s mobile number.
486
     *
487
     * @param string $mobile
488
     *
489
     * @return $this
490
     */
491 6
    public function to($mobile)
492
    {
493 6
        $this->smsData['to'] = $mobile;
494
495 6
        return $this;
496
    }
497
498
    /**
499
     * Set content for content SMS.
500
     *
501
     * @param string $content
502
     *
503
     * @return $this
504
     */
505 3
    public function content($content)
506
    {
507 3
        $this->smsData['content'] = trim((string) $content);
508
509 3
        return $this;
510
    }
511
512
    /**
513
     * Set template id for template SMS.
514
     *
515
     * @param mixed $agentName
516
     * @param mixed $tempId
517
     *
518
     * @return $this
519
     */
520 3
    public function template($agentName, $tempId = null)
521
    {
522 3
        if (is_array($agentName)) {
523 3
            foreach ($agentName as $k => $v) {
524 3
                $this->template($k, $v);
525 3
            }
526 3
        } elseif ($agentName && $tempId) {
527 3
            if (!isset($this->smsData['templates']) || !is_array($this->smsData['templates'])) {
528
                $this->smsData['templates'] = [];
529
            }
530 3
            $this->smsData['templates']["$agentName"] = $tempId;
531 3
        }
532
533 3
        return $this;
534
    }
535
536
    /**
537
     * Set template data for template SMS.
538
     *
539
     * @param array $data
540
     *
541
     * @return $this
542
     */
543 3
    public function data(array $data)
544
    {
545 3
        $this->smsData['templateData'] = $data;
546
547 3
        return $this;
548
    }
549
550
    /**
551
     * Set the first agent by agent`s name.
552
     *
553
     * @param string $name
554
     *
555
     * @return $this
556
     */
557 3
    public function agent($name)
558
    {
559 3
        $this->firstAgent = (string) $name;
560
561 3
        return $this;
562
    }
563
564
    /**
565
     * Start send SMS/voice verify.
566
     *
567
     * If give a true parameter, will immediately start whatever whether to use queue.
568
     * if you are already pushed sms instance to queue, you can recall the method `send()` in queue job without `true` parameter,
569
     * so this mechanism in order to make you convenient use the method `send()` in queue system.
570
     *
571
     * @param bool $immediately
572
     *
573
     * @return mixed
574
     */
575 18
    public function send($immediately = false)
576
    {
577 18
        if (!self::$enableQueue || $this->pushedToQueue) {
578 18
            $immediately = true;
579 18
        }
580 18
        if ($immediately) {
581 18
            $result = Balancer::run(self::TASK, [
582 18
                'data'   => $this->getData(),
583 18
                'driver' => $this->firstAgent,
584 18
            ]);
585 18
        } else {
586 3
            $result = $this->push();
587
        }
588
589 18
        return $result;
590
    }
591
592
    /**
593
     * Push to queue by custom method.
594
     *
595
     * @throws \Exception | PhpSmsException
596
     *
597
     * @return mixed
598
     */
599 3
    public function push()
600
    {
601 3
        if (is_callable(self::$howToUseQueue)) {
602
            try {
603 3
                $this->pushedToQueue = true;
604
605 3
                return call_user_func_array(self::$howToUseQueue, [$this, $this->smsData]);
606
            } catch (\Exception $e) {
607
                $this->pushedToQueue = false;
608
                throw $e;
609
            }
610
        } else {
611
            throw new PhpSmsException('Please define how to use queue by method `queue($enable, $handler)`');
612
        }
613
    }
614
615
    /**
616
     * Get all the data of SMS/voice verify.
617
     *
618
     * @param null|string $name
619
     *
620
     * @return mixed
621
     */
622 36
    public function getData($name = null)
623
    {
624 36
        if (is_string($name) && isset($this->smsData["$name"])) {
625 3
            return $this->smsData[$name];
626
        }
627
628 36
        return $this->smsData;
629
    }
630
631
    /**
632
     * Overload static method.
633
     *
634
     * @param string $name
635
     * @param array  $args
636
     *
637
     * @throws PhpSmsException
638
     */
639 9
    public static function __callStatic($name, $args)
640
    {
641 9
        $name = $name === 'beforeSend' ? 'beforeRun' : $name;
642 9
        $name = $name === 'afterSend' ? 'afterRun' : $name;
643 9
        $name = $name === 'beforeAgentSend' ? 'beforeDriverRun' : $name;
644 9
        $name = $name === 'afterAgentSend' ? 'afterDriverRun' : $name;
645 9
        if (in_array($name, self::$enableHooks)) {
646 9
            $handler = $args[0];
647 9
            $override = isset($args[1]) ? (bool) $args[1] : false;
648 9
            if (is_callable($handler)) {
649 9
                $task = self::getTask();
650 9
                $task->hook($name, $handler, $override);
651 9
            } else {
652
                throw new PhpSmsException("Please give method static $name() a callable parameter");
653
            }
654 9
        } else {
655
            throw new PhpSmsException("Do not find static method $name()");
656
        }
657 9
    }
658
659
    /**
660
     * Overload method.
661
     *
662
     * @param string $name
663
     * @param array  $args
664
     *
665
     * @throws PhpSmsException
666
     * @throws \Exception
667
     */
668 3
    public function __call($name, $args)
669
    {
670
        try {
671 3
            $this->__callStatic($name, $args);
672 3
        } catch (\Exception $e) {
673
            throw $e;
674
        }
675 3
    }
676
677
    /**
678
     * Serialize magic method,
679
     * store current sms instance status.
680
     *
681
     * @return array
682
     */
683 3
    public function __sleep()
684
    {
685
        try {
686 3
            $this->_status_before_enqueue_['enableAgents'] = self::serializeEnableAgents();
687 3
            $this->_status_before_enqueue_['agentsConfig'] = self::getAgentsConfig();
688 3
            $this->_status_before_enqueue_['handlers'] = self::serializeHandlers();
689 3
        } catch (\Exception $e) {
690
            //swallow exception
691
        }
692
693 3
        return ['pushedToQueue', 'smsData', 'firstAgent', '_status_before_enqueue_'];
694
    }
695
696
    /**
697
     * Unserialize magic method,
698
     * note: the force bootstrap must before reinstall handlers!
699
     */
700 3
    public function __wakeup()
701
    {
702 3
        if (empty($this->_status_before_enqueue_)) {
703
            return;
704
        }
705 3
        $status = $this->_status_before_enqueue_;
706 3
        self::$agentsName = self::unserializeEnableAgents($status['enableAgents']);
707 3
        self::$agentsConfig = $status['agentsConfig'];
708 3
        Balancer::destroy(self::TASK);
709 3
        self::bootstrap();
710 3
        self::reinstallHandlers($status['handlers']);
711 3
    }
712
713
    /**
714
     * Get a closure serializer.
715
     *
716
     * @return Serializer
717
     */
718 3
    public static function getSerializer()
719
    {
720 3
        if (!self::$serializer) {
721 3
            self::$serializer = new Serializer();
722 3
        }
723
724 3
        return self::$serializer;
725
    }
726
727
    /**
728
     * Serialize enabled agents.
729
     *
730
     * @return array
731
     */
732 3
    protected static function serializeEnableAgents()
733
    {
734 3
        $enableAgents = self::getEnableAgents();
735 3
        foreach ($enableAgents as $name => &$options) {
736 3
            if (is_array($options)) {
737 3
                self::serializeClosureAndReplace($options, 'sendSms');
738 3
                self::serializeClosureAndReplace($options, 'voiceVerify');
739 3
            }
740 3
        }
741
742 3
        return $enableAgents;
743
    }
744
745
    /**
746
     * Unserialize enabled agents.
747
     *
748
     * @param array $serialized
749
     *
750
     * @return mixed
751
     */
752 3
    protected static function unserializeEnableAgents(array $serialized)
753
    {
754 3
        foreach ($serialized as $name => &$options) {
755 3
            if (is_array($options)) {
756 3
                self::unserializeToClosureAndReplace($options, 'sendSms');
757 3
                self::unserializeToClosureAndReplace($options, 'voiceVerify');
758 3
            }
759 3
        }
760
761 3
        return $serialized;
762
    }
763
764
    /**
765
     * Serialize character closure value of a array and replace origin value.
766
     *
767
     * @param array  $options
768
     * @param string $key
769
     */
770 3
    protected static function serializeClosureAndReplace(array &$options, $key)
771
    {
772 3
        if (isset($options["$key"]) && is_callable($options["$key"])) {
773 3
            $serializer = self::getSerializer();
774 3
            $options["$key"] = (string) $serializer->serialize($options["$key"]);
775 3
        }
776 3
    }
777
778
    /**
779
     * Unserialize character string of a array to closure and replace origin value.
780
     *
781
     * @param array  $options
782
     * @param string $key
783
     */
784 3
    protected static function unserializeToClosureAndReplace(array &$options, $key)
785
    {
786 3
        if (isset($options["$key"])) {
787 3
            $serializer = self::getSerializer();
788 3
            $options["$key"] = $serializer->unserialize($options["$key"]);
789 3
        }
790 3
    }
791
792
    /**
793
     * Serialize these hooks` handlers:
794
     * 'beforeRun','beforeDriverRun','afterDriverRun','afterRun'.
795
     *
796
     * @return array
797
     */
798 3
    protected static function serializeHandlers()
799
    {
800 3
        $hooks = [];
801 3
        $serializer = self::getSerializer();
802 3
        $task = self::getTask();
803 3
        foreach ($task->handlers as $hookName => $handlers) {
804 3
            foreach ($handlers as $handler) {
805 3
                $serialized = $serializer->serialize($handler);
806 3
                if (!isset($hooks[$hookName])) {
807 3
                    $hooks[$hookName] = [];
808 3
                }
809 3
                array_push($hooks[$hookName], $serialized);
810 3
            }
811 3
        }
812
813 3
        return $hooks;
814
    }
815
816
    /**
817
     * Reinstall balance task hooks` handlers by serialized handlers.
818
     *
819
     * @param array $handlers
820
     */
821 3
    protected static function reinstallHandlers(array $handlers)
822
    {
823 3
        $serializer = self::getSerializer();
824 3
        foreach ($handlers as $hookName => $serializedHandlers) {
825 3
            foreach ($serializedHandlers as $index => $handler) {
826 3
                if (is_string($handler)) {
827 3
                    $handler = $serializer->unserialize($handler);
828 3
                }
829 3
                self::$hookName($handler, $index === 0);
830 3
            }
831 3
        }
832 3
    }
833
}
834