1<?php 2 3namespace Doctrine\DBAL\Schema; 4 5use Doctrine\DBAL\Connection; 6use Doctrine\DBAL\ConnectionException; 7use Doctrine\DBAL\DBALException; 8use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs; 9use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs; 10use Doctrine\DBAL\Events; 11use Doctrine\DBAL\Platforms\AbstractPlatform; 12use Throwable; 13use function array_filter; 14use function array_intersect; 15use function array_map; 16use function array_values; 17use function assert; 18use function call_user_func_array; 19use function count; 20use function func_get_args; 21use function is_array; 22use function is_callable; 23use function preg_match; 24use function str_replace; 25use function strtolower; 26 27/** 28 * Base class for schema managers. Schema managers are used to inspect and/or 29 * modify the database schema/structure. 30 */ 31abstract class AbstractSchemaManager 32{ 33 /** 34 * Holds instance of the Doctrine connection for this schema manager. 35 * 36 * @var Connection 37 */ 38 protected $_conn; 39 40 /** 41 * Holds instance of the database platform used for this schema manager. 42 * 43 * @var AbstractPlatform 44 */ 45 protected $_platform; 46 47 /** 48 * Constructor. Accepts the Connection instance to manage the schema for. 49 */ 50 public function __construct(Connection $conn, ?AbstractPlatform $platform = null) 51 { 52 $this->_conn = $conn; 53 $this->_platform = $platform ?: $this->_conn->getDatabasePlatform(); 54 } 55 56 /** 57 * Returns the associated platform. 58 * 59 * @return AbstractPlatform 60 */ 61 public function getDatabasePlatform() 62 { 63 return $this->_platform; 64 } 65 66 /** 67 * Tries any method on the schema manager. Normally a method throws an 68 * exception when your DBMS doesn't support it or if an error occurs. 69 * This method allows you to try and method on your SchemaManager 70 * instance and will return false if it does not work or is not supported. 71 * 72 * <code> 73 * $result = $sm->tryMethod('dropView', 'view_name'); 74 * </code> 75 * 76 * @return mixed 77 */ 78 public function tryMethod() 79 { 80 $args = func_get_args(); 81 $method = $args[0]; 82 unset($args[0]); 83 $args = array_values($args); 84 85 $callback = [$this, $method]; 86 assert(is_callable($callback)); 87 88 try { 89 return call_user_func_array($callback, $args); 90 } catch (Throwable $e) { 91 return false; 92 } 93 } 94 95 /** 96 * Lists the available databases for this connection. 97 * 98 * @return string[] 99 */ 100 public function listDatabases() 101 { 102 $sql = $this->_platform->getListDatabasesSQL(); 103 104 $databases = $this->_conn->fetchAll($sql); 105 106 return $this->_getPortableDatabasesList($databases); 107 } 108 109 /** 110 * Returns a list of all namespaces in the current database. 111 * 112 * @return string[] 113 */ 114 public function listNamespaceNames() 115 { 116 $sql = $this->_platform->getListNamespacesSQL(); 117 118 $namespaces = $this->_conn->fetchAll($sql); 119 120 return $this->getPortableNamespacesList($namespaces); 121 } 122 123 /** 124 * Lists the available sequences for this connection. 125 * 126 * @param string|null $database 127 * 128 * @return Sequence[] 129 */ 130 public function listSequences($database = null) 131 { 132 if ($database === null) { 133 $database = $this->_conn->getDatabase(); 134 } 135 $sql = $this->_platform->getListSequencesSQL($database); 136 137 $sequences = $this->_conn->fetchAll($sql); 138 139 return $this->filterAssetNames($this->_getPortableSequencesList($sequences)); 140 } 141 142 /** 143 * Lists the columns for a given table. 144 * 145 * In contrast to other libraries and to the old version of Doctrine, 146 * this column definition does try to contain the 'primary' field for 147 * the reason that it is not portable across different RDBMS. Use 148 * {@see listTableIndexes($tableName)} to retrieve the primary key 149 * of a table. Where a RDBMS specifies more details, these are held 150 * in the platformDetails array. 151 * 152 * @param string $table The name of the table. 153 * @param string|null $database 154 * 155 * @return Column[] 156 */ 157 public function listTableColumns($table, $database = null) 158 { 159 if (! $database) { 160 $database = $this->_conn->getDatabase(); 161 } 162 163 $sql = $this->_platform->getListTableColumnsSQL($table, $database); 164 165 $tableColumns = $this->_conn->fetchAll($sql); 166 167 return $this->_getPortableTableColumnList($table, $database, $tableColumns); 168 } 169 170 /** 171 * Lists the indexes for a given table returning an array of Index instances. 172 * 173 * Keys of the portable indexes list are all lower-cased. 174 * 175 * @param string $table The name of the table. 176 * 177 * @return Index[] 178 */ 179 public function listTableIndexes($table) 180 { 181 $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); 182 183 $tableIndexes = $this->_conn->fetchAll($sql); 184 185 return $this->_getPortableTableIndexesList($tableIndexes, $table); 186 } 187 188 /** 189 * Returns true if all the given tables exist. 190 * 191 * The usage of a string $tableNames is deprecated. Pass a one-element array instead. 192 * 193 * @param string|string[] $tableNames 194 * 195 * @return bool 196 */ 197 public function tablesExist($tableNames) 198 { 199 $tableNames = array_map('strtolower', (array) $tableNames); 200 201 return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames()))); 202 } 203 204 /** 205 * Returns a list of all tables in the current database. 206 * 207 * @return string[] 208 */ 209 public function listTableNames() 210 { 211 $sql = $this->_platform->getListTablesSQL(); 212 213 $tables = $this->_conn->fetchAll($sql); 214 $tableNames = $this->_getPortableTablesList($tables); 215 216 return $this->filterAssetNames($tableNames); 217 } 218 219 /** 220 * Filters asset names if they are configured to return only a subset of all 221 * the found elements. 222 * 223 * @param mixed[] $assetNames 224 * 225 * @return mixed[] 226 */ 227 protected function filterAssetNames($assetNames) 228 { 229 $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter(); 230 if (! $filter) { 231 return $assetNames; 232 } 233 234 return array_values(array_filter($assetNames, $filter)); 235 } 236 237 /** 238 * @deprecated Use Configuration::getSchemaAssetsFilter() instead 239 * 240 * @return string|null 241 */ 242 protected function getFilterSchemaAssetsExpression() 243 { 244 return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression(); 245 } 246 247 /** 248 * Lists the tables for this connection. 249 * 250 * @return Table[] 251 */ 252 public function listTables() 253 { 254 $tableNames = $this->listTableNames(); 255 256 $tables = []; 257 foreach ($tableNames as $tableName) { 258 $tables[] = $this->listTableDetails($tableName); 259 } 260 261 return $tables; 262 } 263 264 /** 265 * @param string $tableName 266 * 267 * @return Table 268 */ 269 public function listTableDetails($tableName) 270 { 271 $columns = $this->listTableColumns($tableName); 272 $foreignKeys = []; 273 if ($this->_platform->supportsForeignKeyConstraints()) { 274 $foreignKeys = $this->listTableForeignKeys($tableName); 275 } 276 $indexes = $this->listTableIndexes($tableName); 277 278 return new Table($tableName, $columns, $indexes, $foreignKeys); 279 } 280 281 /** 282 * Lists the views this connection has. 283 * 284 * @return View[] 285 */ 286 public function listViews() 287 { 288 $database = $this->_conn->getDatabase(); 289 $sql = $this->_platform->getListViewsSQL($database); 290 $views = $this->_conn->fetchAll($sql); 291 292 return $this->_getPortableViewsList($views); 293 } 294 295 /** 296 * Lists the foreign keys for the given table. 297 * 298 * @param string $table The name of the table. 299 * @param string|null $database 300 * 301 * @return ForeignKeyConstraint[] 302 */ 303 public function listTableForeignKeys($table, $database = null) 304 { 305 if ($database === null) { 306 $database = $this->_conn->getDatabase(); 307 } 308 $sql = $this->_platform->getListTableForeignKeysSQL($table, $database); 309 $tableForeignKeys = $this->_conn->fetchAll($sql); 310 311 return $this->_getPortableTableForeignKeysList($tableForeignKeys); 312 } 313 314 /* drop*() Methods */ 315 316 /** 317 * Drops a database. 318 * 319 * NOTE: You can not drop the database this SchemaManager is currently connected to. 320 * 321 * @param string $database The name of the database to drop. 322 * 323 * @return void 324 */ 325 public function dropDatabase($database) 326 { 327 $this->_execSql($this->_platform->getDropDatabaseSQL($database)); 328 } 329 330 /** 331 * Drops the given table. 332 * 333 * @param string $tableName The name of the table to drop. 334 * 335 * @return void 336 */ 337 public function dropTable($tableName) 338 { 339 $this->_execSql($this->_platform->getDropTableSQL($tableName)); 340 } 341 342 /** 343 * Drops the index from the given table. 344 * 345 * @param Index|string $index The name of the index. 346 * @param Table|string $table The name of the table. 347 * 348 * @return void 349 */ 350 public function dropIndex($index, $table) 351 { 352 if ($index instanceof Index) { 353 $index = $index->getQuotedName($this->_platform); 354 } 355 356 $this->_execSql($this->_platform->getDropIndexSQL($index, $table)); 357 } 358 359 /** 360 * Drops the constraint from the given table. 361 * 362 * @param Table|string $table The name of the table. 363 * 364 * @return void 365 */ 366 public function dropConstraint(Constraint $constraint, $table) 367 { 368 $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table)); 369 } 370 371 /** 372 * Drops a foreign key from a table. 373 * 374 * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key. 375 * @param Table|string $table The name of the table with the foreign key. 376 * 377 * @return void 378 */ 379 public function dropForeignKey($foreignKey, $table) 380 { 381 $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table)); 382 } 383 384 /** 385 * Drops a sequence with a given name. 386 * 387 * @param string $name The name of the sequence to drop. 388 * 389 * @return void 390 */ 391 public function dropSequence($name) 392 { 393 $this->_execSql($this->_platform->getDropSequenceSQL($name)); 394 } 395 396 /** 397 * Drops a view. 398 * 399 * @param string $name The name of the view. 400 * 401 * @return void 402 */ 403 public function dropView($name) 404 { 405 $this->_execSql($this->_platform->getDropViewSQL($name)); 406 } 407 408 /* create*() Methods */ 409 410 /** 411 * Creates a new database. 412 * 413 * @param string $database The name of the database to create. 414 * 415 * @return void 416 */ 417 public function createDatabase($database) 418 { 419 $this->_execSql($this->_platform->getCreateDatabaseSQL($database)); 420 } 421 422 /** 423 * Creates a new table. 424 * 425 * @return void 426 */ 427 public function createTable(Table $table) 428 { 429 $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS; 430 $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags)); 431 } 432 433 /** 434 * Creates a new sequence. 435 * 436 * @param Sequence $sequence 437 * 438 * @return void 439 * 440 * @throws ConnectionException If something fails at database level. 441 */ 442 public function createSequence($sequence) 443 { 444 $this->_execSql($this->_platform->getCreateSequenceSQL($sequence)); 445 } 446 447 /** 448 * Creates a constraint on a table. 449 * 450 * @param Table|string $table 451 * 452 * @return void 453 */ 454 public function createConstraint(Constraint $constraint, $table) 455 { 456 $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table)); 457 } 458 459 /** 460 * Creates a new index on a table. 461 * 462 * @param Table|string $table The name of the table on which the index is to be created. 463 * 464 * @return void 465 */ 466 public function createIndex(Index $index, $table) 467 { 468 $this->_execSql($this->_platform->getCreateIndexSQL($index, $table)); 469 } 470 471 /** 472 * Creates a new foreign key. 473 * 474 * @param ForeignKeyConstraint $foreignKey The ForeignKey instance. 475 * @param Table|string $table The name of the table on which the foreign key is to be created. 476 * 477 * @return void 478 */ 479 public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) 480 { 481 $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table)); 482 } 483 484 /** 485 * Creates a new view. 486 * 487 * @return void 488 */ 489 public function createView(View $view) 490 { 491 $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql())); 492 } 493 494 /* dropAndCreate*() Methods */ 495 496 /** 497 * Drops and creates a constraint. 498 * 499 * @see dropConstraint() 500 * @see createConstraint() 501 * 502 * @param Table|string $table 503 * 504 * @return void 505 */ 506 public function dropAndCreateConstraint(Constraint $constraint, $table) 507 { 508 $this->tryMethod('dropConstraint', $constraint, $table); 509 $this->createConstraint($constraint, $table); 510 } 511 512 /** 513 * Drops and creates a new index on a table. 514 * 515 * @param Table|string $table The name of the table on which the index is to be created. 516 * 517 * @return void 518 */ 519 public function dropAndCreateIndex(Index $index, $table) 520 { 521 $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table); 522 $this->createIndex($index, $table); 523 } 524 525 /** 526 * Drops and creates a new foreign key. 527 * 528 * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created. 529 * @param Table|string $table The name of the table on which the foreign key is to be created. 530 * 531 * @return void 532 */ 533 public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) 534 { 535 $this->tryMethod('dropForeignKey', $foreignKey, $table); 536 $this->createForeignKey($foreignKey, $table); 537 } 538 539 /** 540 * Drops and create a new sequence. 541 * 542 * @return void 543 * 544 * @throws ConnectionException If something fails at database level. 545 */ 546 public function dropAndCreateSequence(Sequence $sequence) 547 { 548 $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform)); 549 $this->createSequence($sequence); 550 } 551 552 /** 553 * Drops and creates a new table. 554 * 555 * @return void 556 */ 557 public function dropAndCreateTable(Table $table) 558 { 559 $this->tryMethod('dropTable', $table->getQuotedName($this->_platform)); 560 $this->createTable($table); 561 } 562 563 /** 564 * Drops and creates a new database. 565 * 566 * @param string $database The name of the database to create. 567 * 568 * @return void 569 */ 570 public function dropAndCreateDatabase($database) 571 { 572 $this->tryMethod('dropDatabase', $database); 573 $this->createDatabase($database); 574 } 575 576 /** 577 * Drops and creates a new view. 578 * 579 * @return void 580 */ 581 public function dropAndCreateView(View $view) 582 { 583 $this->tryMethod('dropView', $view->getQuotedName($this->_platform)); 584 $this->createView($view); 585 } 586 587 /* alterTable() Methods */ 588 589 /** 590 * Alters an existing tables schema. 591 * 592 * @return void 593 */ 594 public function alterTable(TableDiff $tableDiff) 595 { 596 $queries = $this->_platform->getAlterTableSQL($tableDiff); 597 if (! is_array($queries) || ! count($queries)) { 598 return; 599 } 600 601 foreach ($queries as $ddlQuery) { 602 $this->_execSql($ddlQuery); 603 } 604 } 605 606 /** 607 * Renames a given table to another name. 608 * 609 * @param string $name The current name of the table. 610 * @param string $newName The new name of the table. 611 * 612 * @return void 613 */ 614 public function renameTable($name, $newName) 615 { 616 $tableDiff = new TableDiff($name); 617 $tableDiff->newName = $newName; 618 $this->alterTable($tableDiff); 619 } 620 621 /** 622 * Methods for filtering return values of list*() methods to convert 623 * the native DBMS data definition to a portable Doctrine definition 624 */ 625 626 /** 627 * @param mixed[] $databases 628 * 629 * @return string[] 630 */ 631 protected function _getPortableDatabasesList($databases) 632 { 633 $list = []; 634 foreach ($databases as $value) { 635 $value = $this->_getPortableDatabaseDefinition($value); 636 637 if (! $value) { 638 continue; 639 } 640 641 $list[] = $value; 642 } 643 644 return $list; 645 } 646 647 /** 648 * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition. 649 * 650 * @param mixed[][] $namespaces The list of namespace names in the native DBMS data definition. 651 * 652 * @return string[] 653 */ 654 protected function getPortableNamespacesList(array $namespaces) 655 { 656 $namespacesList = []; 657 658 foreach ($namespaces as $namespace) { 659 $namespacesList[] = $this->getPortableNamespaceDefinition($namespace); 660 } 661 662 return $namespacesList; 663 } 664 665 /** 666 * @param mixed $database 667 * 668 * @return mixed 669 */ 670 protected function _getPortableDatabaseDefinition($database) 671 { 672 return $database; 673 } 674 675 /** 676 * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition. 677 * 678 * @param mixed[] $namespace The native DBMS namespace definition. 679 * 680 * @return mixed 681 */ 682 protected function getPortableNamespaceDefinition(array $namespace) 683 { 684 return $namespace; 685 } 686 687 /** 688 * @deprecated 689 * 690 * @param mixed[][] $functions 691 * 692 * @return mixed[][] 693 */ 694 protected function _getPortableFunctionsList($functions) 695 { 696 $list = []; 697 foreach ($functions as $value) { 698 $value = $this->_getPortableFunctionDefinition($value); 699 700 if (! $value) { 701 continue; 702 } 703 704 $list[] = $value; 705 } 706 707 return $list; 708 } 709 710 /** 711 * @deprecated 712 * 713 * @param mixed[] $function 714 * 715 * @return mixed 716 */ 717 protected function _getPortableFunctionDefinition($function) 718 { 719 return $function; 720 } 721 722 /** 723 * @param mixed[][] $triggers 724 * 725 * @return mixed[][] 726 */ 727 protected function _getPortableTriggersList($triggers) 728 { 729 $list = []; 730 foreach ($triggers as $value) { 731 $value = $this->_getPortableTriggerDefinition($value); 732 733 if (! $value) { 734 continue; 735 } 736 737 $list[] = $value; 738 } 739 740 return $list; 741 } 742 743 /** 744 * @param mixed[] $trigger 745 * 746 * @return mixed 747 */ 748 protected function _getPortableTriggerDefinition($trigger) 749 { 750 return $trigger; 751 } 752 753 /** 754 * @param mixed[][] $sequences 755 * 756 * @return Sequence[] 757 */ 758 protected function _getPortableSequencesList($sequences) 759 { 760 $list = []; 761 762 foreach ($sequences as $value) { 763 $list[] = $this->_getPortableSequenceDefinition($value); 764 } 765 766 return $list; 767 } 768 769 /** 770 * @param mixed[] $sequence 771 * 772 * @return Sequence 773 * 774 * @throws DBALException 775 */ 776 protected function _getPortableSequenceDefinition($sequence) 777 { 778 throw DBALException::notSupported('Sequences'); 779 } 780 781 /** 782 * Independent of the database the keys of the column list result are lowercased. 783 * 784 * The name of the created column instance however is kept in its case. 785 * 786 * @param string $table The name of the table. 787 * @param string $database 788 * @param mixed[][] $tableColumns 789 * 790 * @return Column[] 791 */ 792 protected function _getPortableTableColumnList($table, $database, $tableColumns) 793 { 794 $eventManager = $this->_platform->getEventManager(); 795 796 $list = []; 797 foreach ($tableColumns as $tableColumn) { 798 $column = null; 799 $defaultPrevented = false; 800 801 if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) { 802 $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn); 803 $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs); 804 805 $defaultPrevented = $eventArgs->isDefaultPrevented(); 806 $column = $eventArgs->getColumn(); 807 } 808 809 if (! $defaultPrevented) { 810 $column = $this->_getPortableTableColumnDefinition($tableColumn); 811 } 812 813 if (! $column) { 814 continue; 815 } 816 817 $name = strtolower($column->getQuotedName($this->_platform)); 818 $list[$name] = $column; 819 } 820 821 return $list; 822 } 823 824 /** 825 * Gets Table Column Definition. 826 * 827 * @param mixed[] $tableColumn 828 * 829 * @return Column 830 */ 831 abstract protected function _getPortableTableColumnDefinition($tableColumn); 832 833 /** 834 * Aggregates and groups the index results according to the required data result. 835 * 836 * @param mixed[][] $tableIndexRows 837 * @param string|null $tableName 838 * 839 * @return Index[] 840 */ 841 protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) 842 { 843 $result = []; 844 foreach ($tableIndexRows as $tableIndex) { 845 $indexName = $keyName = $tableIndex['key_name']; 846 if ($tableIndex['primary']) { 847 $keyName = 'primary'; 848 } 849 $keyName = strtolower($keyName); 850 851 if (! isset($result[$keyName])) { 852 $options = [ 853 'lengths' => [], 854 ]; 855 856 if (isset($tableIndex['where'])) { 857 $options['where'] = $tableIndex['where']; 858 } 859 860 $result[$keyName] = [ 861 'name' => $indexName, 862 'columns' => [], 863 'unique' => ! $tableIndex['non_unique'], 864 'primary' => $tableIndex['primary'], 865 'flags' => $tableIndex['flags'] ?? [], 866 'options' => $options, 867 ]; 868 } 869 870 $result[$keyName]['columns'][] = $tableIndex['column_name']; 871 $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null; 872 } 873 874 $eventManager = $this->_platform->getEventManager(); 875 876 $indexes = []; 877 foreach ($result as $indexKey => $data) { 878 $index = null; 879 $defaultPrevented = false; 880 881 if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) { 882 $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn); 883 $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs); 884 885 $defaultPrevented = $eventArgs->isDefaultPrevented(); 886 $index = $eventArgs->getIndex(); 887 } 888 889 if (! $defaultPrevented) { 890 $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']); 891 } 892 893 if (! $index) { 894 continue; 895 } 896 897 $indexes[$indexKey] = $index; 898 } 899 900 return $indexes; 901 } 902 903 /** 904 * @param mixed[][] $tables 905 * 906 * @return string[] 907 */ 908 protected function _getPortableTablesList($tables) 909 { 910 $list = []; 911 foreach ($tables as $value) { 912 $value = $this->_getPortableTableDefinition($value); 913 914 if (! $value) { 915 continue; 916 } 917 918 $list[] = $value; 919 } 920 921 return $list; 922 } 923 924 /** 925 * @param mixed $table 926 * 927 * @return string 928 */ 929 protected function _getPortableTableDefinition($table) 930 { 931 return $table; 932 } 933 934 /** 935 * @param mixed[][] $users 936 * 937 * @return string[][] 938 */ 939 protected function _getPortableUsersList($users) 940 { 941 $list = []; 942 foreach ($users as $value) { 943 $value = $this->_getPortableUserDefinition($value); 944 945 if (! $value) { 946 continue; 947 } 948 949 $list[] = $value; 950 } 951 952 return $list; 953 } 954 955 /** 956 * @param string[] $user 957 * 958 * @return string[] 959 */ 960 protected function _getPortableUserDefinition($user) 961 { 962 return $user; 963 } 964 965 /** 966 * @param mixed[][] $views 967 * 968 * @return View[] 969 */ 970 protected function _getPortableViewsList($views) 971 { 972 $list = []; 973 foreach ($views as $value) { 974 $view = $this->_getPortableViewDefinition($value); 975 976 if (! $view) { 977 continue; 978 } 979 980 $viewName = strtolower($view->getQuotedName($this->_platform)); 981 $list[$viewName] = $view; 982 } 983 984 return $list; 985 } 986 987 /** 988 * @param mixed[] $view 989 * 990 * @return View|false 991 */ 992 protected function _getPortableViewDefinition($view) 993 { 994 return false; 995 } 996 997 /** 998 * @param mixed[][] $tableForeignKeys 999 * 1000 * @return ForeignKeyConstraint[] 1001 */ 1002 protected function _getPortableTableForeignKeysList($tableForeignKeys) 1003 { 1004 $list = []; 1005 1006 foreach ($tableForeignKeys as $value) { 1007 $list[] = $this->_getPortableTableForeignKeyDefinition($value); 1008 } 1009 1010 return $list; 1011 } 1012 1013 /** 1014 * @param mixed $tableForeignKey 1015 * 1016 * @return ForeignKeyConstraint 1017 */ 1018 protected function _getPortableTableForeignKeyDefinition($tableForeignKey) 1019 { 1020 return $tableForeignKey; 1021 } 1022 1023 /** 1024 * @param string[]|string $sql 1025 * 1026 * @return void 1027 */ 1028 protected function _execSql($sql) 1029 { 1030 foreach ((array) $sql as $query) { 1031 $this->_conn->executeUpdate($query); 1032 } 1033 } 1034 1035 /** 1036 * Creates a schema instance for the current database. 1037 * 1038 * @return Schema 1039 */ 1040 public function createSchema() 1041 { 1042 $namespaces = []; 1043 1044 if ($this->_platform->supportsSchemas()) { 1045 $namespaces = $this->listNamespaceNames(); 1046 } 1047 1048 $sequences = []; 1049 1050 if ($this->_platform->supportsSequences()) { 1051 $sequences = $this->listSequences(); 1052 } 1053 1054 $tables = $this->listTables(); 1055 1056 return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces); 1057 } 1058 1059 /** 1060 * Creates the configuration for this schema. 1061 * 1062 * @return SchemaConfig 1063 */ 1064 public function createSchemaConfig() 1065 { 1066 $schemaConfig = new SchemaConfig(); 1067 $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength()); 1068 1069 $searchPaths = $this->getSchemaSearchPaths(); 1070 if (isset($searchPaths[0])) { 1071 $schemaConfig->setName($searchPaths[0]); 1072 } 1073 1074 $params = $this->_conn->getParams(); 1075 if (! isset($params['defaultTableOptions'])) { 1076 $params['defaultTableOptions'] = []; 1077 } 1078 if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) { 1079 $params['defaultTableOptions']['charset'] = $params['charset']; 1080 } 1081 $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']); 1082 1083 return $schemaConfig; 1084 } 1085 1086 /** 1087 * The search path for namespaces in the currently connected database. 1088 * 1089 * The first entry is usually the default namespace in the Schema. All 1090 * further namespaces contain tables/sequences which can also be addressed 1091 * with a short, not full-qualified name. 1092 * 1093 * For databases that don't support subschema/namespaces this method 1094 * returns the name of the currently connected database. 1095 * 1096 * @return string[] 1097 */ 1098 public function getSchemaSearchPaths() 1099 { 1100 return [$this->_conn->getDatabase()]; 1101 } 1102 1103 /** 1104 * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns 1105 * the type given as default. 1106 * 1107 * @param string|null $comment 1108 * @param string $currentType 1109 * 1110 * @return string 1111 */ 1112 public function extractDoctrineTypeFromComment($comment, $currentType) 1113 { 1114 if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) { 1115 return $match[1]; 1116 } 1117 1118 return $currentType; 1119 } 1120 1121 /** 1122 * @param string|null $comment 1123 * @param string|null $type 1124 * 1125 * @return string|null 1126 */ 1127 public function removeDoctrineTypeFromComment($comment, $type) 1128 { 1129 if ($comment === null) { 1130 return null; 1131 } 1132 1133 return str_replace('(DC2Type:' . $type . ')', '', $comment); 1134 } 1135} 1136