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

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\Exception\DatabaseRequired;
  9. use Doctrine\DBAL\Platforms\AbstractPlatform;
  10. use Doctrine\DBAL\Result;
  11. use Doctrine\Deprecations\Deprecation;
  12. use Throwable;
  13. use function array_filter;
  14. use function array_intersect;
  15. use function array_map;
  16. use function array_values;
  17. use function assert;
  18. use function call_user_func_array;
  19. use function count;
  20. use function func_get_args;
  21. use function is_callable;
  22. use function is_string;
  23. use function preg_match;
  24. use function str_replace;
  25. use function strtolower;
  26. /**
  27. * Base class for schema managers. Schema managers are used to inspect and/or
  28. * modify the database schema/structure.
  29. *
  30. * @template-covariant T of AbstractPlatform
  31. */
  32. abstract 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. * Holds instance of the database platform used for this schema manager.
  42. *
  43. * @var T
  44. */
  45. protected $_platform;
  46. /** @param T $platform */
  47. public function __construct(Connection $connection, AbstractPlatform $platform)
  48. {
  49. $this->_conn = $connection;
  50. $this->_platform = $platform;
  51. }
  52. /**
  53. * Returns the associated platform.
  54. *
  55. * @deprecated Use {@link Connection::getDatabasePlatform()} instead.
  56. *
  57. * @return T
  58. */
  59. public function getDatabasePlatform()
  60. {
  61. Deprecation::trigger(
  62. 'doctrine/dbal',
  63. 'https://github.com/doctrine/dbal/pull/5387',
  64. 'AbstractSchemaManager::getDatabasePlatform() is deprecated.'
  65. . ' Use Connection::getDatabasePlatform() instead.',
  66. );
  67. return $this->_platform;
  68. }
  69. /**
  70. * Tries any method on the schema manager. Normally a method throws an
  71. * exception when your DBMS doesn't support it or if an error occurs.
  72. * This method allows you to try and method on your SchemaManager
  73. * instance and will return false if it does not work or is not supported.
  74. *
  75. * <code>
  76. * $result = $sm->tryMethod('dropView', 'view_name');
  77. * </code>
  78. *
  79. * @deprecated
  80. *
  81. * @return mixed
  82. */
  83. public function tryMethod()
  84. {
  85. Deprecation::triggerIfCalledFromOutside(
  86. 'doctrine/dbal',
  87. 'https://github.com/doctrine/dbal/pull/4897',
  88. 'AbstractSchemaManager::tryMethod() is deprecated.',
  89. );
  90. $args = func_get_args();
  91. $method = $args[0];
  92. unset($args[0]);
  93. $args = array_values($args);
  94. $callback = [$this, $method];
  95. assert(is_callable($callback));
  96. try {
  97. return call_user_func_array($callback, $args);
  98. } catch (Throwable $e) {
  99. return false;
  100. }
  101. }
  102. /**
  103. * Lists the available databases for this connection.
  104. *
  105. * @return string[]
  106. *
  107. * @throws Exception
  108. */
  109. public function listDatabases()
  110. {
  111. $sql = $this->_platform->getListDatabasesSQL();
  112. $databases = $this->_conn->fetchAllAssociative($sql);
  113. return $this->_getPortableDatabasesList($databases);
  114. }
  115. /**
  116. * Returns a list of all namespaces in the current database.
  117. *
  118. * @deprecated Use {@see listSchemaNames()} instead.
  119. *
  120. * @return string[]
  121. *
  122. * @throws Exception
  123. */
  124. public function listNamespaceNames()
  125. {
  126. Deprecation::triggerIfCalledFromOutside(
  127. 'doctrine/dbal',
  128. 'https://github.com/doctrine/dbal/issues/4503',
  129. 'AbstractSchemaManager::listNamespaceNames() is deprecated,'
  130. . ' use AbstractSchemaManager::listSchemaNames() instead.',
  131. );
  132. $sql = $this->_platform->getListNamespacesSQL();
  133. $namespaces = $this->_conn->fetchAllAssociative($sql);
  134. return $this->getPortableNamespacesList($namespaces);
  135. }
  136. /**
  137. * Returns a list of the names of all schemata in the current database.
  138. *
  139. * @return list<string>
  140. *
  141. * @throws Exception
  142. */
  143. public function listSchemaNames(): array
  144. {
  145. throw Exception::notSupported(__METHOD__);
  146. }
  147. /**
  148. * Lists the available sequences for this connection.
  149. *
  150. * @param string|null $database
  151. *
  152. * @return Sequence[]
  153. *
  154. * @throws Exception
  155. */
  156. public function listSequences($database = null)
  157. {
  158. if ($database === null) {
  159. $database = $this->getDatabase(__METHOD__);
  160. } else {
  161. Deprecation::trigger(
  162. 'doctrine/dbal',
  163. 'https://github.com/doctrine/dbal/issues/5284',
  164. 'Passing $database to AbstractSchemaManager::listSequences() is deprecated.',
  165. );
  166. }
  167. $sql = $this->_platform->getListSequencesSQL($database);
  168. $sequences = $this->_conn->fetchAllAssociative($sql);
  169. return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
  170. }
  171. /**
  172. * Lists the columns for a given table.
  173. *
  174. * In contrast to other libraries and to the old version of Doctrine,
  175. * this column definition does try to contain the 'primary' column for
  176. * the reason that it is not portable across different RDBMS. Use
  177. * {@see listTableIndexes($tableName)} to retrieve the primary key
  178. * of a table. Where a RDBMS specifies more details, these are held
  179. * in the platformDetails array.
  180. *
  181. * @param string $table The name of the table.
  182. * @param string|null $database
  183. *
  184. * @return Column[]
  185. *
  186. * @throws Exception
  187. */
  188. public function listTableColumns($table, $database = null)
  189. {
  190. if ($database === null) {
  191. $database = $this->getDatabase(__METHOD__);
  192. } else {
  193. Deprecation::triggerIfCalledFromOutside(
  194. 'doctrine/dbal',
  195. 'https://github.com/doctrine/dbal/issues/5284',
  196. 'Passing $database to AbstractSchemaManager::listTableColumns() is deprecated.',
  197. );
  198. }
  199. $sql = $this->_platform->getListTableColumnsSQL($table, $database);
  200. $tableColumns = $this->_conn->fetchAllAssociative($sql);
  201. return $this->_getPortableTableColumnList($table, $database, $tableColumns);
  202. }
  203. /**
  204. * @param string $table
  205. * @param string|null $database
  206. *
  207. * @return Column[]
  208. *
  209. * @throws Exception
  210. */
  211. protected function doListTableColumns($table, $database = null): array
  212. {
  213. if ($database === null) {
  214. $database = $this->getDatabase(__METHOD__);
  215. } else {
  216. Deprecation::triggerIfCalledFromOutside(
  217. 'doctrine/dbal',
  218. 'https://github.com/doctrine/dbal/issues/5284',
  219. 'Passing $database to AbstractSchemaManager::doListTableColumns() is deprecated.',
  220. );
  221. }
  222. return $this->_getPortableTableColumnList(
  223. $table,
  224. $database,
  225. $this->selectTableColumns($database, $this->normalizeName($table))
  226. ->fetchAllAssociative(),
  227. );
  228. }
  229. /**
  230. * Lists the indexes for a given table returning an array of Index instances.
  231. *
  232. * Keys of the portable indexes list are all lower-cased.
  233. *
  234. * @param string $table The name of the table.
  235. *
  236. * @return Index[]
  237. *
  238. * @throws Exception
  239. */
  240. public function listTableIndexes($table)
  241. {
  242. $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
  243. $tableIndexes = $this->_conn->fetchAllAssociative($sql);
  244. return $this->_getPortableTableIndexesList($tableIndexes, $table);
  245. }
  246. /**
  247. * @param string $table
  248. *
  249. * @return Index[]
  250. *
  251. * @throws Exception
  252. */
  253. protected function doListTableIndexes($table): array
  254. {
  255. $database = $this->getDatabase(__METHOD__);
  256. $table = $this->normalizeName($table);
  257. return $this->_getPortableTableIndexesList(
  258. $this->selectIndexColumns(
  259. $database,
  260. $table,
  261. )->fetchAllAssociative(),
  262. $table,
  263. );
  264. }
  265. /**
  266. * Returns true if all the given tables exist.
  267. *
  268. * The usage of a string $tableNames is deprecated. Pass a one-element array instead.
  269. *
  270. * @param string|string[] $names
  271. *
  272. * @return bool
  273. *
  274. * @throws Exception
  275. */
  276. public function tablesExist($names)
  277. {
  278. if (is_string($names)) {
  279. Deprecation::trigger(
  280. 'doctrine/dbal',
  281. 'https://github.com/doctrine/dbal/issues/3580',
  282. 'The usage of a string $tableNames in AbstractSchemaManager::tablesExist() is deprecated. ' .
  283. 'Pass a one-element array instead.',
  284. );
  285. }
  286. $names = array_map('strtolower', (array) $names);
  287. return count($names) === count(array_intersect($names, array_map('strtolower', $this->listTableNames())));
  288. }
  289. /**
  290. * Returns a list of all tables in the current database.
  291. *
  292. * @return string[]
  293. *
  294. * @throws Exception
  295. */
  296. public function listTableNames()
  297. {
  298. $sql = $this->_platform->getListTablesSQL();
  299. $tables = $this->_conn->fetchAllAssociative($sql);
  300. $tableNames = $this->_getPortableTablesList($tables);
  301. return $this->filterAssetNames($tableNames);
  302. }
  303. /**
  304. * @return list<string>
  305. *
  306. * @throws Exception
  307. */
  308. protected function doListTableNames(): array
  309. {
  310. $database = $this->getDatabase(__METHOD__);
  311. return $this->filterAssetNames(
  312. $this->_getPortableTablesList(
  313. $this->selectTableNames($database)
  314. ->fetchAllAssociative(),
  315. ),
  316. );
  317. }
  318. /**
  319. * Filters asset names if they are configured to return only a subset of all
  320. * the found elements.
  321. *
  322. * @param mixed[] $assetNames
  323. *
  324. * @return mixed[]
  325. */
  326. protected function filterAssetNames($assetNames)
  327. {
  328. $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
  329. if ($filter === null) {
  330. return $assetNames;
  331. }
  332. return array_values(array_filter($assetNames, $filter));
  333. }
  334. /**
  335. * Lists the tables for this connection.
  336. *
  337. * @return list<Table>
  338. *
  339. * @throws Exception
  340. */
  341. public function listTables()
  342. {
  343. $tableNames = $this->listTableNames();
  344. $tables = [];
  345. foreach ($tableNames as $tableName) {
  346. $tables[] = $this->introspectTable($tableName);
  347. }
  348. return $tables;
  349. }
  350. /**
  351. * @return list<Table>
  352. *
  353. * @throws Exception
  354. */
  355. protected function doListTables(): array
  356. {
  357. $database = $this->getDatabase(__METHOD__);
  358. $tableColumnsByTable = $this->fetchTableColumnsByTable($database);
  359. $indexColumnsByTable = $this->fetchIndexColumnsByTable($database);
  360. $foreignKeyColumnsByTable = $this->fetchForeignKeyColumnsByTable($database);
  361. $tableOptionsByTable = $this->fetchTableOptionsByTable($database);
  362. $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
  363. $tables = [];
  364. foreach ($tableColumnsByTable as $tableName => $tableColumns) {
  365. if ($filter !== null && ! $filter($tableName)) {
  366. continue;
  367. }
  368. $tables[] = new Table(
  369. $tableName,
  370. $this->_getPortableTableColumnList($tableName, $database, $tableColumns),
  371. $this->_getPortableTableIndexesList($indexColumnsByTable[$tableName] ?? [], $tableName),
  372. [],
  373. $this->_getPortableTableForeignKeysList($foreignKeyColumnsByTable[$tableName] ?? []),
  374. $tableOptionsByTable[$tableName] ?? [],
  375. );
  376. }
  377. return $tables;
  378. }
  379. /**
  380. * @deprecated Use {@see introspectTable()} instead.
  381. *
  382. * @param string $name
  383. *
  384. * @return Table
  385. *
  386. * @throws Exception
  387. */
  388. public function listTableDetails($name)
  389. {
  390. Deprecation::triggerIfCalledFromOutside(
  391. 'doctrine/dbal',
  392. 'https://github.com/doctrine/dbal/pull/5595',
  393. '%s is deprecated. Use introspectTable() instead.',
  394. __METHOD__,
  395. );
  396. $columns = $this->listTableColumns($name);
  397. $foreignKeys = [];
  398. if ($this->_platform->supportsForeignKeyConstraints()) {
  399. $foreignKeys = $this->listTableForeignKeys($name);
  400. }
  401. $indexes = $this->listTableIndexes($name);
  402. return new Table($name, $columns, $indexes, [], $foreignKeys);
  403. }
  404. /**
  405. * @param string $name
  406. *
  407. * @throws Exception
  408. */
  409. protected function doListTableDetails($name): Table
  410. {
  411. $database = $this->getDatabase(__METHOD__);
  412. $normalizedName = $this->normalizeName($name);
  413. $tableOptionsByTable = $this->fetchTableOptionsByTable($database, $normalizedName);
  414. if ($this->_platform->supportsForeignKeyConstraints()) {
  415. $foreignKeys = $this->listTableForeignKeys($name);
  416. } else {
  417. $foreignKeys = [];
  418. }
  419. return new Table(
  420. $name,
  421. $this->listTableColumns($name, $database),
  422. $this->listTableIndexes($name),
  423. [],
  424. $foreignKeys,
  425. $tableOptionsByTable[$normalizedName] ?? [],
  426. );
  427. }
  428. /**
  429. * An extension point for those platforms where case sensitivity of the object name depends on whether it's quoted.
  430. *
  431. * Such platforms should convert a possibly quoted name into a value of the corresponding case.
  432. */
  433. protected function normalizeName(string $name): string
  434. {
  435. $identifier = new Identifier($name);
  436. return $identifier->getName();
  437. }
  438. /**
  439. * Selects names of tables in the specified database.
  440. *
  441. * @throws Exception
  442. *
  443. * @abstract
  444. */
  445. protected function selectTableNames(string $databaseName): Result
  446. {
  447. throw Exception::notSupported(__METHOD__);
  448. }
  449. /**
  450. * Selects definitions of table columns in the specified database. If the table name is specified, narrows down
  451. * the selection to this table.
  452. *
  453. * @throws Exception
  454. *
  455. * @abstract
  456. */
  457. protected function selectTableColumns(string $databaseName, ?string $tableName = null): Result
  458. {
  459. throw Exception::notSupported(__METHOD__);
  460. }
  461. /**
  462. * Selects definitions of index columns in the specified database. If the table name is specified, narrows down
  463. * the selection to this table.
  464. *
  465. * @throws Exception
  466. */
  467. protected function selectIndexColumns(string $databaseName, ?string $tableName = null): Result
  468. {
  469. throw Exception::notSupported(__METHOD__);
  470. }
  471. /**
  472. * Selects definitions of foreign key columns in the specified database. If the table name is specified,
  473. * narrows down the selection to this table.
  474. *
  475. * @throws Exception
  476. */
  477. protected function selectForeignKeyColumns(string $databaseName, ?string $tableName = null): Result
  478. {
  479. throw Exception::notSupported(__METHOD__);
  480. }
  481. /**
  482. * Fetches definitions of table columns in the specified database and returns them grouped by table name.
  483. *
  484. * @return array<string,list<array<string,mixed>>>
  485. *
  486. * @throws Exception
  487. */
  488. protected function fetchTableColumnsByTable(string $databaseName): array
  489. {
  490. return $this->fetchAllAssociativeGrouped($this->selectTableColumns($databaseName));
  491. }
  492. /**
  493. * Fetches definitions of index columns in the specified database and returns them grouped by table name.
  494. *
  495. * @return array<string,list<array<string,mixed>>>
  496. *
  497. * @throws Exception
  498. */
  499. protected function fetchIndexColumnsByTable(string $databaseName): array
  500. {
  501. return $this->fetchAllAssociativeGrouped($this->selectIndexColumns($databaseName));
  502. }
  503. /**
  504. * Fetches definitions of foreign key columns in the specified database and returns them grouped by table name.
  505. *
  506. * @return array<string, list<array<string, mixed>>>
  507. *
  508. * @throws Exception
  509. */
  510. protected function fetchForeignKeyColumnsByTable(string $databaseName): array
  511. {
  512. if (! $this->_platform->supportsForeignKeyConstraints()) {
  513. return [];
  514. }
  515. return $this->fetchAllAssociativeGrouped(
  516. $this->selectForeignKeyColumns($databaseName),
  517. );
  518. }
  519. /**
  520. * Fetches table options for the tables in the specified database and returns them grouped by table name.
  521. * If the table name is specified, narrows down the selection to this table.
  522. *
  523. * @return array<string,array<string,mixed>>
  524. *
  525. * @throws Exception
  526. */
  527. protected function fetchTableOptionsByTable(string $databaseName, ?string $tableName = null): array
  528. {
  529. throw Exception::notSupported(__METHOD__);
  530. }
  531. /**
  532. * Introspects the table with the given name.
  533. *
  534. * @throws Exception
  535. */
  536. public function introspectTable(string $name): Table
  537. {
  538. $table = $this->listTableDetails($name);
  539. if ($table->getColumns() === []) {
  540. throw SchemaException::tableDoesNotExist($name);
  541. }
  542. return $table;
  543. }
  544. /**
  545. * Lists the views this connection has.
  546. *
  547. * @return View[]
  548. *
  549. * @throws Exception
  550. */
  551. public function listViews()
  552. {
  553. $database = $this->_conn->getDatabase();
  554. $sql = $this->_platform->getListViewsSQL($database);
  555. $views = $this->_conn->fetchAllAssociative($sql);
  556. return $this->_getPortableViewsList($views);
  557. }
  558. /**
  559. * Lists the foreign keys for the given table.
  560. *
  561. * @param string $table The name of the table.
  562. * @param string|null $database
  563. *
  564. * @return ForeignKeyConstraint[]
  565. *
  566. * @throws Exception
  567. */
  568. public function listTableForeignKeys($table, $database = null)
  569. {
  570. if ($database === null) {
  571. $database = $this->getDatabase(__METHOD__);
  572. } else {
  573. Deprecation::trigger(
  574. 'doctrine/dbal',
  575. 'https://github.com/doctrine/dbal/issues/5284',
  576. 'Passing $database to AbstractSchemaManager::listTableForeignKeys() is deprecated.',
  577. );
  578. }
  579. $sql = $this->_platform->getListTableForeignKeysSQL($table, $database);
  580. $tableForeignKeys = $this->_conn->fetchAllAssociative($sql);
  581. return $this->_getPortableTableForeignKeysList($tableForeignKeys);
  582. }
  583. /**
  584. * @param string $table
  585. * @param string|null $database
  586. *
  587. * @return ForeignKeyConstraint[]
  588. *
  589. * @throws Exception
  590. */
  591. protected function doListTableForeignKeys($table, $database = null): array
  592. {
  593. if ($database === null) {
  594. $database = $this->getDatabase(__METHOD__);
  595. } else {
  596. Deprecation::trigger(
  597. 'doctrine/dbal',
  598. 'https://github.com/doctrine/dbal/issues/5284',
  599. 'Passing $database to AbstractSchemaManager::listTableForeignKeys() is deprecated.',
  600. );
  601. }
  602. return $this->_getPortableTableForeignKeysList(
  603. $this->selectForeignKeyColumns(
  604. $database,
  605. $this->normalizeName($table),
  606. )->fetchAllAssociative(),
  607. );
  608. }
  609. /* drop*() Methods */
  610. /**
  611. * Drops a database.
  612. *
  613. * NOTE: You can not drop the database this SchemaManager is currently connected to.
  614. *
  615. * @param string $database The name of the database to drop.
  616. *
  617. * @return void
  618. *
  619. * @throws Exception
  620. */
  621. public function dropDatabase($database)
  622. {
  623. $this->_conn->executeStatement(
  624. $this->_platform->getDropDatabaseSQL($database),
  625. );
  626. }
  627. /**
  628. * Drops a schema.
  629. *
  630. * @throws Exception
  631. */
  632. public function dropSchema(string $schemaName): void
  633. {
  634. $this->_conn->executeStatement(
  635. $this->_platform->getDropSchemaSQL($schemaName),
  636. );
  637. }
  638. /**
  639. * Drops the given table.
  640. *
  641. * @param string $name The name of the table to drop.
  642. *
  643. * @return void
  644. *
  645. * @throws Exception
  646. */
  647. public function dropTable($name)
  648. {
  649. $this->_conn->executeStatement(
  650. $this->_platform->getDropTableSQL($name),
  651. );
  652. }
  653. /**
  654. * Drops the index from the given table.
  655. *
  656. * @param Index|string $index The name of the index.
  657. * @param Table|string $table The name of the table.
  658. *
  659. * @return void
  660. *
  661. * @throws Exception
  662. */
  663. public function dropIndex($index, $table)
  664. {
  665. if ($index instanceof Index) {
  666. Deprecation::trigger(
  667. 'doctrine/dbal',
  668. 'https://github.com/doctrine/dbal/issues/4798',
  669. 'Passing $index as an Index object to %s is deprecated. Pass it as a quoted name instead.',
  670. __METHOD__,
  671. );
  672. $index = $index->getQuotedName($this->_platform);
  673. }
  674. if ($table instanceof Table) {
  675. Deprecation::trigger(
  676. 'doctrine/dbal',
  677. 'https://github.com/doctrine/dbal/issues/4798',
  678. 'Passing $table as an Table object to %s is deprecated. Pass it as a quoted name instead.',
  679. __METHOD__,
  680. );
  681. $table = $table->getQuotedName($this->_platform);
  682. }
  683. $this->_conn->executeStatement(
  684. $this->_platform->getDropIndexSQL($index, $table),
  685. );
  686. }
  687. /**
  688. * Drops the constraint from the given table.
  689. *
  690. * @deprecated Use {@see dropIndex()}, {@see dropForeignKey()} or {@see dropUniqueConstraint()} instead.
  691. *
  692. * @param Table|string $table The name of the table.
  693. *
  694. * @return void
  695. *
  696. * @throws Exception
  697. */
  698. public function dropConstraint(Constraint $constraint, $table)
  699. {
  700. if ($table instanceof Table) {
  701. Deprecation::trigger(
  702. 'doctrine/dbal',
  703. 'https://github.com/doctrine/dbal/issues/4798',
  704. 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  705. __METHOD__,
  706. );
  707. $table = $table->getQuotedName($this->_platform);
  708. }
  709. $this->_conn->executeStatement($this->_platform->getDropConstraintSQL(
  710. $constraint->getQuotedName($this->_platform),
  711. $table,
  712. ));
  713. }
  714. /**
  715. * Drops a foreign key from a table.
  716. *
  717. * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key.
  718. * @param Table|string $table The name of the table with the foreign key.
  719. *
  720. * @return void
  721. *
  722. * @throws Exception
  723. */
  724. public function dropForeignKey($foreignKey, $table)
  725. {
  726. if ($foreignKey instanceof ForeignKeyConstraint) {
  727. Deprecation::trigger(
  728. 'doctrine/dbal',
  729. 'https://github.com/doctrine/dbal/issues/4798',
  730. 'Passing $foreignKey as a ForeignKeyConstraint object to %s is deprecated.'
  731. . ' Pass it as a quoted name instead.',
  732. __METHOD__,
  733. );
  734. $foreignKey = $foreignKey->getQuotedName($this->_platform);
  735. }
  736. if ($table instanceof Table) {
  737. Deprecation::trigger(
  738. 'doctrine/dbal',
  739. 'https://github.com/doctrine/dbal/issues/4798',
  740. 'Passing $table as a Table object to %s is deprecated. Pass it as a quoted name instead.',
  741. __METHOD__,
  742. );
  743. $table = $table->getQuotedName($this->_platform);
  744. }
  745. $this->_conn->executeStatement(
  746. $this->_platform->getDropForeignKeySQL($foreignKey, $table),
  747. );
  748. }
  749. /**
  750. * Drops a sequence with a given name.
  751. *
  752. * @param string $name The name of the sequence to drop.
  753. *
  754. * @return void
  755. *
  756. * @throws Exception
  757. */
  758. public function dropSequence($name)
  759. {
  760. $this->_conn->executeStatement(
  761. $this->_platform->getDropSequenceSQL($name),
  762. );
  763. }
  764. /**
  765. * Drops the unique constraint from the given table.
  766. *
  767. * @throws Exception
  768. */
  769. public function dropUniqueConstraint(string $name, string $tableName): void
  770. {
  771. $this->_conn->executeStatement(
  772. $this->_platform->getDropUniqueConstraintSQL($name, $tableName),
  773. );
  774. }
  775. /**
  776. * Drops a view.
  777. *
  778. * @param string $name The name of the view.
  779. *
  780. * @return void
  781. *
  782. * @throws Exception
  783. */
  784. public function dropView($name)
  785. {
  786. $this->_conn->executeStatement(
  787. $this->_platform->getDropViewSQL($name),
  788. );
  789. }
  790. /* create*() Methods */
  791. /** @throws Exception */
  792. public function createSchemaObjects(Schema $schema): void
  793. {
  794. $this->_execSql($schema->toSql($this->_platform));
  795. }
  796. /**
  797. * Creates a new database.
  798. *
  799. * @param string $database The name of the database to create.
  800. *
  801. * @return void
  802. *
  803. * @throws Exception
  804. */
  805. public function createDatabase($database)
  806. {
  807. $this->_conn->executeStatement(
  808. $this->_platform->getCreateDatabaseSQL($database),
  809. );
  810. }
  811. /**
  812. * Creates a new table.
  813. *
  814. * @return void
  815. *
  816. * @throws Exception
  817. */
  818. public function createTable(Table $table)
  819. {
  820. $createFlags = AbstractPlatform::CREATE_INDEXES | AbstractPlatform::CREATE_FOREIGNKEYS;
  821. $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
  822. }
  823. /**
  824. * Creates a new sequence.
  825. *
  826. * @param Sequence $sequence
  827. *
  828. * @return void
  829. *
  830. * @throws Exception
  831. */
  832. public function createSequence($sequence)
  833. {
  834. $this->_conn->executeStatement(
  835. $this->_platform->getCreateSequenceSQL($sequence),
  836. );
  837. }
  838. /**
  839. * Creates a constraint on a table.
  840. *
  841. * @deprecated Use {@see createIndex()}, {@see createForeignKey()} or {@see createUniqueConstraint()} instead.
  842. *
  843. * @param Table|string $table
  844. *
  845. * @return void
  846. *
  847. * @throws Exception
  848. */
  849. public function createConstraint(Constraint $constraint, $table)
  850. {
  851. $this->_conn->executeStatement(
  852. $this->_platform->getCreateConstraintSQL($constraint, $table),
  853. );
  854. }
  855. /**
  856. * Creates a new index on a table.
  857. *
  858. * @param Table|string $table The name of the table on which the index is to be created.
  859. *
  860. * @return void
  861. *
  862. * @throws Exception
  863. */
  864. public function createIndex(Index $index, $table)
  865. {
  866. $this->_conn->executeStatement(
  867. $this->_platform->getCreateIndexSQL($index, $table),
  868. );
  869. }
  870. /**
  871. * Creates a new foreign key.
  872. *
  873. * @param ForeignKeyConstraint $foreignKey The ForeignKey instance.
  874. * @param Table|string $table The name of the table on which the foreign key is to be created.
  875. *
  876. * @return void
  877. *
  878. * @throws Exception
  879. */
  880. public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
  881. {
  882. $this->_conn->executeStatement(
  883. $this->_platform->getCreateForeignKeySQL($foreignKey, $table),
  884. );
  885. }
  886. /**
  887. * Creates a unique constraint on a table.
  888. *
  889. * @throws Exception
  890. */
  891. public function createUniqueConstraint(UniqueConstraint $uniqueConstraint, string $tableName): void
  892. {
  893. $this->_conn->executeStatement(
  894. $this->_platform->getCreateUniqueConstraintSQL($uniqueConstraint, $tableName),
  895. );
  896. }
  897. /**
  898. * Creates a new view.
  899. *
  900. * @return void
  901. *
  902. * @throws Exception
  903. */
  904. public function createView(View $view)
  905. {
  906. $this->_conn->executeStatement(
  907. $this->_platform->getCreateViewSQL(
  908. $view->getQuotedName($this->_platform),
  909. $view->getSql(),
  910. ),
  911. );
  912. }
  913. /* dropAndCreate*() Methods */
  914. /** @throws Exception */
  915. public function dropSchemaObjects(Schema $schema): void
  916. {
  917. $this->_execSql($schema->toDropSql($this->_platform));
  918. }
  919. /**
  920. * Drops and creates a constraint.
  921. *
  922. * @deprecated Use {@see dropIndex()} and {@see createIndex()},
  923. * {@see dropForeignKey()} and {@see createForeignKey()}
  924. * or {@see dropUniqueConstraint()} and {@see createUniqueConstraint()} instead.
  925. *
  926. * @see dropConstraint()
  927. * @see createConstraint()
  928. *
  929. * @param Table|string $table
  930. *
  931. * @return void
  932. *
  933. * @throws Exception
  934. */
  935. public function dropAndCreateConstraint(Constraint $constraint, $table)
  936. {
  937. Deprecation::trigger(
  938. 'doctrine/dbal',
  939. 'https://github.com/doctrine/dbal/pull/4897',
  940. 'AbstractSchemaManager::dropAndCreateConstraint() is deprecated.'
  941. . ' Use AbstractSchemaManager::dropIndex() and AbstractSchemaManager::createIndex(),'
  942. . ' AbstractSchemaManager::dropForeignKey() and AbstractSchemaManager::createForeignKey()'
  943. . ' or AbstractSchemaManager::dropUniqueConstraint()'
  944. . ' and AbstractSchemaManager::createUniqueConstraint() instead.',
  945. );
  946. $this->tryMethod('dropConstraint', $constraint, $table);
  947. $this->createConstraint($constraint, $table);
  948. }
  949. /**
  950. * Drops and creates a new index on a table.
  951. *
  952. * @deprecated Use {@see dropIndex()} and {@see createIndex()} instead.
  953. *
  954. * @param Table|string $table The name of the table on which the index is to be created.
  955. *
  956. * @return void
  957. *
  958. * @throws Exception
  959. */
  960. public function dropAndCreateIndex(Index $index, $table)
  961. {
  962. Deprecation::trigger(
  963. 'doctrine/dbal',
  964. 'https://github.com/doctrine/dbal/pull/4897',
  965. 'AbstractSchemaManager::dropAndCreateIndex() is deprecated.'
  966. . ' Use AbstractSchemaManager::dropIndex() and AbstractSchemaManager::createIndex() instead.',
  967. );
  968. $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
  969. $this->createIndex($index, $table);
  970. }
  971. /**
  972. * Drops and creates a new foreign key.
  973. *
  974. * @deprecated Use {@see dropForeignKey()} and {@see createForeignKey()} instead.
  975. *
  976. * @param ForeignKeyConstraint $foreignKey An associative array that defines properties
  977. * of the foreign key to be created.
  978. * @param Table|string $table The name of the table on which the foreign key is to be created.
  979. *
  980. * @return void
  981. *
  982. * @throws Exception
  983. */
  984. public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
  985. {
  986. Deprecation::trigger(
  987. 'doctrine/dbal',
  988. 'https://github.com/doctrine/dbal/pull/4897',
  989. 'AbstractSchemaManager::dropAndCreateForeignKey() is deprecated.'
  990. . ' Use AbstractSchemaManager::dropForeignKey() and AbstractSchemaManager::createForeignKey() instead.',
  991. );
  992. $this->tryMethod('dropForeignKey', $foreignKey, $table);
  993. $this->createForeignKey($foreignKey, $table);
  994. }
  995. /**
  996. * Drops and create a new sequence.
  997. *
  998. * @deprecated Use {@see dropSequence()} and {@see createSequence()} instead.
  999. *
  1000. * @return void
  1001. *
  1002. * @throws Exception
  1003. */
  1004. public function dropAndCreateSequence(Sequence $sequence)
  1005. {
  1006. Deprecation::trigger(
  1007. 'doctrine/dbal',
  1008. 'https://github.com/doctrine/dbal/pull/4897',
  1009. 'AbstractSchemaManager::dropAndCreateSequence() is deprecated.'
  1010. . ' Use AbstractSchemaManager::dropSequence() and AbstractSchemaManager::createSequence() instead.',
  1011. );
  1012. $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
  1013. $this->createSequence($sequence);
  1014. }
  1015. /**
  1016. * Drops and creates a new table.
  1017. *
  1018. * @deprecated Use {@see dropTable()} and {@see createTable()} instead.
  1019. *
  1020. * @return void
  1021. *
  1022. * @throws Exception
  1023. */
  1024. public function dropAndCreateTable(Table $table)
  1025. {
  1026. Deprecation::trigger(
  1027. 'doctrine/dbal',
  1028. 'https://github.com/doctrine/dbal/pull/4897',
  1029. 'AbstractSchemaManager::dropAndCreateTable() is deprecated.'
  1030. . ' Use AbstractSchemaManager::dropTable() and AbstractSchemaManager::createTable() instead.',
  1031. );
  1032. $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
  1033. $this->createTable($table);
  1034. }
  1035. /**
  1036. * Drops and creates a new database.
  1037. *
  1038. * @deprecated Use {@see dropDatabase()} and {@see createDatabase()} instead.
  1039. *
  1040. * @param string $database The name of the database to create.
  1041. *
  1042. * @return void
  1043. *
  1044. * @throws Exception
  1045. */
  1046. public function dropAndCreateDatabase($database)
  1047. {
  1048. Deprecation::trigger(
  1049. 'doctrine/dbal',
  1050. 'https://github.com/doctrine/dbal/pull/4897',
  1051. 'AbstractSchemaManager::dropAndCreateDatabase() is deprecated.'
  1052. . ' Use AbstractSchemaManager::dropDatabase() and AbstractSchemaManager::createDatabase() instead.',
  1053. );
  1054. $this->tryMethod('dropDatabase', $database);
  1055. $this->createDatabase($database);
  1056. }
  1057. /**
  1058. * Drops and creates a new view.
  1059. *
  1060. * @deprecated Use {@see dropView()} and {@see createView()} instead.
  1061. *
  1062. * @return void
  1063. *
  1064. * @throws Exception
  1065. */
  1066. public function dropAndCreateView(View $view)
  1067. {
  1068. Deprecation::trigger(
  1069. 'doctrine/dbal',
  1070. 'https://github.com/doctrine/dbal/pull/4897',
  1071. 'AbstractSchemaManager::dropAndCreateView() is deprecated.'
  1072. . ' Use AbstractSchemaManager::dropView() and AbstractSchemaManager::createView() instead.',
  1073. );
  1074. $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
  1075. $this->createView($view);
  1076. }
  1077. /**
  1078. * Alters an existing schema.
  1079. *
  1080. * @throws Exception
  1081. */
  1082. public function alterSchema(SchemaDiff $schemaDiff): void
  1083. {
  1084. $this->_execSql($this->_platform->getAlterSchemaSQL($schemaDiff));
  1085. }
  1086. /**
  1087. * Migrates an existing schema to a new schema.
  1088. *
  1089. * @throws Exception
  1090. */
  1091. public function migrateSchema(Schema $toSchema): void
  1092. {
  1093. $schemaDiff = $this->createComparator()
  1094. ->compareSchemas($this->introspectSchema(), $toSchema);
  1095. $this->alterSchema($schemaDiff);
  1096. }
  1097. /* alterTable() Methods */
  1098. /**
  1099. * Alters an existing tables schema.
  1100. *
  1101. * @return void
  1102. *
  1103. * @throws Exception
  1104. */
  1105. public function alterTable(TableDiff $tableDiff)
  1106. {
  1107. $this->_execSql($this->_platform->getAlterTableSQL($tableDiff));
  1108. }
  1109. /**
  1110. * Renames a given table to another name.
  1111. *
  1112. * @param string $name The current name of the table.
  1113. * @param string $newName The new name of the table.
  1114. *
  1115. * @return void
  1116. *
  1117. * @throws Exception
  1118. */
  1119. public function renameTable($name, $newName)
  1120. {
  1121. $this->_execSql($this->_platform->getRenameTableSQL($name, $newName));
  1122. }
  1123. /**
  1124. * Methods for filtering return values of list*() methods to convert
  1125. * the native DBMS data definition to a portable Doctrine definition
  1126. */
  1127. /**
  1128. * @param mixed[] $databases
  1129. *
  1130. * @return string[]
  1131. */
  1132. protected function _getPortableDatabasesList($databases)
  1133. {
  1134. $list = [];
  1135. foreach ($databases as $value) {
  1136. $list[] = $this->_getPortableDatabaseDefinition($value);
  1137. }
  1138. return $list;
  1139. }
  1140. /**
  1141. * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
  1142. *
  1143. * @deprecated Use {@see listSchemaNames()} instead.
  1144. *
  1145. * @param array<int, array<string, mixed>> $namespaces The list of namespace names
  1146. * in the native DBMS data definition.
  1147. *
  1148. * @return string[]
  1149. */
  1150. protected function getPortableNamespacesList(array $namespaces)
  1151. {
  1152. Deprecation::triggerIfCalledFromOutside(
  1153. 'doctrine/dbal',
  1154. 'https://github.com/doctrine/dbal/issues/4503',
  1155. 'AbstractSchemaManager::getPortableNamespacesList() is deprecated,'
  1156. . ' use AbstractSchemaManager::listSchemaNames() instead.',
  1157. );
  1158. $namespacesList = [];
  1159. foreach ($namespaces as $namespace) {
  1160. $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
  1161. }
  1162. return $namespacesList;
  1163. }
  1164. /**
  1165. * @param mixed $database
  1166. *
  1167. * @return mixed
  1168. */
  1169. protected function _getPortableDatabaseDefinition($database)
  1170. {
  1171. return $database;
  1172. }
  1173. /**
  1174. * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
  1175. *
  1176. * @deprecated Use {@see listSchemaNames()} instead.
  1177. *
  1178. * @param array<string, mixed> $namespace The native DBMS namespace definition.
  1179. *
  1180. * @return mixed
  1181. */
  1182. protected function getPortableNamespaceDefinition(array $namespace)
  1183. {
  1184. Deprecation::triggerIfCalledFromOutside(
  1185. 'doctrine/dbal',
  1186. 'https://github.com/doctrine/dbal/issues/4503',
  1187. 'AbstractSchemaManager::getPortableNamespaceDefinition() is deprecated,'
  1188. . ' use AbstractSchemaManager::listSchemaNames() instead.',
  1189. );
  1190. return $namespace;
  1191. }
  1192. /**
  1193. * @param mixed[][] $sequences
  1194. *
  1195. * @return Sequence[]
  1196. *
  1197. * @throws Exception
  1198. */
  1199. protected function _getPortableSequencesList($sequences)
  1200. {
  1201. $list = [];
  1202. foreach ($sequences as $value) {
  1203. $list[] = $this->_getPortableSequenceDefinition($value);
  1204. }
  1205. return $list;
  1206. }
  1207. /**
  1208. * @param mixed[] $sequence
  1209. *
  1210. * @return Sequence
  1211. *
  1212. * @throws Exception
  1213. */
  1214. protected function _getPortableSequenceDefinition($sequence)
  1215. {
  1216. throw Exception::notSupported('Sequences');
  1217. }
  1218. /**
  1219. * Independent of the database the keys of the column list result are lowercased.
  1220. *
  1221. * The name of the created column instance however is kept in its case.
  1222. *
  1223. * @param string $table The name of the table.
  1224. * @param string $database
  1225. * @param mixed[][] $tableColumns
  1226. *
  1227. * @return Column[]
  1228. *
  1229. * @throws Exception
  1230. */
  1231. protected function _getPortableTableColumnList($table, $database, $tableColumns)
  1232. {
  1233. $eventManager = $this->_platform->getEventManager();
  1234. $list = [];
  1235. foreach ($tableColumns as $tableColumn) {
  1236. $column = null;
  1237. $defaultPrevented = false;
  1238. if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
  1239. Deprecation::trigger(
  1240. 'doctrine/dbal',
  1241. 'https://github.com/doctrine/dbal/issues/5784',
  1242. 'Subscribing to %s events is deprecated. Use a custom schema manager instead.',
  1243. Events::onSchemaColumnDefinition,
  1244. );
  1245. $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
  1246. $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
  1247. $defaultPrevented = $eventArgs->isDefaultPrevented();
  1248. $column = $eventArgs->getColumn();
  1249. }
  1250. if (! $defaultPrevented) {
  1251. $column = $this->_getPortableTableColumnDefinition($tableColumn);
  1252. }
  1253. if ($column === null) {
  1254. continue;
  1255. }
  1256. $name = strtolower($column->getQuotedName($this->_platform));
  1257. $list[$name] = $column;
  1258. }
  1259. return $list;
  1260. }
  1261. /**
  1262. * Gets Table Column Definition.
  1263. *
  1264. * @param mixed[] $tableColumn
  1265. *
  1266. * @return Column
  1267. *
  1268. * @throws Exception
  1269. */
  1270. abstract protected function _getPortableTableColumnDefinition($tableColumn);
  1271. /**
  1272. * Aggregates and groups the index results according to the required data result.
  1273. *
  1274. * @param mixed[][] $tableIndexes
  1275. * @param string|null $tableName
  1276. *
  1277. * @return Index[]
  1278. *
  1279. * @throws Exception
  1280. */
  1281. protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
  1282. {
  1283. $result = [];
  1284. foreach ($tableIndexes as $tableIndex) {
  1285. $indexName = $keyName = $tableIndex['key_name'];
  1286. if ($tableIndex['primary']) {
  1287. $keyName = 'primary';
  1288. }
  1289. $keyName = strtolower($keyName);
  1290. if (! isset($result[$keyName])) {
  1291. $options = [
  1292. 'lengths' => [],
  1293. ];
  1294. if (isset($tableIndex['where'])) {
  1295. $options['where'] = $tableIndex['where'];
  1296. }
  1297. $result[$keyName] = [
  1298. 'name' => $indexName,
  1299. 'columns' => [],
  1300. 'unique' => ! $tableIndex['non_unique'],
  1301. 'primary' => $tableIndex['primary'],
  1302. 'flags' => $tableIndex['flags'] ?? [],
  1303. 'options' => $options,
  1304. ];
  1305. }
  1306. $result[$keyName]['columns'][] = $tableIndex['column_name'];
  1307. $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null;
  1308. }
  1309. $eventManager = $this->_platform->getEventManager();
  1310. $indexes = [];
  1311. foreach ($result as $indexKey => $data) {
  1312. $index = null;
  1313. $defaultPrevented = false;
  1314. if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
  1315. Deprecation::trigger(
  1316. 'doctrine/dbal',
  1317. 'https://github.com/doctrine/dbal/issues/5784',
  1318. 'Subscribing to %s events is deprecated. Use a custom schema manager instead.',
  1319. Events::onSchemaColumnDefinition,
  1320. );
  1321. $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
  1322. $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
  1323. $defaultPrevented = $eventArgs->isDefaultPrevented();
  1324. $index = $eventArgs->getIndex();
  1325. }
  1326. if (! $defaultPrevented) {
  1327. $index = new Index(
  1328. $data['name'],
  1329. $data['columns'],
  1330. $data['unique'],
  1331. $data['primary'],
  1332. $data['flags'],
  1333. $data['options'],
  1334. );
  1335. }
  1336. if ($index === null) {
  1337. continue;
  1338. }
  1339. $indexes[$indexKey] = $index;
  1340. }
  1341. return $indexes;
  1342. }
  1343. /**
  1344. * @param mixed[][] $tables
  1345. *
  1346. * @return string[]
  1347. */
  1348. protected function _getPortableTablesList($tables)
  1349. {
  1350. $list = [];
  1351. foreach ($tables as $value) {
  1352. $list[] = $this->_getPortableTableDefinition($value);
  1353. }
  1354. return $list;
  1355. }
  1356. /**
  1357. * @param mixed $table
  1358. *
  1359. * @return string
  1360. */
  1361. protected function _getPortableTableDefinition($table)
  1362. {
  1363. return $table;
  1364. }
  1365. /**
  1366. * @param mixed[][] $views
  1367. *
  1368. * @return View[]
  1369. */
  1370. protected function _getPortableViewsList($views)
  1371. {
  1372. $list = [];
  1373. foreach ($views as $value) {
  1374. $view = $this->_getPortableViewDefinition($value);
  1375. if ($view === false) {
  1376. continue;
  1377. }
  1378. $viewName = strtolower($view->getQuotedName($this->_platform));
  1379. $list[$viewName] = $view;
  1380. }
  1381. return $list;
  1382. }
  1383. /**
  1384. * @param mixed[] $view
  1385. *
  1386. * @return View|false
  1387. */
  1388. protected function _getPortableViewDefinition($view)
  1389. {
  1390. return false;
  1391. }
  1392. /**
  1393. * @param mixed[][] $tableForeignKeys
  1394. *
  1395. * @return ForeignKeyConstraint[]
  1396. */
  1397. protected function _getPortableTableForeignKeysList($tableForeignKeys)
  1398. {
  1399. $list = [];
  1400. foreach ($tableForeignKeys as $value) {
  1401. $list[] = $this->_getPortableTableForeignKeyDefinition($value);
  1402. }
  1403. return $list;
  1404. }
  1405. /**
  1406. * @param mixed $tableForeignKey
  1407. *
  1408. * @return ForeignKeyConstraint
  1409. *
  1410. * @abstract
  1411. */
  1412. protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
  1413. {
  1414. return $tableForeignKey;
  1415. }
  1416. /**
  1417. * @internal
  1418. *
  1419. * @param string[]|string $sql
  1420. *
  1421. * @return void
  1422. *
  1423. * @throws Exception
  1424. */
  1425. protected function _execSql($sql)
  1426. {
  1427. foreach ((array) $sql as $query) {
  1428. $this->_conn->executeStatement($query);
  1429. }
  1430. }
  1431. /**
  1432. * Creates a schema instance for the current database.
  1433. *
  1434. * @deprecated Use {@link introspectSchema()} instead.
  1435. *
  1436. * @return Schema
  1437. *
  1438. * @throws Exception
  1439. */
  1440. public function createSchema()
  1441. {
  1442. Deprecation::triggerIfCalledFromOutside(
  1443. 'doctrine/dbal',
  1444. 'https://github.com/doctrine/dbal/pull/5613',
  1445. '%s is deprecated. Use introspectSchema() instead.',
  1446. __METHOD__,
  1447. );
  1448. $schemaNames = [];
  1449. if ($this->_platform->supportsSchemas()) {
  1450. $schemaNames = $this->listNamespaceNames();
  1451. }
  1452. $sequences = [];
  1453. if ($this->_platform->supportsSequences()) {
  1454. $sequences = $this->listSequences();
  1455. }
  1456. $tables = $this->listTables();
  1457. return new Schema($tables, $sequences, $this->createSchemaConfig(), $schemaNames);
  1458. }
  1459. /**
  1460. * Returns a {@see Schema} instance representing the current database schema.
  1461. *
  1462. * @throws Exception
  1463. */
  1464. public function introspectSchema(): Schema
  1465. {
  1466. return $this->createSchema();
  1467. }
  1468. /**
  1469. * Creates the configuration for this schema.
  1470. *
  1471. * @return SchemaConfig
  1472. *
  1473. * @throws Exception
  1474. */
  1475. public function createSchemaConfig()
  1476. {
  1477. $schemaConfig = new SchemaConfig();
  1478. $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
  1479. $searchPaths = $this->getSchemaSearchPaths();
  1480. if (isset($searchPaths[0])) {
  1481. $schemaConfig->setName($searchPaths[0]);
  1482. }
  1483. $params = $this->_conn->getParams();
  1484. if (! isset($params['defaultTableOptions'])) {
  1485. $params['defaultTableOptions'] = [];
  1486. }
  1487. if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
  1488. $params['defaultTableOptions']['charset'] = $params['charset'];
  1489. }
  1490. $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
  1491. return $schemaConfig;
  1492. }
  1493. /**
  1494. * The search path for namespaces in the currently connected database.
  1495. *
  1496. * The first entry is usually the default namespace in the Schema. All
  1497. * further namespaces contain tables/sequences which can also be addressed
  1498. * with a short, not full-qualified name.
  1499. *
  1500. * For databases that don't support subschema/namespaces this method
  1501. * returns the name of the currently connected database.
  1502. *
  1503. * @deprecated
  1504. *
  1505. * @return string[]
  1506. *
  1507. * @throws Exception
  1508. */
  1509. public function getSchemaSearchPaths()
  1510. {
  1511. Deprecation::triggerIfCalledFromOutside(
  1512. 'doctrine/dbal',
  1513. 'https://github.com/doctrine/dbal/pull/4821',
  1514. 'AbstractSchemaManager::getSchemaSearchPaths() is deprecated.',
  1515. );
  1516. $database = $this->_conn->getDatabase();
  1517. if ($database !== null) {
  1518. return [$database];
  1519. }
  1520. return [];
  1521. }
  1522. /**
  1523. * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns
  1524. * the type given as default.
  1525. *
  1526. * @internal This method should be only used from within the AbstractSchemaManager class hierarchy.
  1527. *
  1528. * @param string|null $comment
  1529. * @param string $currentType
  1530. *
  1531. * @return string
  1532. */
  1533. public function extractDoctrineTypeFromComment($comment, $currentType)
  1534. {
  1535. if ($this->_conn->getConfiguration()->getDisableTypeComments()) {
  1536. return $currentType;
  1537. }
  1538. if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match) === 1) {
  1539. return $match[1];
  1540. }
  1541. return $currentType;
  1542. }
  1543. /**
  1544. * @internal This method should be only used from within the AbstractSchemaManager class hierarchy.
  1545. *
  1546. * @param string|null $comment
  1547. * @param string|null $type
  1548. *
  1549. * @return string|null
  1550. */
  1551. public function removeDoctrineTypeFromComment($comment, $type)
  1552. {
  1553. if ($this->_conn->getConfiguration()->getDisableTypeComments()) {
  1554. return $comment;
  1555. }
  1556. if ($comment === null) {
  1557. return null;
  1558. }
  1559. return str_replace('(DC2Type:' . $type . ')', '', $comment);
  1560. }
  1561. /** @throws Exception */
  1562. private function getDatabase(string $methodName): string
  1563. {
  1564. $database = $this->_conn->getDatabase();
  1565. if ($database === null) {
  1566. throw DatabaseRequired::new($methodName);
  1567. }
  1568. return $database;
  1569. }
  1570. public function createComparator(): Comparator
  1571. {
  1572. return new Comparator($this->_platform);
  1573. }
  1574. /**
  1575. * @return array<string,list<array<string,mixed>>>
  1576. *
  1577. * @throws Exception
  1578. */
  1579. private function fetchAllAssociativeGrouped(Result $result): array
  1580. {
  1581. $data = [];
  1582. foreach ($result->fetchAllAssociative() as $row) {
  1583. $tableName = $this->_getPortableTableDefinition($row);
  1584. $data[$tableName][] = $row;
  1585. }
  1586. return $data;
  1587. }
  1588. }