db = $db; $this->channel = $channel; if ($migrations === null) $migrations = static::MIGRATION; if ($migrations === null) $migrations = []; elseif (is_string($migrations)) $migrations = [$migrations]; elseif (is_callable($migrations)) $migrations = [$migrations]; elseif (!is_array($migrations)) $migrations = [strval($migrations)]; $this->migrations = $migrations; } protected ?IDatabase $db; protected string $channel; const MIGRATION_TABLE = "_migration"; const MIGRATION_COLS = [ "channel" => "varchar not null", "name" => "varchar not null", "done" => "integer not null default 0", "primary key (channel, name)", ]; protected function ensureTable(): void { $this->db->exec([ "create table if not exists", "table" => static::MIGRATION_TABLE, "cols" => static::MIGRATION_COLS, ]); } protected function isMigrated(string $name): bool { return boolval($this->db->get([ "select 1", "from" => static::MIGRATION_TABLE, "where" => [ "channel" => $this->channel, "name" => $name, "done" => 1, ], ])); } abstract protected function setMigrated(string $name, bool $done): void; /** @var callable[]|string[] */ protected $migrations; function migrate(?IDatabase $db=null): void { $db = ($this->db ??= $db); $this->ensureTable(); foreach ($this->migrations as $name => $migration) { if ($this->isMigrated($name)) continue; $this->setMigrated($name, false); if (func::is_callable($migration)) { func::with($migration)->bind($this)->invoke([$db, $name]); } else { foreach (cl::with($migration) as $query) { $db->exec($query); } } $this->setMigrated($name, true); } } protected static function sql_prefix(?string $source=null): string { $prefix = "-- -*- coding: utf-8 mode: sql -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8\n"; if ($source !== null) $prefix .= "-- autogénéré à partir de $source\n"; return $prefix; } function getSql(?string $source=null, ?IDatabase $db=null): string { $db = ($this->db ??= $db); $lines = [self::sql_prefix($source)]; foreach ($this->migrations as $name => $migration) { $lines[] = "-- $name"; if (func::is_callable($migration)) { $lines[] = "-- "; } else { foreach (cl::with($migration) as $query) { $sql = $db->getSql($query); $lines[] = "$sql;"; } } $lines[] = ""; } return implode("\n", $lines); } }