Spaces:
No application file
No application file
| namespace Mautic\CoreBundle\Doctrine\Helper; | |
| use Doctrine\DBAL\Connection; | |
| use Doctrine\DBAL\Schema\Index; | |
| use Doctrine\DBAL\Schema\Table; | |
| use Doctrine\DBAL\Types\TextType; | |
| use Mautic\CoreBundle\Exception\SchemaException; | |
| use Mautic\LeadBundle\Entity\LeadField; | |
| class IndexSchemaHelper | |
| { | |
| /** | |
| * @var \Doctrine\DBAL\Schema\AbstractSchemaManager<\Doctrine\DBAL\Platforms\AbstractMySQLPlatform> | |
| */ | |
| protected \Doctrine\DBAL\Schema\AbstractSchemaManager $sm; | |
| /** | |
| * @var \Doctrine\DBAL\Schema\Schema | |
| */ | |
| protected $schema; | |
| /** | |
| * @var Table | |
| */ | |
| protected $table; | |
| /** | |
| * @var array | |
| */ | |
| protected $allowedColumns = []; | |
| /** | |
| * @var array | |
| */ | |
| protected $changedIndexes = []; | |
| /** | |
| * @var array | |
| */ | |
| protected $addedIndexes = []; | |
| /** | |
| * @var array | |
| */ | |
| protected $dropIndexes = []; | |
| /** | |
| * @param string $prefix | |
| */ | |
| public function __construct( | |
| protected Connection $db, | |
| protected $prefix | |
| ) { | |
| $this->sm = $this->db->createSchemaManager(); | |
| } | |
| /** | |
| * @return $this | |
| * | |
| * @throws SchemaException | |
| */ | |
| public function setName($name) | |
| { | |
| if (!$this->sm->tablesExist($this->prefix.$name)) { | |
| throw new SchemaException("Table $name does not exist!"); | |
| } | |
| $this->table = $this->sm->introspectTable($this->prefix.$name); | |
| return $this; | |
| } | |
| public function allowColumn($name): void | |
| { | |
| $this->allowedColumns[] = $name; | |
| } | |
| /** | |
| * @param string $name | |
| * @param array $options | |
| * | |
| * @return $this | |
| * | |
| * @throws \Doctrine\DBAL\Schema\SchemaException | |
| */ | |
| public function addIndex($columns, $name, $options = []) | |
| { | |
| $textColumns = $this->getTextColumns($columns); | |
| if (empty($textColumns)) { | |
| return $this; | |
| } | |
| $index = new Index($this->prefix.$name, $textColumns, false, false, $options); | |
| if ($this->table->hasIndex($this->prefix.$name)) { | |
| $this->changedIndexes[] = $index; | |
| return $this; | |
| } | |
| $this->addedIndexes[] = $index; | |
| return $this; | |
| } | |
| /** | |
| * @param mixed $columns | |
| * @param string $name | |
| * @param array $options | |
| * | |
| * @return self | |
| * | |
| * @throws \Doctrine\DBAL\Schema\SchemaException | |
| */ | |
| public function dropIndex($columns, $name, $options = []) | |
| { | |
| $textColumns = $this->getTextColumns($columns); | |
| $index = new Index($this->prefix.$name, $textColumns, false, false, $options); | |
| if ($this->table->hasIndex($this->prefix.$name)) { | |
| $this->dropIndexes[] = $index; | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Execute changes. | |
| */ | |
| public function executeChanges(): void | |
| { | |
| $platform = $this->db->getDatabasePlatform(); | |
| $sql = []; | |
| foreach ($this->changedIndexes as $index) { | |
| $sql[] = $platform->getDropIndexSQL($index, $this->table); | |
| $sql[] = $platform->getCreateIndexSQL($index, $this->table); | |
| } | |
| foreach ($this->dropIndexes as $index) { | |
| $sql[] = $platform->getDropIndexSQL($index, $this->table); | |
| } | |
| foreach ($this->addedIndexes as $index) { | |
| $sql[] = $platform->getCreateIndexSQL($index, $this->table); | |
| } | |
| if (count($sql)) { | |
| foreach ($sql as $query) { | |
| $this->db->executeStatement($query); | |
| } | |
| $this->changedIndexes = []; | |
| $this->dropIndexes = []; | |
| $this->addedIndexes = []; | |
| } | |
| } | |
| /** | |
| * @throws SchemaException | |
| */ | |
| public function hasIndex(LeadField $leadField): bool | |
| { | |
| $alias = $leadField->getAlias(); | |
| $this->setName($leadField->getCustomFieldObject()); | |
| return $this->table->hasIndex($this->prefix."{$alias}_search"); | |
| } | |
| /** | |
| * @param array<mixed> $uniqueIdentifierColumns | |
| */ | |
| public function hasMatchingUniqueIdentifierIndex(LeadField $leadField, array $uniqueIdentifierColumns): bool | |
| { | |
| $this->setName($leadField->getCustomFieldObject()); | |
| $index = $this->table->getIndex($this->prefix.'unique_identifier_search'); | |
| $columns = $index->getColumns(); | |
| asort($columns); | |
| asort($uniqueIdentifierColumns); | |
| return $columns === $uniqueIdentifierColumns; | |
| } | |
| /** | |
| * @throws SchemaException | |
| */ | |
| public function hasUniqueIdentifierIndex(LeadField $leadField): bool | |
| { | |
| $this->setName($leadField->getCustomFieldObject()); | |
| return $this->table->hasIndex($this->prefix.'unique_identifier_search'); | |
| } | |
| /** | |
| * @param mixed $columns | |
| * | |
| * @throws \Doctrine\DBAL\Schema\SchemaException | |
| */ | |
| private function getTextColumns($columns): array | |
| { | |
| if (!is_array($columns)) { | |
| $columns = [$columns]; | |
| } | |
| foreach ($columns as $column) { | |
| if (!in_array($column, $this->allowedColumns)) { | |
| $columnSchema = $this->table->getColumn($column); | |
| $type = $columnSchema->getType(); | |
| if (!$type instanceof TextType) { | |
| $this->allowedColumns[] = $columnSchema->getName(); | |
| } | |
| } | |
| } | |
| // Indexes are only allowed on columns that are string | |
| $columns = array_intersect($columns, $this->allowedColumns); | |
| return $columns; | |
| } | |
| } | |