%PDF- %PDF-
| Direktori : /www/varak.net/losik.varak.net/vendor/nette/database/src/Database/Table/ |
| Current File : //www/varak.net/losik.varak.net/vendor/nette/database/src/Database/Table/SqlBuilder.php |
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Nette\Database\Table;
use Nette;
use Nette\Database\Conventions;
use Nette\Database\Driver;
use Nette\Database\Explorer;
use Nette\Database\IStructure;
use Nette\Database\SqlLiteral;
/**
* Builds SQL query.
* SqlBuilder is based on great library NotORM http://www.notorm.com written by Jakub Vrana.
*/
class SqlBuilder
{
use Nette\SmartObject;
/** @var string */
protected $tableName;
/** @var Conventions */
protected $conventions;
/** @var string delimited table name */
protected $delimitedTable;
/** @var array of column to select */
protected $select = [];
/** @var array of where conditions */
protected $where = [];
/** @var array of array of join conditions */
protected $joinCondition = [];
/** @var array of where conditions for caching */
protected $conditions = [];
/** @var array of parameters passed to where conditions */
protected $parameters = [
'select' => [],
'joinCondition' => [],
'where' => [],
'group' => [],
'having' => [],
'order' => [],
];
/** @var array or columns to order by */
protected $order = [];
/** @var int number of rows to fetch */
protected $limit;
/** @var int first row to fetch */
protected $offset;
/** @var string columns to grouping */
protected $group = '';
/** @var string grouping condition */
protected $having = '';
/** @var array of reserved table names associated with chain */
protected $reservedTableNames = [];
/** @var array of table aliases */
protected $aliases = [];
/** @var string currently parsing alias for joins */
protected $currentAlias;
/** @var Driver */
private $driver;
/** @var IStructure */
private $structure;
/** @var array */
private $cacheTableList;
/** @var array of expanding joins */
private $expandingJoins = [];
public function __construct(string $tableName, Explorer $explorer)
{
$this->tableName = $tableName;
$this->driver = $explorer->getConnection()->getDriver();
$this->conventions = $explorer->getConventions();
$this->structure = $explorer->getStructure();
$tableNameParts = explode('.', $tableName);
$this->delimitedTable = implode('.', array_map([$this->driver, 'delimite'], $tableNameParts));
$this->checkUniqueTableName(end($tableNameParts), $tableName);
}
public function getTableName(): string
{
return $this->tableName;
}
public function buildInsertQuery(): string
{
return "INSERT INTO {$this->delimitedTable}";
}
public function buildUpdateQuery(): string
{
$query = "UPDATE {$this->delimitedTable} SET ?set" . $this->tryDelimite($this->buildConditions());
if ($this->order !== []) {
$query .= ' ORDER BY ' . implode(', ', $this->order);
}
if ($this->limit !== null || $this->offset) {
$this->driver->applyLimit($query, $this->limit, $this->offset);
}
return $query;
}
public function buildDeleteQuery(): string
{
$query = "DELETE FROM {$this->delimitedTable}" . $this->tryDelimite($this->buildConditions());
if ($this->limit !== null || $this->offset) {
$this->driver->applyLimit($query, $this->limit, $this->offset);
}
return $query;
}
/**
* Returns select query hash for caching.
*/
public function getSelectQueryHash(?array $columns = null): string
{
$parts = [
'delimitedTable' => $this->delimitedTable,
'queryCondition' => $this->buildConditions(),
'queryEnd' => $this->buildQueryEnd(),
$this->aliases,
$this->limit, $this->offset,
];
if ($this->select) {
$parts[] = $this->select;
} elseif ($columns) {
$parts[] = [$this->delimitedTable, $columns];
} elseif ($this->group && !$this->driver->isSupported(Driver::SUPPORT_SELECT_UNGROUPED_COLUMNS)) {
$parts[] = [$this->group];
} else {
$parts[] = "{$this->delimitedTable}.*";
}
return $this->getConditionHash(json_encode($parts), [
$this->parameters['select'],
$this->parameters['joinCondition'],
$this->parameters['where'],
$this->parameters['group'],
$this->parameters['having'],
$this->parameters['order'],
]);
}
/**
* Returns SQL query.
* @param string[] $columns
*/
public function buildSelectQuery(?array $columns = null): string
{
if (!$this->order && ($this->limit !== null || $this->offset)) {
$this->order = array_map(
function ($col) { return "$this->tableName.$col"; },
(array) $this->conventions->getPrimary($this->tableName)
);
}
$queryJoinConditions = $this->buildJoinConditions();
$queryCondition = $this->buildConditions();
$queryEnd = $this->buildQueryEnd();
$joins = [];
$finalJoinConditions = $this->parseJoinConditions($joins, $queryJoinConditions);
$this->parseJoins($joins, $queryCondition);
$this->parseJoins($joins, $queryEnd);
if ($this->select) {
$querySelect = $this->buildSelect($this->select);
$this->parseJoins($joins, $querySelect);
} elseif ($columns) {
$prefix = $joins ? "{$this->delimitedTable}." : '';
$cols = [];
foreach ($columns as $col) {
$cols[] = $prefix . $col;
}
$querySelect = $this->buildSelect($cols);
} elseif ($this->group && !$this->driver->isSupported(Driver::SUPPORT_SELECT_UNGROUPED_COLUMNS)) {
$querySelect = $this->buildSelect([$this->group]);
$this->parseJoins($joins, $querySelect);
} else {
$prefix = $joins ? "{$this->delimitedTable}." : '';
$querySelect = $this->buildSelect([$prefix . '*']);
}
$queryJoins = $this->buildQueryJoins($joins, $finalJoinConditions);
$query = "{$querySelect} FROM {$this->delimitedTable}{$queryJoins}{$queryCondition}{$queryEnd}";
$this->driver->applyLimit($query, $this->limit, $this->offset);
return $this->tryDelimite($query);
}
public function getParameters(): array
{
if (!isset($this->parameters['joinConditionSorted'])) {
$this->buildSelectQuery();
}
return array_merge(
$this->parameters['select'],
$this->parameters['joinConditionSorted'] ? array_merge(...array_values($this->parameters['joinConditionSorted'])) : [],
$this->parameters['where'],
$this->parameters['group'],
$this->parameters['having'],
$this->parameters['order']
);
}
public function importConditions(self $builder): void
{
$this->where = $builder->where;
$this->joinCondition = $builder->joinCondition;
$this->parameters['where'] = $builder->parameters['where'];
$this->parameters['joinCondition'] = $builder->parameters['joinCondition'];
$this->conditions = $builder->conditions;
$this->aliases = $builder->aliases;
$this->reservedTableNames = $builder->reservedTableNames;
}
public function importGroupConditions(self $builder): bool
{
if ($builder->having) {
$this->group = $builder->group;
$this->having = $builder->having;
$this->parameters['group'] = $builder->parameters['group'];
$this->parameters['having'] = $builder->parameters['having'];
return true;
}
return false;
}
/********************* SQL selectors ****************d*g**/
public function addSelect($columns, ...$params): void
{
if (is_array($columns)) {
throw new Nette\InvalidArgumentException('Select column must be a string.');
}
$this->select[] = $columns;
$this->parameters['select'] = array_merge($this->parameters['select'], $params);
}
public function getSelect(): array
{
return $this->select;
}
public function resetSelect(): void
{
$this->select = [];
$this->parameters['select'] = [];
}
public function addWhere($condition, ...$params): bool
{
return $this->addCondition($condition, $params, $this->where, $this->parameters['where']);
}
public function addJoinCondition(string $tableChain, $condition, ...$params): bool
{
$this->parameters['joinConditionSorted'] = null;
if (!isset($this->joinCondition[$tableChain])) {
$this->joinCondition[$tableChain] = $this->parameters['joinCondition'][$tableChain] = [];
}
return $this->addCondition($condition, $params, $this->joinCondition[$tableChain], $this->parameters['joinCondition'][$tableChain]);
}
protected function addCondition($condition, array $params, array &$conditions, array &$conditionsParameters): bool
{
if (is_array($condition) && !empty($params[0]) && is_array($params[0])) {
return $this->addConditionComposition($condition, $params[0], $conditions, $conditionsParameters);
}
$hash = $this->getConditionHash($condition, $params);
if (isset($this->conditions[$hash])) {
return false;
}
$this->conditions[$hash] = $condition;
$placeholderCount = substr_count($condition, '?');
if ($placeholderCount > 1 && count($params) === 1 && is_array($params[0])) {
$params = $params[0];
}
$condition = trim($condition);
if ($placeholderCount === 0 && count($params) === 1) {
$condition .= ' ?';
} elseif ($placeholderCount !== count($params)) {
throw new Nette\InvalidArgumentException('Argument count does not match placeholder count.');
}
$replace = null;
$placeholderNum = 0;
while (count($params)) {
$arg = array_shift($params);
preg_match('#(?:.*?\?.*?){' . $placeholderNum . '}(((?:&|\||^|~|\+|-|\*|/|%|\(|,|<|>|=|(?<=\W|^)(?:REGEXP|ALL|AND|ANY|BETWEEN|EXISTS|IN|[IR]?LIKE|OR|NOT|SOME|INTERVAL))\s*)?(?:\(\?\)|\?))#s', $condition, $match, PREG_OFFSET_CAPTURE);
$hasOperator = ($match[1][0] === '?' && $match[1][1] === 0)
? true
: !empty($match[2][0]);
if ($arg === null) {
$replace = 'IS NULL';
if ($hasOperator) {
if (trim($match[2][0]) === 'NOT') {
$replace = 'IS NOT NULL';
} else {
throw new Nette\InvalidArgumentException('Column operator does not accept null argument.');
}
}
} elseif (is_array($arg) || $arg instanceof Selection) {
if ($hasOperator) {
if (trim($match[2][0]) === 'NOT') {
$match[2][0] = rtrim($match[2][0]) . ' IN ';
} elseif (trim($match[2][0]) !== 'IN') {
throw new Nette\InvalidArgumentException('Column operator does not accept array argument.');
}
} else {
$match[2][0] = 'IN ';
}
if ($arg instanceof Selection) {
$clone = clone $arg;
if (!$clone->getSqlBuilder()->select) {
try {
$clone->select($clone->getPrimary());
} catch (\LogicException $e) {
throw new Nette\InvalidArgumentException('Selection argument must have defined a select column.', 0, $e);
}
}
if ($this->driver->isSupported(Driver::SUPPORT_SUBSELECT)) {
$arg = null;
$subSelectPlaceholderCount = substr_count($clone->getSql(), '?');
$replace = $match[2][0] . '(' . $clone->getSql() . (!$subSelectPlaceholderCount && count($clone->getSqlBuilder()->getParameters()) === 1 ? ' ?' : '') . ')';
if (count($clone->getSqlBuilder()->getParameters())) {
array_unshift($params, ...$clone->getSqlBuilder()->getParameters());
}
} else {
$arg = [];
foreach ($clone as $row) {
$arg[] = array_values(iterator_to_array($row));
}
}
}
if ($arg !== null) {
if (!$arg) {
$hasBrackets = strpos($condition, '(') !== false;
$hasOperators = preg_match('#AND|OR#', $condition);
$hasNot = strpos($condition, 'NOT') !== false;
$hasPrefixNot = strpos($match[2][0], 'NOT') !== false;
if (!$hasBrackets && ($hasOperators || ($hasNot && !$hasPrefixNot))) {
throw new Nette\InvalidArgumentException('Possible SQL query corruption. Add parentheses around operators.');
}
$replace = $hasPrefixNot
? 'IS NULL OR TRUE'
: 'IS NULL AND FALSE';
$arg = null;
} else {
$replace = $match[2][0] . '(?)';
$conditionsParameters[] = $arg;
}
}
} elseif ($arg instanceof SqlLiteral) {
$conditionsParameters[] = $arg;
} else {
if (!$hasOperator) {
$replace = '= ?';
}
$conditionsParameters[] = $arg;
}
if ($replace) {
$condition = substr_replace($condition, $replace, $match[1][1], strlen($match[1][0]));
$replace = null;
}
if ($arg !== null) {
$placeholderNum++;
}
}
$conditions[] = $condition;
return true;
}
public function getConditions(): array
{
return array_values($this->conditions);
}
/**
* Adds alias.
*/
public function addAlias(string $chain, string $alias): void
{
if (isset($chain[0]) && $chain[0] !== '.' && $chain[0] !== ':') {
$chain = '.' . $chain; // unified chain format
}
$this->checkUniqueTableName($alias, $chain);
$this->aliases[$alias] = $chain;
}
protected function checkUniqueTableName(string $tableName, string $chain): void
{
if (isset($this->aliases[$tableName]) && ($chain === '.' . $tableName)) {
$chain = $this->aliases[$tableName];
}
if (isset($this->reservedTableNames[$tableName])) {
if ($this->reservedTableNames[$tableName] === $chain) {
return;
}
throw new Nette\InvalidArgumentException("Table alias '$tableName' from chain '$chain' is already in use by chain '{$this->reservedTableNames[$tableName]}'. Please add/change alias for one of them.");
}
$this->reservedTableNames[$tableName] = $chain;
}
public function addOrder($columns, ...$params): void
{
$this->order[] = $columns;
$this->parameters['order'] = array_merge($this->parameters['order'], $params);
}
public function setOrder(array $columns, array $parameters): void
{
$this->order = $columns;
$this->parameters['order'] = $parameters;
}
public function getOrder(): array
{
return $this->order;
}
public function setLimit(?int $limit, ?int $offset): void
{
$this->limit = $limit;
$this->offset = $offset;
}
public function getLimit(): ?int
{
return $this->limit;
}
public function getOffset(): ?int
{
return $this->offset;
}
public function setGroup($columns, ...$params): void
{
$this->group = $columns;
$this->parameters['group'] = $params;
}
public function getGroup(): string
{
return $this->group;
}
public function setHaving($having, ...$params): void
{
$this->having = $having;
$this->parameters['having'] = $params;
}
public function getHaving(): string
{
return $this->having;
}
/********************* SQL building ****************d*g**/
protected function buildSelect(array $columns): string
{
return 'SELECT ' . implode(', ', $columns);
}
protected function parseJoinConditions(&$joins, $joinConditions): array
{
$tableJoins = $leftJoinDependency = $finalJoinConditions = [];
foreach ($joinConditions as $tableChain => &$joinCondition) {
$fooQuery = $tableChain . '.foo';
$requiredJoins = [];
$this->parseJoins($requiredJoins, $fooQuery);
$tableAlias = substr($fooQuery, 0, -4);
$tableJoins[$tableAlias] = $requiredJoins;
$leftJoinDependency[$tableAlias] = [];
$finalJoinConditions[$tableAlias] = preg_replace_callback($this->getColumnChainsRegxp(), function (array $match) use ($tableAlias, &$tableJoins, &$leftJoinDependency): string {
$requiredJoins = [];
$query = $this->parseJoinsCb($requiredJoins, $match);
$queryParts = explode('.', $query);
$tableJoins[$queryParts[0]] = $requiredJoins;
if ($queryParts[0] !== $tableAlias) {
foreach (array_keys($requiredJoins) as $requiredTable) {
$leftJoinDependency[$tableAlias][$requiredTable] = $requiredTable;
}
}
return $query;
}, $joinCondition);
}
$this->parameters['joinConditionSorted'] = [];
if (count($joinConditions)) {
while ($tableJoins) {
$this->getSortedJoins(key($tableJoins), $leftJoinDependency, $tableJoins, $joins);
}
}
return $finalJoinConditions;
}
protected function getSortedJoins(string $table, &$leftJoinDependency, &$tableJoins, &$finalJoins): void
{
if (isset($this->expandingJoins[$table])) {
$path = implode("' => '", array_map(function (string $value): string { return $this->reservedTableNames[$value]; }, array_merge(array_keys($this->expandingJoins), [$table])));
throw new Nette\InvalidArgumentException("Circular reference detected at left join conditions (tables '$path').");
}
if (isset($tableJoins[$table])) {
$this->expandingJoins[$table] = true;
if (isset($leftJoinDependency[$table])) {
foreach ($leftJoinDependency[$table] as $requiredTable) {
if ($requiredTable === $table) {
continue;
}
$this->getSortedJoins($requiredTable, $leftJoinDependency, $tableJoins, $finalJoins);
}
}
if ($tableJoins[$table]) {
foreach ($tableJoins[$table] as $requiredTable => $tmp) {
if ($requiredTable === $table) {
continue;
}
$this->getSortedJoins($requiredTable, $leftJoinDependency, $tableJoins, $finalJoins);
}
}
$finalJoins += $tableJoins[$table];
$key = isset($this->aliases[$table])
? $table
: $this->reservedTableNames[$table];
if ($key[0] === '.') {
$key = substr($key, 1);
}
$this->parameters['joinConditionSorted'] += isset($this->parameters['joinCondition'][$key])
? [$table => $this->parameters['joinCondition'][$key]]
: [];
unset($tableJoins[$table], $this->expandingJoins[$table]);
}
}
protected function parseJoins(&$joins, &$query): void
{
$query = preg_replace_callback($this->getColumnChainsRegxp(), function (array $match) use (&$joins): string {
return $this->parseJoinsCb($joins, $match);
}, $query);
}
private function getColumnChainsRegxp(): string
{
return '~
(?P<chain> (?!\.) (?: [.:]? (?>[\w_]*[a-z][\w_]*) (\([\w_]*[a-z][\w_]*\))? ) *) \. (?P<column> (?>[\w_]*[a-z][\w_]*) | \* )
~xi';
}
public function parseJoinsCb(&$joins, $match): string
{
$chain = $match['chain'];
if (!empty($chain[0]) && ($chain[0] !== '.' && $chain[0] !== ':')) {
$chain = '.' . $chain; // unified chain format
}
preg_match_all('~
(?P<del> [.:])?(?P<key> [\w_]*[a-z][\w_]* )(\((?P<throughColumn> [\w_]*[a-z][\w_]* )\))?
~xi', $chain, $keyMatches, PREG_SET_ORDER);
$parent = $this->tableName;
$parentAlias = preg_replace('#^(.*\.)?(.*)$#', '$2', $this->tableName);
// join schema keyMatch and table keyMatch to schema.table keyMatch
if ($this->driver->isSupported(Driver::SUPPORT_SCHEMA) && count($keyMatches) > 1) {
$tables = $this->getCachedTableList();
if (
!isset($tables[$keyMatches[0]['key']])
&& isset($tables[$keyMatches[0]['key'] . '.' . $keyMatches[1]['key']])
) {
$keyMatch = array_shift($keyMatches);
$keyMatches[0]['key'] = $keyMatch['key'] . '.' . $keyMatches[0]['key'];
$keyMatches[0]['del'] = $keyMatch['del'];
}
}
// do not make a join when referencing to the current table column - inner conditions
// check it only when not making backjoin on itself - outer condition
if ($keyMatches[0]['del'] === '.') {
if (
count($keyMatches) > 1
&& ($parent === $keyMatches[0]['key']
|| $parentAlias === $keyMatches[0]['key'])
) {
throw new Nette\InvalidArgumentException("Do not prefix table chain with origin table name '{$keyMatches[0]['key']}'. If you want to make self reference, please add alias.");
}
if ($parent === $keyMatches[0]['key']) {
return "{$parent}.{$match['column']}";
} elseif ($parentAlias === $keyMatches[0]['key']) {
return "{$parentAlias}.{$match['column']}";
}
}
$tableChain = null;
foreach ($keyMatches as $index => $keyMatch) {
$isLast = !isset($keyMatches[$index + 1]);
if (!$index && isset($this->aliases[$keyMatch['key']])) {
if ($keyMatch['del'] === ':') {
throw new Nette\InvalidArgumentException("You are using has many syntax with alias (':{$keyMatch['key']}'). You have to move it to alias definition.");
}
$previousAlias = $this->currentAlias;
$this->currentAlias = $keyMatch['key'];
$requiredJoins = [];
$query = $this->aliases[$keyMatch['key']] . '.foo';
$this->parseJoins($requiredJoins, $query);
$aliasJoin = array_pop($requiredJoins);
$joins += $requiredJoins;
[$table, , $parentAlias, $column, $primary] = $aliasJoin;
$this->currentAlias = $previousAlias;
} elseif ($keyMatch['del'] === ':') {
if (isset($keyMatch['throughColumn'])) {
$table = $keyMatch['key'];
$belongsTo = $this->conventions->getBelongsToReference($table, $keyMatch['throughColumn']);
if (!$belongsTo) {
throw new Nette\InvalidArgumentException("No reference found for \${$parent}->{$keyMatch['key']}.");
}
[, $primary] = $belongsTo;
} else {
$hasMany = $this->conventions->getHasManyReference($parent, $keyMatch['key']);
if (!$hasMany) {
throw new Nette\InvalidArgumentException("No reference found for \${$parent}->related({$keyMatch['key']}).");
}
[$table, $primary] = $hasMany;
}
$column = $this->conventions->getPrimary($parent);
} else {
$belongsTo = $this->conventions->getBelongsToReference($parent, $keyMatch['key']);
if (!$belongsTo) {
throw new Nette\InvalidArgumentException("No reference found for \${$parent}->{$keyMatch['key']}.");
}
[$table, $column] = $belongsTo;
$primary = $this->conventions->getPrimary($table);
}
if ($this->currentAlias && $isLast) {
$tableAlias = $this->currentAlias;
} elseif ($parent === $table) {
$tableAlias = $parentAlias . '_ref';
} elseif ($keyMatch['key']) {
$tableAlias = $keyMatch['key'];
} else {
$tableAlias = preg_replace('#^(.*\.)?(.*)$#', '$2', $table);
}
$tableChain .= $keyMatch[0];
if (!$isLast || !$this->currentAlias) {
$this->checkUniqueTableName($tableAlias, $tableChain);
}
$joins[$tableAlias] = [$table, $tableAlias, $parentAlias, $column, $primary];
$parent = $table;
$parentAlias = $tableAlias;
}
return $tableAlias . ".{$match['column']}";
}
protected function buildQueryJoins(array $joins, array $leftJoinConditions = []): string
{
$return = '';
foreach ($joins as [$joinTable, $joinAlias, $table, $tableColumn, $joinColumn]) {
$return .=
" LEFT JOIN {$joinTable}" . ($joinTable !== $joinAlias ? " {$joinAlias}" : '') .
" ON {$table}.{$tableColumn} = {$joinAlias}.{$joinColumn}" .
(isset($leftJoinConditions[$joinAlias]) ? " {$leftJoinConditions[$joinAlias]}" : '');
}
return $return;
}
protected function buildJoinConditions(): array
{
$conditions = [];
foreach ($this->joinCondition as $tableChain => $joinConditions) {
$conditions[$tableChain] = 'AND (' . implode(') AND (', $joinConditions) . ')';
}
return $conditions;
}
protected function buildConditions(): string
{
return $this->where
? ' WHERE (' . implode(') AND (', $this->where) . ')'
: '';
}
protected function buildQueryEnd(): string
{
$return = '';
if ($this->group) {
$return .= ' GROUP BY ' . $this->group;
}
if ($this->having) {
$return .= ' HAVING ' . $this->having;
}
if ($this->order) {
$return .= ' ORDER BY ' . implode(', ', $this->order);
}
return $return;
}
protected function tryDelimite(string $s): string
{
return preg_replace_callback('#(?<=[^\w`"\[?:]|^)[a-z_][a-z0-9_]*(?=[^\w`"(\]]|$)#Di', function (array $m): string {
return strtoupper($m[0]) === $m[0]
? $m[0]
: $this->driver->delimite($m[0]);
}, $s);
}
protected function addConditionComposition(
array $columns,
array $parameters,
array &$conditions,
array &$conditionsParameters
): bool
{
if ($this->driver->isSupported(Driver::SUPPORT_MULTI_COLUMN_AS_OR_COND)) {
$conditionFragment = '(' . implode(' = ? AND ', $columns) . ' = ?) OR ';
$condition = substr(str_repeat($conditionFragment, count($parameters)), 0, -4);
return $this->addCondition($condition, [Nette\Utils\Arrays::flatten($parameters)], $conditions, $conditionsParameters);
} else {
return $this->addCondition('(' . implode(', ', $columns) . ') IN', [$parameters], $conditions, $conditionsParameters);
}
}
private function getConditionHash($condition, array $parameters): string
{
foreach ($parameters as $key => &$parameter) {
if ($parameter instanceof Selection) {
$parameter = $this->getConditionHash($parameter->getSql(), $parameter->getSqlBuilder()->getParameters());
} elseif ($parameter instanceof SqlLiteral) {
$parameter = $this->getConditionHash($parameter->__toString(), $parameter->getParameters());
} elseif (is_object($parameter) && method_exists($parameter, '__toString')) {
$parameter = $parameter->__toString();
} elseif (is_array($parameter) || $parameter instanceof \ArrayAccess) {
$parameter = $this->getConditionHash($key, $parameter);
}
}
return md5($condition . json_encode($parameters));
}
private function getCachedTableList(): array
{
if (!$this->cacheTableList) {
$this->cacheTableList = array_flip(array_map(function (array $pair): string {
return $pair['fullName'] ?? $pair['name'];
}, $this->structure->getTables()));
}
return $this->cacheTableList;
}
}