ConnectionManager::checkAllServices()   B
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 5
nop 0
1
<?php
2
/**
3
 * This file is part of the fangface/yii2-concord package
4
 *
5
 * For the full copyright and license information, please view
6
 * the file LICENSE.md that was distributed with this source code.
7
 *
8
 * @package fangface/yii2-concord
9
 * @author Fangface <[email protected]>
10
 * @copyright Copyright (c) 2014 Fangface <[email protected]>
11
 * @license https://github.com/fangface/yii2-concord/blob/master/LICENSE.md MIT License
12
 *
13
 */
14
15
namespace fangface\db;
16
17
use fangface\base\traits\ServiceGetter;
18
use fangface\db\Exception;
19
use fangface\models\db\Client;
20
use fangface\models\db\DbResource;
21
use fangface\models\db\client\DbResource as ClientDbResource;
22
use yii\base\Component;
23
use yii\db\Connection;
24
use yii\db\Exception as YiiDbException;
25
26
/**
27
 * ConnectionManager Class
28
 *
29
 * Class that provides methods to allow for db connection management, initially
30
 * designed for use with yii2-concord but can serve as a standalone connection
31
 * manager as well if useful. Connections can be automatically obtained from
32
 * component config for the base application and/or can supplment those connections.
33
 * New connections are by default added to yii components so they can be accessed
34
 * as typical yii db connections would be accessed e.g.
35
 *
36
 *     \Yii::$app->get('db2');
37
 *     \Yii::$app->get('dbFactory')->getConnection('db2');
38
 *
39
 * Ideally suited when multiple database connections are required within an
40
 * application and especially if those connections dynamically change but models
41
 * are re-used to point to multiple database connections sharing the same alias
42
 * at run-time.
43
 *
44
 * @author Fangface <[email protected]>
45
 */
