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