1<?php 2/** 3 * Zend Framework (http://framework.zend.com/) 4 * 5 * @link http://github.com/zendframework/zf2 for the canonical source repository 6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 7 * @license http://framework.zend.com/license/new-bsd New BSD License 8 */ 9 10namespace Zend\Db\Metadata\Source; 11 12use Zend\Db\Adapter\Adapter; 13use Zend\Db\Metadata\MetadataInterface; 14use Zend\Db\Metadata\Object; 15 16abstract class AbstractSource implements MetadataInterface 17{ 18 const DEFAULT_SCHEMA = '__DEFAULT_SCHEMA__'; 19 20 /** 21 * 22 * @var Adapter 23 */ 24 protected $adapter = null; 25 26 /** 27 * 28 * @var string 29 */ 30 protected $defaultSchema = null; 31 32 /** 33 * 34 * @var array 35 */ 36 protected $data = array(); 37 38 /** 39 * Constructor 40 * 41 * @param Adapter $adapter 42 */ 43 public function __construct(Adapter $adapter) 44 { 45 $this->adapter = $adapter; 46 $this->defaultSchema = ($adapter->getCurrentSchema()) ?: self::DEFAULT_SCHEMA; 47 } 48 49 /** 50 * Get schemas 51 * 52 */ 53 public function getSchemas() 54 { 55 $this->loadSchemaData(); 56 57 return $this->data['schemas']; 58 } 59 60 /** 61 * Get table names 62 * 63 * @param string $schema 64 * @param bool $includeViews 65 * @return string[] 66 */ 67 public function getTableNames($schema = null, $includeViews = false) 68 { 69 if ($schema === null) { 70 $schema = $this->defaultSchema; 71 } 72 73 $this->loadTableNameData($schema); 74 75 if ($includeViews) { 76 return array_keys($this->data['table_names'][$schema]); 77 } 78 79 $tableNames = array(); 80 foreach ($this->data['table_names'][$schema] as $tableName => $data) { 81 if ('BASE TABLE' == $data['table_type']) { 82 $tableNames[] = $tableName; 83 } 84 } 85 return $tableNames; 86 } 87 88 /** 89 * Get tables 90 * 91 * @param string $schema 92 * @param bool $includeViews 93 * @return Object\TableObject[] 94 */ 95 public function getTables($schema = null, $includeViews = false) 96 { 97 if ($schema === null) { 98 $schema = $this->defaultSchema; 99 } 100 101 $tables = array(); 102 foreach ($this->getTableNames($schema, $includeViews) as $tableName) { 103 $tables[] = $this->getTable($tableName, $schema); 104 } 105 return $tables; 106 } 107 108 /** 109 * Get table 110 * 111 * @param string $tableName 112 * @param string $schema 113 * @return Object\TableObject 114 */ 115 public function getTable($tableName, $schema = null) 116 { 117 if ($schema === null) { 118 $schema = $this->defaultSchema; 119 } 120 121 $this->loadTableNameData($schema); 122 123 if (!isset($this->data['table_names'][$schema][$tableName])) { 124 throw new \Exception('Table "' . $tableName . '" does not exist'); 125 } 126 127 $data = $this->data['table_names'][$schema][$tableName]; 128 switch ($data['table_type']) { 129 case 'BASE TABLE': 130 $table = new Object\TableObject($tableName); 131 break; 132 case 'VIEW': 133 $table = new Object\ViewObject($tableName); 134 $table->setViewDefinition($data['view_definition']); 135 $table->setCheckOption($data['check_option']); 136 $table->setIsUpdatable($data['is_updatable']); 137 break; 138 default: 139 throw new \Exception('Table "' . $tableName . '" is of an unsupported type "' . $data['table_type'] . '"'); 140 } 141 $table->setColumns($this->getColumns($tableName, $schema)); 142 $table->setConstraints($this->getConstraints($tableName, $schema)); 143 return $table; 144 } 145 146 /** 147 * Get view names 148 * 149 * @param string $schema 150 * @return array 151 */ 152 public function getViewNames($schema = null) 153 { 154 if ($schema === null) { 155 $schema = $this->defaultSchema; 156 } 157 158 $this->loadTableNameData($schema); 159 160 $viewNames = array(); 161 foreach ($this->data['table_names'][$schema] as $tableName => $data) { 162 if ('VIEW' == $data['table_type']) { 163 $viewNames[] = $tableName; 164 } 165 } 166 return $viewNames; 167 } 168 169 /** 170 * Get views 171 * 172 * @param string $schema 173 * @return array 174 */ 175 public function getViews($schema = null) 176 { 177 if ($schema === null) { 178 $schema = $this->defaultSchema; 179 } 180 181 $views = array(); 182 foreach ($this->getViewNames($schema) as $tableName) { 183 $views[] = $this->getTable($tableName, $schema); 184 } 185 return $views; 186 } 187 188 /** 189 * Get view 190 * 191 * @param string $viewName 192 * @param string $schema 193 * @return \Zend\Db\Metadata\Object\TableObject 194 */ 195 public function getView($viewName, $schema = null) 196 { 197 if ($schema === null) { 198 $schema = $this->defaultSchema; 199 } 200 201 $this->loadTableNameData($schema); 202 203 $tableNames = $this->data['table_names'][$schema]; 204 if (isset($tableNames[$viewName]) && 'VIEW' == $tableNames[$viewName]['table_type']) { 205 return $this->getTable($viewName, $schema); 206 } 207 throw new \Exception('View "' . $viewName . '" does not exist'); 208 } 209 210 /** 211 * Gt column names 212 * 213 * @param string $table 214 * @param string $schema 215 * @return array 216 */ 217 public function getColumnNames($table, $schema = null) 218 { 219 if ($schema === null) { 220 $schema = $this->defaultSchema; 221 } 222 223 $this->loadColumnData($table, $schema); 224 225 if (!isset($this->data['columns'][$schema][$table])) { 226 throw new \Exception('"' . $table . '" does not exist'); 227 } 228 229 return array_keys($this->data['columns'][$schema][$table]); 230 } 231 232 /** 233 * Get columns 234 * 235 * @param string $table 236 * @param string $schema 237 * @return array 238 */ 239 public function getColumns($table, $schema = null) 240 { 241 if ($schema === null) { 242 $schema = $this->defaultSchema; 243 } 244 245 $this->loadColumnData($table, $schema); 246 247 $columns = array(); 248 foreach ($this->getColumnNames($table, $schema) as $columnName) { 249 $columns[] = $this->getColumn($columnName, $table, $schema); 250 } 251 return $columns; 252 } 253 254 /** 255 * Get column 256 * 257 * @param string $columnName 258 * @param string $table 259 * @param string $schema 260 * @return Object\ColumnObject 261 */ 262 public function getColumn($columnName, $table, $schema = null) 263 { 264 if ($schema === null) { 265 $schema = $this->defaultSchema; 266 } 267 268 $this->loadColumnData($table, $schema); 269 270 if (!isset($this->data['columns'][$schema][$table][$columnName])) { 271 throw new \Exception('A column by that name was not found.'); 272 } 273 274 $info = $this->data['columns'][$schema][$table][$columnName]; 275 276 $column = new Object\ColumnObject($columnName, $table, $schema); 277 $props = array( 278 'ordinal_position', 'column_default', 'is_nullable', 279 'data_type', 'character_maximum_length', 'character_octet_length', 280 'numeric_precision', 'numeric_scale', 'numeric_unsigned', 281 'erratas' 282 ); 283 foreach ($props as $prop) { 284 if (isset($info[$prop])) { 285 $column->{'set' . str_replace('_', '', $prop)}($info[$prop]); 286 } 287 } 288 289 $column->setOrdinalPosition($info['ordinal_position']); 290 $column->setColumnDefault($info['column_default']); 291 $column->setIsNullable($info['is_nullable']); 292 $column->setDataType($info['data_type']); 293 $column->setCharacterMaximumLength($info['character_maximum_length']); 294 $column->setCharacterOctetLength($info['character_octet_length']); 295 $column->setNumericPrecision($info['numeric_precision']); 296 $column->setNumericScale($info['numeric_scale']); 297 $column->setNumericUnsigned($info['numeric_unsigned']); 298 $column->setErratas($info['erratas']); 299 300 return $column; 301 } 302 303 /** 304 * Get constraints 305 * 306 * @param string $table 307 * @param string $schema 308 * @return array 309 */ 310 public function getConstraints($table, $schema = null) 311 { 312 if ($schema === null) { 313 $schema = $this->defaultSchema; 314 } 315 316 $this->loadConstraintData($table, $schema); 317 318 $constraints = array(); 319 foreach (array_keys($this->data['constraints'][$schema][$table]) as $constraintName) { 320 $constraints[] = $this->getConstraint($constraintName, $table, $schema); 321 } 322 323 return $constraints; 324 } 325 326 /** 327 * Get constraint 328 * 329 * @param string $constraintName 330 * @param string $table 331 * @param string $schema 332 * @return Object\ConstraintObject 333 */ 334 public function getConstraint($constraintName, $table, $schema = null) 335 { 336 if ($schema === null) { 337 $schema = $this->defaultSchema; 338 } 339 340 $this->loadConstraintData($table, $schema); 341 342 if (!isset($this->data['constraints'][$schema][$table][$constraintName])) { 343 throw new \Exception('Cannot find a constraint by that name in this table'); 344 } 345 346 $info = $this->data['constraints'][$schema][$table][$constraintName]; 347 $constraint = new Object\ConstraintObject($constraintName, $table, $schema); 348 349 foreach (array( 350 'constraint_type' => 'setType', 351 'match_option' => 'setMatchOption', 352 'update_rule' => 'setUpdateRule', 353 'delete_rule' => 'setDeleteRule', 354 'columns' => 'setColumns', 355 'referenced_table_schema' => 'setReferencedTableSchema', 356 'referenced_table_name' => 'setReferencedTableName', 357 'referenced_columns' => 'setReferencedColumns', 358 'check_clause' => 'setCheckClause', 359 ) as $key => $setMethod) { 360 if (isset($info[$key])) { 361 $constraint->{$setMethod}($info[$key]); 362 } 363 } 364 365 return $constraint; 366 } 367 368 /** 369 * Get constraint keys 370 * 371 * @param string $constraint 372 * @param string $table 373 * @param string $schema 374 * @return array 375 */ 376 public function getConstraintKeys($constraint, $table, $schema = null) 377 { 378 if ($schema === null) { 379 $schema = $this->defaultSchema; 380 } 381 382 $this->loadConstraintReferences($table, $schema); 383 384 // organize references first 385 $references = array(); 386 foreach ($this->data['constraint_references'][$schema] as $refKeyInfo) { 387 if ($refKeyInfo['constraint_name'] == $constraint) { 388 $references[$refKeyInfo['constraint_name']] = $refKeyInfo; 389 } 390 } 391 392 $this->loadConstraintDataKeys($schema); 393 394 $keys = array(); 395 foreach ($this->data['constraint_keys'][$schema] as $constraintKeyInfo) { 396 if ($constraintKeyInfo['table_name'] == $table && $constraintKeyInfo['constraint_name'] === $constraint) { 397 $keys[] = $key = new Object\ConstraintKeyObject($constraintKeyInfo['column_name']); 398 $key->setOrdinalPosition($constraintKeyInfo['ordinal_position']); 399 if (isset($references[$constraint])) { 400 //$key->setReferencedTableSchema($constraintKeyInfo['referenced_table_schema']); 401 $key->setForeignKeyUpdateRule($references[$constraint]['update_rule']); 402 $key->setForeignKeyDeleteRule($references[$constraint]['delete_rule']); 403 //$key->setReferencedTableSchema($references[$constraint]['referenced_table_schema']); 404 $key->setReferencedTableName($references[$constraint]['referenced_table_name']); 405 $key->setReferencedColumnName($references[$constraint]['referenced_column_name']); 406 } 407 } 408 } 409 410 return $keys; 411 } 412 413 /** 414 * Get trigger names 415 * 416 * @param string $schema 417 * @return array 418 */ 419 public function getTriggerNames($schema = null) 420 { 421 if ($schema === null) { 422 $schema = $this->defaultSchema; 423 } 424 425 $this->loadTriggerData($schema); 426 427 return array_keys($this->data['triggers'][$schema]); 428 } 429 430 /** 431 * Get triggers 432 * 433 * @param string $schema 434 * @return array 435 */ 436 public function getTriggers($schema = null) 437 { 438 if ($schema === null) { 439 $schema = $this->defaultSchema; 440 } 441 442 $triggers = array(); 443 foreach ($this->getTriggerNames($schema) as $triggerName) { 444 $triggers[] = $this->getTrigger($triggerName, $schema); 445 } 446 return $triggers; 447 } 448 449 /** 450 * Get trigger 451 * 452 * @param string $triggerName 453 * @param string $schema 454 * @return Object\TriggerObject 455 */ 456 public function getTrigger($triggerName, $schema = null) 457 { 458 if ($schema === null) { 459 $schema = $this->defaultSchema; 460 } 461 462 $this->loadTriggerData($schema); 463 464 if (!isset($this->data['triggers'][$schema][$triggerName])) { 465 throw new \Exception('Trigger "' . $triggerName . '" does not exist'); 466 } 467 468 $info = $this->data['triggers'][$schema][$triggerName]; 469 470 $trigger = new Object\TriggerObject(); 471 472 $trigger->setName($triggerName); 473 $trigger->setEventManipulation($info['event_manipulation']); 474 $trigger->setEventObjectCatalog($info['event_object_catalog']); 475 $trigger->setEventObjectSchema($info['event_object_schema']); 476 $trigger->setEventObjectTable($info['event_object_table']); 477 $trigger->setActionOrder($info['action_order']); 478 $trigger->setActionCondition($info['action_condition']); 479 $trigger->setActionStatement($info['action_statement']); 480 $trigger->setActionOrientation($info['action_orientation']); 481 $trigger->setActionTiming($info['action_timing']); 482 $trigger->setActionReferenceOldTable($info['action_reference_old_table']); 483 $trigger->setActionReferenceNewTable($info['action_reference_new_table']); 484 $trigger->setActionReferenceOldRow($info['action_reference_old_row']); 485 $trigger->setActionReferenceNewRow($info['action_reference_new_row']); 486 $trigger->setCreated($info['created']); 487 488 return $trigger; 489 } 490 491 /** 492 * Prepare data hierarchy 493 * 494 * @param string $type 495 * @param string $key ... 496 */ 497 protected function prepareDataHierarchy($type) 498 { 499 $data = &$this->data; 500 foreach (func_get_args() as $key) { 501 if (!isset($data[$key])) { 502 $data[$key] = array(); 503 } 504 $data = &$data[$key]; 505 } 506 } 507 508 /** 509 * Load schema data 510 */ 511 protected function loadSchemaData() 512 { 513 } 514 515 /** 516 * Load table name data 517 * 518 * @param string $schema 519 */ 520 protected function loadTableNameData($schema) 521 { 522 if (isset($this->data['table_names'][$schema])) { 523 return; 524 } 525 526 $this->prepareDataHierarchy('table_names', $schema); 527 } 528 529 /** 530 * Load column data 531 * 532 * @param string $table 533 * @param string $schema 534 */ 535 protected function loadColumnData($table, $schema) 536 { 537 if (isset($this->data['columns'][$schema][$table])) { 538 return; 539 } 540 541 $this->prepareDataHierarchy('columns', $schema, $table); 542 } 543 544 /** 545 * Load constraint data 546 * 547 * @param string $table 548 * @param string $schema 549 */ 550 protected function loadConstraintData($table, $schema) 551 { 552 if (isset($this->data['constraints'][$schema])) { 553 return; 554 } 555 556 $this->prepareDataHierarchy('constraints', $schema); 557 } 558 559 /** 560 * Load constraint data keys 561 * 562 * @param string $schema 563 */ 564 protected function loadConstraintDataKeys($schema) 565 { 566 if (isset($this->data['constraint_keys'][$schema])) { 567 return; 568 } 569 570 $this->prepareDataHierarchy('constraint_keys', $schema); 571 } 572 573 /** 574 * Load constraint references 575 * 576 * @param string $table 577 * @param string $schema 578 */ 579 protected function loadConstraintReferences($table, $schema) 580 { 581 if (isset($this->data['constraint_references'][$schema])) { 582 return; 583 } 584 585 $this->prepareDataHierarchy('constraint_references', $schema); 586 } 587 588 /** 589 * Load trigger data 590 * 591 * @param string $schema 592 */ 593 protected function loadTriggerData($schema) 594 { 595 if (isset($this->data['triggers'][$schema])) { 596 return; 597 } 598 599 $this->prepareDataHierarchy('triggers', $schema); 600 } 601} 602