Files
michaelschiemer/src/Framework/Database/Schema/SchemaBuilder.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

240 lines
6.2 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Database\Schema;
use App\Framework\Database\ConnectionInterface;
use App\Framework\Database\Platform\DatabasePlatform;
use App\Framework\Database\Platform\ValueObjects\ColumnDefinition;
use App\Framework\Database\Platform\ValueObjects\IndexDefinition;
use App\Framework\Database\Platform\ValueObjects\TableOptions;
/**
* Schema builder for database-independent table creation
*/
final readonly class SchemaBuilder
{
public function __construct(
private DatabasePlatform $platform,
private ConnectionInterface $connection
) {
}
public function createTable(string $tableName, array $columns, ?TableOptions $options = null): void
{
$tableOptions = $options ?? TableOptions::default();
$sql = $this->platform->getCreateTableSQL($tableName, $columns, $tableOptions);
$this->connection->execute($sql);
}
public function dropTable(string $tableName, bool $ifExists = true): void
{
$sql = $this->platform->getDropTableSQL($tableName, $ifExists);
$this->connection->execute($sql);
}
public function tableExists(string $tableName): bool
{
$sql = $this->platform->getTableExistsSQL($tableName);
$result = $this->connection->queryColumn($sql, [$tableName]);
return ! empty($result) && (int) $result[0] > 0;
}
public function createIndex(string $tableName, IndexDefinition $index): void
{
$sql = $this->platform->getCreateIndexSQL(
$tableName,
$index->name,
$index->columns,
['type' => $index->type]
);
$this->connection->execute($sql);
}
public function listTables(): array
{
$sql = $this->platform->getListTablesSQL();
return $this->connection->queryColumn($sql);
}
/**
* Builder pattern for table creation
*/
public function table(string $tableName): TableBuilder
{
return new TableBuilder($this, $tableName);
}
}
/**
* Fluent table builder for easy table creation
*/
final class TableBuilder
{
private array $columns = [];
private array $indexes = [];
private ?TableOptions $options = null;
public function __construct(
private readonly SchemaBuilder $schemaBuilder,
private readonly string $tableName
) {
}
public function id(string $name = 'id'): self
{
$this->columns[] = ColumnDefinition::id($name);
return $this;
}
public function string(string $name, int $length = 255, bool $nullable = true): self
{
$this->columns[] = ColumnDefinition::string($name, $length, $nullable);
return $this;
}
public function text(string $name, bool $nullable = true): self
{
$this->columns[] = ColumnDefinition::text($name, $nullable);
return $this;
}
public function integer(string $name, bool $nullable = true, bool $unsigned = false): self
{
$this->columns[] = ColumnDefinition::integer($name, $nullable, $unsigned);
return $this;
}
public function bigInteger(string $name, bool $nullable = true, bool $unsigned = false): self
{
$this->columns[] = ColumnDefinition::bigInteger($name, $nullable, $unsigned);
return $this;
}
public function decimal(string $name, int $precision = 8, int $scale = 2, bool $nullable = true): self
{
$this->columns[] = ColumnDefinition::decimal($name, $precision, $scale, $nullable);
return $this;
}
public function boolean(string $name, bool $nullable = true, ?bool $default = null): self
{
$this->columns[] = ColumnDefinition::boolean($name, $nullable, $default);
return $this;
}
public function timestamp(string $name, bool $nullable = true): self
{
$this->columns[] = ColumnDefinition::timestamp($name, $nullable);
return $this;
}
public function timestamps(): self
{
$timestamps = ColumnDefinition::timestamps();
foreach ($timestamps as $timestamp) {
$this->columns[] = $timestamp;
}
return $this;
}
public function json(string $name, bool $nullable = true): self
{
$this->columns[] = ColumnDefinition::json($name, $nullable);
return $this;
}
public function uuid(string $name, bool $nullable = true): self
{
$this->columns[] = ColumnDefinition::uuid($name, $nullable);
return $this;
}
public function column(ColumnDefinition $column): self
{
$this->columns[] = $column;
return $this;
}
public function index(IndexDefinition $index): self
{
$this->indexes[] = $index;
return $this;
}
public function unique(string $name, array $columns): self
{
$this->indexes[] = IndexDefinition::unique($name, $columns);
return $this;
}
public function foreignKey(string $column, string $referencedTable, string $referencedColumn = 'id'): self
{
// Foreign keys will be handled in a separate method/builder
return $this;
}
public function engine(string $engine): self
{
$this->options = ($this->options ?? TableOptions::default())->withCustomOption('engine', $engine);
return $this;
}
public function charset(string $charset, ?string $collation = null): self
{
$this->options = ($this->options ?? TableOptions::default())->withCharset($charset, $collation);
return $this;
}
public function comment(string $comment): self
{
$this->options = ($this->options ?? TableOptions::default())->withComment($comment);
return $this;
}
public function temporary(): self
{
$this->options = TableOptions::temporary();
return $this;
}
public function create(): void
{
if (empty($this->columns)) {
throw new \RuntimeException("Cannot create table '{$this->tableName}' without columns");
}
$this->schemaBuilder->createTable($this->tableName, $this->columns, $this->options);
// Create additional indexes
foreach ($this->indexes as $index) {
$this->schemaBuilder->createIndex($this->tableName, $index);
}
}
}