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