PageRenderTime 22ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/concrete/src/Updater/Migrations/AbstractMigration.php

http://github.com/concrete5/concrete5
PHP | 243 lines | 151 code | 25 blank | 67 comment | 10 complexity | e4f6314a4f26afd59f41d3fd3e0939e9 MD5 | raw file
Possible License(s): MIT, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. <?php
  2. namespace Concrete\Core\Updater\Migrations;
  3. use Concrete\Core\Attribute\Category\PageCategory;
  4. use Concrete\Core\Block\BlockType\BlockType;
  5. use Concrete\Core\Database\DatabaseStructureManager;
  6. use Concrete\Core\Page\Page;
  7. use Concrete\Core\Page\Single as SinglePage;
  8. use Concrete\Core\Support\Facade\Application;
  9. use Concrete\Core\Support\Facade\Facade;
  10. use Doctrine\DBAL\Migrations\AbstractMigration as DoctrineAbstractMigration;
  11. use Doctrine\DBAL\Migrations\Version;
  12. use Doctrine\DBAL\Schema\Schema;
  13. use Doctrine\ORM\Tools\SchemaTool;
  14. /**
  15. * @property \Concrete\Core\Database\Connection\Connection $connection
  16. */
  17. abstract class AbstractMigration extends DoctrineAbstractMigration
  18. {
  19. protected $app;
  20. protected $validAttributes = [];
  21. public function __construct(Version $version)
  22. {
  23. parent::__construct($version);
  24. $app = Facade::getFacadeApplication();
  25. $this->app = $app;
  26. }
  27. /**
  28. * Override this method when the database structure is upgraded using ONLY the DBAL Schema object.
  29. *
  30. * @param Schema $schema
  31. */
  32. public function upgradeSchema(Schema $schema)
  33. {
  34. }
  35. /**
  36. * Override this method when database schema is not upgraded, or when it's upgraded without using a Schema.
  37. *
  38. * @param Schema $schema
  39. */
  40. public function upgradeDatabase()
  41. {
  42. }
  43. /**
  44. * Override this method when the database structure is downgraded using ONLY the DBAL Schema object.
  45. *
  46. * @param Schema $schema
  47. */
  48. public function downgradeSchema(Schema $schema)
  49. {
  50. }
  51. /**
  52. * Override this method when database schema is not downgraded, or when it's downgraded without using a Schema.
  53. */
  54. public function downgradeDatabase()
  55. {
  56. }
  57. /**
  58. * {@inheritdoc}
  59. *
  60. * @see \Doctrine\DBAL\Migrations\AbstractMigration::up()
  61. */
  62. final public function up(Schema $schema)
  63. {
  64. $this->upgradeSchema($schema);
  65. }
  66. /**
  67. * {@inheritdoc}
  68. *
  69. * @see \Doctrine\DBAL\Migrations\AbstractMigration::postUp()
  70. */
  71. final public function postUp(Schema $schema)
  72. {
  73. $this->upgradeDatabase();
  74. }
  75. /**
  76. * {@inheritdoc}
  77. *
  78. * @see \Doctrine\DBAL\Migrations\AbstractMigration::down()
  79. */
  80. final public function down(Schema $schema)
  81. {
  82. $this->downgradeSchema($schema);
  83. }
  84. /**
  85. * {@inheritdoc}
  86. *
  87. * @see \Doctrine\DBAL\Migrations\AbstractMigration::postDown()
  88. */
  89. final public function postDown(Schema $schema)
  90. {
  91. $this->downgradeDatabase();
  92. }
  93. protected function output($message)
  94. {
  95. $this->version->getConfiguration()->getOutputWriter()->write($message);
  96. }
  97. protected function refreshEntities($entities = null)
  98. {
  99. $em = $this->connection->getEntityManager();
  100. $sm = new DatabaseStructureManager($em);
  101. $sm->clearCacheAndProxies();
  102. $classes = [];
  103. $tool = new SchemaTool($em);
  104. foreach ($entities as $entity) {
  105. $this->output(t('Refreshing schema for %s...', $entity));
  106. $classes[] = $em->getClassMetadata($entity);
  107. }
  108. $tool->updateSchema($classes, true);
  109. }
  110. protected function refreshDatabaseTables($tables)
  111. {
  112. $this->output(t('Updating database tables found in doctrine xml...'));
  113. \Concrete\Core\Database\Schema\Schema::refreshCoreXMLSchema($tables);
  114. }
  115. protected function refreshBlockType($btHandle)
  116. {
  117. $this->output(t('Refreshing block type %s', $btHandle));
  118. $bt = BlockType::getByHandle($btHandle);
  119. if (is_object($bt)) {
  120. $bt->refresh();
  121. }
  122. }
  123. /**
  124. * Set to NULL the fields in a table that reference not existing values of another table.
  125. *
  126. * @param string $table The table containing the problematic field
  127. * @param string $field The problematic field
  128. * @param string $linkedTable The referenced table
  129. * @param string $linkedField The referenced field
  130. */
  131. protected function nullifyInvalidForeignKey($table, $field, $linkedTable, $linkedField)
  132. {
  133. $platform = $this->connection->getDatabasePlatform();
  134. $sqlTable = $platform->quoteSingleIdentifier($table);
  135. $sqlField = $platform->quoteSingleIdentifier($field);
  136. $sqlLinkedTable = $platform->quoteSingleIdentifier($linkedTable);
  137. $sqlLinkedField = $platform->quoteSingleIdentifier($linkedField);
  138. $this->connection->executeQuery("
  139. update {$sqlTable}
  140. left join {$sqlLinkedTable} on {$sqlTable}.{$sqlField} = {$sqlLinkedTable}.{$sqlLinkedField}
  141. set {$sqlTable}.{$sqlField} = null
  142. where {$sqlLinkedTable}.{$sqlLinkedField} is null
  143. ");
  144. }
  145. /**
  146. * Delete the records in a table whose field references not existing values of another table.
  147. *
  148. * @param string $table The table containing the problematic field
  149. * @param string $field The problematic field
  150. * @param string $linkedTable The referenced table
  151. * @param string $linkedField The referenced field
  152. */
  153. protected function deleteInvalidForeignKey($table, $field, $linkedTable, $linkedField)
  154. {
  155. $platform = $this->connection->getDatabasePlatform();
  156. $sqlTable = $platform->quoteSingleIdentifier($table);
  157. $sqlField = $platform->quoteSingleIdentifier($field);
  158. $sqlLinkedTable = $platform->quoteSingleIdentifier($linkedTable);
  159. $sqlLinkedField = $platform->quoteSingleIdentifier($linkedField);
  160. $this->connection->executeQuery("
  161. delete {$sqlTable}
  162. from {$sqlTable}
  163. left join {$sqlLinkedTable} on {$sqlTable}.{$sqlField} = {$sqlLinkedTable}.{$sqlLinkedField}
  164. where {$sqlLinkedTable}.{$sqlLinkedField} is null
  165. ");
  166. }
  167. protected function isAttributeHandleValid($categoryClass, $handle)
  168. {
  169. if (!isset($this->validAttributes[$categoryClass])) {
  170. $this->validAttributes[$categoryClass] = [];
  171. }
  172. if (!isset($this->validAttributes[$categoryClass][$handle])) {
  173. $app = Application::getFacadeApplication();
  174. $category = $app->make($categoryClass);
  175. $this->validAttributes[$categoryClass][$handle] = $category->getAttributeKeyByHandle($handle) ? true : false;
  176. }
  177. return $this->validAttributes[$categoryClass][$handle];
  178. }
  179. /**
  180. * Create a new SinglePage (if it does not exist).
  181. *
  182. * @param string $path the single page path
  183. * @param string $name the single page name
  184. * @param array $attributes the attribute values (keys are the attribute handles, values are the attribute values)
  185. *
  186. * @return \Concrete\Core\Page\Page
  187. */
  188. protected function createSinglePage($path, $name = '', array $attributes = [])
  189. {
  190. $sp = Page::getByPath($path);
  191. if (!is_object($sp) || $sp->isError()) {
  192. $this->output(t('Creating single page at %s...', $path));
  193. $sp = SinglePage::add($path);
  194. $update = [];
  195. $name = (string) $name;
  196. if ($name !== '') {
  197. $update['cName'] = $name;
  198. }
  199. if (array_key_exists('cDescription', $attributes)) {
  200. $description = (string) $attributes['cDescription'];
  201. unset($attributes['cDescription']);
  202. if ($description !== '') {
  203. $update['cDescription'] = $description;
  204. }
  205. }
  206. if (count($update) > 0) {
  207. $sp->update($update);
  208. }
  209. foreach ($attributes as $attributeHandle => $attributeValue) {
  210. if ($this->isAttributeHandleValid(PageCategory::class, $attributeHandle)) {
  211. $sp->setAttribute($attributeHandle, $attributeValue);
  212. }
  213. }
  214. }
  215. return $sp;
  216. }
  217. }