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