1: <?php
2:
3: namespace Alchemy\core\schema;
4: use Alchemy\core\Element;
5: use Alchemy\core\query\TableRef;
6: use Alchemy\util\DataTypeLexer;
7: use Alchemy\util\promise\IPromisable;
8: use Exception;
9:
10:
11: 12: 13:
14: class Table extends Element implements IPromisable {
15: protected static $registered = array();
16:
17: protected $name;
18: protected $resolved;
19: protected $args = array();
20: protected $columns = array();
21: protected $indexes = array();
22:
23: private $dependancies = array();
24: private $dependants = array();
25:
26:
27: public static function list_promisable_methods() {
28: return array(
29: 'getColumn' => "Alchemy\core\schema\Column",
30: 'getRef' => "Alchemy\core\query\TableRef",
31: 'copy' => "Alchemy\core\schema\Table");
32: }
33:
34:
35: 36: 37: 38: 39: 40:
41: public static function find($name) {
42: if (isset(self::$registered[$name])) {
43: return self::$registered[$name];
44: }
45:
46: throw new \Exception("No table registered for name '{$name}'.");
47: }
48:
49:
50: public static function register_name($name, $table, $force = false) {
51: if (!$force && isset(self::$registered[$name])
52: && self::$registered[$name] !== $table) {
53: throw new \Exception("A table is already registered for name '{$name}'.");
54: }
55:
56: self::$registered[$name] = $table;
57: }
58:
59:
60: 61: 62: 63: 64: 65: 66:
67: public function __construct($type, $name, $args = array()) {
68: parent::__construct($type);
69:
70: $this->name = $name;
71: $def = static::get_definition($this->type);
72: $this->args = self::normalize_arg($args, $def['defaults']);
73: }
74:
75:
76: public function getColumn($name) {
77: if (!array_key_exists($name, $this->columns)) {
78: if (array_key_exists($name, $this->args['columns'])) {
79: $column = $this->args['columns'][$name];
80:
81: if (is_string($column)) {
82: $type = new DataTypeLexer($column);
83: $t = $type->getType();
84: $column = Column::$t($type->getArgs());
85: }
86:
87: $this->columns[$name] = $column->copy(array(), $this, $name);
88: } else {
89: throw new Exception("Unknown column '{$this->name}.{$name}'");
90: }
91: }
92:
93: return $this->columns[$name];
94: }
95:
96:
97: public function copy() {
98: return new static($this->name, $this->args);
99: }
100:
101:
102: 103: 104: 105: 106:
107: public function getName() {
108: return $this->name;
109: }
110:
111:
112: public function getRef() {
113: return new TableRef($this);
114: }
115:
116:
117: 118: 119: 120: 121: 122:
123: public function hasColumn($name) {
124: return array_key_exists($name, $this->args['columns']);
125: }
126:
127:
128: 129: 130: 131: 132:
133: public function listColumns() {
134: $this->resolve();
135: return $this->columns;
136: }
137:
138:
139: 140: 141: 142: 143:
144: public function listDependancies() {
145: $this->resolve();
146: return $this->dependancies;
147: }
148:
149:
150: 151: 152: 153: 154:
155: public function listDependants() {
156: $this->resolve();
157: return $this->dependants;
158: }
159:
160:
161: 162: 163: 164: 165:
166: public function listIndexes() {
167: $this->resolve();
168: return $this->indexes;
169: }
170:
171:
172: 173: 174: 175: 176:
177: public function getPrimaryKey() {
178: $this->resolve();
179: return array_key_exists('PRIMARY', $this->indexes)
180: ? $this->indexes['PRIMARY']
181: : null;
182: }
183:
184:
185: 186: 187:
188: public function register($force = false) {
189: self::register_name($this->name, $this, $force);
190: }
191:
192:
193: 194: 195:
196: protected function resolve() {
197: if ($this->resolved) return;
198: $primary = array();
199:
200: foreach ($this->args['columns'] as $name => $prop) {
201: $column = $this->getColumn($name);
202:
203: $this->indexes[$name] = $column->getIndex();
204:
205: if ($fk = $column->getForeignKey()) {
206: $this->indexes[$fk->getName()] = $fk;
207:
208: $source = $fk->getSourceTable();
209: if ($source != $this) {
210: $this->dependancies[] = $source->getName();
211: $source->dependants[] = $this->getName();
212: }
213: }
214:
215: if ($column->isPrimaryKeyPart()) {
216: $primary[] = $column;
217: }
218: }
219:
220: if ($primary) {
221: $this->indexes['PRIMARY'] = Index::PrimaryKey(array($primary), $this, 'PRIMARY');
222: }
223:
224:
225: foreach ($this->args['indexes'] as $name => $index) {
226: if (is_string($index)) {
227: $type = new DataTypeLexer($index);
228: $t = $type->getType();
229: $index = Index::$t($type->getArgs(), $this, $name);
230: }
231:
232: $this->indexes[$name] = $index;
233: }
234:
235: $this->indexes = array_filter($this->indexes);
236: $this->resolved = true;
237: }
238: }
239: