Passed
Push — master ( 1a5f01...95cf58 )
by Aimeos
09:39
created

PDO::acquire()   B

Complexity

Conditions 9
Paths 44

Size

Total Lines 32
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
c 1
b 0
f 0
dl 0
loc 32
rs 8.0555
cc 9
nc 44
nop 1
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2022
6
 * @package Base
7
 * @subpackage DB
8
 */
9
10
11
namespace Aimeos\Base\DB\Manager;
12
13
14
/**
15
 * Manager for database connections using the PDO library.
16
 *
17
 * @package Base
18
 * @subpackage DB
19
 */
20
class PDO implements \Aimeos\Base\DB\Manager\Iface
21
{
22
	private $connections = [];
23
	private $conns = [];
24
	private $count = [];
25
	private $config;
26
27
28
	/**
29
	 * Initializes the database manager object
30
	 *
31
	 * @param array $config Database resource configuration
32
	 */
33
	public function __construct( array $config )
34
	{
35
		$this->config = $config;
36
	}
37
38
39
	/**
40
	 * Cleans up the object
41
	 */
42
	public function __destruct()
43
	{
44
		foreach( $this->connections as $name => $list )
45
		{
46
			foreach( $list as $key => $conn ) {
47
				unset( $this->connections[$name][$key] );
48
			}
49
		}
50
51
		foreach( $this->conns as $key => $conn ) {
52
			unset( $this->conns[$key] );
53
		}
54
	}
55
56
57
	/**
58
	 * Reset when cloning the object
59
	 */
60
	public function __clone()
61
	{
62
		$this->connections = [];
63
		$this->conns = [];
64
		$this->count = [];
65
	}
66
67
68
	/**
69
	 * Clean up the objects inside
70
	 */
71
	public function __sleep()
72
	{
73
		$this->__destruct();
74
75
		$this->connections = [];
76
		$this->conns = [];
77
		$this->count = [];
78
79
		return get_object_vars( $this );
80
	}
81
82
83
	/**
84
	 * Returns a database connection.
85
	 *
86
	 * @param string $name Name of the resource in configuration
87
	 * @param bool $new Create a new connection instead of returning the existing one
88
	 * @return \Aimeos\Base\DB\Connection\Iface
89
	 */
90
	public function get( string $name = 'db', bool $new = false ) : \Aimeos\Base\DB\Connection\Iface
91
	{
92
		$name = isset( $this->config[$name] ) ? $name : 'db';
93
94
		if( $new ) {
95
			return $this->create( $name );
96
		}
97
98
		if( !isset( $this->conns[$name] ) ) {
99
			$this->conns[$name] = $this->create( $name );
100
		}
101
102
		return $this->conns[$name];
103
	}
104
105
106
	/**
107
	 * Returns a database connection.
108
	 *
109
	 * @param string $name Name of the resource in configuration
110
	 * @return \Aimeos\Base\DB\Connection\Iface
111
	 */
112
	public function acquire( string $name = 'db' ) : \Aimeos\Base\DB\Connection\Iface
113
	{
114
		try
115
		{
116
			$name = isset( $this->config[$name] ) ? $name : 'db';
117
118
			if( !isset( $this->config[$name] ) ) {
119
				throw new \Aimeos\Base\DB\Exception( "No database configuration for resource \"$name\" available" );
120
			}
121
122
			if( !isset( $this->connections[$name] ) || empty( $this->connections[$name] ) )
123
			{
124
				if( !isset( $this->count[$name] ) ) {
125
					$this->count[$name] = 0;
126
				}
127
128
				$limit = $cfg['limit'] ?? -1;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $cfg seems to never exist and therefore isset should always be false.
Loading history...
129
130
				if( $limit >= 0 && $this->count[$name] >= $limit )
131
				{
132
					$msg = "Maximum number of connections ($limit) for \"$name\" exceeded";
133
					throw new \Aimeos\Base\DB\Exception( $msg );
134
				}
135
136
				$this->connections[$name] = array( $this->create( $name ) );
137
				$this->count[$name]++;
138
			}
139
140
			return array_pop( $this->connections[$name] );
141
		}
142
		catch( \PDOException $e ) {
143
			throw new \Aimeos\Base\DB\Exception( $e->getMessage(), $e->getCode(), $e->errorInfo );
144
		}
145
	}
146
147
148
	/**
149
	 * Releases the connection for reuse
150
	 *
151
	 * @param \Aimeos\Base\DB\Connection\Iface $connection Connection object
152
	 * @param string $name Name of resource
153
	 */
154
	public function release( \Aimeos\Base\DB\Connection\Iface $connection, string $name = 'db' )
155
	{
156
		if( ( $connection instanceof \Aimeos\Base\DB\Connection\PDO ) === false ) {
157
			throw new \Aimeos\Base\DB\Exception( 'Connection object isn\'t of type \PDO' );
158
		}
159
160
		$name = isset( $this->config[$name] ) ? $name : 'db';
161
162
		$this->connections[$name][] = $connection;
163
	}
164
165
166
	/**
167
	 * Creates a new database connection.
168
	 *
169
	 * @param string $name Name to the database configuration in the resource file
170
	 * @return \Aimeos\Base\DB\Connection\Iface Database connection
171
	 */
172
	protected function create( string $name ) : \Aimeos\Base\DB\Connection\Iface
173
	{
174
		$params = $this->config[$name] ?? [];
175
176
		if( !isset( $params['dsn'] ) )
177
		{
178
			$adapter = $params['adapter'] ?? 'mysql';
179
			$host = $params['host'] ?? null;
180
			$port = $params['port'] ?? null;
181
			$sock = $params['socket'] ?? null;
182
			$dbase = $params['database'] ?? null;
183
184
			$dsn = $adapter . ':';
185
186
			if( $adapter === 'sqlsrv' )
187
			{
188
				$dsn .= 'Database=' . $dbase;
189
				$dsn .= isset( $host ) ? ';Server=' . $host . ( isset( $port ) ? ',' . $port : '' ) : '';
190
			}
191
			elseif( $sock == null )
192
			{
193
				$dsn .= 'dbname=' . $dbase;
194
				$dsn .= isset( $host ) ? ';host=' . $host : '';
195
				$dsn .= isset( $port ) ? ';port=' . $port : '';
196
			}
197
			else
198
			{
199
				$dsn .= 'dbname=' . $dbase . ';unix_socket=' . $sock;
200
			}
201
202
			$params['dsn'] = $dsn;
203
		}
204
205
		return new \Aimeos\Base\DB\Connection\PDO( $params, $params['stmt'] ?? [] );
206
	}
207
}
208