Completed
Push — develop ( e4ca03...908b9f )
by Timothy
06:32
created

ConnectionManager::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * Query
4
 *
5
 * SQL Query Builder / Database Abstraction Layer
6
 *
7
 * PHP version 7.1
8
 *
9
 * @package     Query
10
 * @author      Timothy J. Warren <[email protected]>
11
 * @copyright   2012 - 2018 Timothy J. Warren
12
 * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
 * @link        https://git.timshomepage.net/aviat4ion/Query
14
 */
15
namespace Query;
16
17
use DomainException;
18
use InvalidArgumentException;
19
20
/**
21
 * Connection manager class to manage connections for the
22
 * Query method
23
 */
24
final class ConnectionManager {
25
26
	/**
27
	 * Map of named database connections
28
	 * @var array
29
	 */
30
	private $connections = [];
31
32
	/**
33
	 * Class instance variable
34
	 * @var ConnectionManager|null
35
	 */
36
	private static $instance;
37
38
	/**
39
	 * Private constructor to prevent multiple instances
40
	 * @codeCoverageIgnore
41
	 */
42
	private function __construct()
43
	{
44
	}
45
46
	/**
47
	 * Private clone method to prevent cloning
48
	 *
49
	 * @throws DomainException
50
	 * @return void
51
	 */
52
	public function __clone()
53
	{
54
		throw new DomainException("Can't clone singleton");
55
	}
56
57
	/**
58
	 * Prevent serialization of this object
59
	 *
60
	 * @throws DomainException
61
	 * @return void
62
	 */
63
	public function __sleep()
64
	{
65
		throw new DomainException('No serializing of singleton');
66
	}
67
68
	/**
69
	 * Make sure serialize/deserialize doesn't work
70
	 *
71
	 * @throws DomainException
72
	 * @return void
73
	 */
74
	public function __wakeup()
75
	{
76
		throw new DomainException("Can't unserialize singleton");
77
	}
78
79
	/**
80
	 * Return  a connection manager instance
81
	 *
82
	 * @staticvar null $instance
83
	 * @return ConnectionManager
84
	 */
85
	public static function getInstance(): ConnectionManager
86
	{
87
		if (self::$instance === NULL)
88
		{
89
			self::$instance = new self();
90
		}
91
92
		return self::$instance;
93
	}
94
95
	/**
96
	 * Returns the connection specified by the name given
97
	 *
98
	 * @param string|array|object $name
99
	 * @return QueryBuilderInterface
100
	 * @throws InvalidArgumentException
101
	 */
102
	public function getConnection($name = ''): QueryBuilderInterface
103
	{
104
		// If the parameter is a string, use it as an array index
105
		if (is_scalar($name) && isset($this->connections[$name]))
106
		{
107
			return $this->connections[$name];
108
		}
109
		elseif (empty($name) && ! empty($this->connections)) // Otherwise, return the last one
110
		{
111
			return end($this->connections);
112
		}
113
114
		// You should actually connect before trying to get a connection...
115
		throw new InvalidArgumentException('The specified connection does not exist');
116
	}
117
118
	/**
119
	 * Parse the passed parameters and return a connection
120
	 *
121
	 * @param \stdClass $params
122
	 * @return QueryBuilderInterface
123
	 */
124
	public function connect(\stdClass $params): QueryBuilderInterface
125
	{
126
		list($dsn, $dbtype, $params, $options) = $this->parseParams($params);
127
128
		$dbtype = ucfirst($dbtype);
129
		$driver = "\\Query\\Drivers\\{$dbtype}\\Driver";
130
131
		// Create the database connection
132
		$db =  ! empty($params->user)
133
			? new $driver($dsn, $params->user, $params->pass, $options)
134
			: new $driver($dsn, '', '', $options);
135
136
		// Set the table prefix, if it exists
137
		if (isset($params->prefix))
138
		{
139
			$db->setTablePrefix($params->prefix);
140
		}
141
142
		// Create Query Builder object
143
		$conn = new QueryBuilder($db, new QueryParser($db));
144
145
146
		// Save it for later
147
		if (isset($params->alias))
148
		{
149
			$this->connections[$params->alias] = $conn;
150
		}
151
		else
152
		{
153
			$this->connections[] = $conn;
154
		}
155
156
		return $conn;
157
	}
158
159
	/**
160
	 * Parses params into a dsn and option array
161
	 *
162
	 * @param \stdClass $params
163
	 * @return array
164
	 * @throws BadDBDriverException
165
	 */
166
	public function parseParams(\stdClass $params): array
167
	{
168
		$params->type = strtolower($params->type);
169
		$dbtype = ($params->type !== 'postgresql') ? $params->type : 'pgsql';
170
		$dbtype = ucfirst($dbtype);
171
172
		// Make sure the class exists
173
		if ( ! class_exists("\\Query\\Drivers\\{$dbtype}\\Driver"))
174
		{
175
			throw new BadDBDriverException('Database driver does not exist, or is not supported');
176
		}
177
178
		// Set additional PDO options
179
		$options = [];
180
181
		if (isset($params->options))
182
		{
183
			$options = (array) $params->options;
184
		}
185
186
		// Create the dsn for the database to connect to
187
		if(strtolower($dbtype) === 'sqlite')
188
		{
189
			$dsn = $params->file;
190
		}
191
		else
192
		{
193
			$dsn = $this->createDsn($dbtype, $params);
194
		}
195
196
197
		return [$dsn, $dbtype, $params, $options];
198
	}
199
200
	/**
201
	 * Create the dsn from the db type and params
202
	 *
203
	 * @param string $dbtype
204
	 * @param \stdClass $params
205
	 * @return string
206
	 */
207
	private function createDsn(string $dbtype, \stdClass $params): string
208
	{
209
		$pairs = [];
210
211
		if ( ! empty($params->database))
212
		{
213
			$pairs[] = implode('=', ['dbname', $params->database]);
214
		}
215
216
		$skip = [
217
			'name' => 'name',
218
			'pass' => 'pass',
219
			'user' => 'user',
220
			'type' => 'type',
221
			'prefix' => 'prefix',
222
			'options' => 'options',
223
			'database' => 'database',
224
			'alias' => 'alias'
225
		];
226
227
		foreach($params as $key => $val)
0 ignored issues
show
Bug introduced by
The expression $params of type object<stdClass> is not traversable.
Loading history...
228
		{
229
			if (( ! array_key_exists($key, $skip)) &&  ! empty($val))
230
			{
231
				$pairs[] = implode('=', [$key, $val]);
232
			}
233
		}
234
235
		return strtolower($dbtype) . ':' . implode(';', $pairs);
236
	}
237
}