Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Utils
  • none
  • Tracy
    • Bridges
      • Nette

Classes

  • Connection
  • Context
  • Helpers
  • ResultSet
  • Row
  • SqlLiteral
  • SqlPreprocessor
  • Structure

Interfaces

  • IConventions
  • IRow
  • IRowContainer
  • IStructure
  • ISupplementalDriver

Exceptions

  • ConnectionException
  • ConstraintViolationException
  • DriverException
  • ForeignKeyConstraintViolationException
  • NotNullConstraintViolationException
  • UniqueConstraintViolationException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Database;
  9: 
 10: use Nette;
 11: 
 12: 
 13: /**
 14:  * Cached reflection of database structure.
 15:  */
 16: class Structure implements IStructure
 17: {
 18:     use Nette\SmartObject;
 19: 
 20:     /** @var Connection */
 21:     protected $connection;
 22: 
 23:     /** @var Nette\Caching\Cache */
 24:     protected $cache;
 25: 
 26:     /** @var array */
 27:     protected $structure;
 28: 
 29:     /** @var bool */
 30:     protected $isRebuilt = FALSE;
 31: 
 32: 
 33:     public function __construct(Connection $connection, Nette\Caching\IStorage $cacheStorage)
 34:     {
 35:         $this->connection = $connection;
 36:         $this->cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Database.Structure.' . md5($this->connection->getDsn()));
 37:     }
 38: 
 39: 
 40:     public function getTables()
 41:     {
 42:         $this->needStructure();
 43:         return $this->structure['tables'];
 44:     }
 45: 
 46: 
 47:     public function getColumns($table)
 48:     {
 49:         $this->needStructure();
 50:         $table = $this->resolveFQTableName($table);
 51: 
 52:         return $this->structure['columns'][$table];
 53:     }
 54: 
 55: 
 56:     public function getPrimaryKey($table)
 57:     {
 58:         $this->needStructure();
 59:         $table = $this->resolveFQTableName($table);
 60: 
 61:         if (!isset($this->structure['primary'][$table])) {
 62:             return NULL;
 63:         }
 64: 
 65:         return $this->structure['primary'][$table];
 66:     }
 67: 
 68: 
 69:     public function getPrimaryKeySequence($table)
 70:     {
 71:         $this->needStructure();
 72:         $table = $this->resolveFQTableName($table);
 73: 
 74:         if (!$this->connection->getSupplementalDriver()->isSupported(ISupplementalDriver::SUPPORT_SEQUENCE)) {
 75:             return NULL;
 76:         }
 77: 
 78:         $primary = $this->getPrimaryKey($table);
 79:         if (!$primary || is_array($primary)) {
 80:             return NULL;
 81:         }
 82: 
 83:         foreach ($this->structure['columns'][$table] as $columnMeta) {
 84:             if ($columnMeta['name'] === $primary) {
 85:                 return isset($columnMeta['vendor']['sequence']) ? $columnMeta['vendor']['sequence'] : NULL;
 86:             }
 87:         }
 88: 
 89:         return NULL;
 90:     }
 91: 
 92: 
 93:     public function getHasManyReference($table, $targetTable = NULL)
 94:     {
 95:         $this->needStructure();
 96:         $table = $this->resolveFQTableName($table);
 97: 
 98:         if ($targetTable) {
 99:             $targetTable = $this->resolveFQTableName($targetTable);
100:             foreach ($this->structure['hasMany'][$table] as $key => $value) {
101:                 if (strtolower($key) === $targetTable) {
102:                     return $this->structure['hasMany'][$table][$key];
103:                 }
104:             }
105: 
106:             return NULL;
107: 
108:         } else {
109:             if (!isset($this->structure['hasMany'][$table])) {
110:                 return [];
111:             }
112:             return $this->structure['hasMany'][$table];
113:         }
114:     }
115: 
116: 
117:     public function getBelongsToReference($table, $column = NULL)
118:     {
119:         $this->needStructure();
120:         $table = $this->resolveFQTableName($table);
121: 
122:         if ($column) {
123:             $column = strtolower($column);
124:             if (!isset($this->structure['belongsTo'][$table][$column])) {
125:                 return NULL;
126:             }
127:             return $this->structure['belongsTo'][$table][$column];
128: 
129:         } else {
130:             if (!isset($this->structure['belongsTo'][$table])) {
131:                 return [];
132:             }
133:             return $this->structure['belongsTo'][$table];
134:         }
135:     }
136: 
137: 
138:     public function rebuild()
139:     {
140:         $this->structure = $this->loadStructure();
141:         $this->cache->save('structure', $this->structure);
142:     }
143: 
144: 
145:     public function isRebuilt()
146:     {
147:         return $this->isRebuilt;
148:     }
149: 
150: 
151:     protected function needStructure()
152:     {
153:         if ($this->structure !== NULL) {
154:             return;
155:         }
156: 
157:         $this->structure = $this->cache->load('structure', [$this, 'loadStructure']);
158:     }
159: 
160: 
161:     /**
162:      * @internal
163:      */
164:     public function loadStructure()
165:     {
166:         $driver = $this->connection->getSupplementalDriver();
167: 
168:         $structure = [];
169:         $structure['tables'] = $driver->getTables();
170: 
171:         foreach ($structure['tables'] as $tablePair) {
172:             if (isset($tablePair['fullName'])) {
173:                 $table = $tablePair['fullName'];
174:                 $structure['aliases'][strtolower($tablePair['name'])] = strtolower($table);
175:             } else {
176:                 $table = $tablePair['name'];
177:             }
178: 
179:             $structure['columns'][strtolower($table)] = $columns = $driver->getColumns($table);
180: 
181:             if (!$tablePair['view']) {
182:                 $structure['primary'][strtolower($table)] = $this->analyzePrimaryKey($columns);
183:                 $this->analyzeForeignKeys($structure, $table);
184:             }
185:         }
186: 
187:         if (isset($structure['hasMany'])) {
188:             foreach ($structure['hasMany'] as & $table) {
189:                 uksort($table, function ($a, $b) {
190:                     return strlen($a) - strlen($b);
191:                 });
192:             }
193:         }
194: 
195:         $this->isRebuilt = TRUE;
196: 
197:         return $structure;
198:     }
199: 
200: 
201:     protected function analyzePrimaryKey(array $columns)
202:     {
203:         $primary = [];
204:         foreach ($columns as $column) {
205:             if ($column['primary']) {
206:                 $primary[] = $column['name'];
207:             }
208:         }
209: 
210:         if (count($primary) === 0) {
211:             return NULL;
212:         } elseif (count($primary) === 1) {
213:             return reset($primary);
214:         } else {
215:             return $primary;
216:         }
217:     }
218: 
219: 
220:     protected function analyzeForeignKeys(& $structure, $table)
221:     {
222:         $lowerTable = strtolower($table);
223:         foreach ($this->connection->getSupplementalDriver()->getForeignKeys($table) as $row) {
224:             $structure['belongsTo'][$lowerTable][$row['local']] = $row['table'];
225:             $structure['hasMany'][strtolower($row['table'])][$table][] = $row['local'];
226:         }
227: 
228:         if (isset($structure['belongsTo'][$lowerTable])) {
229:             uksort($structure['belongsTo'][$lowerTable], function ($a, $b) {
230:                 return strlen($a) - strlen($b);
231:             });
232:         }
233:     }
234: 
235: 
236:     protected function resolveFQTableName($table)
237:     {
238:         $name = strtolower($table);
239:         if (isset($this->structure['columns'][$name])) {
240:             return $name;
241:         }
242: 
243:         if (isset($this->structure['aliases'][$name])) {
244:             return $this->structure['aliases'][$name];
245:         }
246: 
247:         if (!$this->isRebuilt()) {
248:             $this->rebuild();
249:             return $this->resolveFQTableName($table);
250:         }
251: 
252:         throw new Nette\InvalidArgumentException("Table '$name' does not exist.");
253:     }
254: 
255: }
256: 
Nette 2.4-20161109 API API documentation generated by ApiGen 2.8.0