46
class ConnectionManager extends Component
47
{
48
    use ServiceGetter;
49
50
    /**
51
     * Key to use to recover dbResource passwords
52
     *
53
     * @var string
54
     */
55
    public $secretKey = null;
56
57
    /**
58
     * Array of resources (connections) currently setup
59
     *
60
     * @var array
61
     */
62
    protected $resources = array();
63
64
    /**
65
     * Default resource name
66
     *
67
     * @var string
68
     */
69
    protected $defaultResourceName = 'db';
70
71
72
    /**
73
     * Called by the Object::__construct()
74
     */
75
    public function init()
76
    {
77
        $this->resources = array(
78
            'Resources' => array(),
79
            'Aliases' => array()
80
        );
81
    }
82
83
84
    /**
85
     * Set the default resource name e.g. 'db'
86
     *
87
     * @param string $resourceName
88
     */
89
    public function setDefaultResourceName($resourceName = 'db')
90
    {
91
        $this->defaultResourceName = $resourceName;
92
    }
93
94
95
    /**
96
     * Return name of default resource e.g. 'db'
97
     *
98
     * @return string
99
     */
100
    public function getDefaultResourceName()
101
    {
102
        return $this->defaultResourceName;
103
    }
104
105
106
    /**
107
     * Return the actual resource name based on an existing resource name or alias
108
     *
109
     * @param string $resourceName
110
     * @return string|false
111
     */
112
    public function getResourceNameByAlias($resourceName)
113
    {
114
        if (isset($this->resources['Resources'][$resourceName])) {
115
            return $resourceName;
116
        } elseif (isset($this->resources['Aliases'][$resourceName]) && isset($this->resources['Resources'][$this->resources['Aliases'][$resourceName]])) {
117
            return $this->resources['Aliases'][$resourceName];
118
        }
119
120
        return false;
121
    }
122
123
124
    /**
125
     * Obtain the connection for the specified resource name
126
     *
127
     * @param string $resourceName [OPTIONAL] (default is the current default resource name)
128
     * @param boolean $addResource [OPTIONAL] add resource if it is not already loaded (default false)
129
     * @param boolean $checkServices [OPTIONAL] check services for db connections that have not been registered via the connection manager (default true)
130
     * @param boolean $clientResource if $addResource is true default to loading the resource from the clients resources table rather than the master resources table
131
     * @return Connection|false
132
     */
133
    public function getConnection($resourceName='', $addResource = false, $checkServices = true, $clientResource = false)
134
    {
135
136
        if ($resourceName == 'Default' || $resourceName == '') {
137
            $resourceName = $this->defaultResourceName;
138
        }
139
140
        $resourceNameIn = $resourceName;
141
142
        $resourceName = $this->getResourceNameByAlias($resourceName);
143
144
        if ($resourceName && isset($this->resources['Resources'][$resourceName])) {
145
146
            $connection = $this->resources['Resources'][$resourceName]['Connection'];
147
148
        } else {
149
150
            // check to see if an existing component exists for this connection that we
151
            // can adopt
152
153
            if ($checkServices && $this->hasService($resourceNameIn)) {
154
                $connection = $this->getService($resourceNameIn);
155
                if ($connection) {
156
                    /* @var Connection $connection */
157
                    $class = get_class($connection);
158
                    $this->extendResourceArray($resourceNameIn, $connection, $class);
159
                    return $connection;
160
                }
161
            }
162
163
            if (!$addResource) {
164
165
                return false;
166
167
            } else {
168
169
                // attempt to add the resourceName and setup the connection
170
                $success = $this->addResource($resourceNameIn, $clientResource, false);
171
                if ($success) {
172
                    $connection = $this->getConnection($resourceNameIn);
173
                } else {
174
                    return false;
175
                }
176
177
            }
178
179
        }
180
181
        return $connection;
182
    }
183
184
185
    /**
186
     * Obtain the current client main db connection
187
     *
188
     * @param boolean $addResource [OPTIONAL] add resource if it is not already loaded (default false)
189
     * @return Connection|false
190
     */
191
    public function getClientConnection($addResource = false)
192
    {
193
        return $this->getConnection('dbClient', $addResource);
194
    }
195
196
    /**
197
     * Obtain the client resource connection for the specified client resource name
198
     *
199
     * @param string $resourceName [OPTIONAL] (default is the current default resource name)
200
     * @param boolean $addResource [OPTIONAL] add resource if it is not already loaded (default false)
201
     * @return Connection|false
202
     */
203
    public function getClientResourceConnection($resourceName='', $addResource = false)
204
    {
205
        // client resources in a multi client environment will never be defined as a component
206
        // so third parameter is false
207
        return $this->getConnection($resourceName, $addResource, false, true);
208
    }
209
210
    /**
211
     * Add a new resource and setup the DB connection
212
     *
213
     * @param string $resourceName
214
     * @param boolean $clientResource default to loading the resource from the clients resources table rather than the master resources table
215
     * @param boolean $checkServices check services for db connections that have not been registered via the connection manager (default true)
216
     * @param array|false $dbParams array of parameters for the connection, similar to what would be found in config (default false)
217
     * @return boolean success
218
     */
219
    public function addResource($resourceName, $clientResource = false, $checkServices = true, $dbParams = false)
220
    {
221
        if ($checkServices) {
222
            if ($this->hasService($resourceName)) {
223
                /* @var Connection $connection */
224
                $connection = $this->getService($resourceName);
225
                if ($connection) {
226
                    $class = get_class($connection);
227
                    $this->extendResourceArray($resourceName, $connection, $class);
228
                }
229
            }
230
        }
231
        $resourceNameCheck = $this->getResourceNameByAlias($resourceName);
232
        if ($resourceName && isset($this->resources['Resources'][$resourceNameCheck])) {
233
            // resource already exists
234
            return true;
235
        } elseif ($resourceName) {
236
            $dbResource = false;
237
            if ($dbParams && is_array($dbParams)) {
238
                // use the dbParams provided
239
            } elseif ($resourceName == 'dbClient') {
240
                /*
241
                 * We need to load up the client DB connection and it is not defined as config
242
                 * so we will get the details from the db.clients table
243
                 */
244
                $dbResource = $this->getService('client');
245
                if ($dbResource && $dbResource instanceof Client) {
246
                    // take some default values form the defaul connection (which would have come from config
247
                    $connection = $this->getConnection();
248
                }
249
250
            } elseif ($clientResource) {
251
                $client = $this->getService('client');
252
                if ($client && $client instanceof Client) {
253
                    $connection = $this->getClientConnection(true);
254
                    if ($connection && $connection instanceof Connection) {
255
                        try {
256
                            $dbResource = ClientDbResource::find()
257
                                ->where(['resourceName' => $resourceName])
258
                                ->one();
259
                        } catch (YiiDbException $e) {
260
                            throw new Exception('Unable to load client dbResources');
261
                        }
262
                    } else {
263
                        throw new Exception('No connections to client db available');
264
                    }
265
                } else {
266
                    throw new Exception('No client service available');
267
                }
268
            } else {
269
                $connection = $this->getConnection();
270
                if ($connection && $connection instanceof Connection) {
271
                    try {
272
                        $dbResource = DbResource::find()
273
                            ->where(['resourceName' => $resourceName])
274
                            ->one();
275
                    } catch (YiiDbException $e) {
276
                        throw new Exception('Unable to load dbResources');
277
                    }
278
                } else {
279
                    throw new Exception('No connections to load dbResources');
280
                }
281
            }
282
283
            if ($dbResource) {
284
                $dbParams = array(
285
                    'class'                => $dbResource->dbClass,
286
                    'dsn'                  => $dbResource->dbDsn,
287
                    'username'             => $dbResource->dbUser,
288
                    'password'             => $dbResource->dbPass,
289
                    'charset'              => $dbResource->dbCharset,
290
                    'tablePrefix'          => $dbResource->dbPrefix,
291
                    'connect'              => false,
292
                    'enableSchemaCache'    => $connection->enableSchemaCache,
293
                    'schemaCacheDuration'  => $connection->schemaCacheDuration,
294
                    'schemaCacheExclude'   => array(), // $connection->schemaCacheExclude,
295
                    'schemaCache'          => $connection->schemaCache,
296
                    'enableQueryCache'     => $connection->enableQueryCache,
297
                    'queryCacheDuration'   => $connection->queryCacheDuration,
298
                    'queryCache'           => $connection->queryCache,
299
                    'emulatePrepare'       => NULL, // $connection->emulatePrepare,
300
                );
301
            }
302
303
            if ($dbParams) {
304
                if (isset($dbParams['password']) && substr($dbParams['password'], 0, 1) == '#') {
305
                    $dbParams['password'] = $this->decrypt($dbParams['password']);
306
                }
307
                $connection = $this->setupConnection($dbParams);
308
                if ($connection) {
309
310
                    $class = get_class($connection);
311
                    $this->extendResourceArray($resourceName, $connection, $class, (isset($dbParams['connect']) ? $dbParams['connect'] : false));
312
313
                    // add resourceName to the service manager as well (setup as not shared)
314
                    if ($this->hasService($resourceName)) {
315
                        $this->setService($resourceName, null);
316
                    }
317
                    $this->setService($resourceName, $connection);
318
319
                    return true;
320
                }
321
            } else {
322
                throw new Exception('Missing dbParams on addResource');
323
            }
324
        }
325
        return false;
326
    }
327
328
329
    /**
330
     * Extend internal resources array
331
     *
332
     * @param string $resourceName
333
     * @param Connection $connection
334
     * @param string $className
335
     * @param boolean $connect
336
     */
337
    public function extendResourceArray($resourceName, $connection, $className, $connect = false) {
338
        $this->resources['Resources'][$resourceName]['Connection'] = $connection;
339
        $this->resources['Resources'][$resourceName]['Connected'] = $connection->getIsActive();
340
        $this->resources['Resources'][$resourceName]['Aliases'] = array();
341
        $this->resources['Resources'][$resourceName]['Settings'] = array(
342
            'class'                => $className,
343
            'dsn'                  => $connection->dsn,
344
            'username'             => $connection->username,
345
            'password'             => $connection->password,
346
            'attributes'           => $connection->attributes,
347
            'charset'              => $connection->charset,
348
            'enableSchemaCache'    => $connection->enableSchemaCache,
349
            'schemaCacheDuration'  => $connection->schemaCacheDuration,
350
            'schemaCacheExclude'   => $connection->schemaCacheExclude,
351
            'schemaCache'          => $connection->schemaCache,
352
            'enableQueryCache'     => $connection->enableQueryCache,
353
            'queryCacheDuration'   => $connection->queryCacheDuration,
354
            'queryCache'           => $connection->queryCache,
355
            'emulatePrepare'       => $connection->emulatePrepare,
356
            'tablePrefix'          => $connection->tablePrefix,
357
            'connect'              => $connect,
358
        );
359
    }
360
361
    /**
362
     * Setup and return the connection for the specified resource name
363
     *
364
     * @param array $dbParams
365
     * @return Connection|false
366
     */
367
    public function setupConnection($dbParams)
368
    {
369
        $connected = false;
370
        $class = (isset($dbParams['class']) && is_string($dbParams['class']) && $dbParams['class'] != '' ? $dbParams['class'] : Connection::className());
371
        $connect = (isset($dbParams['connect']) && is_string($dbParams['connect']) ? $dbParams['connect'] : false);
372
        unset($dbParams['connect']);
373
374
        $connection = \Yii::createObject($dbParams);
375
376
        if ($connection instanceof $class) {
377
            if ($connect) {
378
                $connection->open();
379
                $connected = $connection->getIsActive();
380
            } elseif ($connection) {
381
                $connected = true;
382
            }
383
        }
384
385
        return ($connected ? $connection : $connected);
386
    }
387
388
389
    /**
390
     * Re-Connect a resources connection to the db if it has been previously closed or just to make sure the
391
     * connection is really still open
392
     *
393
     * @param string $resourceName [OPTIONAL] (default is the current default resource name)
394
     * @return boolean success
395
     */
396
    public function connectResource($resourceName = '')
397
    {
398
        $connected = false;
399
400
        $resourceName = ($resourceName != '' ? $resourceName : $this->defaultResourceName);
401
        $resourceName = $this->getResourceNameByAlias($resourceName);
402
403
        if ($resourceName && isset($this->resources['Resources'][$resourceName])) {
404
405
            if ($this->isResourceConnected($resourceName)) {
406
407
                $connected = true;
408
409
            } else {
410
411
                $connection = $this->getConnection($resourceName);
412
413
                try {
414
415
                    if (!$connection->getIsActive()) {
416
                        $connection->open();
417
                    }
418
419
                    $connected = $connection->getIsActive();
420
421
                } catch (\Exception $ex) {
422
423
                    // connection failed but we have caught the error so we can handle it gracefully
424
                    trigger_error($ex->getMessage() . ' in ' . $ex->getFile() . ' on line ' . $ex->getLine(), E_USER_WARNING);
425
426
                }
427
            }
428
429
        }
430
431
        return $connected;
432
    }
433
434
435
    /**
436
     * Disconnect a resources from the db
437
     *
438
     * @param string $resourceName [OPTIONAL] (default is the current default resource name)
439
     * @return boolean success
440
     */
441
    public function disconnectResource($resourceName = '')
442
    {
443
        $closed = false;
444
445
        $resourceName = ($resourceName != '' ? $resourceName : $this->defaultResourceName);
446
        $resourceName = $this->getResourceNameByAlias($resourceName);
447
448
        if ($resourceName && isset($this->resources['Resources'][$resourceName])) {
449
450
            if (!$this->isResourceConnected($resourceName)) {
451
452
                $closed = true;
453
454
            } else {
455
456
                $connection = $this->getConnection($resourceName);
457
458
                try {
459
460
                    if ($connection->getIsActive()) {
461
                        $connection->close();
462
                    }
463
464
                    $closed = ($connection->getIsActive() ? false : true);
465
466
                } catch (\Exception $ex) {
467
468
                    // connection failed but we have caught the error so that we can handle it gracefully
469
                    trigger_error($ex->getMessage() . ' in ' . $ex->getFile() . ' on line ' . $ex->getLine(), E_USER_WARNING);
470
471
                }
472
            }
473
474
        }
475
476
        return $closed;
477
    }
478
479
480
    /**
481
     * Add resource alias and return true/false upon success
482
     *
483
     * @param string $resourceName
484
     * @param string $alias
485
     * @return boolean
486
     */
487
    public function addResourceAlias($resourceName, $alias)
488
    {
489
        $aliasName = $this->getResourceNameByAlias($alias);
490
491
        if ($aliasName) {
492
493
            // new alias already exists as a resource or an alias
494
495
        } elseif ($resourceName == $alias) {
496
497
            // whoops
498
499
        } else {
500
501
            // do we have a resource to alias to?
502
            $resourceNameCheck = $this->getResourceNameByAlias($resourceName);
503
504
            if (!isset($this->resources['Resources'][$resourceNameCheck])) {
505
                // maybe we are setting up an alias to the main database connection before that main
506
                // database connection has been used - we will attempt to set that up now if there is @author Waine
507
                // service entry for it
508
                if ($this->hasService($resourceName)) {
509
                    if ($this->getConnection($resourceName, true)) {
510
                        $resourceNameCheck = $this->getResourceNameByAlias($resourceName);
511
                    }
512
                }
513
            }
514
515
            if (isset($this->resources['Resources'][$resourceNameCheck])) {
516
517
                $this->resources['Aliases'][$alias] = $resourceNameCheck;
518
                $this->resources['Resources'][$resourceNameCheck]['Aliases'][$alias] = true;
519
520
                // add alias to the service manager as well (setup as not shared)
521
                if ($this->hasService($alias)) {
522
                    $this->setService($alias, null);
523
                }
524
                $this->setService($alias, $this->resources['Resources'][$resourceNameCheck]['Connection']);
525
526
                return true;
527
            }
528
        }
529
530
        return false;
531
    }
532
533
534
    /**
535
     * Remove resource alias and return true/false upon success
536
     *
537
     * @param string $alias
538
     * @return boolean
539
     */
540
    public function removeResourceAlias($alias)
541
    {
542
        if (isset($this->resources['Resources'][$alias])) {
543
544
            // alias specified is not just an alias but a full resource entry
545
546
        } elseif (isset($this->resources['Aliases'][$alias])) {
547
548
            if (isset($this->resources['Resources'][$this->resources['Aliases'][$alias]]['Aliases'][$alias])) {
549
                unset($this->resources['Resources'][$this->resources['Aliases'][$alias]]['Aliases'][$alias]);
550
            }
551
            unset($this->resources['Aliases'][$alias]);
552
553
            // remove the alias from the service manager
554
            if ($this->hasService($alias)) {
555
                $this->setService($alias, null);
556
            }
557
558
            return true;
559
        }
560
561
        return false;
562
    }
563
564
565
    /**
566
     * Confirm if a resource has been setup
567
     *
568
     * @param string $resourceName [OPTIONAL] (default is the current default resource name)
569
     * @return boolean
570
     */
571
    public function isResource($resourceName = '')
572
    {
573
        $resourceName = ($resourceName != '' ? $resourceName : $this->defaultResourceName);
574
        $resourceName = $this->getResourceNameByAlias($resourceName);
575
        if ($resourceName && isset($this->resources['Resources'][$resourceName])) {
576
            return true;
577
        }
578
579
        return false;
580
    }
581
582
583
    /**
584
     * Confirm if a resouce has been setup and is currently connected
585
     *
586
     * @param string $resourceName [OPTIONAL] (default is the current default resource name)
587
     * @return boolean
588
     */
589
    public function isResourceConnected($resourceName='')
590
    {
591
        $resourceName = ($resourceName != '' ? $resourceName : $this->defaultResourceName);
592
        $resourceName = $this->getResourceNameByAlias($resourceName);
593
594
        if ($resourceName && isset($this->resources['Resources'][$resourceName])) {
595
            return $this->resources['Resources'][$resourceName]['Connection']->getIsActive();
596
        }
597
598
        return false;
599
    }
600
601
602
    /**
603
     * Remove resource and close the existing connection if required
604
     *
605
     * @param string $resourceName [OPTIONAL] (default is the current default resource name)
606
     * @return boolean
607
     */
608
    public function removeResource($resourceName = '')
609
    {
610
        $resourceName = ($resourceName != '' ? $resourceName : $this->defaultResourceName);
611
        $resourceName = $this->getResourceNameByAlias($resourceName);
612
613
        if ($resourceName && isset($this->resources['Resources'][$resourceName])) {
614
615
            if ($this->isResourceConnected($resourceName)) {
616
                $this->disconnectResource($resourceName);
617
            }
618
619
            $aliases = $this->resources['Resources'][$resourceName]['Aliases'];
620
621
            if ($aliases) {
622
                foreach ($aliases as $alias => $data) {
623
                    $this->removeResourceAlias($alias);
624
                }
625
            }
626
627
            unset($this->resources['Resources'][$resourceName]);
628
629
            // remove the resource from the service manager
630
            if ($this->hasService($resourceName)) {
631
                $this->setService($resourceName, null);
632
            }
633
634
            return true;
635
        }
636
637
        return false;
638
    }
639
640
641
    /**
642
     * Remove all DB resources and close the existing connections if required
643
     * optionally leave the 'db' connection open (default is to leave open so sessions etc can be completed)
644
     *
645
     * @param boolean $includeCore default false
646
     * @return boolean $success
647
     */
648
    public function removeAllResources($includeCore = false)
649
    {
650
        foreach ($this->resources['Resources'] as $resource => $data) {
651
            if ($resource == 'db' && !$includeCore) {
652
                // do not remove
653
            } else {
654
                $this->removeResource($resource);
655
            }
656
        }
657
        if ($includeCore) {
658
            $this->resources['Aliases'] = array();
659
        }
660
        return true;
661
    }
662
663
664
    /**
665
     * Check components for db connections that have not been registered via the connection manager
666
     */
667
    public function checkAllServices()
668
    {
669
        $services = $this->getServices();
670
        foreach ($services as $serviceName => $service) {
671
            if ($service instanceof Connection) {
672
                if (!isset($this->resources['Resources'][$serviceName])) {
673
                    $resourceName = $this->getResourceNameByAlias($serviceName);
674
                    if ($resourceName) {
675
                        throw new Exception('Service manager has db connection instance that is also an alias within ConnectionManager');
676
                    }
677
                    $class = get_class($service);
678
                    $this->extendResourceArray($serviceName, $service, $class);
679
                }
680
            }
681
        }
682
    }
683
684
685
    /**
686
     * Get a count of the number of resources defined
687
     *
688
     * @return integer
689
     */
690
    public function getResourceCount()
691
    {
692
        return count($this->resources['Resources']);
693
    }
694
695
696
    /**
697
     * Get a count of the number of aliases
698
     *
699
     * @return integer
700
     */
701
    public function getAliasCount()
702
    {
703
        return count($this->resources['Aliases']);
704
    }
705
706
707
    /**
708
     * Get an array of the setup resources, by default excluding connection objects
709
     *
710
     * @param boolean $includeConnections include the connection objects in the response
711
     * @param boolean $checkServices check services for db connections that have not been registered via the connection manager
712
     * @return array
713
     */
714
    public function getResourceArray($includeConnections = false, $checkServices = true)
715
    {
716
717
        if ($checkServices) {
718
            $this->checkAllServices();
719
        }
720
721
        $array = array();
722
        $array['Resources'] = array();
723
        $array['Aliases'] = $this->resources['Aliases'];
724
        foreach ($this->resources['Resources'] as $resource => $data) {
725
            $settings = $data['Settings'];
726
            $settings['password'] = '{password}';
727
            $array['Resources'][$resource] = array(
728
                'Aliases' => $data['Aliases'],
729
                'Settings' => $settings,
730
                'Default' => ($resource == $this->defaultResourceName ? true : false),
731
                'Connected' => $data['Connection']->getIsActive(),
732
            );
733
            if ($includeConnections) {
734
                $array['Resources'][$resource]['Connection'] = $data['Connection'];
735
            }
736
        }
737
        return $array;
738
    }
739
740
741
    /**
742
     * Alias fpr $this->getResourceArray()
743
     * @return array
744
     */
745
    public function toArray() {
746
        return $this->getResourceArray(true);
747
    }
748
749
750
    /**
751
     * Obtain resource settings
752
     * @param string $resourceName [OPTIONAL] (default is the current default resource name)
753
     * @return array|false
754
     */
755
    public function getResourceSettings($resourceName = '')
756
    {
757
        $resourceName = ($resourceName != '' ? $resourceName : $this->defaultResourceName);
758
        $resourceName = $this->getResourceNameByAlias($resourceName);
759
        if ($resourceName && isset($this->resources['Resources'][$resourceName]['Settings'])) {
760
            return $this->resources['Resources'][$resourceName]['Settings'];
761
        }
762
        return false;
763
    }
764
765
766
    /**
767
     * Obtain the last error code info on the specified connection
768
     * <code>
769
     *      list($pdoErrorCode, $dbErrorCode, $dbErrorString) = \Yii::$app->get('dbFactory')->getLastError('db');
770
     * </code>
771
     * @param string $resourceName [OPTIONAL] (default is the current default resource name)
772
     * @return array|false
773
     */
774
    public function getLastError($resourceName = '')
775
    {
776
        $resourceName = ($resourceName != '' ? $resourceName : $this->defaultResourceName);
777
        $connection = $this->getConnection($resourceName);
778
        if ($connection) {
779
            return $connection->pdo->errorInfo();
780
        }
781
        return false;
782
    }
783
784
    /**
785
     * Encrypt a string suitable for storing against a db resource for use within
786
     * this connection manager
787
     *
788
     * @param string $unencrypted
789
     * @return string encrypted
790
     */
791
    private function encrypt($unencrypted)
792
    {
793
        $td = mcrypt_module_open('blowfish', '', 'ecb', '');
794
        $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? MCRYPT_RAND : MCRYPT_DEV_RANDOM));
