Completed
Pull Request — master (#62)
by lan tian
02:21
created

Sms::createDrivers()   D

Complexity

Conditions 9
Paths 5

Size

Total Lines 38
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 9.0027

Importance

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