class StatementBase
StatementInterface base implementation.
This class is meant to be generic enough for any type of database client, even if all Drupal core database drivers currently use PDO clients. We implement \Iterator instead of \IteratorAggregate to allow iteration to be kept in sync with the underlying database resultset cursor. PDO is not able to execute a database operation while a cursor is open on the result of an earlier select query, so Drupal by default uses buffered queries setting \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY to TRUE on the connection. This forces the query to return all the results in a buffer local to the client library, potentially leading to memory issues in case of large datasets being returned by a query. Other database clients, however, could allow multithread queries, or developers could disable buffered queries in PDO: in that case, this class prevents the resultset to be entirely fetched in PHP memory (that an \IteratorAggregate implementation would force) and therefore optimize memory usage while iterating the resultset.
Hierarchy
- class \Drupal\Core\Database\Statement\StatementBase implements \Drupal\Core\Database\Statement\Iterator, \Drupal\Core\Database\StatementInterface uses \Drupal\Core\Database\FetchModeTrait, \Drupal\Core\Database\Statement\PdoTrait, \Drupal\Core\Database\StatementIteratorTrait
Expanded class hierarchy of StatementBase
2 files declare their use of StatementBase
- StatementPrefetchIterator.php in core/
lib/ Drupal/ Core/ Database/ StatementPrefetchIterator.php - StatementWrapperIterator.php in core/
lib/ Drupal/ Core/ Database/ StatementWrapperIterator.php
File
-
core/
lib/ Drupal/ Core/ Database/ Statement/ StatementBase.php, line 34
Namespace
Drupal\Core\Database\StatementView source
abstract class StatementBase implements \Iterator, StatementInterface {
use FetchModeTrait;
use PdoTrait;
use StatementIteratorTrait;
/**
* The client database Statement object.
*
* For a \PDO client connection, this will be a \PDOStatement object.
*/
protected ?object $clientStatement;
/**
* The results of a data query language (DQL) statement.
*/
protected ?ResultBase $result = NULL;
/**
* Holds the default fetch mode.
*/
protected FetchAs $fetchMode = FetchAs::Object;
/**
* Holds fetch options.
*
* @var array{'class': class-string, 'constructor_args': list<mixed>, 'column': int}
*/
protected array $fetchOptions = [
'class' => 'stdClass',
'constructor_args' => [],
'column' => 0,
];
/**
* Constructor.
*
* @param \Drupal\Core\Database\Connection $connection
* Drupal database connection object.
* @param object $clientConnection
* Client database connection object, for example \PDO.
* @param string $queryString
* The query string.
* @param bool $rowCountEnabled
* (optional) Enables counting the rows matched. Defaults to FALSE.
*/
public function __construct(Connection $connection, object $clientConnection, string $queryString, bool $rowCountEnabled = FALSE) {
}
/**
* {@inheritdoc}
*/
public function getConnectionTarget() : string {
return $this->connection
->getTarget();
}
/**
* {@inheritdoc}
*/
public abstract function execute($args = [], $options = []);
/**
* Dispatches an event informing that the statement execution begins.
*
* @param array $args
* An array of values with as many elements as there are bound parameters in
* the SQL statement being executed. This can be empty.
*
* @return \Drupal\Core\Database\Event\StatementExecutionStartEvent|null
* The dispatched event or NULL if event dispatching is not enabled.
*/
protected function dispatchStatementExecutionStartEvent(array $args) : ?StatementExecutionStartEvent {
if ($this->connection
->isEventEnabled(StatementExecutionStartEvent::class)) {
$startEvent = new StatementExecutionStartEvent(spl_object_id($this), $this->connection
->getKey(), $this->connection
->getTarget(), $this->getQueryString(), $args, $this->connection
->findCallerFromDebugBacktrace());
$this->connection
->dispatchEvent($startEvent);
return $startEvent;
}
return NULL;
}
/**
* Dispatches an event informing that the statement execution succeeded.
*
* @param \Drupal\Core\Database\Event\StatementExecutionStartEvent|null $startEvent
* The start event or NULL if event dispatching is not enabled.
*/
protected function dispatchStatementExecutionEndEvent(?StatementExecutionStartEvent $startEvent) : void {
if (isset($startEvent) && $this->connection
->isEventEnabled(StatementExecutionEndEvent::class)) {
$this->connection
->dispatchEvent(new StatementExecutionEndEvent($startEvent->statementObjectId, $startEvent->key, $startEvent->target, $startEvent->queryString, $startEvent->args, $startEvent->caller, $startEvent->time));
}
}
/**
* Dispatches an event informing of the statement execution failure.
*
* @param \Drupal\Core\Database\Event\StatementExecutionStartEvent|null $startEvent
* The start event or NULL if event dispatching is not enabled.
* @param \Exception $e
* The statement exception thrown.
*/
protected function dispatchStatementExecutionFailureEvent(?StatementExecutionStartEvent $startEvent, \Exception $e) : void {
if (isset($startEvent) && $this->connection
->isEventEnabled(StatementExecutionFailureEvent::class)) {
$this->connection
->dispatchEvent(new StatementExecutionFailureEvent($startEvent->statementObjectId, $startEvent->key, $startEvent->target, $startEvent->queryString, $startEvent->args, $startEvent->caller, $startEvent->time, get_class($e), $e->getCode(), $e->getMessage()));
}
}
/**
* {@inheritdoc}
*/
public function getQueryString() {
return $this->queryString;
}
/**
* {@inheritdoc}
*/
public function setFetchMode($mode, $a1 = NULL, $a2 = []) {
if (is_int($mode)) {
@trigger_error("Passing the \$mode argument as an integer to setFetchMode() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use a case of \\Drupal\\Core\\Database\\FetchAs enum instead. See https://www.drupal.org/node/3488338", E_USER_DEPRECATED);
$mode = $this->pdoToFetchAs($mode);
}
assert($mode instanceof FetchAs);
$this->fetchMode = $mode;
switch ($mode) {
case FetchAs::ClassObject:
$this->fetchOptions['class'] = $a1;
if ($a2) {
$this->fetchOptions['constructor_args'] = $a2;
}
break;
case FetchAs::Column:
$this->fetchOptions['column'] = $a1;
break;
}
// If the result object is missing, just do with the properties setting.
try {
if ($this->result) {
return $this->result
->setFetchMode($mode, $this->fetchOptions);
}
return TRUE;
} catch (\LogicException) {
return TRUE;
}
}
/**
* {@inheritdoc}
*/
public function fetch($mode = NULL, $cursorOrientation = NULL, $cursorOffset = NULL) {
if (is_int($mode)) {
@trigger_error("Passing the \$mode argument as an integer to fetch() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use a case of \\Drupal\\Core\\Database\\FetchAs enum instead. See https://www.drupal.org/node/3488338", E_USER_DEPRECATED);
$mode = $this->pdoToFetchAs($mode);
}
assert($mode === NULL || $mode instanceof FetchAs);
$fetchOptions = match (func_num_args()) { 0 => $this->fetchOptions,
1 => $this->fetchOptions,
2 => $this->fetchOptions + [
'cursor_orientation' => $cursorOrientation,
],
default => $this->fetchOptions + [
'cursor_orientation' => $cursorOrientation,
'cursor_offset' => $cursorOffset,
],
};
$row = $this->result
->fetch($mode ?? $this->fetchMode, $fetchOptions);
if ($row === FALSE) {
$this->markResultsetFetchingComplete();
return FALSE;
}
$this->setResultsetCurrentRow($row);
return $row;
}
/**
* {@inheritdoc}
*/
public function fetchObject(?string $className = NULL, array $constructorArguments = []) {
$row = $className === NULL ? $this->result
->fetch(FetchAs::Object, []) : $this->result
->fetch(FetchAs::ClassObject, [
'class' => $className,
'constructor_args' => $constructorArguments,
]);
if ($row === FALSE) {
$this->markResultsetFetchingComplete();
return FALSE;
}
$this->setResultsetCurrentRow($row);
return $row;
}
/**
* {@inheritdoc}
*/
public function fetchAssoc() {
return $this->fetch(FetchAs::Associative);
}
/**
* {@inheritdoc}
*/
public function fetchField($index = 0) {
$column = $this->result
->fetch(FetchAs::Column, [
'column' => $index,
]);
if ($column === FALSE) {
$this->markResultsetFetchingComplete();
return FALSE;
}
$this->setResultsetCurrentRow($column);
return $column;
}
/**
* {@inheritdoc}
*/
public function fetchAll($mode = NULL, $columnIndex = NULL, $constructorArguments = NULL) {
if (is_int($mode)) {
@trigger_error("Passing the \$mode argument as an integer to fetchAll() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use a case of \\Drupal\\Core\\Database\\FetchAs enum instead. See https://www.drupal.org/node/3488338", E_USER_DEPRECATED);
$mode = $this->pdoToFetchAs($mode);
}
assert($mode === NULL || $mode instanceof FetchAs);
$fetchMode = $mode ?? $this->fetchMode;
if (isset($columnIndex)) {
$this->fetchOptions['column'] = $columnIndex;
}
if (isset($constructorArguments)) {
$this->fetchOptions['constructor_args'] = $constructorArguments;
}
$return = $this->result
->fetchAll($fetchMode, $this->fetchOptions);
$this->markResultsetFetchingComplete();
return $return;
}
/**
* {@inheritdoc}
*/
public function fetchCol($index = 0) {
return $this->fetchAll(FetchAs::Column, $index);
}
/**
* {@inheritdoc}
*/
public function fetchAllAssoc($key, $fetch = NULL) {
if (is_int($fetch)) {
@trigger_error("Passing the \$fetch argument as an integer to fetchAllAssoc() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use a case of \\Drupal\\Core\\Database\\FetchAs enum instead. See https://www.drupal.org/node/3488338", E_USER_DEPRECATED);
$fetch = $this->pdoToFetchAs($fetch);
}
assert($fetch === NULL || $fetch instanceof FetchAs);
$result = $this->result
->fetchAllAssoc($key, $fetch ?? $this->fetchMode, $this->fetchOptions);
$this->markResultsetFetchingComplete();
return $result;
}
/**
* {@inheritdoc}
*/
public function fetchAllKeyed($keyIndex = 0, $valueIndex = 1) {
$result = $this->result
->fetchAllKeyed($keyIndex, $valueIndex);
$this->markResultsetFetchingComplete();
return $result;
}
/**
* {@inheritdoc}
*/
public function rowCount() {
// SELECT query should not use the method.
if ($this->rowCountEnabled) {
return $this->result
->rowCount();
}
else {
throw new RowCountException();
}
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|
FetchModeTrait::$fetchModeLiterals | protected | property | Map FETCH_* modes to their literal for inclusion in messages. | ||
FetchModeTrait::$supportedFetchModes | protected | property | The fetch modes supported. | ||
FetchModeTrait::assocToClass | protected | function | Converts a row of data in FETCH_ASSOC format to FETCH_CLASS. | ||
FetchModeTrait::assocToColumn | protected | function | Converts a row of data in FETCH_ASSOC format to FETCH_COLUMN. | ||
FetchModeTrait::assocToFetchMode | protected | function | Converts a row of data in associative format to a specified format. | ||
FetchModeTrait::assocToNum | protected | function | Converts a row of data in FETCH_ASSOC format to FETCH_NUM. | ||
FetchModeTrait::assocToObj | protected | function | Converts a row of data in FETCH_ASSOC format to FETCH_OBJ. | ||
PdoTrait::clientExecute | protected | function | Executes the prepared PDO statement. | ||
PdoTrait::clientFetch | protected | function | Fetches the next row from the PDO statement. | ||
PdoTrait::clientFetchAll | protected | function | |||
PdoTrait::clientFetchColumn | protected | function | Returns a single column from the next row of a result set. | ||
PdoTrait::clientFetchObject | protected | function | Fetches the next row and returns it as an object. | ||
PdoTrait::clientQueryString | protected | function | Returns the query string used to prepare the statement. | ||
PdoTrait::clientRowCount | protected | function | Returns the number of rows affected by the last SQL statement. | ||
PdoTrait::clientSetFetchMode | protected | function | Sets the default fetch mode for the PDO statement. | ||
PdoTrait::fetchAsToPdo | protected | function | Converts a FetchAs mode to a \PDO::FETCH_* constant value. | ||
PdoTrait::getClientStatement | public | function | Returns the client-level database PDO statement object. | ||
PdoTrait::pdoToFetchAs | protected | function | Converts a \PDO::FETCH_* constant value to a FetchAs mode. | ||
StatementBase::$clientStatement | protected | property | The client database Statement object. | ||
StatementBase::$fetchMode | protected | property | Holds the default fetch mode. | ||
StatementBase::$fetchOptions | protected | property | Holds fetch options. | ||
StatementBase::$result | protected | property | The results of a data query language (DQL) statement. | ||
StatementBase::dispatchStatementExecutionEndEvent | protected | function | Dispatches an event informing that the statement execution succeeded. | ||
StatementBase::dispatchStatementExecutionFailureEvent | protected | function | Dispatches an event informing of the statement execution failure. | ||
StatementBase::dispatchStatementExecutionStartEvent | protected | function | Dispatches an event informing that the statement execution begins. | ||
StatementBase::execute | abstract public | function | Executes a prepared statement. | Overrides StatementInterface::execute | 2 |
StatementBase::fetch | public | function | Fetches the next row from a result set. | Overrides StatementInterface::fetch | |
StatementBase::fetchAll | public | function | Returns an array containing all of the result set rows. | Overrides StatementInterface::fetchAll | |
StatementBase::fetchAllAssoc | public | function | Returns the result set as an associative array keyed by the given field. | Overrides StatementInterface::fetchAllAssoc | |
StatementBase::fetchAllKeyed | public | function | Returns the entire result set as a single associative array. | Overrides StatementInterface::fetchAllKeyed | |
StatementBase::fetchAssoc | public | function | Fetches the next row and returns it as an associative array. | Overrides StatementInterface::fetchAssoc | |
StatementBase::fetchCol | public | function | Returns an entire single column of a result set as an indexed array. | Overrides StatementInterface::fetchCol | |
StatementBase::fetchField | public | function | Returns a single field from the next record of a result set. | Overrides StatementInterface::fetchField | |
StatementBase::fetchObject | public | function | Fetches the next row and returns it as an object. | Overrides StatementInterface::fetchObject | |
StatementBase::getConnectionTarget | public | function | Returns the target connection this statement is associated with. | Overrides StatementInterface::getConnectionTarget | |
StatementBase::getQueryString | public | function | Gets the query string of this statement. | Overrides StatementInterface::getQueryString | |
StatementBase::rowCount | public | function | Returns the number of rows matched by the last SQL statement. | Overrides StatementInterface::rowCount | |
StatementBase::setFetchMode | public | function | Sets the default fetch mode for this statement. | Overrides StatementInterface::setFetchMode | |
StatementBase::__construct | public | function | Constructor. | 2 | |
StatementIteratorTrait::$isResultsetIterable | private | property | Traces if rows can be fetched from the resultset. | ||
StatementIteratorTrait::$resultsetKey | private | property | The key of the current row. | ||
StatementIteratorTrait::$resultsetRow | private | property | The current row, retrieved in the current fetch format. | ||
StatementIteratorTrait::current | public | function | Returns the current element. | ||
StatementIteratorTrait::getResultsetCurrentRowIndex | protected | function | Returns the row index of the current element in the resultset. | ||
StatementIteratorTrait::key | public | function | Returns the key of the current element. | ||
StatementIteratorTrait::markResultsetFetchingComplete | protected | function | Informs the iterator that no more rows can be fetched from the resultset. | ||
StatementIteratorTrait::markResultsetIterable | protected | function | Informs the iterator whether rows can be fetched from the resultset. | ||
StatementIteratorTrait::next | public | function | Moves the current position to the next element. | ||
StatementIteratorTrait::rewind | public | function | Rewinds back to the first element of the Iterator. | ||
StatementIteratorTrait::setResultsetCurrentRow | protected | function | Sets the current resultset row for the iterator, and increments the key. | ||
StatementIteratorTrait::valid | public | function | Checks if current position is valid. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.