795
        $key = substr(md5($this->secretKey), 0, mcrypt_enc_get_key_size($td));
796
        mcrypt_generic_init($td, $key, $iv);
797
        $enc = mcrypt_generic($td, $unencrypted);
798
        $encrypted = trim($enc) . "||||" . $iv;
799
        mcrypt_generic_deinit($td);
800
        mcrypt_module_close($td);
801
        return '#' . base64_encode($encrypted);
802
    }
803
804
    /**
805
     * Decrypt a db resource password
806
     *
807
     * @param string $encrypted encrypted
808
     * @return string decrypted
809
     */
810
    private function decrypt($encrypted)
811
    {
812
        if (substr($encrypted,0,1) == '#') {
813
            $encrypted = substr($encrypted,1);
814
        } else {
815
            $encrypted = '';
816
        }
817
        if ($encrypted != '') {
818
            $encrypted = base64_decode($encrypted);
819
            list($encrypted,$iv) = explode("||||", $encrypted,2);
820
            $td = mcrypt_module_open('blowfish', '', 'ecb', '');
821
            $key = substr(md5($this->secretKey),0,mcrypt_enc_get_key_size($td));
822
            mcrypt_generic_init($td, $key, $iv);
823
            $unencrypted = mdecrypt_generic($td, $encrypted);
824
            mcrypt_generic_deinit($td);
825
            mcrypt_module_close($td);
826
            return trim($unencrypted);
827
        }
828
        return '';
829
    }
830
831
}
832