1<?php 2 3declare(strict_types=1); 4 5/* 6 * This file is part of the TYPO3 CMS project. 7 * 8 * It is free software; you can redistribute it and/or modify it under 9 * the terms of the GNU General Public License, either version 2 10 * of the License, or any later version. 11 * 12 * For the full copyright and license information, please read the 13 * LICENSE.txt file that was distributed with this source code. 14 * 15 * The TYPO3 project - inspiring people to share! 16 */ 17 18namespace TYPO3\CMS\Core\Database\Schema; 19 20use Doctrine\DBAL\Platforms\AbstractPlatform; 21use Doctrine\DBAL\Platforms\MySqlPlatform; 22use Doctrine\DBAL\Schema\Column; 23use Doctrine\DBAL\Schema\Table; 24use Doctrine\DBAL\Types\BlobType; 25use Doctrine\DBAL\Types\TextType; 26use TYPO3\CMS\Core\Utility\ArrayUtility; 27use TYPO3\CMS\Core\Utility\GeneralUtility; 28 29/** 30 * Compares two Schemas and returns an instance of SchemaDiff. 31 * 32 * @internal 33 */ 34class Comparator extends \Doctrine\DBAL\Schema\Comparator 35{ 36 /** 37 * @var AbstractPlatform|null 38 */ 39 protected $databasePlatform; 40 41 /** 42 * Comparator constructor. 43 * 44 * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform 45 */ 46 public function __construct(AbstractPlatform $platform = null) 47 { 48 $this->databasePlatform = $platform; 49 } 50 51 /** 52 * Returns the difference between the tables $fromTable and $toTable. 53 * 54 * If there are no differences this method returns the boolean false. 55 * 56 * @param \Doctrine\DBAL\Schema\Table $fromTable 57 * @param \Doctrine\DBAL\Schema\Table $toTable 58 * @return false|\Doctrine\DBAL\Schema\TableDiff|\TYPO3\CMS\Core\Database\Schema\TableDiff 59 * @throws \InvalidArgumentException 60 */ 61 public function diffTable(Table $fromTable, Table $toTable) 62 { 63 $newTableOptions = array_merge($fromTable->getOptions(), $toTable->getOptions()); 64 $optionDiff = ArrayUtility::arrayDiffAssocRecursive($newTableOptions, $fromTable->getOptions(), true); 65 $tableDifferences = parent::diffTable($fromTable, $toTable); 66 67 // No changed table options, return parent result 68 if (count($optionDiff) === 0) { 69 return $tableDifferences; 70 } 71 72 if ($tableDifferences === false) { 73 $tableDifferences = GeneralUtility::makeInstance(TableDiff::class, $fromTable->getName()); 74 $tableDifferences->fromTable = $fromTable; 75 } else { 76 $renamedColumns = $tableDifferences->renamedColumns; 77 $renamedIndexes = $tableDifferences->renamedIndexes; 78 // Rebuild TableDiff with enhanced TYPO3 TableDiff class 79 $tableDifferences = GeneralUtility::makeInstance( 80 TableDiff::class, 81 $tableDifferences->name, 82 $tableDifferences->addedColumns, 83 $tableDifferences->changedColumns, 84 $tableDifferences->removedColumns, 85 $tableDifferences->addedIndexes, 86 $tableDifferences->changedIndexes, 87 $tableDifferences->removedIndexes, 88 $tableDifferences->fromTable 89 ); 90 $tableDifferences->renamedColumns = $renamedColumns; 91 $tableDifferences->renamedIndexes = $renamedIndexes; 92 } 93 94 // Set the table options to be parsed in the AlterTable event. 95 $tableDifferences->setTableOptions($optionDiff); 96 97 return $tableDifferences; 98 } 99 100 /** 101 * Returns the difference between the columns $column1 and $column2 102 * by first checking the doctrine diffColumn. Extend the Doctrine 103 * method by taking into account MySQL TINY/MEDIUM/LONG type variants. 104 * 105 * @param \Doctrine\DBAL\Schema\Column $column1 106 * @param \Doctrine\DBAL\Schema\Column $column2 107 * @return array 108 */ 109 public function diffColumn(Column $column1, Column $column2) 110 { 111 $changedProperties = parent::diffColumn($column1, $column2); 112 113 // Only MySQL has variable length versions of TEXT/BLOB 114 if (!$this->databasePlatform instanceof MySqlPlatform) { 115 return $changedProperties; 116 } 117 118 $properties1 = $column1->toArray(); 119 $properties2 = $column2->toArray(); 120 121 if ($properties1['type'] instanceof BlobType || $properties1['type'] instanceof TextType) { 122 // Doctrine does not provide a length for LONGTEXT/LONGBLOB columns 123 $length1 = $properties1['length'] ?: 2147483647; 124 $length2 = $properties2['length'] ?: 2147483647; 125 126 if ($length1 !== $length2) { 127 $changedProperties[] = 'length'; 128 } 129 } 130 131 return array_unique($changedProperties); 132 } 133} 134