Overview

Namespaces

  • Alchemy
    • core
      • query
      • schema
    • dialect
    • engine
    • orm
    • tests
    • util
      • promise
  • PHP

Classes

  • Column
  • Foreign
  • ForeignKey
  • Index
  • Table
  • TableElement
  • Overview
  • Namespace
  • Class
  • Tree
  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:  * Represent a table in SQL
 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:      * Retrieve the table registered for a given name.
 37:      *
 38:      * @param  string $name
 39:      * @return Table
 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:      * Object constructor
 62:      *
 63:      * @param string $name       name of table
 64:      * @param array  $columndefs array("name" => Column, "name" => Column, ...)
 65:      * @param array  $indexdefs  array("name" => Index, "name" => Index, ...)
 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:      * Get the table name
104:      *
105:      * @return string
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:      * Return true if the given column exists
119:      *
120:      * @param string $name
121:      * @return bool
122:      */
123:     public function hasColumn($name) {
124:         return array_key_exists($name, $this->args['columns']);
125:     }
126: 
127: 
128:     /**
129:      * List all configured columns
130:      *
131:      * @return array array(Name => Column, ...)
132:      */
133:     public function listColumns() {
134:         $this->resolve();
135:         return $this->columns;
136:     }
137: 
138: 
139:     /**
140:      * List names of table I depend on
141:      *
142:      * @return array
143:      */
144:     public function listDependancies() {
145:         $this->resolve();
146:         return $this->dependancies;
147:     }
148: 
149: 
150:     /**
151:      * List names of tables that depend on me
152:      *
153:      * @return array
154:      */
155:     public function listDependants() {
156:         $this->resolve();
157:         return $this->dependants;
158:     }
159: 
160: 
161:     /**
162:      * List all additional column indexes
163:      *
164:      * @return array array(Name => Index, ...)
165:      */
166:     public function listIndexes() {
167:         $this->resolve();
168:         return $this->indexes;
169:     }
170: 
171: 
172:     /**
173:      * Get this table's primary key index
174:      *
175:      * @return Index::PrimaryKey
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:      * Register this Table as canonical for its name
187:      */
188:     public function register($force = false) {
189:         self::register_name($this->name, $this, $force);
190:     }
191: 
192: 
193:     /**
194:      * Lazy-resolve the whole Table
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:         // Set multi-column indexes
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: 
API documentation generated by ApiGen 2.8.0