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