Issues (50)

src/DB/Connection/PDO.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2025
6
 * @package Base
7
 * @subpackage DB
8
 */
9
10
11
namespace Aimeos\Base\DB\Connection;
12
13
14
/**
15
 * Database connection class for \PDO connections.
16
 *
17
 * @package Base
18
 * @subpackage DB
19
 */
20
class PDO extends Base implements Iface
21
{
22
	private ?\PDO $connection = null;
23
	private int $txnumber = 0;
24
	private array $stmts = [];
25
26
27
	/**
28
	 * Initializes the PDO connection object.
29
	 *
30
	 * @param array $params Associative list of connection parameters
31
	 */
32
	public function __construct( array $params )
33
	{
34
		if( !isset( $params['dsn'] ) ) {
35
			$params['dsn'] = $this->dsn( $params );
36
		}
37
38
		parent::__construct( $params );
39
40
		$this->stmts = $params['stmt'] ?? [];
41
		$this->connect();
42
	}
43
44
45
	/**
46
	 * Closes the connection to the database server
47
	 *
48
	 * @return \Aimeos\Base\DB\Connection\Iface Connection instance for method chaining
49
	 */
50
	public function close() : Iface
51
	{
52
		if( $this->inTransaction() ) {
53
			$this->rollback();
54
		}
55
56
		unset( $this->connection );
57
		return $this;
58
	}
59
60
61
	/**
62
	 * Connects (or reconnects) to the database server
63
	 *
64
	 * @return \Aimeos\Base\DB\Connection\Iface Connection instance for method chaining
65
	 */
66
	public function connect() : Iface
67
	{
68
		$param = $this->getParameters();
69
		$param['driverOptions'][\PDO::ATTR_CASE] = \PDO::CASE_NATURAL;
70
		$param['driverOptions'][\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_EXCEPTION;
71
		$param['driverOptions'][\PDO::ATTR_ORACLE_NULLS] = \PDO::NULL_NATURAL;
72
		$param['driverOptions'][\PDO::ATTR_STRINGIFY_FETCHES] = false;
73
74
		$pdo = new \PDO( $param['dsn'], $param['username'] ?? '', $param['password'] ?? '', $param['driverOptions'] );
75
		$conn = $this->connection;
76
77
		$this->connection = $pdo;
78
		$this->txnumber = 0;
79
80
		unset( $conn );
81
82
		foreach( $this->stmts as $stmt ) {
83
			$this->create( $stmt )->execute()->finish();
84
		}
85
86
		return $this;
87
	}
88
89
90
	/**
91
	 * Creates a \PDO database statement.
92
	 *
93
	 * @param string $sql SQL statement, maybe with place holders
94
	 * @return \Aimeos\Base\DB\Statement\Iface PDO statement object
95
	 * @throws \Aimeos\Base\DB\Exception if type is invalid or the \PDO object throws an exception
96
	 */
97
	public function create( string $sql ) : \Aimeos\Base\DB\Statement\Iface
98
	{
99
		try
100
		{
101
			if( strpos( $sql, '?' ) === false ) {
102
				return new \Aimeos\Base\DB\Statement\PDO\Simple( $this, $sql );
103
			}
104
105
			return new \Aimeos\Base\DB\Statement\PDO\Prepared( $this, $sql );
106
		}
107
		catch( \PDOException $e )
108
		{
109
			throw new \Aimeos\Base\DB\Exception( $e->getMessage(), $e->getCode(), $e->errorInfo );
110
		}
111
	}
112
113
114
	/**
115
	 * Returns the underlying connection object
116
	 *
117
	 * @return \PDO Underlying connection object
118
	 */
119
	public function getRawObject()
120
	{
121
		return $this->connection;
122
	}
123
124
125
	/**
126
	 * Checks if a transaction is currently running
127
	 *
128
	 * @return bool True if transaction is currently running, false if not
129
	 */
130
	public function inTransaction() : bool
131
	{
132
		return $this->connection->inTransaction();
0 ignored issues
show
The method inTransaction() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

132
		return $this->connection->/** @scrutinizer ignore-call */ inTransaction();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
133
	}
134
135
136
	/**
137
	 * Starts a transaction for this connection.
138
	 *
139
	 * Transactions can't be nested and a new transaction can only be started
140
	 * if the previous transaction was committed or rolled back before.
141
	 *
142
	 * @return \Aimeos\Base\DB\Connection\Iface Connection instance for method chaining
143
	 */
144
	public function begin() : Iface
145
	{
146
		if( $this->txnumber === 0 )
147
		{
148
			if( $this->connection->beginTransaction() === false ) {
149
				throw new \Aimeos\Base\DB\Exception( 'Unable to start new transaction' );
150
			}
151
		}
152
153
		$this->txnumber++;
154
		return $this;
155
	}
156
157
158
	/**
159
	 * Commits the changes done inside of the transaction to the storage.
160
	 *
161
	 * @return \Aimeos\Base\DB\Connection\Iface Connection instance for method chaining
162
	 */
163
	public function commit() : Iface
164
	{
165
		if( $this->txnumber === 1 )
166
		{
167
			if( $this->connection->commit() === false ) {
168
				throw new \Aimeos\Base\DB\Exception( 'Failed to commit transaction' );
169
			}
170
		}
171
172
		$this->txnumber--;
173
		return $this;
174
	}
175
176
177
	/**
178
	 * Discards the changes done inside of the transaction.
179
	 *
180
	 * @return \Aimeos\Base\DB\Connection\Iface Connection instance for method chaining
181
	 */
182
	public function rollback() : Iface
183
	{
184
		if( $this->txnumber === 1 )
185
		{
186
			if( $this->connection->rollBack() === false ) {
187
				throw new \Aimeos\Base\DB\Exception( 'Failed to roll back transaction' );
188
			}
189
		}
190
191
		$this->txnumber--;
192
		return $this;
193
	}
194
195
196
	/**
197
	 * Returns the connection DSN
198
	 *
199
	 * @param array $params Associative list of connection parameters
200
	 * @return string Connection DSN
201
	 */
202
	protected function dsn( array $params ) : string
203
	{
204
		$adapter = $params['adapter'] ?? 'mysql';
205
		$host = $params['host'] ?? null;
206
		$port = $params['port'] ?? null;
207
		$sock = $params['socket'] ?? null;
208
		$dbase = $params['database'] ?? null;
209
210
		$dsn = $adapter . ':';
211
212
		if( $adapter === 'sqlsrv' )
213
		{
214
			$dsn .= 'Database=' . $dbase;
215
			$dsn .= isset( $host ) ? ';Server=' . $host . ( isset( $port ) ? ',' . $port : '' ) : '';
216
		}
217
		elseif( $sock == null )
218
		{
219
			$dsn .= 'dbname=' . $dbase;
220
			$dsn .= isset( $host ) ? ';host=' . $host : '';
221
			$dsn .= isset( $port ) ? ';port=' . $port : '';
222
		}
223
		else
224
		{
225
			$dsn .= 'dbname=' . $dbase . ';unix_socket=' . $sock;
226
		}
227
228
		return $dsn;
229
	}
230
}
231