vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php line 242

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