prefix` at runtime and is not known at * compile time, so every DDL and DML call site that needs a physical * table name routes the resolution through this interface. * * Decoupling logical from physical names gives us three practical * benefits: * * 1. Migration classes can be unit-tested against an in-memory fake * that maps logical names to deterministic test-only strings * (for example `test_affilun_products`), without standing up a * `$wpdb` instance or a real database connection. * * 2. Multisite installations that vary the prefix per site ID * (`wp_2_`, `wp_3_`, ...) can inject a resolver that reads the * active site's prefix on each call, rather than caching a value * that was correct only at plugin-load time. * * 3. Future refactors that want to migrate a table to a new name * have one seam to update, instead of every call site that * concatenates `$wpdb->prefix` with a string literal. * * Naming contract: * * - Logical names are the bare, unprefixed identifiers used in * `specifications/database-schema.md` — for example * `affilun_products`, `affilun_embed_items`, `affilun_sync_jobs`. They are * ASCII, lowercase, and already include the `affilun_` plugin prefix * that distinguishes AFFILUN tables from WordPress core and other * plugins' tables. * * - Physical names are whatever the resolver produces after applying * the site's table prefix — typically `{$wpdb->prefix}affilun_products` * in production (`wp_affilun_products` on a default install). * * Implementations MUST: * * - Return a non-empty string for every well-known logical name. * Resolvers are not expected to validate the logical name against * a whitelist; callers pass the literal names they own, and a * typo is a programming error that will surface as a missing- * table SQL error, not as a silent empty string. * * - Be pure and side-effect-free. Resolving a name MUST NOT issue * SQL, emit logs, or mutate shared state. The method is called on * the hot path (once per query) and must stay cheap. * * - Be stable within a single request. Repeat calls with the same * logical name MUST return the same physical name so that a * migration that resolves a table name for its `CREATE TABLE` and * then again for an index statement does not accidentally target * two different physical tables. * * Implementations MAY cache resolved names internally and MAY apply * additional normalization (trimming, lowercasing) as long as the * stability contract above is preserved. * * @package Affilun\Infrastructure\Persistence */ declare(strict_types=1); namespace Affilun\Infrastructure\Persistence; /** * Maps logical AFFILUN table names to their physical, prefix-applied form. * * See the file-level docblock for the logical/physical naming contract * and the purity / stability requirements implementations must honor. */ interface TableNameResolver { /** * Resolve a logical AFFILUN table name into its physical name. * * The logical name is the bare identifier used in the database * schema specification (for example `affilun_products`). The returned * physical name is whatever the host site uses after applying its * table prefix (typically `{$wpdb->prefix}affilun_products`). * * Implementations MUST be pure and MUST return the same physical * name for repeated calls with the same logical name within a * single request; see the file-level docblock for the full * contract. * * @param string $logicalName Logical, unprefixed AFFILUN table name * (for example `affilun_products`). * * @return string Physical, prefix-applied table name suitable for * direct interpolation into SQL. */ public function resolve( string $logicalName ): string; }