get_charset_collate()` (per §17.2) and relies on * `InnoDB` as the storage engine (§17.1). * * Scope explicitly NOT covered here: * * - Foreign keys to `affilun_products.id`. Per §11.2 and §13.4, AFFILUN does * not declare foreign keys at the DB level; referential integrity * is enforced by the application layer when rows are inserted * and when a product is archived or deleted. * * - `DEFAULT CURRENT_TIMESTAMP` on `created_at` / `updated_at`. Per * §13.4, environment-sensitive default clauses are avoided; * timestamps are supplied by the application layer on insert / * update. * * - Any DML. This migration creates the empty table only; seed data * and backfills belong in later migrations or runtime code paths. * * The shared DDL-assembly and installer-dispatch skeleton lives in * {@see AbstractCreateTableMigration}; this subclass only declares the * bits that actually differ between tables (target version, * description, logical name, column manifest, index manifest). See the * base class's file-level docblock for the idempotency and * failure-propagation guarantees inherited here. * * @package Affilun\Infrastructure\Persistence\Migrations */ declare(strict_types=1); namespace Affilun\Infrastructure\Persistence\Migrations; use Affilun\Infrastructure\Persistence\SchemaVersion; /** * Creates the `affilun_product_meta` table at schema version 2. * * Concrete {@see AbstractCreateTableMigration} subclass. See the * file-level docblock for the scope of this migration and the columns * and indexes it installs; see the base class for the formatting rules * and failure semantics that apply to every AFFILUN table-creation * migration. */ final class CreateProductMetaTable extends AbstractCreateTableMigration { /** * Logical, unprefixed AFFILUN table name installed by this migration. * * Kept as a class-level constant so tests can reference the exact * name without duplicating the string literal, and so a future * rename has a single location to update. */ public const TABLE_LOGICAL_NAME = 'affilun_product_meta'; /** * Target schema version installed by this migration. * * Returns version 2 — the revision that adds auxiliary product * metadata storage on top of the initial `affilun_products` table * (schema version 1). See `database-schema.md` §13.2 for the * canonical version numbering. */ public function targetVersion(): SchemaVersion { return SchemaVersion::of( 2 ); } /** * Short, human-readable description of this migration. * * Used by the diagnostics surface and migration logs. Kept terse * and operator-friendly per the * {@see \Affilun\Infrastructure\Persistence\Migration::description()} * contract. */ public function description(): string { return 'create affilun_product_meta table'; } /** * Logical, unprefixed AFFILUN table name installed by this migration. * * Consumed by {@see AbstractCreateTableMigration::up()} and * {@see AbstractCreateTableMigration::tableName()} to resolve the * physical, prefix-applied name through the injected * {@see \Affilun\Infrastructure\Persistence\TableNameResolver}. */ protected function logicalTableName(): string { return self::TABLE_LOGICAL_NAME; } /** * Column definitions for `affilun_product_meta`, in the canonical order * defined by `database-schema.md` §5.2. * * Each entry is a single column definition without its trailing * comma; the base class adds the indent and inter-column commas. * * @return list */ protected function columnDefinitions(): array { return array( 'id bigint unsigned NOT NULL AUTO_INCREMENT', 'product_id bigint unsigned NOT NULL', 'meta_key varchar(191) NOT NULL', 'meta_value longtext NULL', 'created_at datetime NOT NULL', 'updated_at datetime NOT NULL', ); } /** * Index definitions for `affilun_product_meta`, in the canonical order * defined by `database-schema.md` §5.3. * * The `PRIMARY KEY` entry uses the two-space separator that * `dbDelta()` relies on to detect the primary key line — this is * a WordPress-specific formatting quirk, not a typo. * * The unique constraint on `(product_id, meta_key)` is required * from the initial version (per §5.3 "推奨方針"); future needs * for multi-value meta are handled by introducing a new table * rather than by relaxing this constraint. * * @return list */ protected function indexDefinitions(): array { return array( 'PRIMARY KEY (id)', 'UNIQUE KEY uq_product_meta (product_id, meta_key)', 'KEY idx_product_id (product_id)', 'KEY idx_meta_key (meta_key)', ); } }