*/ 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 $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; } }