src/structure/index/Index.php
<?php
declare(strict_types = 1);
namespace mheinzerling\commons\database\structure\index;
use mheinzerling\commons\database\structure\builder\TableBuilder;
use mheinzerling\commons\database\structure\Field;
use mheinzerling\commons\database\structure\SqlSetting;
use mheinzerling\commons\database\structure\Table;
use mheinzerling\commons\StringUtils;
class Index
{
/**
* @var Table
*/
private $table;
/**
* @var Field[]
*/
protected $fields;
/**
* @var string
*/
private $name;
public function __construct(array $fields = null, string $name = null)
{
$this->fields = $fields;
$this->name = $name;
}
/**
* @param Table $table
*/
public function setTable(Table $table): void
{
$this->table = $table;
}
/**
* @return string[]
*/
public function getFieldNames(): array
{
return array_map(function (Field $f) {
return $f->getName();
}, $this->fields);
}
/**
* @return Field[]
*/
public function getFields(): array
{
return $this->fields;
}
public static function fromSql(TableBuilder $tb, string $constraint): void
{
//TODO more robust
if (StringUtils::contains($constraint, "FOREIGN KEY", true)) {
$onUpdate = ReferenceOption::memberByValueWithDefault(StringUtils::findAndRemove($constraint, "@ON UPDATE (RESTRICT|CASCADE|SET NULL|NO ACTION)@i"), null);
$onDelete = ReferenceOption::memberByValueWithDefault(StringUtils::findAndRemove($constraint, "@ON DELETE (RESTRICT|CASCADE|SET NULL|NO ACTION)@i"), null);
$parts = explode("FOREIGN KEY", $constraint);
$name = trim(str_replace("CONSTRAINT ", "", $parts[0]), "`\t\r\n ");
$parts = explode("REFERENCES", $parts[1]);
$fieldNames = StringUtils::trimExplode(",", $parts[0], StringUtils::TRIM_DEFAULT . "`()");
$parts = explode("(", $parts[1]);
$referenceTableName = trim($parts[0], "`\t\r\n ");
$referenceFieldNames = StringUtils::trimExplode(",", $parts[1], StringUtils::TRIM_DEFAULT . "`()");
$tb->foreign($fieldNames, $referenceTableName, $referenceFieldNames, $onUpdate, $onDelete, $name);
} else {
$primary = StringUtils::findAndRemove($constraint, "@(primary key)@i") != null;
$unique = StringUtils::findAndRemove($constraint, "@(unique key)@i") != null;
$details = StringUtils::trimExplode("(", $constraint);
$name = trim($details[0], "`\t\r\n ");
if (StringUtils::startsWith($constraint, "KEY ", true)) $name = trim(substr($name, 4), "`");
$values = StringUtils::trimExplode(",", $details[1], StringUtils::TRIM_DEFAULT . "`)");
if ($primary) $tb->primary($values);
else if ($unique) $tb->unique($values, $name);
else $tb->index($values, $name);
}
}
public function getName(): string
{
if ($this->name == null) $this->name = $this->getGeneratedName();
return $this->name;
}
protected function getGeneratedName(): string
{
return "idx_" . $this->table->getName() . "_" . $this->getImplodedFieldNames($this->fields);
}
protected function getImplodedFieldNames(array $fields): string
{
return StringUtils::implode("_", $fields, function ($_, $field) {
/**
* @var $field Field
*/
return $field->getName();
});
}
public function toSql(SqlSetting $setting): string
{
$sql = "KEY ";
if ($this->name != null) $sql .= "`" . $this->name . "` ";
$sql .= "(`" . implode("`, `", array_keys($this->fields)) . "`)";
return $sql;
}
public function toAlterAddSql(SqlSetting $setting): string
{
return "ADD " . $this->toSql($setting);
}
public function toAlterDropSql(SqlSetting $setting): string
{
return "DROP KEY `" . $this->name . "`";
}
public function modifySql(Index $before, SqlSetting $setting):?string
{
if ($this->same($before)) return null;
return "TODO: change index " . $this->name;
}
public function same(Index $other): bool
{
$sameClass = get_class($this) == get_class($other);
$sameTable = $this->table->same($other->table);
$sameFields = array_keys($this->fields) == array_keys($other->fields);
return $sameClass && $sameTable && $sameFields;
}
public function toBuilderCode(): string
{
return '->index(["' . implode('", "', array_keys($this->fields)) . '"])';
}
}