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