vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php line 52

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