%PDF- %PDF-
Direktori : /data/www_bck/varak.net_bck/losik.varak.net/vendor/nette/database/src/Database/ |
Current File : //data/www_bck/varak.net_bck/losik.varak.net/vendor/nette/database/src/Database/Structure.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; use Nette; /** * Cached reflection of database structure. */ class Structure implements IStructure { use Nette\SmartObject; /** @var Connection */ protected $connection; /** @var Nette\Caching\Cache */ protected $cache; /** @var array */ protected $structure; /** @var bool */ protected $isRebuilt = false; public function __construct(Connection $connection, Nette\Caching\IStorage $cacheStorage) { $this->connection = $connection; $this->cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Database.Structure.' . md5($this->connection->getDsn())); } public function getTables(): array { $this->needStructure(); return $this->structure['tables']; } public function getColumns(string $table): array { $this->needStructure(); $table = $this->resolveFQTableName($table); return $this->structure['columns'][$table]; } /** * @return string|string[]|null */ public function getPrimaryKey(string $table) { $this->needStructure(); $table = $this->resolveFQTableName($table); return $this->structure['primary'][$table] ?? null; } public function getPrimaryAutoincrementKey(string $table): ?string { $primaryKey = $this->getPrimaryKey($table); if (!$primaryKey) { return null; } // Search for autoincrement key from multi primary key if (is_array($primaryKey)) { $keys = array_flip($primaryKey); foreach ($this->getColumns($table) as $column) { if (isset($keys[$column['name']]) && $column['autoincrement']) { return $column['name']; } } return null; } // Search for autoincrement key from simple primary key foreach ($this->getColumns($table) as $column) { if ($column['name'] === $primaryKey) { return $column['autoincrement'] ? $column['name'] : null; } } return null; } public function getPrimaryKeySequence(string $table): ?string { $this->needStructure(); $table = $this->resolveFQTableName($table); if (!$this->connection->getDriver()->isSupported(Driver::SUPPORT_SEQUENCE)) { return null; } $autoincrementPrimaryKeyName = $this->getPrimaryAutoincrementKey($table); if (!$autoincrementPrimaryKeyName) { return null; } // Search for sequence from simple primary key foreach ($this->structure['columns'][$table] as $columnMeta) { if ($columnMeta['name'] === $autoincrementPrimaryKeyName) { return $columnMeta['vendor']['sequence'] ?? null; } } return null; } public function getHasManyReference(string $table, ?string $targetTable = null): ?array { $this->needStructure(); $table = $this->resolveFQTableName($table); if ($targetTable) { $targetTable = $this->resolveFQTableName($targetTable); foreach ($this->structure['hasMany'][$table] as $key => $value) { if (strtolower($key) === $targetTable) { return $this->structure['hasMany'][$table][$key]; } } return null; } else { return $this->structure['hasMany'][$table] ?? []; } } public function getBelongsToReference(string $table, ?string $column = null): ?array { $this->needStructure(); $table = $this->resolveFQTableName($table); if ($column) { $column = strtolower($column); return isset($this->structure['belongsTo'][$table][$column]) ? [$this->structure['belongsTo'][$table][$column], $column] : null; } else { return $this->structure['belongsTo'][$table] ?? []; } } public function rebuild(): void { $this->structure = $this->loadStructure(); $this->cache->save('structure', $this->structure); } public function isRebuilt(): bool { return $this->isRebuilt; } protected function needStructure(): void { if ($this->structure !== null) { return; } $this->structure = $this->cache->load('structure', \Closure::fromCallable([$this, 'loadStructure'])); } protected function loadStructure(): array { $driver = $this->connection->getDriver(); $structure = []; $structure['tables'] = $driver->getTables(); foreach ($structure['tables'] as $tablePair) { if (isset($tablePair['fullName'])) { $table = $tablePair['fullName']; $structure['aliases'][strtolower($tablePair['name'])] = strtolower($table); } else { $table = $tablePair['name']; } $structure['columns'][strtolower($table)] = $columns = $driver->getColumns($table); if (!$tablePair['view']) { $structure['primary'][strtolower($table)] = $this->analyzePrimaryKey($columns); $this->analyzeForeignKeys($structure, $table); } } if (isset($structure['hasMany'])) { foreach ($structure['hasMany'] as &$table) { uksort($table, function ($a, $b): int { return strlen($a) <=> strlen($b); }); } } $this->isRebuilt = true; return $structure; } protected function analyzePrimaryKey(array $columns) { $primary = []; foreach ($columns as $column) { if ($column['primary']) { $primary[] = $column['name']; } } if (count($primary) === 0) { return null; } elseif (count($primary) === 1) { return reset($primary); } else { return $primary; } } protected function analyzeForeignKeys(array &$structure, string $table): void { $lowerTable = strtolower($table); $foreignKeys = $this->connection->getDriver()->getForeignKeys($table); $fksColumnsCounts = []; foreach ($foreignKeys as $foreignKey) { $tmp = &$fksColumnsCounts[$foreignKey['name']]; $tmp++; } usort($foreignKeys, function ($a, $b) use ($fksColumnsCounts): int { return $fksColumnsCounts[$b['name']] <=> $fksColumnsCounts[$a['name']]; }); foreach ($foreignKeys as $row) { $structure['belongsTo'][$lowerTable][$row['local']] = $row['table']; $structure['hasMany'][strtolower($row['table'])][$table][] = $row['local']; } if (isset($structure['belongsTo'][$lowerTable])) { uksort($structure['belongsTo'][$lowerTable], function ($a, $b): int { return strlen($a) <=> strlen($b); }); } } protected function resolveFQTableName(string $table): string { $name = strtolower($table); if (isset($this->structure['columns'][$name])) { return $name; } if (isset($this->structure['aliases'][$name])) { return $this->structure['aliases'][$name]; } if (!$this->isRebuilt()) { $this->rebuild(); return $this->resolveFQTableName($table); } throw new Nette\InvalidArgumentException("Table '$name' does not exist."); } }