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
      • Reflection
      • 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
  • IReflection
  • IRow
  • IRowContainer
  • IStructure
  • ISupplementalDriver

Exceptions

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