Completed
Push — master ( 382c3e...13cabb )
by lan tian
9s
created

Sms::serializeOrDeserializeScheme()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

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