diff --git a/includes/class-tmdo-schema-registry.php b/includes/class-tmdo-schema-registry.php index 45ef898..93b390c 100644 --- a/includes/class-tmdo-schema-registry.php +++ b/includes/class-tmdo-schema-registry.php @@ -67,6 +67,13 @@ class TMDO_Schema_Registry { */ private array $warm_fields = array(); + /** + * Providers already told the Hot zone is frozen (once per request). + * + * @var array + */ + private array $hot_deprecation_flagged = array(); + /** * Private constructor — use instance() to get the singleton. */ @@ -138,6 +145,7 @@ class TMDO_Schema_Registry { switch ( $config['zone'] ) { case 'hot': $this->hot_columns[ $config['post_type'] ][ $config['column'] ] = $config['data_type']; + $this->flag_hot_deprecation( $provider, $config['meta_key'] ); break; case 'warm': @@ -159,6 +167,29 @@ class TMDO_Schema_Registry { } } + /** + * The Hot zone is frozen (ADR-003): fields still register so existing hot + * data stays readable, but each provider gets one notice per request. + * + * @param string $provider Provider name. + * @param string $meta_key First hot meta_key seen from it. + */ + private function flag_hot_deprecation( string $provider, string $meta_key ): void { + if ( isset( $this->hot_deprecation_flagged[ $provider ] ) ) { + return; + } + $this->hot_deprecation_flagged[ $provider ] = true; + _doing_it_wrong( + __CLASS__ . '::register', + sprintf( + 'Provider "%1$s" registered Hot zone field "%2$s". The Hot zone is frozen; register an entity group (TMDO_Entity_Registry::register_group) instead.', + esc_html( $provider ), + esc_html( $meta_key ) + ), + esc_html( TMDO_VERSION ) + ); + } + /** * Bulk register multiple fields. * diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 2c897b0..ccef6bc 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -231,7 +231,7 @@ if ( ! function_exists( 'esc_sql' ) ) { } } if ( ! function_exists( '_doing_it_wrong' ) ) { - function _doing_it_wrong( string $fn, string $msg, string $ver ): void {} + function _doing_it_wrong( string $fn, string $msg, string $ver ): void { $GLOBALS['_doing_it_wrong_calls'][] = array( $fn, $msg ); } } if ( ! function_exists( 'get_option' ) ) { function get_option( string $key, $default = false ) { return $GLOBALS['_wp_options'][ $key ] ?? $default; } diff --git a/tests/unit/SchemaRegistryTest.php b/tests/unit/SchemaRegistryTest.php index 73cfe93..91c0af7 100644 --- a/tests/unit/SchemaRegistryTest.php +++ b/tests/unit/SchemaRegistryTest.php @@ -18,6 +18,30 @@ class SchemaRegistryTest extends TestCase { $instance->setValue( null, null ); $this->registry = WPDO_Schema_Registry::instance(); + $GLOBALS['_doing_it_wrong_calls'] = array(); + } + + // ── Hot zone deprecation (ADR-003) ────────────────────────────────────── + + public function test_hot_registration_is_flagged_once_per_provider(): void { + foreach ( array( 'p1', 'p1', 'p2' ) as $i => $provider ) { + $this->registry->register( $provider, array( 'post_type' => 'x', 'meta_key' => "k{$i}", 'zone' => 'hot' ) ); + } + $this->registry->register( 'p1', array( 'post_type' => 'x', 'meta_key' => 'k9' ) ); // zone defaults to hot. + + $calls = $GLOBALS['_doing_it_wrong_calls']; + $this->assertCount( 2, $calls ); + $this->assertStringContainsString( 'p1', $calls[0][1] ); + $this->assertStringContainsString( 'p2', $calls[1][1] ); + $this->assertSame( 'hot', $this->registry->get_field_zone( 'x', 'k9' ), 'still registered: frozen, not rejected' ); + } + + public function test_other_zones_are_not_flagged(): void { + $this->registry->register( 'p', array( 'post_type' => 'x', 'meta_key' => 'c', 'zone' => 'cold' ) ); + $this->registry->register( 'p', array( 'post_type' => 'x', 'meta_key' => 'w', 'zone' => 'warm' ) ); + $this->registry->register( 'p', array( 'post_type' => 'x', 'meta_key' => 'a', 'zone' => 'archive' ) ); + + $this->assertSame( array(), $GLOBALS['_doing_it_wrong_calls'] ); } // ── register() ──────────────────────────────────────────────────────────