144 lines
4.9 KiB
PHP
144 lines
4.9 KiB
PHP
<?php
|
|
namespace DatabaseHelper;
|
|
|
|
use DatabaseHelper\enums\CascadeTypes;
|
|
use DatabaseHelper\enums\CharsetTypes;
|
|
use DatabaseHelper\enums\CollationTypes;
|
|
use DatabaseHelper\enums\ColumnTypes;
|
|
use DatabaseHelper\enums\EngineTypes;
|
|
use DatabaseHelper\interfaces\TableBlueprint;
|
|
use InvalidArgumentException;
|
|
|
|
class Table implements TableBlueprint
|
|
{
|
|
public string $tableName;
|
|
|
|
public array $columns = [];
|
|
|
|
public array $primaryKey;
|
|
|
|
public array $foreignKeys = [];
|
|
|
|
// Table settings
|
|
protected EngineTypes $engine = EngineTypes::INNODB;
|
|
protected CharsetTypes $charset = CharsetTypes::UTF8;
|
|
protected CollationTypes $collation = CollationTypes::UTF8_GENERAL_CI;
|
|
|
|
public function __construct(string $tableName) {
|
|
Database::standardizeTableNames($tableName);
|
|
$this->tableName = $tableName;
|
|
}
|
|
|
|
public function column(string $colName, ColumnTypes $colType, mixed $default = null, bool $nullable = false, bool $unique = false): TableBlueprint {
|
|
if(isset($this->columns[$colName]))
|
|
throw new InvalidArgumentException('Column name already exists.');
|
|
|
|
$this->columns[$colName] = [
|
|
'colName' => $colName,
|
|
'defaultVal' => $default,
|
|
'colType' => $colType,
|
|
'nullable' => $nullable,
|
|
'unique' => $unique
|
|
];
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function primary(string $colName, ColumnTypes $colType, bool $autoInc = false): TableBlueprint {
|
|
if(isset($this->primaryKey))
|
|
throw new InvalidArgumentException('Primary column already exists.');
|
|
|
|
$this->primaryKey = [
|
|
'colName' => $colName,
|
|
'colType' => $colType,
|
|
'autoincrement' => $autoInc
|
|
];
|
|
|
|
return $this->column($colName, $colType);
|
|
}
|
|
|
|
public function referenceColumn(TableBlueprint $foreignTable, CascadeTypes $onDelete = CascadeTypes::CASCADE, CascadeTypes $onUpdate = CascadeTypes::CASCADE): TableBlueprint {
|
|
$colName = $foreignTable->primaryKey['colName'];
|
|
if(isset($this->columns[$colName]))
|
|
throw new InvalidArgumentException('Column name already exists.');
|
|
|
|
$this->foreignKeys[] = [
|
|
'colName' => $colName,
|
|
'tableName' => $foreignTable->tableName,
|
|
'onDelete' => $onDelete,
|
|
'onUpdate' => $onUpdate
|
|
];
|
|
|
|
$this->columns[$colName] = $foreignTable->columns[$colName];
|
|
return $this;
|
|
}
|
|
|
|
public function engine(EngineTypes $engine): TableBlueprint {
|
|
$this->engine = $engine;
|
|
return $this;
|
|
}
|
|
|
|
public function charset(CharsetTypes $charset): TableBlueprint {
|
|
$this->charset = $charset;
|
|
return $this;
|
|
}
|
|
|
|
public function collation(CollationTypes $collation): TableBlueprint {
|
|
$this->collation = $collation;
|
|
return $this;
|
|
}
|
|
|
|
public function toSql(): string {
|
|
$sql = "CREATE TABLE `{$this->tableName}` (\n";
|
|
|
|
// Add primary key constraint if present
|
|
if (!empty($this->primaryKey))
|
|
$sql .= " PRIMARY KEY (`{$this->primaryKey['colName']}`),\n";
|
|
|
|
foreach ($this->columns as $column) {
|
|
if ($column['colName'] !== $this->primaryKey['colName']) {
|
|
$sql .= " `{$column['colName']}` {$column['colType']->value}";
|
|
|
|
// Handle nulls, uniqueness, and defaults
|
|
if (!$column['nullable'])
|
|
$sql .= " NOT NULL";
|
|
if ($column['unique'])
|
|
$sql .= " UNIQUE";
|
|
if ($column['defaultVal'] !== null) {
|
|
$default = is_string($column['defaultVal']) ? "'{$column['defaultVal']}'" : $column['defaultVal'];
|
|
$sql .= " DEFAULT $default";
|
|
}
|
|
|
|
$sql .= ",\n";
|
|
}
|
|
}
|
|
|
|
// Add secondary constraints if present
|
|
foreach ($this->foreignKeys as $foreignKey) {
|
|
$sql .= " FOREIGN KEY (`{$foreignKey['colName']}`) REFERENCES `{$foreignKey['tableName']}` (`{$foreignKey['colName']}`)";
|
|
$sql .= " ON DELETE {$foreignKey['onDelete']->type()} ON UPDATE {$foreignKey['onUpdate']->type()},\n";
|
|
}
|
|
|
|
// Close the SQL string and add constraints
|
|
$sql = rtrim($sql, ",\n") . "\n";
|
|
$sql .= ") ENGINE={$this->engine->type()} CHARSET={$this->charset->type()} COLLATE={$this->collation->type()};";
|
|
|
|
return esc_sql($sql);
|
|
}
|
|
|
|
public function create(): TableBlueprint {
|
|
global $wpdb;
|
|
|
|
if (empty($this->primaryKey))
|
|
throw new InvalidArgumentException('A primary key must be defined.');
|
|
$table_name = $wpdb->prefix . $this->tableName;
|
|
|
|
if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") !== $table_name) {
|
|
$sql = $this->toSql();
|
|
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
|
dbDelta($sql);
|
|
}
|
|
return $this;
|
|
}
|
|
}
|