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