PK %‘R¨½ SECURITY.mdnu €žÙ˜ Security
========
The Doctrine library is operating very close to your database and as such needs
to handle and make assumptions about SQL injection vulnerabilities.
It is vital that you understand how Doctrine approaches security because
we cannot protect you from SQL injection.
Please read the documentation chapter on Security in Doctrine DBAL to
understand the assumptions we make.
- [Latest security.rst page on Github](https://github.com/doctrine/dbal/blob/4.0.x/docs/en/reference/security.rst)
- [Security Page in rendered documentation](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/security.html)
PK %‘Rµ"ÐÅ[ Å[ psalm.xml.distnu €žÙ˜
PK %‘Rð+ÿ1 1 > lib/Doctrine/DBAL/Connections/PrimaryReadReplicaConnection.phpnu €žÙ˜ executeQuery("DELETE FROM table");
*
* Be aware that Connection#executeQuery is a method specifically for READ
* operations only.
*
* Use Connection#executeStatement for any SQL statement that changes/updates
* state in the database (UPDATE, INSERT, DELETE or DDL statements).
*
* This connection is limited to replica operations using the
* Connection#executeQuery operation only, because it wouldn't be compatible
* with the ORM or SchemaManager code otherwise. Both use all the other
* operations in a context where writes could happen to a replica, which makes
* this restricted approach necessary.
*
* You can manually connect to the primary at any time by calling:
*
* $conn->ensureConnectedToPrimary();
*
* Instantiation through the DriverManager looks like:
*
* @psalm-import-type Params from \Doctrine\DBAL\DriverManager
* @example
*
* $conn = DriverManager::getConnection(array(
* 'wrapperClass' => 'Doctrine\DBAL\Connections\PrimaryReadReplicaConnection',
* 'driver' => 'pdo_mysql',
* 'primary' => array('user' => '', 'password' => '', 'host' => '', 'dbname' => ''),
* 'replica' => array(
* array('user' => 'replica1', 'password', 'host' => '', 'dbname' => ''),
* array('user' => 'replica2', 'password', 'host' => '', 'dbname' => ''),
* )
* ));
*
* You can also pass 'driverOptions' and any other documented option to each of this drivers
* to pass additional information.
*/
class PrimaryReadReplicaConnection extends Connection
{
/**
* Primary and Replica connection (one of the randomly picked replicas).
*
* @var DriverConnection[]|null[]
*/
protected $connections = ['primary' => null, 'replica' => null];
/**
* You can keep the replica connection and then switch back to it
* during the request if you know what you are doing.
*
* @var bool
*/
protected $keepReplica = false;
/**
* Creates Primary Replica Connection.
*
* @internal The connection can be only instantiated by the driver manager.
*
* @param array $params
*
* @throws InvalidArgumentException
*
* @phpstan-param array $params
* @psalm-param Params $params
*/
public function __construct(
array $params,
Driver $driver,
?Configuration $config = null,
?EventManager $eventManager = null
) {
if (! isset($params['replica'], $params['primary'])) {
throw new InvalidArgumentException('primary or replica configuration missing');
}
if (count($params['replica']) === 0) {
throw new InvalidArgumentException('You have to configure at least one replica.');
}
if (isset($params['driver'])) {
$params['primary']['driver'] = $params['driver'];
foreach ($params['replica'] as $replicaKey => $replica) {
$params['replica'][$replicaKey]['driver'] = $params['driver'];
}
}
$this->keepReplica = (bool) ($params['keepReplica'] ?? false);
parent::__construct($params, $driver, $config, $eventManager);
}
/**
* Checks if the connection is currently towards the primary or not.
*/
public function isConnectedToPrimary(): bool
{
return $this->_conn !== null && $this->_conn === $this->connections['primary'];
}
/**
* @param string|null $connectionName
*
* @return bool
*/
public function connect($connectionName = null)
{
if ($connectionName !== null) {
throw new InvalidArgumentException(
'Passing a connection name as first argument is not supported anymore.'
. ' Use ensureConnectedToPrimary()/ensureConnectedToReplica() instead.'
);
}
return $this->performConnect();
}
protected function performConnect(?string $connectionName = null): bool
{
$requestedConnectionChange = ($connectionName !== null);
$connectionName = $connectionName ?: 'replica';
if ($connectionName !== 'replica' && $connectionName !== 'primary') {
throw new InvalidArgumentException('Invalid option to connect(), only primary or replica allowed.');
}
// If we have a connection open, and this is not an explicit connection
// change request, then abort right here, because we are already done.
// This prevents writes to the replica in case of "keepReplica" option enabled.
if ($this->_conn !== null && ! $requestedConnectionChange) {
return false;
}
$forcePrimaryAsReplica = false;
if ($this->getTransactionNestingLevel() > 0) {
$connectionName = 'primary';
$forcePrimaryAsReplica = true;
}
if (isset($this->connections[$connectionName])) {
$this->_conn = $this->connections[$connectionName];
if ($forcePrimaryAsReplica && ! $this->keepReplica) {
$this->connections['replica'] = $this->_conn;
}
return false;
}
if ($connectionName === 'primary') {
$this->connections['primary'] = $this->_conn = $this->connectTo($connectionName);
// Set replica connection to primary to avoid invalid reads
if (! $this->keepReplica) {
$this->connections['replica'] = $this->connections['primary'];
}
} else {
$this->connections['replica'] = $this->_conn = $this->connectTo($connectionName);
}
if ($this->_eventManager->hasListeners(Events::postConnect)) {
$eventArgs = new ConnectionEventArgs($this);
$this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
}
return true;
}
/**
* Connects to the primary node of the database cluster.
*
* All following statements after this will be executed against the primary node.
*/
public function ensureConnectedToPrimary(): bool
{
return $this->performConnect('primary');
}
/**
* Connects to a replica node of the database cluster.
*
* All following statements after this will be executed against the replica node,
* unless the keepReplica option is set to false and a primary connection
* was already opened.
*/
public function ensureConnectedToReplica(): bool
{
return $this->performConnect('replica');
}
/**
* Connects to a specific connection.
*
* @param string $connectionName
*
* @return DriverConnection
*/
protected function connectTo($connectionName)
{
$params = $this->getParams();
$driverOptions = $params['driverOptions'] ?? [];
$connectionParams = $this->chooseConnectionConfiguration($connectionName, $params);
$user = $connectionParams['user'] ?? null;
$password = $connectionParams['password'] ?? null;
return $this->_driver->connect($connectionParams, $user, $password, $driverOptions);
}
/**
* @param string $connectionName
* @param mixed[] $params
*
* @return mixed
*/
protected function chooseConnectionConfiguration($connectionName, $params)
{
if ($connectionName === 'primary') {
return $params['primary'];
}
$config = $params['replica'][array_rand($params['replica'])];
if (! isset($config['charset']) && isset($params['primary']['charset'])) {
$config['charset'] = $params['primary']['charset'];
}
return $config;
}
/**
* {@inheritDoc}
*
* @deprecated Use {@link executeStatement()} instead.
*/
public function executeUpdate($sql, array $params = [], array $types = [])
{
$this->ensureConnectedToPrimary();
return parent::executeUpdate($sql, $params, $types);
}
/**
* {@inheritDoc}
*/
public function executeStatement($sql, array $params = [], array $types = [])
{
$this->ensureConnectedToPrimary();
return parent::executeStatement($sql, $params, $types);
}
/**
* {@inheritDoc}
*/
public function beginTransaction()
{
$this->ensureConnectedToPrimary();
return parent::beginTransaction();
}
/**
* {@inheritDoc}
*/
public function commit()
{
$this->ensureConnectedToPrimary();
return parent::commit();
}
/**
* {@inheritDoc}
*/
public function rollBack()
{
$this->ensureConnectedToPrimary();
return parent::rollBack();
}
/**
* {@inheritDoc}
*/
public function delete($table, array $criteria, array $types = [])
{
$this->ensureConnectedToPrimary();
return parent::delete($table, $criteria, $types);
}
/**
* {@inheritDoc}
*/
public function close()
{
unset($this->connections['primary'], $this->connections['replica']);
parent::close();
$this->_conn = null;
$this->connections = ['primary' => null, 'replica' => null];
}
/**
* {@inheritDoc}
*/
public function update($table, array $data, array $criteria, array $types = [])
{
$this->ensureConnectedToPrimary();
return parent::update($table, $data, $criteria, $types);
}
/**
* {@inheritDoc}
*/
public function insert($table, array $data, array $types = [])
{
$this->ensureConnectedToPrimary();
return parent::insert($table, $data, $types);
}
/**
* {@inheritDoc}
*/
public function exec($statement)
{
$this->ensureConnectedToPrimary();
return parent::exec($statement);
}
/**
* {@inheritDoc}
*/
public function createSavepoint($savepoint)
{
$this->ensureConnectedToPrimary();
parent::createSavepoint($savepoint);
}
/**
* {@inheritDoc}
*/
public function releaseSavepoint($savepoint)
{
$this->ensureConnectedToPrimary();
parent::releaseSavepoint($savepoint);
}
/**
* {@inheritDoc}
*/
public function rollbackSavepoint($savepoint)
{
$this->ensureConnectedToPrimary();
parent::rollbackSavepoint($savepoint);
}
/**
* {@inheritDoc}
*/
public function query()
{
$this->ensureConnectedToPrimary();
assert($this->_conn instanceof DriverConnection);
$args = func_get_args();
$logger = $this->getConfiguration()->getSQLLogger();
if ($logger) {
$logger->startQuery($args[0]);
}
$statement = $this->_conn->query(...$args);
$statement->setFetchMode($this->defaultFetchMode);
if ($logger) {
$logger->stopQuery();
}
return $statement;
}
/**
* {@inheritDoc}
*/
public function prepare($statement)
{
$this->ensureConnectedToPrimary();
return parent::prepare($statement);
}
}
PK %‘RÌéyÚá
á
7 lib/Doctrine/DBAL/Connections/MasterSlaveConnection.phpnu €žÙ˜ $params
*
* @throws InvalidArgumentException
*
* @phpstan-param array $params
* @psalm-param Params $params
*/
public function __construct(
array $params,
Driver $driver,
?Configuration $config = null,
?EventManager $eventManager = null
) {
$this->deprecated(self::class, PrimaryReadReplicaConnection::class);
if (isset($params['master'])) {
$this->deprecated('Params key "master"', '"primary"');
$params['primary'] = $params['master'];
}
if (isset($params['slaves'])) {
$this->deprecated('Params key "slaves"', '"replica"');
$params['replica'] = $params['slaves'];
}
if (isset($params['keepSlave'])) {
$this->deprecated('Params key "keepSlave"', '"keepReplica"');
$params['keepReplica'] = $params['keepSlave'];
}
parent::__construct($params, $driver, $config, $eventManager);
}
/**
* Checks if the connection is currently towards the primary or not.
*/
public function isConnectedToMaster(): bool
{
$this->deprecated('isConnectedtoMaster()', 'isConnectedToPrimary()');
return $this->isConnectedToPrimary();
}
/**
* @param string|null $connectionName
*
* @return bool
*/
public function connect($connectionName = null)
{
if ($connectionName === 'master') {
$connectionName = 'primary';
$this->deprecated('connect("master")', 'ensureConnectedToPrimary()');
}
if ($connectionName === 'slave') {
$connectionName = 'replica';
$this->deprecated('connect("slave")', 'ensureConnectedToReplica()');
}
return $this->performConnect($connectionName);
}
private function deprecated(string $thing, string $instead): void
{
Deprecation::trigger(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/4054',
'%s is deprecated since doctrine/dbal 2.11 and will be removed in 3.0, use %s instead.',
$thing,
$instead
);
}
}
PK %‘R*sYäY äY lib/Doctrine/DBAL/Statement.phpnu €žÙ˜ Statement for the given SQL and Connection.
*
* @internal The statement can be only instantiated by {@link Connection}.
*
* @param string $sql The SQL of the statement.
* @param Connection $conn The connection on which the statement should be executed.
*/
public function __construct($sql, Connection $conn)
{
$this->sql = $sql;
$this->stmt = $conn->getWrappedConnection()->prepare($sql);
$this->conn = $conn;
$this->platform = $conn->getDatabasePlatform();
}
/**
* Binds a parameter value to the statement.
*
* The value can optionally be bound with a PDO binding type or a DBAL mapping type.
* If bound with a DBAL mapping type, the binding type is derived from the mapping
* type and the value undergoes the conversion routines of the mapping type before
* being bound.
*
* @param string|int $param The name or position of the parameter.
* @param mixed $value The value of the parameter.
* @param mixed $type Either a PDO binding type or a DBAL mapping type name or instance.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function bindValue($param, $value, $type = ParameterType::STRING)
{
$this->params[$param] = $value;
$this->types[$param] = $type;
if ($type !== null) {
if (is_string($type)) {
$type = Type::getType($type);
}
if ($type instanceof Type) {
$value = $type->convertToDatabaseValue($value, $this->platform);
$bindingType = $type->getBindingType();
} else {
$bindingType = $type;
}
return $this->stmt->bindValue($param, $value, $bindingType);
}
return $this->stmt->bindValue($param, $value);
}
/**
* Binds a parameter to a value by reference.
*
* Binding a parameter by reference does not support DBAL mapping types.
*
* @param string|int $param The name or position of the parameter.
* @param mixed $variable The reference to the variable to bind.
* @param int $type The PDO binding type.
* @param int|null $length Must be specified when using an OUT bind
* so that PHP allocates enough memory to hold the returned value.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null)
{
$this->params[$param] = $variable;
$this->types[$param] = $type;
if ($this->stmt instanceof PDOStatement) {
$length = $length ?? 0;
}
return $this->stmt->bindParam($param, $variable, $type, $length);
}
/**
* Executes the statement with the currently bound parameters.
*
* @deprecated Statement::execute() is deprecated, use Statement::executeQuery() or executeStatement() instead
*
* @param mixed[]|null $params
*
* @return bool TRUE on success, FALSE on failure.
*
* @throws Exception
*/
public function execute($params = null)
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/4580',
'Statement::execute() is deprecated, use Statement::executeQuery() or Statement::executeStatement() instead'
);
if (is_array($params)) {
$this->params = $params;
}
$logger = $this->conn->getConfiguration()->getSQLLogger();
if ($logger) {
$logger->startQuery($this->sql, $this->params, $this->types);
}
try {
$stmt = $this->stmt->execute($params);
} catch (Throwable $ex) {
if ($logger) {
$logger->stopQuery();
}
$this->conn->handleExceptionDuringQuery($ex, $this->sql, $this->params, $this->types);
}
if ($logger) {
$logger->stopQuery();
}
return $stmt;
}
/**
* Executes the statement with the currently bound parameters and return result.
*
* @param mixed[] $params
*
* @throws Exception
*/
public function executeQuery(array $params = []): BaseResult
{
if ($params === []) {
$params = null; // Workaround as long execute() exists and used internally.
}
$this->execute($params);
return new ForwardCompatibility\Result($this);
}
/**
* Executes the statement with the currently bound parameters and return affected rows.
*
* @param mixed[] $params
*
* @throws Exception
*/
public function executeStatement(array $params = []): int
{
if ($params === []) {
$params = null; // Workaround as long execute() exists and used internally.
}
$this->execute($params);
return $this->rowCount();
}
/**
* Closes the cursor, freeing the database resources used by this statement.
*
* @deprecated Use Result::free() instead.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function closeCursor()
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/4049',
'Statement::closeCursor() is deprecated, use Result::free() instead.'
);
return $this->stmt->closeCursor();
}
/**
* Returns the number of columns in the result set.
*
* @return int
*/
public function columnCount()
{
return $this->stmt->columnCount();
}
/**
* Fetches the SQLSTATE associated with the last operation on the statement.
*
* @deprecated The error information is available via exceptions.
*
* @return string|int|bool
*/
public function errorCode()
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/3507',
'Connection::errorCode() is deprecated, use getCode() or getSQLState() on Exception instead.'
);
return $this->stmt->errorCode();
}
/**
* {@inheritDoc}
*
* @deprecated The error information is available via exceptions.
*/
public function errorInfo()
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/3507',
'Connection::errorInfo() is deprecated, use getCode() or getSQLState() on Exception instead.'
);
return $this->stmt->errorInfo();
}
/**
* {@inheritdoc}
*
* @deprecated Use one of the fetch- or iterate-related methods.
*/
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/4019',
'Statement::setFetchMode() is deprecated, use explicit Result::fetch*() APIs instead.'
);
if ($arg2 === null) {
return $this->stmt->setFetchMode($fetchMode);
}
if ($arg3 === null) {
return $this->stmt->setFetchMode($fetchMode, $arg2);
}
return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3);
}
/**
* Required by interface IteratorAggregate.
*
* @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead.
*
* {@inheritdoc}
*/
public function getIterator()
{
Deprecation::trigger(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/4019',
'Statement::getIterator() is deprecated, use Result::iterateNumeric(), iterateAssociative() ' .
'or iterateColumn() instead.'
);
return $this->stmt;
}
/**
* {@inheritdoc}
*
* @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead.
*/
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/4019',
'Statement::fetch() is deprecated, use Result::fetchNumeric(), fetchAssociative() or fetchOne() instead.'
);
return $this->stmt->fetch($fetchMode);
}
/**
* {@inheritdoc}
*
* @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead.
*/
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/4019',
'Statement::fetchAll() is deprecated, use Result::fetchAllNumeric(), fetchAllAssociative() or ' .
'fetchFirstColumn() instead.'
);
if ($ctorArgs !== null) {
return $this->stmt->fetchAll($fetchMode, $fetchArgument, $ctorArgs);
}
if ($fetchArgument !== null) {
return $this->stmt->fetchAll($fetchMode, $fetchArgument);
}
return $this->stmt->fetchAll($fetchMode);
}
/**
* {@inheritDoc}
*
* @deprecated Use fetchOne() instead.
*/
public function fetchColumn($columnIndex = 0)
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/4019',
'Statement::fetchColumn() is deprecated, use Result::fetchOne() instead.'
);
return $this->stmt->fetchColumn($columnIndex);
}
/**
* {@inheritdoc}
*
* @deprecated Use Result::fetchNumeric() instead
*
* @throws Exception
*/
public function fetchNumeric()
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
try {
if ($this->stmt instanceof Result) {
return $this->stmt->fetchNumeric();
}
return $this->stmt->fetch(FetchMode::NUMERIC);
} catch (Exception $e) {
$this->conn->handleDriverException($e);
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Result::fetchAssociative() instead
*
* @throws Exception
*/
public function fetchAssociative()
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
try {
if ($this->stmt instanceof Result) {
return $this->stmt->fetchAssociative();
}
return $this->stmt->fetch(FetchMode::ASSOCIATIVE);
} catch (Exception $e) {
$this->conn->handleDriverException($e);
}
}
/**
* {@inheritDoc}
*
* @deprecated Use Result::fetchOne() instead
*
* @throws Exception
*/
public function fetchOne()
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
try {
if ($this->stmt instanceof Result) {
return $this->stmt->fetchOne();
}
return $this->stmt->fetch(FetchMode::COLUMN);
} catch (Exception $e) {
$this->conn->handleDriverException($e);
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Result::fetchAllNumeric() instead
*
* @throws Exception
*/
public function fetchAllNumeric(): array
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
try {
if ($this->stmt instanceof Result) {
return $this->stmt->fetchAllNumeric();
}
return $this->stmt->fetchAll(FetchMode::NUMERIC);
} catch (Exception $e) {
$this->conn->handleDriverException($e);
}
}
/**
* {@inheritdoc}
*
* @deprecated Use Result::fetchAllAssociative() instead
*
* @throws Exception
*/
public function fetchAllAssociative(): array
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
try {
if ($this->stmt instanceof Result) {
return $this->stmt->fetchAllAssociative();
}
return $this->stmt->fetchAll(FetchMode::ASSOCIATIVE);
} catch (Exception $e) {
$this->conn->handleDriverException($e);
}
}
/**
* Returns an associative array with the keys mapped to the first column and the values mapped to the second column.
*
* The result must contain at least two columns.
*
* @deprecated Use Result::fetchAllKeyValue() instead
*
* @return array
*
* @throws Exception
*/
public function fetchAllKeyValue(): array
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
$this->ensureHasKeyValue();
$data = [];
foreach ($this->fetchAllNumeric() as [$key, $value]) {
$data[$key] = $value;
}
return $data;
}
/**
* Returns 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.
*
* @deprecated Use Result::fetchAllAssociativeIndexed() instead
*
* @return array>
*
* @throws Exception
*/
public function fetchAllAssociativeIndexed(): array
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
$data = [];
foreach ($this->fetchAll(FetchMode::ASSOCIATIVE) as $row) {
$data[array_shift($row)] = $row;
}
return $data;
}
/**
* {@inheritdoc}
*
* @deprecated Use Result::fetchFirstColumn() instead
*
* @throws Exception
*/
public function fetchFirstColumn(): array
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
try {
if ($this->stmt instanceof Result) {
return $this->stmt->fetchFirstColumn();
}
return $this->stmt->fetchAll(FetchMode::COLUMN);
} catch (Exception $e) {
$this->conn->handleDriverException($e);
}
}
/**
* {@inheritDoc}
*
* @deprecated Use Result::iterateNumeric() instead
*
* @return Traversable>
*
* @throws Exception
*/
public function iterateNumeric(): Traversable
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
try {
if ($this->stmt instanceof Result) {
while (($row = $this->stmt->fetchNumeric()) !== false) {
yield $row;
}
} else {
while (($row = $this->stmt->fetch(FetchMode::NUMERIC)) !== false) {
yield $row;
}
}
} catch (Exception $e) {
$this->conn->handleDriverException($e);
}
}
/**
* {@inheritDoc}
*
* @deprecated Use Result::iterateAssociative() instead
*
* @return Traversable>
*
* @throws Exception
*/
public function iterateAssociative(): Traversable
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
try {
if ($this->stmt instanceof Result) {
while (($row = $this->stmt->fetchAssociative()) !== false) {
yield $row;
}
} else {
while (($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) {
yield $row;
}
}
} catch (Exception $e) {
$this->conn->handleDriverException($e);
}
}
/**
* Returns an iterator over the result set with the keys mapped to the first column
* and the values mapped to the second column.
*
* The result must contain at least two columns.
*
* @deprecated Use Result::iterateKeyValue() instead
*
* @return Traversable
*
* @throws Exception
*/
public function iterateKeyValue(): Traversable
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
$this->ensureHasKeyValue();
foreach ($this->iterateNumeric() as [$key, $value]) {
yield $key => $value;
}
}
/**
* Returns an iterator over the result set with the keys mapped to the first column and the values being
* an associative array representing the rest of the columns and their values.
*
* @deprecated Use Result::iterateAssociativeIndexed() instead
*
* @return Traversable>
*
* @throws Exception
*/
public function iterateAssociativeIndexed(): Traversable
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
while (($row = $this->stmt->fetch(FetchMode::ASSOCIATIVE)) !== false) {
yield array_shift($row) => $row;
}
}
/**
* {@inheritDoc}
*
* @deprecated Use Result::iterateColumn() instead
*
* @return Traversable
*
* @throws Exception
*/
public function iterateColumn(): Traversable
{
Deprecation::triggerIfCalledFromOutside(
'doctrine/dbal',
'https://github.com/doctrine/dbal/issues/4554',
'Statement::%s() is deprecated, use Result::%s() instead.',
__FUNCTION__,
__FUNCTION__
);
try {
if ($this->stmt instanceof Result) {
while (($value = $this->stmt->fetchOne()) !== false) {
yield $value;
}
} else {
while (($value = $this->stmt->fetch(FetchMode::COLUMN)) !== false) {
yield $value;
}
}
} catch (Exception $e) {
$this->conn->handleDriverException($e);
}
}
/**
* Returns the number of rows affected by the last execution of this statement.
*
* @return int The number of affected rows.
*/
public function rowCount()
{
return $this->stmt->rowCount();
}
public function free(): void
{
if ($this->stmt instanceof Result) {
$this->stmt->free();
return;
}
$this->stmt->closeCursor();
}
/**
* Gets the wrapped driver statement.
*
* @return \Doctrine\DBAL\Driver\Statement
*/
public function getWrappedStatement()
{
return $this->stmt;
}
private function ensureHasKeyValue(): void
{
$columnCount = $this->columnCount();
if ($columnCount < 2) {
throw NoKeyValue::fromColumnCount($columnCount);
}
}
}
PK %‘Rxà j j lib/Doctrine/DBAL/Events.phpnu €žÙ˜ driverException = $driverException;
}
/**
* Returns the driver specific error code if given.
*
* Returns null if no error code was given by the driver.
*
* @return int|string|null
*/
public function getErrorCode()
{
return $this->driverException->getErrorCode();
}
/**
* Returns the SQLSTATE the driver was in at the time the error occurred, if given.
*
* Returns null if no SQLSTATE was given by the driver.
*
* @return string|null
*/
public function getSQLState()
{
return $this->driverException->getSQLState();
}
}
PK %‘RÚu†4Ø Ø * lib/Doctrine/DBAL/Exception/NoKeyValue.phpnu €žÙ˜ >
*/
public $queries = [];
/**
* If Debug Stack is enabled (log queries) or not.
*
* @var bool
*/
public $enabled = true;
/** @var float|null */
public $start = null;
/** @var int */
public $currentQuery = 0;
/**
* {@inheritdoc}
*/
public function startQuery($sql, ?array $params = null, ?array $types = null)
{
if (! $this->enabled) {
return;
}
$this->start = microtime(true);
$this->queries[++$this->currentQuery] = [
'sql' => $sql,
'params' => $params,
'types' => $types,
'executionMS' => 0,
];
}
/**
* {@inheritdoc}
*/
public function stopQuery()
{
if (! $this->enabled) {
return;
}
$this->queries[$this->currentQuery]['executionMS'] = microtime(true) - $this->start;
}
}
PK %‘RÒJ®™° ° + lib/Doctrine/DBAL/Logging/EchoSQLLogger.phpnu €žÙ˜ loggers = $loggers;
}
/**
* Adds a logger in the chain.
*
* @deprecated Inject list of loggers via constructor instead
*
* @return void
*/
public function addLogger(SQLLogger $logger)
{
Deprecation::trigger(
'doctrine/dbal',
'https://github.com/doctrine/dbal/pull/3572',
'LoggerChain::addLogger() is deprecated, use LoggerChain constructor instead.'
);
$this->loggers[] = $logger;
}
/**
* {@inheritdoc}
*/
public function startQuery($sql, ?array $params = null, ?array $types = null)
{
foreach ($this->loggers as $logger) {
$logger->startQuery($sql, $params, $types);
}
}
/**
* {@inheritdoc}
*/
public function stopQuery()
{
foreach ($this->loggers as $logger) {
$logger->stopQuery();
}
}
}
PK %‘R‘î”* * ' lib/Doctrine/DBAL/Logging/SQLLogger.phpnu €žÙ˜ |array|null $params Statement parameters
* @param array|array|null $types Parameter types
*
* @return void
*/
public function startQuery($sql, ?array $params = null, ?array $types = null);
/**
* Marks the last started query as stopped. This can be used for timing of queries.
*
* @return void
*/
public function stopQuery();
}
PK %‘R›õúü£ £ lib/Doctrine/DBAL/LockMode.phpnu €žÙ˜ generatorTableName = $generatorTableName;
}
/**
* {@inheritdoc}
*/
public function acceptSchema(Schema $schema)
{
$table = $schema->createTable($this->generatorTableName);
$table->addColumn('sequence_name', 'string');
$table->addColumn('sequence_value', 'integer', ['default' => 1]);
$table->addColumn('sequence_increment_by', 'integer', ['default' => 1]);
}
/**
* {@inheritdoc}
*/
public function acceptTable(Table $table)
{
}
/**
* {@inheritdoc}
*/
public function acceptColumn(Table $table, Column $column)
{
}
/**
* {@inheritdoc}
*/
public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
{
}
/**
* {@inheritdoc}
*/
public function acceptIndex(Table $table, Index $index)
{
}
/**
* {@inheritdoc}
*/
public function acceptSequence(Sequence $sequence)
{
}
}
PK %‘R£÷½ƒ~ ~ ' lib/Doctrine/DBAL/Id/TableGenerator.phpnu €žÙ˜ getDriver() instanceof Driver\PDOSqlite\Driver) {
throw new Exception('Cannot use TableGenerator with SQLite.');
}
$this->conn = DriverManager::getConnection(
$conn->getParams(),
$conn->getConfiguration(),
$conn->getEventManager()
);
$this->generatorTableName = $generatorTableName;
}
/**
* Generates the next unused value for the given sequence name.
*
* @param string $sequence
*
* @return int
*
* @throws Exception
*/
public function nextValue($sequence)
{
if (isset($this->sequences[$sequence])) {
$value = $this->sequences[$sequence]['value'];
$this->sequences[$sequence]['value']++;
if ($this->sequences[$sequence]['value'] >= $this->sequences[$sequence]['max']) {
unset($this->sequences[$sequence]);
}
return $value;
}
$this->conn->beginTransaction();
try {
$platform = $this->conn->getDatabasePlatform();
$sql = 'SELECT sequence_value, sequence_increment_by'
. ' FROM ' . $platform->appendLockHint($this->generatorTableName, LockMode::PESSIMISTIC_WRITE)
. ' WHERE sequence_name = ? ' . $platform->getWriteLockSQL();
$row = $this->conn->fetchAssociative($sql, [$sequence]);
if ($row !== false) {
$row = array_change_key_case($row, CASE_LOWER);
$value = $row['sequence_value'];
$value++;
assert(is_int($value));
if ($row['sequence_increment_by'] > 1) {
$this->sequences[$sequence] = [
'value' => $value,
'max' => $row['sequence_value'] + $row['sequence_increment_by'],
];
}
$sql = 'UPDATE ' . $this->generatorTableName . ' ' .
'SET sequence_value = sequence_value + sequence_increment_by ' .
'WHERE sequence_name = ? AND sequence_value = ?';
$rows = $this->conn->executeStatement($sql, [$sequence, $row['sequence_value']]);
if ($rows !== 1) {
throw new Exception('Race-condition detected while updating sequence. Aborting generation');
}
} else {
$this->conn->insert(
$this->generatorTableName,
['sequence_name' => $sequence, 'sequence_value' => 1, 'sequence_increment_by' => 1]
);
$value = 1;
}
$this->conn->commit();
} catch (Throwable $e) {
$this->conn->rollBack();
throw new Exception(
'Error occurred while generating ID with TableGenerator, aborted generation: ' . $e->getMessage(),
0,
$e
);
}
return $value;
}
}
PK %‘R;9Q5d d lib/Doctrine/DBAL/Version.phpnu €žÙ˜ _schemaConfig = $schemaConfig;
$this->_setName($schemaConfig->getName() ?: 'public');
foreach ($namespaces as $namespace) {
$this->createNamespace($namespace);
}
foreach ($tables as $table) {
$this->_addTable($table);
}
foreach ($sequences as $sequence) {
$this->_addSequence($sequence);
}
}
/**
* @return bool
*/
public function hasExplicitForeignKeyIndexes()
{
return $this->_schemaConfig->hasExplicitForeignKeyIndexes();
}
/**
* @return void
*
* @throws SchemaException
*/
protected function _addTable(Table $table)
{
$namespaceName = $table->getNamespaceName();
$tableName = $table->getFullQualifiedName($this->getName());
if (isset($this->_tables[$tableName])) {
throw SchemaException::tableAlreadyExists($tableName);
}
if (
$namespaceName !== null
&& ! $table->isInDefaultNamespace($this->getName())
&& ! $this->hasNamespace($namespaceName)
) {
$this->createNamespace($namespaceName);
}
$this->_tables[$tableName] = $table;
$table->setSchemaConfig($this->_schemaConfig);
}
/**
* @return void
*
* @throws SchemaException
*/
protected function _addSequence(Sequence $sequence)
{
$namespaceName = $sequence->getNamespaceName();
$seqName = $sequence->getFullQualifiedName($this->getName());
if (isset($this->_sequences[$seqName])) {
throw SchemaException::sequenceAlreadyExists($seqName);
}
if (
$namespaceName !== null
&& ! $sequence->isInDefaultNamespace($this->getName())
&& ! $this->hasNamespace($namespaceName)
) {
$this->createNamespace($namespaceName);
}
$this->_sequences[$seqName] = $sequence;
}
/**
* Returns the namespaces of this schema.
*
* @return string[] A list of namespace names.
*/
public function getNamespaces()
{
return $this->namespaces;
}
/**
* Gets all tables of this schema.
*
* @return Table[]
*/
public function getTables()
{
return $this->_tables;
}
/**
* @param string $name
*
* @return Table
*
* @throws SchemaException
*/
public function getTable($name)
{
$name = $this->getFullQualifiedAssetName($name);
if (! isset($this->_tables[$name])) {
throw SchemaException::tableDoesNotExist($name);
}
return $this->_tables[$name];
}
/**
* @param string $name
*
* @return string
*/
private function getFullQualifiedAssetName($name)
{
$name = $this->getUnquotedAssetName($name);
if (strpos($name, '.') === false) {
$name = $this->getName() . '.' . $name;
}
return strtolower($name);
}
/**
* Returns the unquoted representation of a given asset name.
*
* @param string $assetName Quoted or unquoted representation of an asset name.
*
* @return string
*/
private function getUnquotedAssetName($assetName)
{
if ($this->isIdentifierQuoted($assetName)) {
return $this->trimQuotes($assetName);
}
return $assetName;
}
/**
* Does this schema have a namespace with the given name?
*
* @param string $name
*
* @return bool
*/
public function hasNamespace($name)
{
$name = strtolower($this->getUnquotedAssetName($name));
return isset($this->namespaces[$name]);
}
/**
* Does this schema have a table with the given name?
*
* @param string $name
*
* @return bool
*/
public function hasTable($name)
{
$name = $this->getFullQualifiedAssetName($name);
return isset($this->_tables[$name]);
}
/**
* Gets all table names, prefixed with a schema name, even the default one if present.
*
* @return string[]
*/
public function getTableNames()
{
return array_keys($this->_tables);
}
/**
* @param string $name
*
* @return bool
*/
public function hasSequence($name)
{
$name = $this->getFullQualifiedAssetName($name);
return isset($this->_sequences[$name]);
}
/**
* @param string $name
*
* @return Sequence
*
* @throws SchemaException
*/
public function getSequence($name)
{
$name = $this->getFullQualifiedAssetName($name);
if (! $this->hasSequence($name)) {
throw SchemaException::sequenceDoesNotExist($name);
}
return $this->_sequences[$name];
}
/**
* @return Sequence[]
*/
public function getSequences()
{
return $this->_sequences;
}
/**
* Creates a new namespace.
*
* @param string $name The name of the namespace to create.
*
* @return Schema This schema instance.
*
* @throws SchemaException
*/
public function createNamespace($name)
{
$unquotedName = strtolower($this->getUnquotedAssetName($name));
if (isset($this->namespaces[$unquotedName])) {
throw SchemaException::namespaceAlreadyExists($unquotedName);
}
$this->namespaces[$unquotedName] = $name;
return $this;
}
/**
* Creates a new table.
*
* @param string $name
*
* @return Table
*/
public function createTable($name)
{
$table = new Table($name);
$this->_addTable($table);
foreach ($this->_schemaConfig->getDefaultTableOptions() as $option => $value) {
$table->addOption($option, $value);
}
return $table;
}
/**
* Renames a table.
*
* @param string $oldName
* @param string $newName
*
* @return Schema
*/
public function renameTable($oldName, $newName)
{
$table = $this->getTable($oldName);
$table->_setName($newName);
$this->dropTable($oldName);
$this->_addTable($table);
return $this;
}
/**
* Drops a table from the schema.
*
* @param string $name
*
* @return Schema
*/
public function dropTable($name)
{
$name = $this->getFullQualifiedAssetName($name);
$this->getTable($name);
unset($this->_tables[$name]);
return $this;
}
/**
* Creates a new sequence.
*
* @param string $name
* @param int $allocationSize
* @param int $initialValue
*
* @return Sequence
*/
public function createSequence($name, $allocationSize = 1, $initialValue = 1)
{
$seq = new Sequence($name, $allocationSize, $initialValue);
$this->_addSequence($seq);
return $seq;
}
/**
* @param string $name
*
* @return Schema
*/
public function dropSequence($name)
{
$name = $this->getFullQualifiedAssetName($name);
unset($this->_sequences[$name]);
return $this;
}
/**
* Returns an array of necessary SQL queries to create the schema on the given platform.
*
* @return string[]
*/
public function toSql(AbstractPlatform $platform)
{
$sqlCollector = new CreateSchemaSqlCollector($platform);
$this->visit($sqlCollector);
return $sqlCollector->getQueries();
}
/**
* Return an array of necessary SQL queries to drop the schema on the given platform.
*
* @return string[]
*/
public function toDropSql(AbstractPlatform $platform)
{
$dropSqlCollector = new DropSchemaSqlCollector($platform);
$this->visit($dropSqlCollector);
return $dropSqlCollector->getQueries();
}
/**
* @return string[]
*/
public function getMigrateToSql(Schema $toSchema, AbstractPlatform $platform)
{
$comparator = new Comparator();
$schemaDiff = $comparator->compare($this, $toSchema);
return $schemaDiff->toSql($platform);
}
/**
* @return string[]
*/
public function getMigrateFromSql(Schema $fromSchema, AbstractPlatform $platform)
{
$comparator = new Comparator();
$schemaDiff = $comparator->compare($fromSchema, $this);
return $schemaDiff->toSql($platform);
}
/**
* @return void
*/
public function visit(Visitor $visitor)
{
$visitor->acceptSchema($this);
if ($visitor instanceof NamespaceVisitor) {
foreach ($this->namespaces as $namespace) {
$visitor->acceptNamespace($namespace);
}
}
foreach ($this->_tables as $table) {
$table->visit($visitor);
}
foreach ($this->_sequences as $sequence) {
$sequence->visit($visitor);
}
}
/**
* Cloning a Schema triggers a deep clone of all related assets.
*
* @return void
*/
public function __clone()
{
foreach ($this->_tables as $k => $table) {
$this->_tables[$k] = clone $table;
}
foreach ($this->_sequences as $k => $sequence) {
$this->_sequences[$k] = clone $sequence;
}
}
}
PK %‘RŠ)݈q q &