1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette\Database\Reflection;
13:
14: use Nette;
15:
16:
17:
18: 19: 20: 21: 22: 23:
24: class DiscoveredReflection extends Nette\Object implements Nette\Database\IReflection
25: {
26:
27: protected $cache;
28:
29:
30: protected $cacheStorage;
31:
32:
33: protected $connection;
34:
35:
36: protected $structure = array(
37: 'primary' => array(),
38: 'hasMany' => array(),
39: 'belongsTo' => array(),
40: );
41:
42:
43:
44: 45: 46: 47:
48: public function __construct(Nette\Caching\IStorage $storage = NULL)
49: {
50: $this->cacheStorage = $storage;
51: }
52:
53:
54:
55: public function setConnection(Nette\Database\Connection $connection)
56: {
57: $this->connection = $connection;
58: if ($this->cacheStorage) {
59: $this->cache = new Nette\Caching\Cache($this->cacheStorage, 'Nette.Database.' . md5($connection->getDsn()));
60: $this->structure = $this->cache->load('structure') ?: $this->structure;
61: }
62: }
63:
64:
65:
66: public function __destruct()
67: {
68: if ($this->cache) {
69: $this->cache->save('structure', $this->structure);
70: }
71: }
72:
73:
74:
75: public function getPrimary($table)
76: {
77: $primary = & $this->structure['primary'][$table];
78: if (isset($primary)) {
79: return empty($primary) ? NULL : $primary;
80: }
81:
82: $columns = $this->connection->getSupplementalDriver()->getColumns($table);
83: $primaryCount = 0;
84: foreach ($columns as $column) {
85: if ($column['primary']) {
86: $primary = $column['name'];
87: $primaryCount++;
88: }
89: }
90:
91: if ($primaryCount !== 1) {
92: $primary = '';
93: return NULL;
94: }
95:
96: return $primary;
97: }
98:
99:
100:
101: public function getHasManyReference($table, $key, $refresh = TRUE)
102: {
103: $reference = $this->structure['hasMany'];
104: if (!empty($reference[$table])) {
105: foreach ($reference[$table] as $targetTable => $targetColumn) {
106: if (stripos($targetTable, $key) !== FALSE) {
107: return array(
108: $targetTable,
109: $targetColumn,
110: );
111: }
112: }
113: }
114:
115: if (!$refresh) {
116: throw new \PDOException("No reference found for \${$table}->related({$key}).");
117: }
118:
119: $this->reloadAllForeignKeys();
120: return $this->getHasManyReference($table, $key, FALSE);
121: }
122:
123:
124:
125: public function getBelongsToReference($table, $key, $refresh = TRUE)
126: {
127: $reference = $this->structure['belongsTo'];
128: if (!empty($reference[$table])) {
129: foreach ($reference[$table] as $column => $targetTable) {
130: if (stripos($column, $key) !== FALSE) {
131: return array(
132: $targetTable,
133: $column,
134: );
135: }
136: }
137: }
138:
139: if (!$refresh) {
140: throw new \PDOException("No reference found for \${$table}->{$key}.");
141: }
142:
143: $this->reloadForeignKeys($table);
144: return $this->getBelongsToReference($table, $key, FALSE);
145: }
146:
147:
148:
149: protected function reloadAllForeignKeys()
150: {
151: foreach ($this->connection->getSupplementalDriver()->getTables() as $table) {
152: if ($table['view'] == FALSE) {
153: $this->reloadForeignKeys($table['name']);
154: }
155: }
156:
157: foreach (array_keys($this->structure['hasMany']) as $table) {
158: uksort($this->structure['hasMany'][$table], function($a, $b) {
159: return strlen($a) - strlen($b);
160: });
161: }
162: }
163:
164:
165:
166: protected function reloadForeignKeys($table)
167: {
168: foreach ($this->connection->getSupplementalDriver()->getForeignKeys($table) as $row) {
169: $this->structure['belongsTo'][$table][$row['local']] = $row['table'];
170: $this->structure['hasMany'][$row['table']][$table] = $row['local'];
171: }
172:
173: if (isset($this->structure['belongsTo'][$table])) {
174: uksort($this->structure['belongsTo'][$table], function($a, $b) {
175: return strlen($a) - strlen($b);
176: });
177: }
178: }
179:
180: }
181: