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: if (isset($this->structure['hasMany'][strtolower($table)])) {
100: $candidates = $columnCandidates = array();
101: foreach ($this->structure['hasMany'][strtolower($table)] as $targetPair) {
102: list($targetColumn, $targetTable) = $targetPair;
103: if (stripos($targetTable, $key) === FALSE) {
104: continue;
105: }
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:
116: if (count($columnCandidates) === 1) {
117: return reset($columnCandidates);
118: } elseif (count($candidates) === 1) {
119: return reset($candidates);
120: }
121:
122: foreach ($candidates as $candidate) {
123: list($targetTable, $targetColumn) = $candidate;
124: if (strtolower($targetTable) === strtolower($key)) {
125: return $candidate;
126: }
127: }
128: }
129:
130: if ($refresh) {
131: $this->reloadAllForeignKeys();
132: return $this->getHasManyReference($table, $key, FALSE);
133: }
134:
135: if (empty($candidates)) {
136: throw new NMissingReferenceException("No reference found for \${$table}->related({$key}).");
137: } else {
138: throw new NAmbiguousReferenceKeyException('Ambiguous joining column in related call.');
139: }
140: }
141:
142:
143:
144: public function getBelongsToReference($table, $key, $refresh = TRUE)
145: {
146: if (isset($this->structure['belongsTo'][strtolower($table)])) {
147: foreach ($this->structure['belongsTo'][strtolower($table)] as $column => $targetTable) {
148: if (stripos($column, $key) !== FALSE) {
149: return array($targetTable, $column);
150: }
151: }
152: }
153:
154: if ($refresh) {
155: $this->reloadForeignKeys($table);
156: return $this->getBelongsToReference($table, $key, FALSE);
157: }
158:
159: throw new NMissingReferenceException("No reference found for \${$table}->{$key}.");
160: }
161:
162:
163:
164: protected function reloadAllForeignKeys()
165: {
166: foreach ($this->connection->getSupplementalDriver()->getTables() as $table) {
167: if ($table['view'] == FALSE) {
168: $this->reloadForeignKeys($table['name']);
169: }
170: }
171:
172: foreach ($this->structure['hasMany'] as & $table) {
173: uksort($table, create_function('$a, $b', '
174: return strlen($a) - strlen($b);
175: '));
176: }
177: }
178:
179:
180:
181: protected function reloadForeignKeys($table)
182: {
183: foreach ($this->connection->getSupplementalDriver()->getForeignKeys($table) as $row) {
184: $this->structure['belongsTo'][strtolower($table)][$row['local']] = $row['table'];
185: $this->structure['hasMany'][strtolower($row['table'])][$row['local'] . $table] = array($row['local'], $table);
186: }
187:
188: if (isset($this->structure['belongsTo'][$table])) {
189: uksort($this->structure['belongsTo'][$table], create_function('$a, $b', '
190: return strlen($a) - strlen($b);
191: '));
192: }
193: }
194:
195: }
196: