Deprecated : Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 58
Deprecated : Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 76
Symfony Profiler
<?php
namespace Doctrine\DBAL ;
use Closure ;
use Doctrine\Common\EventManager ;
use Doctrine\DBAL\Cache\ArrayResult ;
use Doctrine\DBAL\Cache\CacheException ;
use Doctrine\DBAL\Cache\QueryCacheProfile ;
use Doctrine\DBAL\Driver\API\ExceptionConverter ;
use Doctrine\DBAL\Driver\Connection as DriverConnection ;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection ;
use Doctrine\DBAL\Driver\Statement as DriverStatement ;
use Doctrine\DBAL\Event\TransactionBeginEventArgs ;
use Doctrine\DBAL\Event\TransactionCommitEventArgs ;
use Doctrine\DBAL\Event\TransactionRollBackEventArgs ;
use Doctrine\DBAL\Exception\ConnectionLost ;
use Doctrine\DBAL\Exception\DriverException ;
use Doctrine\DBAL\Exception\InvalidArgumentException ;
use Doctrine\DBAL\Platforms\AbstractPlatform ;
use Doctrine\DBAL\Query\Expression\ExpressionBuilder ;
use Doctrine\DBAL\Query\QueryBuilder ;
use Doctrine\DBAL\Schema\AbstractSchemaManager ;
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory ;
use Doctrine\DBAL\Schema\LegacySchemaManagerFactory ;
use Doctrine\DBAL\Schema\SchemaManagerFactory ;
use Doctrine\DBAL\SQL\Parser ;
use Doctrine\DBAL\Types\Type ;
use Doctrine\Deprecations\Deprecation ;
use LogicException ;
use SensitiveParameter ;
use Throwable ;
use Traversable ;
use function array_key_exists ;
use function assert ;
use function count ;
use function get_class ;
use function implode ;
use function is_int ;
use function is_string ;
use function key ;
use function method_exists ;
use function sprintf ;
/**
* A database abstraction-level connection that implements features like events, transaction isolation levels,
* configuration, emulated transaction nesting, lazy connecting and more.
*
* @psalm-import-type Params from DriverManager
* @psalm-consistent-constructor
*/
class Connection
{
/**
* Represents an array of ints to be expanded by Doctrine SQL parsing.
*
* @deprecated Use {@see ArrayParameterType::INTEGER} instead.
*/
public const PARAM_INT_ARRAY = ArrayParameterType :: INTEGER ;
/**
* Represents an array of strings to be expanded by Doctrine SQL parsing.
*
* @deprecated Use {@see ArrayParameterType::STRING} instead.
*/
public const PARAM_STR_ARRAY = ArrayParameterType :: STRING ;
/**
* Represents an array of ascii strings to be expanded by Doctrine SQL parsing.
*
* @deprecated Use {@see ArrayParameterType::ASCII} instead.
*/
public const PARAM_ASCII_STR_ARRAY = ArrayParameterType :: ASCII ;
/**
* Offset by which PARAM_* constants are detected as arrays of the param type.
*
* @internal Should be used only within the wrapper layer.
*/
public const ARRAY_PARAM_OFFSET = 100 ;
/**
* The wrapped driver connection.
*
* @var DriverConnection|null
*/
protected $_conn ;
/** @var Configuration */
protected $_config ;
/**
* @deprecated
*
* @var EventManager
*/
protected $_eventManager ;
/**
* @deprecated Use {@see createExpressionBuilder()} instead.
*
* @var ExpressionBuilder
*/
protected $_expr ;
/**
* The current auto-commit mode of this connection.
*/
private bool $autoCommit = true ;
/**
* The transaction nesting level.
*/
private int $transactionNestingLevel = 0 ;
/**
* The currently active transaction isolation level or NULL before it has been determined.
*
* @var TransactionIsolationLevel::*|null
*/
private $transactionIsolationLevel ;
/**
* If nested transactions should use savepoints.
*/
private bool $nestTransactionsWithSavepoints = false ;
/**
* The parameters used during creation of the Connection instance.
*
* @var array<string,mixed>
* @psalm-var Params
*/
private array $params ;
/**
* The database platform object used by the connection or NULL before it's initialized.
*/
private ? AbstractPlatform $platform = null ;
private ?ExceptionConverter $exceptionConverter = null ;
private ?Parser $parser = null ;
/**
* The schema manager.
*
* @deprecated Use {@see createSchemaManager()} instead.
*
* @var AbstractSchemaManager|null
*/
protected $_schemaManager ;
/**
* The used DBAL driver.
*
* @var Driver
*/
protected $_driver ;
/**
* Flag that indicates whether the current transaction is marked for rollback only.
*/
private bool $isRollbackOnly = false ;
private SchemaManagerFactory $schemaManagerFactory ;
/**
* Initializes a new instance of the Connection class.
*
* @internal The connection can be only instantiated by the driver manager.
*
* @param array<string,mixed> $params The connection parameters.
* @param Driver $driver The driver to use.
* @param Configuration|null $config The configuration, optional.
* @param EventManager|null $eventManager The event manager, optional.
* @psalm-param Params $params
*
* @throws Exception
*/
public function __construct (
#[SensitiveParameter ]
array $params ,
Driver $driver ,
?Configuration $config = null ,
?EventManager $eventManager = null
) {
$this -> _driver = $driver ;
$this -> params = $params ;
// Create default config and event manager if none given
$config ??= new Configuration ();
$eventManager ??= new EventManager ();
$this -> _config = $config ;
$this -> _eventManager = $eventManager ;
if (isset($params [ 'platform' ])) {
if (! $params [ 'platform' ] instanceof Platforms\AbstractPlatform ) {
throw Exception :: invalidPlatformType ( $params [ 'platform' ]);
}
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/5699' ,
'The "platform" connection parameter is deprecated.'
. ' Use a driver middleware that would instantiate the platform instead.' ,
);
$this -> platform = $params [ 'platform' ];
$this -> platform -> setEventManager ( $this -> _eventManager );
$this -> platform -> setDisableTypeComments ( $config -> getDisableTypeComments ());
}
$this -> _expr = $this -> createExpressionBuilder ();
$this -> autoCommit = $config -> getAutoCommit ();
$schemaManagerFactory = $config -> getSchemaManagerFactory ();
if ($schemaManagerFactory === null ) {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/5812' ,
'Not configuring a schema manager factory is deprecated.'
. ' Use %s which is going to be the default in DBAL 4.' ,
DefaultSchemaManagerFactory ::class,
);
$schemaManagerFactory = new LegacySchemaManagerFactory ();
}
$this -> schemaManagerFactory = $schemaManagerFactory ;
}
/**
* Gets the parameters used during instantiation.
*
* @internal
*
* @return array<string,mixed>
* @psalm-return Params
*/
public function getParams ()
{
return $this -> params ;
}
/**
* Gets the name of the currently selected database.
*
* @return string|null The name of the database or NULL if a database is not selected.
* The platforms which don't support the concept of a database (e.g. embedded databases)
* must always return a string as an indicator of an implicitly selected database.
*
* @throws Exception
*/
public function getDatabase ()
{
$platform = $this -> getDatabasePlatform ();
$query = $platform -> getDummySelectSQL ( $platform -> getCurrentDatabaseExpression ());
$database = $this -> fetchOne ( $query );
assert ( is_string ( $database ) || $database === null );
return $database ;
}
/**
* Gets the DBAL driver instance.
*
* @return Driver
*/
public function getDriver ()
{
return $this -> _driver ;
}
/**
* Gets the Configuration used by the Connection.
*
* @return Configuration
*/
public function getConfiguration ()
{
return $this -> _config ;
}
/**
* Gets the EventManager used by the Connection.
*
* @deprecated
*
* @return EventManager
*/
public function getEventManager ()
{
Deprecation :: triggerIfCalledFromOutside (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/5784' ,
'%s is deprecated.' ,
__METHOD__ ,
);
return $this -> _eventManager ;
}
/**
* Gets the DatabasePlatform for the connection.
*
* @return AbstractPlatform
*
* @throws Exception
*/
public function getDatabasePlatform ()
{
if ($this -> platform === null ) {
$this -> platform = $this -> detectDatabasePlatform ();
$this -> platform -> setEventManager ( $this -> _eventManager );
$this -> platform -> setDisableTypeComments ( $this -> _config -> getDisableTypeComments ());
}
return $this -> platform ;
}
/**
* Creates an expression builder for the connection.
*/
public function createExpressionBuilder (): ExpressionBuilder
{
return new ExpressionBuilder ( $this );
}
/**
* Gets the ExpressionBuilder for the connection.
*
* @deprecated Use {@see createExpressionBuilder()} instead.
*
* @return ExpressionBuilder
*/
public function getExpressionBuilder ()
{
Deprecation :: triggerIfCalledFromOutside (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/4515' ,
'Connection::getExpressionBuilder() is deprecated,'
. ' use Connection::createExpressionBuilder() instead.' ,
);
return $this -> _expr ;
}
/**
* Establishes the connection with the database.
*
* @internal This method will be made protected in DBAL 4.0.
*
* @return bool TRUE if the connection was successfully established, FALSE if
* the connection is already open.
*
* @throws Exception
*
* @psalm-assert !null $this->_conn
*/
public function connect ()
{
Deprecation :: triggerIfCalledFromOutside (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/4966' ,
'Public access to Connection::connect() is deprecated.' ,
);
if ($this -> _conn !== null ) {
return false ;
}
try {
$this -> _conn = $this -> _driver -> connect ( $this -> params );
} catch (Driver\Exception $e ) {
throw $this -> convertException ( $e );
}
if ($this -> autoCommit === false ) {
$this -> beginTransaction ();
}
if ($this -> _eventManager -> hasListeners ( Events :: postConnect )) {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/5784' ,
'Subscribing to %s events is deprecated. Implement a middleware instead.' ,
Events :: postConnect ,
);
$eventArgs = new Event\ConnectionEventArgs ( $this );
$this -> _eventManager -> dispatchEvent ( Events :: postConnect , $eventArgs );
}
return true ;
}
/**
* Detects and sets the database platform.
*
* Evaluates custom platform class and version in order to set the correct platform.
*
* @throws Exception If an invalid platform was specified for this connection.
*/
private function detectDatabasePlatform (): AbstractPlatform
{
$version = $this -> getDatabasePlatformVersion ();
if ($version !== null ) {
assert ( $this -> _driver instanceof VersionAwarePlatformDriver );
return $this -> _driver -> createDatabasePlatformForVersion ( $version );
}
return $this -> _driver -> getDatabasePlatform ();
}
/**
* Returns the version of the related platform if applicable.
*
* Returns null if either the driver is not capable to create version
* specific platform instances, no explicit server version was specified
* or the underlying driver connection cannot determine the platform
* version without having to query it (performance reasons).
*
* @return string|null
*
* @throws Throwable
*/
private function getDatabasePlatformVersion ()
{
// Driver does not support version specific platforms.
if (! $this -> _driver instanceof VersionAwarePlatformDriver ) {
return null ;
}
// Explicit platform version requested (supersedes auto-detection).
if (isset( $this -> params [ 'serverVersion' ])) {
return $this -> params [ 'serverVersion' ];
}
if (isset($this -> params [ 'primary' ]) && isset( $this -> params [ 'primary' ][ 'serverVersion' ])) {
return $this -> params [ 'primary' ][ 'serverVersion' ];
}
// If not connected, we need to connect now to determine the platform version.
if ( $this -> _conn === null ) {
try {
$this -> connect ();
} catch (Exception $originalException ) {
if (! isset($this -> params [ 'dbname' ])) {
throw $originalException ;
}
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/5707' ,
'Relying on a fallback connection used to determine the database platform while connecting'
. ' to a non-existing database is deprecated. Either use an existing database name in'
. ' connection parameters or omit the database name if the platform'
. ' and the server configuration allow that.' ,
);
// The database to connect to might not yet exist.
// Retry detection without database name connection parameter.
$params = $this -> params ;
unset($this -> params [ 'dbname' ]);
try {
$this -> connect ();
} catch (Exception $fallbackException ) {
// Either the platform does not support database-less connections
// or something else went wrong.
throw $originalException ;
} finally {
$this -> params = $params ;
}
$serverVersion = $this -> getServerVersion ();
// Close "temporary" connection to allow connecting to the real database again.
$this -> close ();
return $serverVersion ;
}
}
return $this -> getServerVersion ();
}
/**
* Returns the database server version if the underlying driver supports it.
*
* @return string|null
*
* @throws Exception
*/
private function getServerVersion ()
{
$connection = $this -> getWrappedConnection ();
// Automatic platform version detection.
if ( $connection instanceof ServerInfoAwareConnection ) {
try {
return $connection -> getServerVersion ();
} catch (Driver\Exception $e ) {
throw $this -> convertException ( $e );
}
}
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/4750' ,
'Not implementing the ServerInfoAwareConnection interface in %s is deprecated' ,
get_class ( $connection ),
);
// Unable to detect platform version.
return null ;
}
/**
* Returns the current auto-commit mode for this connection.
*
* @see setAutoCommit
*
* @return bool True if auto-commit mode is currently enabled for this connection, false otherwise.
*/
public function isAutoCommit ()
{
return $this -> autoCommit === true ;
}
/**
* Sets auto-commit mode for this connection.
*
* If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual
* transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either
* the method commit or the method rollback. By default, new connections are in auto-commit mode.
*
* NOTE: If this method is called during a transaction and the auto-commit mode is changed, the transaction is
* committed. If this method is called and the auto-commit mode is not changed, the call is a no-op.
*
* @see isAutoCommit
*
* @param bool $autoCommit True to enable auto-commit mode; false to disable it.
*
* @return void
*/
public function setAutoCommit ( $autoCommit )
{
$autoCommit = (bool) $autoCommit ;
// Mode not changed, no-op.
if ( $autoCommit === $this -> autoCommit ) {
return;
}
$this -> autoCommit = $autoCommit ;
// Commit all currently active transactions if any when switching auto-commit mode.
if ( $this -> _conn === null || $this -> transactionNestingLevel === 0 ) {
return;
}
$this -> commitAll ();
}
/**
* Prepares and executes an SQL query and returns the first row of the result
* as an associative array.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return array<string, mixed>|false False is returned if no rows are found.
*
* @throws Exception
*/
public function fetchAssociative ( string $query , array $params = [], array $types = [])
{
return $this -> executeQuery ( $query , $params , $types )-> fetchAssociative ();
}
/**
* Prepares and executes an SQL query and returns the first row of the result
* as a numerically indexed array.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return list<mixed>|false False is returned if no rows are found.
*
* @throws Exception
*/
public function fetchNumeric ( string $query , array $params = [], array $types = [])
{
return $this -> executeQuery ( $query , $params , $types )-> fetchNumeric ();
}
/**
* Prepares and executes an SQL query and returns the value of a single column
* of the first row of the result.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return mixed|false False is returned if no rows are found.
*
* @throws Exception
*/
public function fetchOne ( string $query , array $params = [], array $types = [])
{
return $this -> executeQuery ( $query , $params , $types )-> fetchOne ();
}
/**
* Whether an actual connection to the database is established.
*
* @return bool
*/
public function isConnected ()
{
return $this -> _conn !== null ;
}
/**
* Checks whether a transaction is currently active.
*
* @return bool TRUE if a transaction is currently active, FALSE otherwise.
*/
public function isTransactionActive ()
{
return $this -> transactionNestingLevel > 0 ;
}
/**
* Adds condition based on the criteria to the query components
*
* @param array<string,mixed> $criteria Map of key columns to their values
* @param string[] $columns Column names
* @param mixed[] $values Column values
* @param string[] $conditions Key conditions
*
* @throws Exception
*/
private function addCriteriaCondition (
array $criteria ,
array &$columns ,
array &$values ,
array &$conditions
): void {
$platform = $this -> getDatabasePlatform ();
foreach ($criteria as $columnName => $value ) {
if ($value === null ) {
$conditions [] = $platform -> getIsNullExpression ( $columnName );
continue;
}
$columns [] = $columnName ;
$values [] = $value ;
$conditions [] = $columnName . ' = ?' ;
}
}
/**
* Executes an SQL DELETE statement on a table.
*
* Table expression and columns are not escaped and are not safe for user-input.
*
* @param string $table Table name
* @param array<string, mixed> $criteria Deletion criteria
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return int|string The number of affected rows.
*
* @throws Exception
*/
public function delete ( $table , array $criteria , array $types = [])
{
if (count ( $criteria ) === 0 ) {
throw InvalidArgumentException :: fromEmptyCriteria ();
}
$columns = $values = $conditions = [];
$this -> addCriteriaCondition ( $criteria , $columns , $values , $conditions );
return $this -> executeStatement (
'DELETE FROM ' . $table . ' WHERE ' . implode ( ' AND ' , $conditions ),
$values ,
is_string ( key ( $types )) ? $this -> extractTypeValues ( $columns , $types ) : $types ,
);
}
/**
* Closes the connection.
*
* @return void
*/
public function close ()
{
$this -> _conn = null ;
$this -> transactionNestingLevel = 0 ;
}
/**
* Sets the transaction isolation level.
*
* @param TransactionIsolationLevel::* $level The level to set.
*
* @return int|string
*
* @throws Exception
*/
public function setTransactionIsolation ( $level )
{
$this -> transactionIsolationLevel = $level ;
return $this -> executeStatement ( $this -> getDatabasePlatform ()-> getSetTransactionIsolationSQL ( $level ));
}
/**
* Gets the currently active transaction isolation level.
*
* @return TransactionIsolationLevel::* The current transaction isolation level.
*
* @throws Exception
*/
public function getTransactionIsolation ()
{
return $this -> transactionIsolationLevel ??= $this -> getDatabasePlatform ()-> getDefaultTransactionIsolationLevel ();
}
/**
* Executes an SQL UPDATE statement on a table.
*
* Table expression and columns are not escaped and are not safe for user-input.
*
* @param string $table Table name
* @param array<string, mixed> $data Column-value pairs
* @param array<string, mixed> $criteria Update criteria
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return int|string The number of affected rows.
*
* @throws Exception
*/
public function update ( $table , array $data , array $criteria , array $types = [])
{
$columns = $values = $conditions = $set = [];
foreach ($data as $columnName => $value ) {
$columns [] = $columnName ;
$values [] = $value ;
$set [] = $columnName . ' = ?' ;
}
$this -> addCriteriaCondition ( $criteria , $columns , $values , $conditions );
if (is_string ( key ( $types ))) {
$types = $this -> extractTypeValues ( $columns , $types );
}
$sql = 'UPDATE ' . $table . ' SET ' . implode ( ', ' , $set )
. ' WHERE ' . implode ( ' AND ' , $conditions );
return $this -> executeStatement ( $sql , $values , $types );
}
/**
* Inserts a table row with specified data.
*
* Table expression and columns are not escaped and are not safe for user-input.
*
* @param string $table Table name
* @param array<string, mixed> $data Column-value pairs
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return int|string The number of affected rows.
*
* @throws Exception
*/
public function insert ( $table , array $data , array $types = [])
{
if (count ( $data ) === 0 ) {
return $this -> executeStatement ( 'INSERT INTO ' . $table . ' () VALUES ()' );
}
$columns = [];
$values = [];
$set = [];
foreach ($data as $columnName => $value ) {
$columns [] = $columnName ;
$values [] = $value ;
$set [] = '?' ;
}
return $this -> executeStatement (
'INSERT INTO ' . $table . ' (' . implode ( ', ' , $columns ) . ')' .
' VALUES (' . implode ( ', ' , $set ) . ')' ,
$values ,
is_string ( key ( $types )) ? $this -> extractTypeValues ( $columns , $types ) : $types ,
);
}
/**
* Extract ordered type list from an ordered column list and type map.
*
* @param array<int, string> $columnList
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
*
* @return array<int, int|string|Type|null>|array<string, int|string|Type|null>
*/
private function extractTypeValues (array $columnList , array $types ): array
{
$typeValues = [];
foreach ($columnList as $columnName ) {
$typeValues [] = $types [ $columnName ] ?? ParameterType :: STRING ;
}
return $typeValues ;
}
/**
* Quotes a string so it can be safely used as a table or column name, even if
* it is a reserved name.
*
* Delimiting style depends on the underlying database platform that is being used.
*
* NOTE: Just because you CAN use quoted identifiers does not mean
* you SHOULD use them. In general, they end up causing way more
* problems than they solve.
*
* @param string $str The name to be quoted.
*
* @return string The quoted name.
*/
public function quoteIdentifier ( $str )
{
return $this -> getDatabasePlatform ()-> quoteIdentifier ( $str );
}
/**
* The usage of this method is discouraged. Use prepared statements
* or {@see AbstractPlatform::quoteStringLiteral()} instead.
*
* @param mixed $value
* @param int|string|Type|null $type
*
* @return mixed
*/
public function quote ( $value , $type = ParameterType :: STRING )
{
$connection = $this -> getWrappedConnection ();
[$value , $bindingType ] = $this -> getBindingInfo ( $value , $type );
return $connection -> quote ( $value , $bindingType );
}
/**
* Prepares and executes an SQL query and returns the result as an array of numeric arrays.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return list<list<mixed>>
*
* @throws Exception
*/
public function fetchAllNumeric ( string $query , array $params = [], array $types = []): array
{
return $this -> executeQuery ( $query , $params , $types )-> fetchAllNumeric ();
}
/**
* Prepares and executes an SQL query and returns the result as an array of associative arrays.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return list<array<string,mixed>>
*
* @throws Exception
*/
public function fetchAllAssociative ( string $query , array $params = [], array $types = []): array
{
return $this -> executeQuery ( $query , $params , $types )-> fetchAllAssociative ();
}
/**
* Prepares and executes an SQL query and returns the result as an associative array with the keys
* mapped to the first column and the values mapped to the second column.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return array<mixed,mixed>
*
* @throws Exception
*/
public function fetchAllKeyValue ( string $query , array $params = [], array $types = []): array
{
return $this -> executeQuery ( $query , $params , $types )-> fetchAllKeyValue ();
}
/**
* Prepares and executes an SQL query and returns the result as an associative array with the keys mapped
* to the first column and the values being an associative array representing the rest of the columns
* and their values.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return array<mixed,array<string,mixed>>
*
* @throws Exception
*/
public function fetchAllAssociativeIndexed ( string $query , array $params = [], array $types = []): array
{
return $this -> executeQuery ( $query , $params , $types )-> fetchAllAssociativeIndexed ();
}
/**
* Prepares and executes an SQL query and returns the result as an array of the first column values.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return list<mixed>
*
* @throws Exception
*/
public function fetchFirstColumn ( string $query , array $params = [], array $types = []): array
{
return $this -> executeQuery ( $query , $params , $types )-> fetchFirstColumn ();
}
/**
* Prepares and executes an SQL query and returns the result as an iterator over rows represented as numeric arrays.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return Traversable<int,list<mixed>>
*
* @throws Exception
*/
public function iterateNumeric ( string $query , array $params = [], array $types = []): Traversable
{
return $this -> executeQuery ( $query , $params , $types )-> iterateNumeric ();
}
/**
* Prepares and executes an SQL query and returns the result as an iterator over rows represented
* as associative arrays.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return Traversable<int,array<string,mixed>>
*
* @throws Exception
*/
public function iterateAssociative ( string $query , array $params = [], array $types = []): Traversable
{
return $this -> executeQuery ( $query , $params , $types )-> iterateAssociative ();
}
/**
* Prepares and executes an SQL query and returns the result as an iterator with the keys
* mapped to the first column and the values mapped to the second column.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return Traversable<mixed,mixed>
*
* @throws Exception
*/
public function iterateKeyValue ( string $query , array $params = [], array $types = []): Traversable
{
return $this -> executeQuery ( $query , $params , $types )-> iterateKeyValue ();
}
/**
* Prepares and executes an SQL query and returns the result as an iterator with the keys mapped
* to the first column and the values being an associative array representing the rest of the columns
* and their values.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string>|array<string, int|string> $types Parameter types
*
* @return Traversable<mixed,array<string,mixed>>
*
* @throws Exception
*/
public function iterateAssociativeIndexed ( string $query , array $params = [], array $types = []): Traversable
{
return $this -> executeQuery ( $query , $params , $types )-> iterateAssociativeIndexed ();
}
/**
* Prepares and executes an SQL query and returns the result as an iterator over the first column values.
*
* @param string $query SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return Traversable<int,mixed>
*
* @throws Exception
*/
public function iterateColumn ( string $query , array $params = [], array $types = []): Traversable
{
return $this -> executeQuery ( $query , $params , $types )-> iterateColumn ();
}
/**
* Prepares an SQL statement.
*
* @param string $sql The SQL statement to prepare.
*
* @throws Exception
*/
public function prepare ( string $sql ): Statement
{
$connection = $this -> getWrappedConnection ();
try {
$statement = $connection -> prepare ( $sql );
} catch (Driver\Exception $e ) {
throw $this -> convertExceptionDuringQuery ( $e , $sql );
}
return new Statement ( $this , $statement , $sql );
}
/**
* Executes an, optionally parameterized, SQL query.
*
* If the query is parametrized, a prepared statement is used.
* If an SQLLogger is configured, the execution is logged.
*
* @param string $sql SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @throws Exception
*/
public function executeQuery (
string $sql ,
array $params = [],
$types = [],
?QueryCacheProfile $qcp = null
): Result {
if ($qcp !== null ) {
return $this -> executeCacheQuery ( $sql , $params , $types , $qcp );
}
$connection = $this -> getWrappedConnection ();
$logger = $this -> _config -> getSQLLogger ();
if ($logger !== null ) {
$logger -> startQuery ( $sql , $params , $types );
}
try {
if (count ( $params ) > 0 ) {
if ($this -> needsArrayParameterConversion ( $params , $types )) {
[$sql , $params , $types ] = $this -> expandArrayParameters ( $sql , $params , $types );
}
$stmt = $connection -> prepare ( $sql );
$this -> bindParameters ( $stmt , $params , $types );
$result = $stmt -> execute ();
} else {
$result = $connection -> query ( $sql );
}
return new Result ( $result , $this );
} catch (Driver\Exception $e ) {
throw $this -> convertExceptionDuringQuery ( $e , $sql , $params , $types );
} finally {
if ($logger !== null ) {
$logger -> stopQuery ();
}
}
}
/**
* Executes a caching query.
*
* @param string $sql SQL query
* @param list<mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @throws CacheException
* @throws Exception
*/
public function executeCacheQuery ( $sql , $params , $types , QueryCacheProfile $qcp ): Result
{
$resultCache = $qcp -> getResultCache () ?? $this -> _config -> getResultCache ();
if ($resultCache === null ) {
throw CacheException :: noResultDriverConfigured ();
}
$connectionParams = $this -> params ;
unset($connectionParams [ 'platform' ], $connectionParams [ 'password' ], $connectionParams [ 'url' ]);
[$cacheKey , $realKey ] = $qcp -> generateCacheKeys ( $sql , $params , $types , $connectionParams );
$item = $resultCache -> getItem ( $cacheKey );
if ($item -> isHit ()) {
$value = $item -> get ();
if (isset($value [ $realKey ])) {
return new Result (new ArrayResult ( $value [ $realKey ]), $this );
}
} else {
$value = [];
}
$data = $this -> fetchAllAssociative ( $sql , $params , $types );
$value [ $realKey ] = $data ;
$item -> set ( $value );
$lifetime = $qcp -> getLifetime ();
if ($lifetime > 0 ) {
$item -> expiresAfter ( $lifetime );
}
$resultCache -> save ( $item );
return new Result (new ArrayResult ( $data ), $this );
}
/**
* Executes an SQL statement with the given parameters and returns the number of affected rows.
*
* Could be used for:
* - DML statements: INSERT, UPDATE, DELETE, etc.
* - DDL statements: CREATE, DROP, ALTER, etc.
* - DCL statements: GRANT, REVOKE, etc.
* - Session control statements: ALTER SESSION, SET, DECLARE, etc.
* - Other statements that don't yield a row set.
*
* This method supports PDO binding types as well as DBAL mapping types.
*
* @param string $sql SQL statement
* @param list<mixed>|array<string, mixed> $params Statement parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @return int|string The number of affected rows.
*
* @throws Exception
*/
public function executeStatement ( $sql , array $params = [], array $types = [])
{
$connection = $this -> getWrappedConnection ();
$logger = $this -> _config -> getSQLLogger ();
if ($logger !== null ) {
$logger -> startQuery ( $sql , $params , $types );
}
try {
if (count ( $params ) > 0 ) {
if ($this -> needsArrayParameterConversion ( $params , $types )) {
[$sql , $params , $types ] = $this -> expandArrayParameters ( $sql , $params , $types );
}
$stmt = $connection -> prepare ( $sql );
$this -> bindParameters ( $stmt , $params , $types );
return $stmt -> execute ()
->rowCount ();
}
return $connection -> exec ( $sql );
} catch (Driver\Exception $e ) {
throw $this -> convertExceptionDuringQuery ( $e , $sql , $params , $types );
} finally {
if ($logger !== null ) {
$logger -> stopQuery ();
}
}
}
/**
* Returns the current transaction nesting level.
*
* @return int The nesting level. A value of 0 means there's no active transaction.
*/
public function getTransactionNestingLevel ()
{
return $this -> transactionNestingLevel ;
}
/**
* Returns the ID of the last inserted row, or the last value from a sequence object,
* depending on the underlying driver.
*
* Note: This method may not return a meaningful or consistent result across different drivers,
* because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
* columns or sequences.
*
* @param string|null $name Name of the sequence object from which the ID should be returned.
*
* @return string|int|false A string representation of the last inserted ID.
*
* @throws Exception
*/
public function lastInsertId ( $name = null )
{
if ($name !== null ) {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/4687' ,
'The usage of Connection::lastInsertId() with a sequence name is deprecated.' ,
);
}
try {
return $this -> getWrappedConnection ()-> lastInsertId ( $name );
} catch (Driver\Exception $e ) {
throw $this -> convertException ( $e );
}
}
/**
* Executes a function in a transaction.
*
* The function gets passed this Connection instance as an (optional) parameter.
*
* If an exception occurs during execution of the function or transaction commit,
* the transaction is rolled back and the exception re-thrown.
*
* @param Closure(self):T $func The function to execute transactionally.
*
* @return T The value returned by $func
*
* @throws Throwable
*
* @template T
*/
public function transactional ( Closure $func )
{
$this -> beginTransaction ();
try {
$res = $func ( $this );
$this -> commit ();
return $res ;
} catch (Throwable $e ) {
$this -> rollBack ();
throw $e ;
}
}
/**
* Sets if nested transactions should use savepoints.
*
* @param bool $nestTransactionsWithSavepoints
*
* @return void
*
* @throws Exception
*/
public function setNestTransactionsWithSavepoints ( $nestTransactionsWithSavepoints )
{
if (! $nestTransactionsWithSavepoints ) {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/5383' ,
<<<'DEPRECATION'
Nesting transactions without enabling savepoints is deprecated.
Call %s::setNestTransactionsWithSavepoints(true) to enable savepoints.
DEPRECATION,
self ::class,
);
}
if ($this -> transactionNestingLevel > 0 ) {
throw ConnectionException :: mayNotAlterNestedTransactionWithSavepointsInTransaction ();
}
if (! $this -> getDatabasePlatform ()-> supportsSavepoints ()) {
throw ConnectionException :: savepointsNotSupported ();
}
$this -> nestTransactionsWithSavepoints = (bool) $nestTransactionsWithSavepoints ;
}
/**
* Gets if nested transactions should use savepoints.
*
* @return bool
*/
public function getNestTransactionsWithSavepoints ()
{
return $this -> nestTransactionsWithSavepoints ;
}
/**
* Returns the savepoint name to use for nested transactions.
*
* @return string
*/
protected function _getNestedTransactionSavePointName ()
{
return 'DOCTRINE2_SAVEPOINT_' . $this -> transactionNestingLevel ;
}
/**
* @return bool
*
* @throws Exception
*/
public function beginTransaction ()
{
$connection = $this -> getWrappedConnection ();
++$this -> transactionNestingLevel ;
$logger = $this -> _config -> getSQLLogger ();
if ($this -> transactionNestingLevel === 1 ) {
if ($logger !== null ) {
$logger -> startQuery ( '"START TRANSACTION"' );
}
$connection -> beginTransaction ();
if ($logger !== null ) {
$logger -> stopQuery ();
}
} elseif ($this -> nestTransactionsWithSavepoints ) {
if ($logger !== null ) {
$logger -> startQuery ( '"SAVEPOINT"' );
}
$this -> createSavepoint ( $this -> _getNestedTransactionSavePointName ());
if ($logger !== null ) {
$logger -> stopQuery ();
}
} else {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/5383' ,
<<<'DEPRECATION'
Nesting transactions without enabling savepoints is deprecated.
Call %s::setNestTransactionsWithSavepoints(true) to enable savepoints.
DEPRECATION,
self ::class,
);
}
$eventManager = $this -> getEventManager ();
if ($eventManager -> hasListeners ( Events :: onTransactionBegin )) {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/5784' ,
'Subscribing to %s events is deprecated.' ,
Events :: onTransactionBegin ,
);
$eventManager -> dispatchEvent ( Events :: onTransactionBegin , new TransactionBeginEventArgs ( $this ));
}
return true ;
}
/**
* @return bool
*
* @throws Exception
*/
public function commit ()
{
if ($this -> transactionNestingLevel === 0 ) {
throw ConnectionException :: noActiveTransaction ();
}
if ($this -> isRollbackOnly ) {
throw ConnectionException :: commitFailedRollbackOnly ();
}
$result = true ;
$connection = $this -> getWrappedConnection ();
if ($this -> transactionNestingLevel === 1 ) {
$result = $this -> doCommit ( $connection );
} elseif ($this -> nestTransactionsWithSavepoints ) {
$this -> releaseSavepoint ( $this -> _getNestedTransactionSavePointName ());
}
--$this -> transactionNestingLevel ;
$eventManager = $this -> getEventManager ();
if ($eventManager -> hasListeners ( Events :: onTransactionCommit )) {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/5784' ,
'Subscribing to %s events is deprecated.' ,
Events :: onTransactionCommit ,
);
$eventManager -> dispatchEvent ( Events :: onTransactionCommit , new TransactionCommitEventArgs ( $this ));
}
if ($this -> autoCommit !== false || $this -> transactionNestingLevel !== 0 ) {
return $result ;
}
$this -> beginTransaction ();
return $result ;
}
/**
* @return bool
*
* @throws DriverException
*/
private function doCommit ( DriverConnection $connection )
{
$logger = $this -> _config -> getSQLLogger ();
if ($logger !== null ) {
$logger -> startQuery ( '"COMMIT"' );
}
$result = $connection -> commit ();
if ($logger !== null ) {
$logger -> stopQuery ();
}
return $result ;
}
/**
* Commits all current nesting transactions.
*
* @throws Exception
*/
private function commitAll (): void
{
while ($this -> transactionNestingLevel !== 0 ) {
if ($this -> autoCommit === false && $this -> transactionNestingLevel === 1 ) {
// When in no auto-commit mode, the last nesting commit immediately starts a new transaction.
// Therefore we need to do the final commit here and then leave to avoid an infinite loop.
$this -> commit ();
return;
}
$this -> commit ();
}
}
/**
* Cancels any database changes done during the current transaction.
*
* @return bool
*
* @throws Exception
*/
public function rollBack ()
{
if ($this -> transactionNestingLevel === 0 ) {
throw ConnectionException :: noActiveTransaction ();
}
$connection = $this -> getWrappedConnection ();
$logger = $this -> _config -> getSQLLogger ();
if ($this -> transactionNestingLevel === 1 ) {
if ($logger !== null ) {
$logger -> startQuery ( '"ROLLBACK"' );
}
$this -> transactionNestingLevel = 0 ;
$connection -> rollBack ();
$this -> isRollbackOnly = false ;
if ($logger !== null ) {
$logger -> stopQuery ();
}
if ($this -> autoCommit === false ) {
$this -> beginTransaction ();
}
} elseif ($this -> nestTransactionsWithSavepoints ) {
if ($logger !== null ) {
$logger -> startQuery ( '"ROLLBACK TO SAVEPOINT"' );
}
$this -> rollbackSavepoint ( $this -> _getNestedTransactionSavePointName ());
--$this -> transactionNestingLevel ;
if ($logger !== null ) {
$logger -> stopQuery ();
}
} else {
$this -> isRollbackOnly = true ;
--$this -> transactionNestingLevel ;
}
$eventManager = $this -> getEventManager ();
if ($eventManager -> hasListeners ( Events :: onTransactionRollBack )) {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/5784' ,
'Subscribing to %s events is deprecated.' ,
Events :: onTransactionRollBack ,
);
$eventManager -> dispatchEvent ( Events :: onTransactionRollBack , new TransactionRollBackEventArgs ( $this ));
}
return true ;
}
/**
* Creates a new savepoint.
*
* @param string $savepoint The name of the savepoint to create.
*
* @return void
*
* @throws Exception
*/
public function createSavepoint ( $savepoint )
{
$platform = $this -> getDatabasePlatform ();
if (! $platform -> supportsSavepoints ()) {
throw ConnectionException :: savepointsNotSupported ();
}
$this -> executeStatement ( $platform -> createSavePoint ( $savepoint ));
}
/**
* Releases the given savepoint.
*
* @param string $savepoint The name of the savepoint to release.
*
* @return void
*
* @throws Exception
*/
public function releaseSavepoint ( $savepoint )
{
$logger = $this -> _config -> getSQLLogger ();
$platform = $this -> getDatabasePlatform ();
if (! $platform -> supportsSavepoints ()) {
throw ConnectionException :: savepointsNotSupported ();
}
if (! $platform -> supportsReleaseSavepoints ()) {
if ($logger !== null ) {
$logger -> stopQuery ();
}
return;
}
if ($logger !== null ) {
$logger -> startQuery ( '"RELEASE SAVEPOINT"' );
}
$this -> executeStatement ( $platform -> releaseSavePoint ( $savepoint ));
if ($logger === null ) {
return;
}
$logger -> stopQuery ();
}
/**
* Rolls back to the given savepoint.
*
* @param string $savepoint The name of the savepoint to rollback to.
*
* @return void
*
* @throws Exception
*/
public function rollbackSavepoint ( $savepoint )
{
$platform = $this -> getDatabasePlatform ();
if (! $platform -> supportsSavepoints ()) {
throw ConnectionException :: savepointsNotSupported ();
}
$this -> executeStatement ( $platform -> rollbackSavePoint ( $savepoint ));
}
/**
* Gets the wrapped driver connection.
*
* @deprecated Use {@link getNativeConnection()} to access the native connection.
*
* @return DriverConnection
*
* @throws Exception
*/
public function getWrappedConnection ()
{
Deprecation :: triggerIfCalledFromOutside (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/4966' ,
'Connection::getWrappedConnection() is deprecated.'
. ' Use Connection::getNativeConnection() to access the native connection.' ,
);
$this -> connect ();
return $this -> _conn ;
}
/** @return resource|object */
public function getNativeConnection ()
{
$this -> connect ();
if (! method_exists ( $this -> _conn , 'getNativeConnection' )) {
throw new LogicException ( sprintf (
'The driver connection %s does not support accessing the native connection.' ,
get_class ( $this -> _conn ),
));
}
return $this -> _conn -> getNativeConnection ();
}
/**
* Creates a SchemaManager that can be used to inspect or change the
* database schema through the connection.
*
* @throws Exception
*/
public function createSchemaManager (): AbstractSchemaManager
{
return $this -> schemaManagerFactory -> createSchemaManager ( $this );
}
/**
* Gets the SchemaManager that can be used to inspect or change the
* database schema through the connection.
*
* @deprecated Use {@see createSchemaManager()} instead.
*
* @return AbstractSchemaManager
*
* @throws Exception
*/
public function getSchemaManager ()
{
Deprecation :: triggerIfCalledFromOutside (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/issues/4515' ,
'Connection::getSchemaManager() is deprecated, use Connection::createSchemaManager() instead.' ,
);
return $this -> _schemaManager ??= $this -> createSchemaManager ();
}
/**
* Marks the current transaction so that the only possible
* outcome for the transaction to be rolled back.
*
* @return void
*
* @throws ConnectionException If no transaction is active.
*/
public function setRollbackOnly ()
{
if ($this -> transactionNestingLevel === 0 ) {
throw ConnectionException :: noActiveTransaction ();
}
$this -> isRollbackOnly = true ;
}
/**
* Checks whether the current transaction is marked for rollback only.
*
* @return bool
*
* @throws ConnectionException If no transaction is active.
*/
public function isRollbackOnly ()
{
if ($this -> transactionNestingLevel === 0 ) {
throw ConnectionException :: noActiveTransaction ();
}
return $this -> isRollbackOnly ;
}
/**
* Converts a given value to its database representation according to the conversion
* rules of a specific DBAL mapping type.
*
* @param mixed $value The value to convert.
* @param string $type The name of the DBAL mapping type.
*
* @return mixed The converted value.
*
* @throws Exception
*/
public function convertToDatabaseValue ( $value , $type )
{
return Type :: getType ( $type )-> convertToDatabaseValue ( $value , $this -> getDatabasePlatform ());
}
/**
* Converts a given value to its PHP representation according to the conversion
* rules of a specific DBAL mapping type.
*
* @param mixed $value The value to convert.
* @param string $type The name of the DBAL mapping type.
*
* @return mixed The converted type.
*
* @throws Exception
*/
public function convertToPHPValue ( $value , $type )
{
return Type :: getType ( $type )-> convertToPHPValue ( $value , $this -> getDatabasePlatform ());
}
/**
* Binds a set of parameters, some or all of which are typed with a PDO binding type
* or DBAL mapping type, to a given statement.
*
* @param DriverStatement $stmt Prepared statement
* @param list<mixed>|array<string, mixed> $params Statement parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
*
* @throws Exception
*/
private function bindParameters ( DriverStatement $stmt , array $params , array $types ): void
{
// Check whether parameters are positional or named. Mixing is not allowed.
if ( is_int ( key ( $params ))) {
$bindIndex = 1 ;
foreach ($params as $key => $value ) {
if (isset($types [ $key ])) {
$type = $types [ $key ];
[$value , $bindingType ] = $this -> getBindingInfo ( $value , $type );
} else {
if (array_key_exists ( $key , $types )) {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/5550' ,
'Using NULL as prepared statement parameter type is deprecated.'
. 'Omit or use Parameter::STRING instead' ,
);
}
$bindingType = ParameterType :: STRING ;
}
$stmt -> bindValue ( $bindIndex , $value , $bindingType );
++$bindIndex ;
}
} else {
// Named parameters
foreach ( $params as $name => $value ) {
if (isset($types [ $name ])) {
$type = $types [ $name ];
[$value , $bindingType ] = $this -> getBindingInfo ( $value , $type );
} else {
if (array_key_exists ( $name , $types )) {
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/5550' ,
'Using NULL as prepared statement parameter type is deprecated.'
. 'Omit or use Parameter::STRING instead' ,
);
}
$bindingType = ParameterType :: STRING ;
}
$stmt -> bindValue ( $name , $value , $bindingType );
}
}
}
/**
* Gets the binding type of a given type.
*
* @param mixed $value The value to bind.
* @param int|string|Type|null $type The type to bind (PDO or DBAL).
*
* @return array{mixed, int} [0] => the (escaped) value, [1] => the binding type.
*
* @throws Exception
*/
private function getBindingInfo ( $value , $type ): array
{
if (is_string ( $type )) {
$type = Type :: getType ( $type );
}
if ($type instanceof Type ) {
$value = $type -> convertToDatabaseValue ( $value , $this -> getDatabasePlatform ());
$bindingType = $type -> getBindingType ();
} else {
$bindingType = $type ?? ParameterType :: STRING ;
}
return [$value , $bindingType ];
}
/**
* Creates a new instance of a SQL query builder.
*
* @return QueryBuilder
*/
public function createQueryBuilder ()
{
return new Query\QueryBuilder ( $this );
}
/**
* @internal
*
* @param list<mixed>|array<string, mixed> $params
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
*/
final public function convertExceptionDuringQuery (
Driver\Exception $e ,
string $sql ,
array $params = [],
array $types = []
): DriverException {
return $this -> handleDriverException ( $e , new Query ( $sql , $params , $types ));
}
/** @internal */
final public function convertException ( Driver\Exception $e ): DriverException
{
return $this -> handleDriverException ( $e , null );
}
/**
* @param array<int, mixed>|array<string, mixed> $params
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
*
* @return array{string, list<mixed>, array<int,Type|int|string|null>}
*/
private function expandArrayParameters ( string $sql , array $params , array $types ): array
{
$this -> parser ??= $this -> getDatabasePlatform ()-> createSQLParser ();
$visitor = new ExpandArrayParameters ( $params , $types );
$this -> parser -> parse ( $sql , $visitor );
return [
$visitor -> getSQL (),
$visitor -> getParameters (),
$visitor -> getTypes (),
];
}
/**
* @param array<int, mixed>|array<string, mixed> $params
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
*/
private function needsArrayParameterConversion (array $params , array $types ): bool
{
if (is_string ( key ( $params ))) {
return true ;
}
foreach ($types as $type ) {
if (
$type === ArrayParameterType :: INTEGER
|| $type === ArrayParameterType :: STRING
|| $type === ArrayParameterType :: ASCII
|| $type === ArrayParameterType :: BINARY
) {
return true ;
}
}
return false ;
}
private function handleDriverException (
Driver\Exception $driverException ,
?Query $query
): DriverException {
$this -> exceptionConverter ??= $this -> _driver -> getExceptionConverter ();
$exception = $this -> exceptionConverter -> convert ( $driverException , $query );
if ($exception instanceof ConnectionLost ) {
$this -> close ();
}
return $exception ;
}
/**
* BC layer for a wide-spread use-case of old DBAL APIs
*
* @deprecated Use {@see executeStatement()} instead
*
* @param array<mixed> $params The query parameters
* @param array<int|string|null> $types The parameter types
*/
public function executeUpdate ( string $sql , array $params = [], array $types = []): int
{
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/4163' ,
'%s is deprecated, please use executeStatement() instead.' ,
__METHOD__ ,
);
return $this -> executeStatement ( $sql , $params , $types );
}
/**
* BC layer for a wide-spread use-case of old DBAL APIs
*
* @deprecated Use {@see executeQuery()} instead
*/
public function query ( string $sql ): Result
{
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/4163' ,
'%s is deprecated, please use executeQuery() instead.' ,
__METHOD__ ,
);
return $this -> executeQuery ( $sql );
}
/**
* BC layer for a wide-spread use-case of old DBAL APIs
*
* @deprecated please use {@see executeStatement()} instead
*/
public function exec ( string $sql ): int
{
Deprecation :: trigger (
'doctrine/dbal' ,
'https://github.com/doctrine/dbal/pull/4163' ,
'%s is deprecated, please use executeStatement() instead.' ,
__METHOD__ ,
);
return $this -> executeStatement ( $sql );
}
}