1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 0.10.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\Datasource;
16:
17: use Cake\Core\StaticConfigTrait;
18: use Cake\Datasource\Exception\MissingDatasourceConfigException;
19:
20: /**
21: * Manages and loads instances of Connection
22: *
23: * Provides an interface to loading and creating connection objects. Acts as
24: * a registry for the connections defined in an application.
25: *
26: * Provides an interface for loading and enumerating connections defined in
27: * config/app.php
28: */
29: class ConnectionManager
30: {
31:
32: use StaticConfigTrait {
33: setConfig as protected _setConfig;
34: parseDsn as protected _parseDsn;
35: }
36:
37: /**
38: * A map of connection aliases.
39: *
40: * @var array
41: */
42: protected static $_aliasMap = [];
43:
44: /**
45: * An array mapping url schemes to fully qualified driver class names
46: *
47: * @return array
48: */
49: protected static $_dsnClassMap = [
50: 'mysql' => 'Cake\Database\Driver\Mysql',
51: 'postgres' => 'Cake\Database\Driver\Postgres',
52: 'sqlite' => 'Cake\Database\Driver\Sqlite',
53: 'sqlserver' => 'Cake\Database\Driver\Sqlserver',
54: ];
55:
56: /**
57: * The ConnectionRegistry used by the manager.
58: *
59: * @var \Cake\Datasource\ConnectionRegistry
60: */
61: protected static $_registry;
62:
63: /**
64: * Configure a new connection object.
65: *
66: * The connection will not be constructed until it is first used.
67: *
68: * @param string|array $key The name of the connection config, or an array of multiple configs.
69: * @param array|null $config An array of name => config data for adapter.
70: * @return void
71: * @throws \Cake\Core\Exception\Exception When trying to modify an existing config.
72: * @see \Cake\Core\StaticConfigTrait::config()
73: */
74: public static function setConfig($key, $config = null)
75: {
76: if (is_array($config)) {
77: $config['name'] = $key;
78: }
79:
80: static::_setConfig($key, $config);
81: }
82:
83: /**
84: * Parses a DSN into a valid connection configuration
85: *
86: * This method allows setting a DSN using formatting similar to that used by PEAR::DB.
87: * The following is an example of its usage:
88: *
89: * ```
90: * $dsn = 'mysql://user:pass@localhost/database';
91: * $config = ConnectionManager::parseDsn($dsn);
92: *
93: * $dsn = 'Cake\Database\Driver\Mysql://localhost:3306/database?className=Cake\Database\Connection';
94: * $config = ConnectionManager::parseDsn($dsn);
95: *
96: * $dsn = 'Cake\Database\Connection://localhost:3306/database?driver=Cake\Database\Driver\Mysql';
97: * $config = ConnectionManager::parseDsn($dsn);
98: * ```
99: *
100: * For all classes, the value of `scheme` is set as the value of both the `className` and `driver`
101: * unless they have been otherwise specified.
102: *
103: * Note that query-string arguments are also parsed and set as values in the returned configuration.
104: *
105: * @param string|null $config The DSN string to convert to a configuration array
106: * @return array The configuration array to be stored after parsing the DSN
107: */
108: public static function parseDsn($config = null)
109: {
110: $config = static::_parseDsn($config);
111:
112: if (isset($config['path']) && empty($config['database'])) {
113: $config['database'] = substr($config['path'], 1);
114: }
115:
116: if (empty($config['driver'])) {
117: $config['driver'] = $config['className'];
118: $config['className'] = 'Cake\Database\Connection';
119: }
120:
121: unset($config['path']);
122:
123: return $config;
124: }
125:
126: /**
127: * Set one or more connection aliases.
128: *
129: * Connection aliases allow you to rename active connections without overwriting
130: * the aliased connection. This is most useful in the test-suite for replacing
131: * connections with their test variant.
132: *
133: * Defined aliases will take precedence over normal connection names. For example,
134: * if you alias 'default' to 'test', fetching 'default' will always return the 'test'
135: * connection as long as the alias is defined.
136: *
137: * You can remove aliases with ConnectionManager::dropAlias().
138: *
139: * ### Usage
140: *
141: * ```
142: * // Make 'things' resolve to 'test_things' connection
143: * ConnectionManager::alias('test_things', 'things');
144: * ```
145: *
146: * @param string $alias The alias to add. Fetching $source will return $alias when loaded with get.
147: * @param string $source The connection to add an alias to.
148: * @return void
149: * @throws \Cake\Datasource\Exception\MissingDatasourceConfigException When aliasing a
150: * connection that does not exist.
151: */
152: public static function alias($alias, $source)
153: {
154: if (empty(static::$_config[$source]) && empty(static::$_config[$alias])) {
155: throw new MissingDatasourceConfigException(
156: sprintf('Cannot create alias of "%s" as it does not exist.', $alias)
157: );
158: }
159: static::$_aliasMap[$source] = $alias;
160: }
161:
162: /**
163: * Drop an alias.
164: *
165: * Removes an alias from ConnectionManager. Fetching the aliased
166: * connection may fail if there is no other connection with that name.
167: *
168: * @param string $name The connection name to remove aliases for.
169: * @return void
170: */
171: public static function dropAlias($name)
172: {
173: unset(static::$_aliasMap[$name]);
174: }
175:
176: /**
177: * Get a connection.
178: *
179: * If the connection has not been constructed an instance will be added
180: * to the registry. This method will use any aliases that have been
181: * defined. If you want the original unaliased connections pass `false`
182: * as second parameter.
183: *
184: * @param string $name The connection name.
185: * @param bool $useAliases Set to false to not use aliased connections.
186: * @return \Cake\Datasource\ConnectionInterface A connection object.
187: * @throws \Cake\Datasource\Exception\MissingDatasourceConfigException When config
188: * data is missing.
189: */
190: public static function get($name, $useAliases = true)
191: {
192: if ($useAliases && isset(static::$_aliasMap[$name])) {
193: $name = static::$_aliasMap[$name];
194: }
195: if (empty(static::$_config[$name])) {
196: throw new MissingDatasourceConfigException(['name' => $name]);
197: }
198: if (empty(static::$_registry)) {
199: static::$_registry = new ConnectionRegistry();
200: }
201: if (isset(static::$_registry->{$name})) {
202: return static::$_registry->{$name};
203: }
204:
205: return static::$_registry->load($name, static::$_config[$name]);
206: }
207: }
208: