AbstractSchemaManager.php 30 KB

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