From 37b2e2815d49f31000178f3bfbf4cf5f06e51d9f Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Tue, 11 Feb 2025 14:57:05 +1100 Subject: [PATCH 01/19] Add the migration service, and a sample migration for the SFCC --- inc/Config/ArraySerializable.php | 13 +++- inc/Config/ArraySerializableInterface.php | 10 +++ inc/Config/DataSource/HttpDataSource.php | 59 +++++++++++++++ .../SalesforceB2C/SalesforceB2CDataSource.php | 11 ++- inc/MigrationService/MigrationService.php | 72 +++++++++++++++++++ remote-data-blocks.php | 3 + 6 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 inc/MigrationService/MigrationService.php diff --git a/inc/Config/ArraySerializable.php b/inc/Config/ArraySerializable.php index e3373c5c2..679c6cfd1 100644 --- a/inc/Config/ArraySerializable.php +++ b/inc/Config/ArraySerializable.php @@ -13,7 +13,11 @@ * ArraySerializable class */ abstract class ArraySerializable implements ArraySerializableInterface { - final private function __construct( protected array $config ) {} + public readonly bool $perform_migrations_only; + + final private function __construct( protected array $config, bool $perform_migrations_only = false ) { + $this->perform_migrations_only = $perform_migrations_only; + } protected function get_or_call_from_config( string $property_name, mixed ...$callable_args ): mixed { $config_value = $this->config[ $property_name ] ?? null; @@ -44,6 +48,13 @@ public static function from_array( array $config, ?ValidatorInterface $validator return new static( $sanitized ); } + /** + * @inheritDoc + */ + public static function from_array_for_migrations( array $config ): self { + return new static( $config, true ); + } + /** * @inheritDoc */ diff --git a/inc/Config/ArraySerializableInterface.php b/inc/Config/ArraySerializableInterface.php index 42fc24916..39096dec5 100644 --- a/inc/Config/ArraySerializableInterface.php +++ b/inc/Config/ArraySerializableInterface.php @@ -28,4 +28,14 @@ public static function from_array( array $config, ?ValidatorInterface $validator * @return array An associative array representing the object's current state. */ public function to_array(): array; + + /** + * Creates an instance of the class from an array representation for migrations only. + * + * Note that, no other operations will be allowed. + * + * @param array $config An associative array containing the configuration or data needed to create an instance of the class. + * @return mixed Returns a new instance of the implementing class. + */ + public static function from_array_for_migrations( array $config ): mixed; } diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index 9942a1686..87c844425 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -76,6 +76,25 @@ public static function from_uuid( string $uuid ): DataSourceInterface|WP_Error { return static::from_array( $config ); } + /** + * @inheritDoc + */ + public static function from_array_for_migrations( array $config ): self { + $service_config = $config['service_config'] ?? []; + + return parent::from_array_for_migrations( + array_merge( + static::map_service_config( $service_config ), + [ + // Store the exact data used to create the instance to preserve determinism. + 'service' => static::SERVICE_NAME, + 'service_config' => $service_config, + 'uuid' => $config['uuid'] ?? null, + ] + ) + ); + } + /** * @inheritDoc * @@ -89,6 +108,38 @@ final public function to_array(): array { ]; } + /** + * Performs a migration if the config is out of date. + */ + final public function perform_migration( array $service_config ): array { + // By default, we want to have an active data source. + if ( ! isset( $service_config['active'] ) ) { + $service_config['active'] = true; + } + + // By default, we want to have no error. + if ( ! isset( $service_config['error'] ) ) { + $service_config['error'] = null; + } + + if ( static::SERVICE_SCHEMA_VERSION === $service_config['__version'] ) { + return $service_config; + } + + $migrated_service_config = $this->migrate_config( $service_config ); + + if ( is_wp_error( $migrated_service_config ) ) { + $service_config['active'] = false; + $service_config['error'] = $migrated_service_config->get_error_message(); + } else { + $service_config['__version'] = static::SERVICE_SCHEMA_VERSION; + $service_config['active'] = true; + $service_config['error'] = null; + } + + return $service_config; + } + /** * @inheritDoc */ @@ -107,4 +158,12 @@ protected static function map_service_config( array $service_config ): array { 'request_headers' => $service_config['request_headers'] ?? [], ]; } + + /** + * Migrates the config to the current schema version. + * Can be overridden by child classes to perform custom migrations. + */ + protected function migrate_config( array $service_config ): array|WP_Error { + return $service_config; + } } diff --git a/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php b/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php index 806f7ae90..17a7ef7f2 100644 --- a/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php +++ b/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php @@ -4,13 +4,14 @@ use RemoteDataBlocks\Config\DataSource\HttpDataSource; use RemoteDataBlocks\Validation\Types; +use WP_Error; use function plugins_url; defined( 'ABSPATH' ) || exit(); class SalesforceB2CDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_SALESFORCE_B2C_SERVICE; - protected const SERVICE_SCHEMA_VERSION = 1; + protected const SERVICE_SCHEMA_VERSION = 2; protected static function get_service_config_schema(): array { return Types::object( [ @@ -34,4 +35,12 @@ protected static function map_service_config( array $service_config ): array { ], ]; } + + protected function migrate_config( array $service_config ): array|WP_Error { + if ( ! isset( $service_config['site_id'] ) ) { + $service_config['site_id'] = 'RefArchGlobal'; + } + + return $service_config; + } } diff --git a/inc/MigrationService/MigrationService.php b/inc/MigrationService/MigrationService.php new file mode 100644 index 000000000..355cd5228 --- /dev/null +++ b/inc/MigrationService/MigrationService.php @@ -0,0 +1,72 @@ +perform_migration( $data_source['service_config'] ); + if ( is_wp_error( $migrated_service_config ) ) { + return $migrated_service_config; + } + + // verify if the configs are the same so we can exit early + if ( $data_source['service_config'] === $migrated_service_config ) { + continue; + } + + $updated_config = DataSourceCrud::update_config_by_uuid( $data_source['uuid'], $migrated_service_config ); + if ( is_wp_error( $updated_config ) ) { + return $updated_config; + } + } + + self::set_migration_version(); + + return true; + } + + private static function set_migration_version(): bool|WP_Error { + return update_option( self::MIGRATION_OPTION_NAME, PluginSettings::get_version() ); + } + + private static function get_migration_version(): string { + return get_option( self::MIGRATION_OPTION_NAME, '' ); + } +} diff --git a/remote-data-blocks.php b/remote-data-blocks.php index 996feaf11..2f1f58874 100644 --- a/remote-data-blocks.php +++ b/remote-data-blocks.php @@ -52,6 +52,9 @@ // REST endpoints REST\RemoteDataController::init(); +// Migrations +MigrationService\MigrationService::init(); + // Plugin developers: If you need to register additional code for testing, you // can do so here, e.g.: // require_once __DIR__ . '/example/shopify/register.php'; From d83d9b50000991ac5442ecd8de808346a51761e3 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Tue, 11 Feb 2025 15:04:35 +1100 Subject: [PATCH 02/19] Tweaking the migration code --- inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php | 2 +- remote-data-blocks.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php b/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php index 17a7ef7f2..be7bbe20e 100644 --- a/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php +++ b/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php @@ -11,7 +11,7 @@ class SalesforceB2CDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_SALESFORCE_B2C_SERVICE; - protected const SERVICE_SCHEMA_VERSION = 2; + protected const SERVICE_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ diff --git a/remote-data-blocks.php b/remote-data-blocks.php index 2f1f58874..dff1fc8fc 100644 --- a/remote-data-blocks.php +++ b/remote-data-blocks.php @@ -42,6 +42,9 @@ // Load Settings Page PluginSettings\PluginSettings::init(); +// Migrations +MigrationService\MigrationService::init(); + // Integrations Integrations\Airtable\AirtableIntegration::init(); Integrations\Google\Sheets\GoogleSheetsIntegration::init(); @@ -52,9 +55,6 @@ // REST endpoints REST\RemoteDataController::init(); -// Migrations -MigrationService\MigrationService::init(); - // Plugin developers: If you need to register additional code for testing, you // can do so here, e.g.: // require_once __DIR__ . '/example/shopify/register.php'; From 16297bf7cbd104a814a02939245312a5a72fa893 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 12 Feb 2025 15:23:55 +1100 Subject: [PATCH 03/19] Make use of the migrations variable and fix the return value of the migration version --- inc/Config/DataSource/HttpDataSource.php | 4 ++++ inc/MigrationService/MigrationService.php | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index 87c844425..5bcb21eef 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -112,6 +112,10 @@ final public function to_array(): array { * Performs a migration if the config is out of date. */ final public function perform_migration( array $service_config ): array { + if ( ! $this->perform_migrations_only ) { + return new WP_Error( 'migration_not_allowed', 'Migrations are not allowed for this data source.' ); + } + // By default, we want to have an active data source. if ( ! isset( $service_config['active'] ) ) { $service_config['active'] = true; diff --git a/inc/MigrationService/MigrationService.php b/inc/MigrationService/MigrationService.php index 355cd5228..450d7a19d 100644 --- a/inc/MigrationService/MigrationService.php +++ b/inc/MigrationService/MigrationService.php @@ -62,8 +62,8 @@ public static function migrate_data_source_configs( ): WP_Error|bool { return true; } - private static function set_migration_version(): bool|WP_Error { - return update_option( self::MIGRATION_OPTION_NAME, PluginSettings::get_version() ); + private static function set_migration_version(): void { + update_option( self::MIGRATION_OPTION_NAME, PluginSettings::get_version() ); } private static function get_migration_version(): string { From 4cb4bbb8c0a4776df0df22c10c86a1f800d4d238 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 12 Feb 2025 15:33:10 +1100 Subject: [PATCH 04/19] Fix the phpcs issue --- inc/MigrationService/MigrationService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/MigrationService/MigrationService.php b/inc/MigrationService/MigrationService.php index 450d7a19d..1e404c587 100644 --- a/inc/MigrationService/MigrationService.php +++ b/inc/MigrationService/MigrationService.php @@ -17,7 +17,7 @@ public static function init(): void { add_action( 'init', [ __CLASS__, 'migrate_data_source_configs' ] ); } - public static function migrate_data_source_configs( ): WP_Error|bool { + public static function migrate_data_source_configs(): WP_Error|bool { $migration_version = self::get_migration_version(); if ( $migration_version === PluginSettings::get_version() ) { From 21ddd46c70c4160d95ab7bb578b9ce13b10d8c43 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 12 Feb 2025 15:34:15 +1100 Subject: [PATCH 05/19] Fix the yoda condition problems --- inc/MigrationService/MigrationService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/MigrationService/MigrationService.php b/inc/MigrationService/MigrationService.php index 1e404c587..06dfc0513 100644 --- a/inc/MigrationService/MigrationService.php +++ b/inc/MigrationService/MigrationService.php @@ -20,7 +20,7 @@ public static function init(): void { public static function migrate_data_source_configs(): WP_Error|bool { $migration_version = self::get_migration_version(); - if ( $migration_version === PluginSettings::get_version() ) { + if ( PluginSettings::get_version() === $migration_version ) { return true; } From 72925902c507fb5c6c27475cb7deb2ae430e9580 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Thu, 13 Feb 2025 09:29:03 +1100 Subject: [PATCH 06/19] Attempting to refactor the migration strategy based on feedback --- inc/Config/ArraySerializable.php | 12 +-- inc/Config/ArraySerializableInterface.php | 10 --- inc/Config/DataSource/HttpDataSource.php | 86 +++++++------------ .../SalesforceB2C/SalesforceB2CDataSource.php | 12 +-- inc/MigrationService/MigrationService.php | 72 ---------------- remote-data-blocks.php | 3 - 6 files changed, 36 insertions(+), 159 deletions(-) delete mode 100644 inc/MigrationService/MigrationService.php diff --git a/inc/Config/ArraySerializable.php b/inc/Config/ArraySerializable.php index 679c6cfd1..0088ea2a1 100644 --- a/inc/Config/ArraySerializable.php +++ b/inc/Config/ArraySerializable.php @@ -13,10 +13,7 @@ * ArraySerializable class */ abstract class ArraySerializable implements ArraySerializableInterface { - public readonly bool $perform_migrations_only; - - final private function __construct( protected array $config, bool $perform_migrations_only = false ) { - $this->perform_migrations_only = $perform_migrations_only; + final private function __construct( protected array $config ) { } protected function get_or_call_from_config( string $property_name, mixed ...$callable_args ): mixed { @@ -48,13 +45,6 @@ public static function from_array( array $config, ?ValidatorInterface $validator return new static( $sanitized ); } - /** - * @inheritDoc - */ - public static function from_array_for_migrations( array $config ): self { - return new static( $config, true ); - } - /** * @inheritDoc */ diff --git a/inc/Config/ArraySerializableInterface.php b/inc/Config/ArraySerializableInterface.php index 39096dec5..42fc24916 100644 --- a/inc/Config/ArraySerializableInterface.php +++ b/inc/Config/ArraySerializableInterface.php @@ -28,14 +28,4 @@ public static function from_array( array $config, ?ValidatorInterface $validator * @return array An associative array representing the object's current state. */ public function to_array(): array; - - /** - * Creates an instance of the class from an array representation for migrations only. - * - * Note that, no other operations will be allowed. - * - * @param array $config An associative array containing the configuration or data needed to create an instance of the class. - * @return mixed Returns a new instance of the implementing class. - */ - public static function from_array_for_migrations( array $config ): mixed; } diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index 5bcb21eef..5e3f52522 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -45,6 +45,8 @@ final public function get_service_name(): string { * define their own validation schema. */ public static function from_array( array $config, ?ValidatorInterface $validator = null ): self|WP_Error { + $config = static::perform_migration( $config ); + $service_config = $config['service_config'] ?? []; $validator = $validator ?? new Validator( static::get_service_config_schema() ); $validated = $validator->validate( $service_config ); @@ -66,6 +68,31 @@ public static function from_array( array $config, ?ValidatorInterface $validator ); } + /** + * Performs a migration if the config is out of date. + */ + private static function perform_migration( array $config ): array { + // By default, we want to have an active data source. + if ( ! isset( $config['active'] ) ) { + $config['active'] = true; + } + + if ( static::SERVICE_SCHEMA_VERSION === $config['service_config']['__version'] ) { + return $config; + } + + $migrated_config = static::migrate_config( $config ); + + if ( is_wp_error( $migrated_config ) ) { + $config['active'] = false; + } else { + $config['service_config']['__version'] = static::SERVICE_SCHEMA_VERSION; + $config['active'] = true; + } + + return $config; + } + public static function from_uuid( string $uuid ): DataSourceInterface|WP_Error { $config = DataSourceCrud::get_config_by_uuid( $uuid ); @@ -76,25 +103,6 @@ public static function from_uuid( string $uuid ): DataSourceInterface|WP_Error { return static::from_array( $config ); } - /** - * @inheritDoc - */ - public static function from_array_for_migrations( array $config ): self { - $service_config = $config['service_config'] ?? []; - - return parent::from_array_for_migrations( - array_merge( - static::map_service_config( $service_config ), - [ - // Store the exact data used to create the instance to preserve determinism. - 'service' => static::SERVICE_NAME, - 'service_config' => $service_config, - 'uuid' => $config['uuid'] ?? null, - ] - ) - ); - } - /** * @inheritDoc * @@ -108,42 +116,6 @@ final public function to_array(): array { ]; } - /** - * Performs a migration if the config is out of date. - */ - final public function perform_migration( array $service_config ): array { - if ( ! $this->perform_migrations_only ) { - return new WP_Error( 'migration_not_allowed', 'Migrations are not allowed for this data source.' ); - } - - // By default, we want to have an active data source. - if ( ! isset( $service_config['active'] ) ) { - $service_config['active'] = true; - } - - // By default, we want to have no error. - if ( ! isset( $service_config['error'] ) ) { - $service_config['error'] = null; - } - - if ( static::SERVICE_SCHEMA_VERSION === $service_config['__version'] ) { - return $service_config; - } - - $migrated_service_config = $this->migrate_config( $service_config ); - - if ( is_wp_error( $migrated_service_config ) ) { - $service_config['active'] = false; - $service_config['error'] = $migrated_service_config->get_error_message(); - } else { - $service_config['__version'] = static::SERVICE_SCHEMA_VERSION; - $service_config['active'] = true; - $service_config['error'] = null; - } - - return $service_config; - } - /** * @inheritDoc */ @@ -167,7 +139,7 @@ protected static function map_service_config( array $service_config ): array { * Migrates the config to the current schema version. * Can be overridden by child classes to perform custom migrations. */ - protected function migrate_config( array $service_config ): array|WP_Error { - return $service_config; + protected static function migrate_config( array $config ): array { + return $config; } } diff --git a/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php b/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php index be7bbe20e..c2e629b41 100644 --- a/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php +++ b/inc/Integrations/SalesforceB2C/SalesforceB2CDataSource.php @@ -4,14 +4,13 @@ use RemoteDataBlocks\Config\DataSource\HttpDataSource; use RemoteDataBlocks\Validation\Types; -use WP_Error; use function plugins_url; defined( 'ABSPATH' ) || exit(); class SalesforceB2CDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_SALESFORCE_B2C_SERVICE; - protected const SERVICE_SCHEMA_VERSION = 1; + protected const SERVICE_SCHEMA_VERSION = 2; protected static function get_service_config_schema(): array { return Types::object( [ @@ -22,6 +21,7 @@ protected static function get_service_config_schema(): array { 'enable_blocks' => Types::nullable( Types::boolean() ), 'organization_id' => Types::string(), 'shortcode' => Types::string(), + 'site_id' => Types::string(), ] ); } @@ -36,11 +36,11 @@ protected static function map_service_config( array $service_config ): array { ]; } - protected function migrate_config( array $service_config ): array|WP_Error { - if ( ! isset( $service_config['site_id'] ) ) { - $service_config['site_id'] = 'RefArchGlobal'; + protected static function migrate_config( array $config ): array { + if ( ! isset( $config['service_config']['site_id'] ) ) { + $config['service_config']['site_id'] = 'RefArchGlobal'; } - return $service_config; + return $config; } } diff --git a/inc/MigrationService/MigrationService.php b/inc/MigrationService/MigrationService.php deleted file mode 100644 index 06dfc0513..000000000 --- a/inc/MigrationService/MigrationService.php +++ /dev/null @@ -1,72 +0,0 @@ -perform_migration( $data_source['service_config'] ); - if ( is_wp_error( $migrated_service_config ) ) { - return $migrated_service_config; - } - - // verify if the configs are the same so we can exit early - if ( $data_source['service_config'] === $migrated_service_config ) { - continue; - } - - $updated_config = DataSourceCrud::update_config_by_uuid( $data_source['uuid'], $migrated_service_config ); - if ( is_wp_error( $updated_config ) ) { - return $updated_config; - } - } - - self::set_migration_version(); - - return true; - } - - private static function set_migration_version(): void { - update_option( self::MIGRATION_OPTION_NAME, PluginSettings::get_version() ); - } - - private static function get_migration_version(): string { - return get_option( self::MIGRATION_OPTION_NAME, '' ); - } -} diff --git a/remote-data-blocks.php b/remote-data-blocks.php index dff1fc8fc..996feaf11 100644 --- a/remote-data-blocks.php +++ b/remote-data-blocks.php @@ -42,9 +42,6 @@ // Load Settings Page PluginSettings\PluginSettings::init(); -// Migrations -MigrationService\MigrationService::init(); - // Integrations Integrations\Airtable\AirtableIntegration::init(); Integrations\Google\Sheets\GoogleSheetsIntegration::init(); From d16e8c195c05578cff9ac1a2137b1c932ee73e7d Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Fri, 21 Feb 2025 13:41:40 +1100 Subject: [PATCH 07/19] Remove old code --- inc/Config/ArraySerializable.php | 3 +-- .../SalesforceD2C/SalesforceD2CDataSource.php | 8 -------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/inc/Config/ArraySerializable.php b/inc/Config/ArraySerializable.php index 47830c8f5..94f39dd47 100644 --- a/inc/Config/ArraySerializable.php +++ b/inc/Config/ArraySerializable.php @@ -13,8 +13,7 @@ * ArraySerializable class */ abstract class ArraySerializable implements ArraySerializableInterface { - final private function __construct( protected array $config ) { - } + final private function __construct( protected array $config ) {} protected function get_or_call_from_config( string $property_name, mixed ...$callable_args ): mixed { $config_value = $this->config[ $property_name ] ?? null; diff --git a/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php b/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php index 41ec57889..ea75d2f16 100644 --- a/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php +++ b/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php @@ -34,12 +34,4 @@ protected static function map_service_config( array $service_config ): array { ], ]; } - - protected static function migrate_config( array $config ): array { - if ( ! isset( $config['service_config']['site_id'] ) ) { - $config['service_config']['site_id'] = 'RefArchGlobal'; - } - - return $config; - } } From d6e520128c31e243c88f4269b6bc67ee5401650c Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 26 Feb 2025 12:24:37 +1100 Subject: [PATCH 08/19] Experimenting with making a single migration method that can be overriden and values merged all the way through --- inc/Config/ArraySerializable.php | 11 ++++++++ inc/Config/DataSource/HttpDataSource.php | 35 ++++-------------------- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/inc/Config/ArraySerializable.php b/inc/Config/ArraySerializable.php index 94f39dd47..1efaaa64a 100644 --- a/inc/Config/ArraySerializable.php +++ b/inc/Config/ArraySerializable.php @@ -91,4 +91,15 @@ protected static function get_implementor( array $config ): ?string { * @inheritDoc */ abstract public static function get_config_schema(): array; + + /** + * Migrates the config to the current schema version. + * Can be overridden by child classes to perform custom migrations. + * + * @param array $config The config to migrate. + * @return array The migrated config. + */ + protected static function migrate_config( array $config ): array|WP_Error { + return $config; + } } diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index 06f10c849..b3ea7723e 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -44,7 +44,7 @@ final public function get_service_name(): string { * define their own validation schema. */ public static function preprocess_config( array $config ): array|WP_Error { - $config = static::perform_migration( $config ); + $config = static::migrate_config( $config ); $service_config = $config['service_config'] ?? []; $validator = new Validator( static::get_service_config_schema() ); @@ -65,31 +65,6 @@ public static function preprocess_config( array $config ): array|WP_Error { ); } - /** - * Performs a migration if the config is out of date. - */ - private static function perform_migration( array $config ): array { - // By default, we want to have an active data source. - if ( ! isset( $config['active'] ) ) { - $config['active'] = true; - } - - if ( static::SERVICE_SCHEMA_VERSION === $config['service_config']['__version'] ) { - return $config; - } - - $migrated_config = static::migrate_config( $config ); - - if ( is_wp_error( $migrated_config ) ) { - $config['active'] = false; - } else { - $config['service_config']['__version'] = static::SERVICE_SCHEMA_VERSION; - $config['active'] = true; - } - - return $config; - } - public static function from_uuid( string $uuid ): DataSourceInterface|WP_Error { $config = DataSourceCrud::get_config_by_uuid( $uuid ); @@ -134,10 +109,10 @@ protected static function map_service_config( array $service_config ): array { } /** - * Migrates the config to the current schema version. - * Can be overridden by child classes to perform custom migrations. + * @inheritDoc */ - protected static function migrate_config( array $config ): array { - return $config; + protected static function migrate_config( array $config ): array|WP_Error { + return static::migrate_config( $config ); } + } From daf40ca29045c4f869e81c3646cddddbb6a1d34f Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 26 Feb 2025 12:27:35 +1100 Subject: [PATCH 09/19] Fix the linting issues --- inc/Config/DataSource/HttpDataSource.php | 1 - 1 file changed, 1 deletion(-) diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index b3ea7723e..637e8a489 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -114,5 +114,4 @@ protected static function map_service_config( array $service_config ): array { protected static function migrate_config( array $config ): array|WP_Error { return static::migrate_config( $config ); } - } From 0c52b34eafeca83346c56c36f5dac2c2827a2420 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 26 Feb 2025 12:35:15 +1100 Subject: [PATCH 10/19] Stop the seg fault --- inc/Config/DataSource/HttpDataSource.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index 637e8a489..3ba1262ac 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -112,6 +112,6 @@ protected static function map_service_config( array $service_config ): array { * @inheritDoc */ protected static function migrate_config( array $config ): array|WP_Error { - return static::migrate_config( $config ); + return $config; } } From ddda49347eaef793c6c917801db054143c5c7b81 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 26 Feb 2025 13:31:34 +1100 Subject: [PATCH 11/19] Move the migrate method into from_array and make it public --- inc/Config/ArraySerializable.php | 7 ++++++- inc/Config/ArraySerializableInterface.php | 8 ++++++++ inc/Config/DataSource/HttpDataSource.php | 4 +--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/inc/Config/ArraySerializable.php b/inc/Config/ArraySerializable.php index 1efaaa64a..ef45ab21a 100644 --- a/inc/Config/ArraySerializable.php +++ b/inc/Config/ArraySerializable.php @@ -34,6 +34,11 @@ final public static function from_array( array $config, ?ValidatorInterface $val return $subclass::from_array( $config, $validator ); } + $config = static::migrate_config( $config ); + if ( is_wp_error( $config ) ) { + return $config; + } + $config = static::preprocess_config( $config ); if ( is_wp_error( $config ) ) { return $config; @@ -99,7 +104,7 @@ abstract public static function get_config_schema(): array; * @param array $config The config to migrate. * @return array The migrated config. */ - protected static function migrate_config( array $config ): array|WP_Error { + public static function migrate_config( array $config ): array|WP_Error { return $config; } } diff --git a/inc/Config/ArraySerializableInterface.php b/inc/Config/ArraySerializableInterface.php index 92f3243c5..2cee6b9a6 100644 --- a/inc/Config/ArraySerializableInterface.php +++ b/inc/Config/ArraySerializableInterface.php @@ -39,6 +39,14 @@ public static function preprocess_config( array $config ): array|WP_Error; */ public static function get_config_schema(): array; + /** + * Migrates the config to the current schema version. + * + * @param array $config The config to migrate. + * @return array The migrated config. + */ + public static function migrate_config( array $config ): array|WP_Error; + /** * Converts the current object to an array representation. * diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index 3ba1262ac..1be71bde3 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -44,8 +44,6 @@ final public function get_service_name(): string { * define their own validation schema. */ public static function preprocess_config( array $config ): array|WP_Error { - $config = static::migrate_config( $config ); - $service_config = $config['service_config'] ?? []; $validator = new Validator( static::get_service_config_schema() ); $validated = $validator->validate( $service_config ); @@ -111,7 +109,7 @@ protected static function map_service_config( array $service_config ): array { /** * @inheritDoc */ - protected static function migrate_config( array $config ): array|WP_Error { + public static function migrate_config( array $config ): array|WP_Error { return $config; } } From 56215aee04f7039db23b8ff3a86e8d3053d258de Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Tue, 4 Mar 2025 14:35:03 +1100 Subject: [PATCH 12/19] Moving __version from the service config to the root config level --- example/airtable/events/register.php | 1 - .../build/blocks/leaflet-map/render.php | 1 - .../src/blocks/leaflet-map/render.php | 1 - example/github/markdown-file/register.php | 1 - .../westeros-houses/register.php | 1 - .../rest-api/art-institute/art-institute.php | 1 - example/shopify/product/register.php | 1 - inc/Config/ArraySerializable.php | 1 + inc/Config/DataSource/HttpDataSource.php | 14 +++++++++- inc/ExampleApi/ExampleApi.php | 1 - .../Airtable/AirtableDataSource.php | 3 +-- inc/Integrations/GitHub/GitHubDataSource.php | 3 +-- .../Google/Sheets/GoogleSheetsDataSource.php | 3 +-- .../SalesforceD2C/SalesforceD2CDataSource.php | 3 +-- .../Shopify/ShopifyDataSource.php | 3 +-- .../DataSource/DataSourceConfigManager.php | 27 ++++++++++--------- inc/Validation/ConfigSchemas.php | 2 +- .../airtable/AirtableSettings.tsx | 2 +- .../google-sheets/GoogleSheetsSettings.tsx | 4 +-- src/data-sources/http/HttpSettings.tsx | 4 +-- .../salesforce-d2c/SalesforceD2CSettings.tsx | 2 +- src/data-sources/shopify/ShopifySettings.tsx | 4 +-- src/data-sources/types.ts | 4 +-- tests/inc/Config/HttpDataSourceTest.php | 1 - tests/inc/Editor/ConfigStoreTest.php | 1 - tests/inc/Functions/FunctionsTest.php | 1 - .../Airtable/AirtableDataSourceTest.php | 1 - .../Sheets/GoogleSheetsDataSourceTest.php | 1 - tests/inc/Mocks/MockDataSource.php | 1 - .../DataSource/ConstantConfigStoreTest.php | 1 - .../DataSourceConfigManagerTest.php | 23 +++++++--------- tests/inc/Telemetry/TracksTelemetryTest.php | 2 -- tests/inc/WpdbStorage/DataSourceCrudTest.php | 6 ----- tests/integration/RDBTestCase.php | 2 -- .../blocks/BlockWithNestedConfigTest.php | 1 - 35 files changed, 54 insertions(+), 74 deletions(-) diff --git a/example/airtable/events/register.php b/example/airtable/events/register.php index a731779c2..7ffb015fe 100644 --- a/example/airtable/events/register.php +++ b/example/airtable/events/register.php @@ -17,7 +17,6 @@ function register_airtable_events_block(): void { // Define the data source $airtable_data_source = AirtableDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'access_token' => $access_token, 'base' => [ 'id' => $base_id, diff --git a/example/airtable/leaflet-map/build/blocks/leaflet-map/render.php b/example/airtable/leaflet-map/build/blocks/leaflet-map/render.php index 21f3621d8..05407fe2f 100644 --- a/example/airtable/leaflet-map/build/blocks/leaflet-map/render.php +++ b/example/airtable/leaflet-map/build/blocks/leaflet-map/render.php @@ -42,7 +42,6 @@ $map_data_source = AirtableDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'access_token' => $access_token, 'base' => [ 'id' => $base_id, diff --git a/example/airtable/leaflet-map/src/blocks/leaflet-map/render.php b/example/airtable/leaflet-map/src/blocks/leaflet-map/render.php index 21f3621d8..05407fe2f 100644 --- a/example/airtable/leaflet-map/src/blocks/leaflet-map/render.php +++ b/example/airtable/leaflet-map/src/blocks/leaflet-map/render.php @@ -42,7 +42,6 @@ $map_data_source = AirtableDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'access_token' => $access_token, 'base' => [ 'id' => $base_id, diff --git a/example/github/markdown-file/register.php b/example/github/markdown-file/register.php index b3f2755ba..0dfffd95f 100644 --- a/example/github/markdown-file/register.php +++ b/example/github/markdown-file/register.php @@ -11,7 +11,6 @@ function register_github_file_as_html_block(): void { // Note: This repository is public, so GitHub's API does not require authorization. $service_config = [ - '__version' => 1, 'display_name' => 'Automattic/remote-data-blocks#trunk', 'ref' => 'trunk', 'repo_owner' => 'Automattic', diff --git a/example/google-sheets/westeros-houses/register.php b/example/google-sheets/westeros-houses/register.php index e54803729..48b31919f 100644 --- a/example/google-sheets/westeros-houses/register.php +++ b/example/google-sheets/westeros-houses/register.php @@ -18,7 +18,6 @@ function register_google_sheets_westeros_houses_blocks(): void { $westeros_houses_data_source = GoogleSheetsDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'credentials' => $credentials, 'display_name' => 'Westeros Houses', 'spreadsheet' => [ diff --git a/example/rest-api/art-institute/art-institute.php b/example/rest-api/art-institute/art-institute.php index f0e9c4188..6abd6a44a 100644 --- a/example/rest-api/art-institute/art-institute.php +++ b/example/rest-api/art-institute/art-institute.php @@ -19,7 +19,6 @@ function register_aic_block(): void { $aic_data_source = HttpDataSource::from_array([ 'service_config' => [ - '__version' => 1, 'display_name' => 'Art Institute of Chicago', 'endpoint' => 'https://api.artic.edu/api/v1/artworks', 'request_headers' => [ diff --git a/example/shopify/product/register.php b/example/shopify/product/register.php index 2b5caa5f6..e1c5b088c 100644 --- a/example/shopify/product/register.php +++ b/example/shopify/product/register.php @@ -15,7 +15,6 @@ function register_shopify_block(): void { $shopify_data_source = ShopifyDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'access_token' => $access_token, 'display_name' => 'Shopify Example', 'store_name' => $store_slug, diff --git a/inc/Config/ArraySerializable.php b/inc/Config/ArraySerializable.php index ef45ab21a..dd7537c6e 100644 --- a/inc/Config/ArraySerializable.php +++ b/inc/Config/ArraySerializable.php @@ -29,6 +29,7 @@ protected function get_or_call_from_config( string $property_name, mixed ...$cal * @inheritDoc */ final public static function from_array( array $config, ?ValidatorInterface $validator = null ): static|WP_Error { + /* check if class exists and implements ArraySerializableInterface */ $subclass = static::get_implementor( $config ); if ( null !== $subclass ) { return $subclass::from_array( $config, $validator ); diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index 1be71bde3..d1d63eb46 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -15,7 +15,7 @@ */ class HttpDataSource extends ArraySerializable implements HttpDataSourceInterface { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_GENERIC_HTTP_SERVICE; - protected const SERVICE_SCHEMA_VERSION = 1; + protected const CONFIG_SCHEMA_VERSION = 1; final public function get_display_name(): string { return $this->config['display_name']; @@ -37,6 +37,10 @@ final public function get_service_name(): string { return static::SERVICE_NAME; } + final public function get_config_schema_version(): int { + return static::CONFIG_SCHEMA_VERSION; + } + /** * @inheritDoc * @@ -59,6 +63,7 @@ public static function preprocess_config( array $config ): array|WP_Error { 'service' => static::SERVICE_NAME, 'service_config' => $service_config, 'uuid' => $config['uuid'] ?? null, + '__version' => static::CONFIG_SCHEMA_VERSION, ] ); } @@ -84,6 +89,7 @@ final public function to_array(): array { 'service' => static::SERVICE_NAME, 'service_config' => $this->config['service_config'], 'uuid' => $this->config['uuid'], + '__version' => static::CONFIG_SCHEMA_VERSION, ]; } @@ -110,6 +116,12 @@ protected static function map_service_config( array $service_config ): array { * @inheritDoc */ public static function migrate_config( array $config ): array|WP_Error { + // Migration: Move __version from service_config to the root level. + if ( isset( $config['service_config']['__version'] ) ) { + $config['__version'] = $config['service_config']['__version']; + unset( $config['service_config']['__version'] ); + } + return $config; } } diff --git a/inc/ExampleApi/ExampleApi.php b/inc/ExampleApi/ExampleApi.php index 4f297326e..8c94a8554 100644 --- a/inc/ExampleApi/ExampleApi.php +++ b/inc/ExampleApi/ExampleApi.php @@ -41,7 +41,6 @@ public static function register_remote_data_block(): void { $data_source = HttpDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'display_name' => 'Example API (Conference Event)', 'endpoint' => 'https://example.com/api/v1', // dummy URL ], diff --git a/inc/Integrations/Airtable/AirtableDataSource.php b/inc/Integrations/Airtable/AirtableDataSource.php index d37f60035..b67148559 100644 --- a/inc/Integrations/Airtable/AirtableDataSource.php +++ b/inc/Integrations/Airtable/AirtableDataSource.php @@ -7,11 +7,10 @@ class AirtableDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE; - protected const SERVICE_SCHEMA_VERSION = 1; + protected const CONFIG_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ - '__version' => Types::integer(), 'access_token' => Types::string(), 'base' => Types::object( [ 'id' => Types::string(), diff --git a/inc/Integrations/GitHub/GitHubDataSource.php b/inc/Integrations/GitHub/GitHubDataSource.php index f67406fbd..7fe29f2f3 100644 --- a/inc/Integrations/GitHub/GitHubDataSource.php +++ b/inc/Integrations/GitHub/GitHubDataSource.php @@ -7,11 +7,10 @@ class GitHubDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_GITHUB_SERVICE; - protected const SERVICE_SCHEMA_VERSION = 1; + protected const CONFIG_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ - '__version' => Types::integer(), 'display_name' => Types::string(), 'repo_owner' => Types::string(), 'repo_name' => Types::string(), diff --git a/inc/Integrations/Google/Sheets/GoogleSheetsDataSource.php b/inc/Integrations/Google/Sheets/GoogleSheetsDataSource.php index 9c7c6977c..188151526 100644 --- a/inc/Integrations/Google/Sheets/GoogleSheetsDataSource.php +++ b/inc/Integrations/Google/Sheets/GoogleSheetsDataSource.php @@ -8,11 +8,10 @@ class GoogleSheetsDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_GOOGLE_SHEETS_SERVICE; - protected const SERVICE_SCHEMA_VERSION = 1; + protected const CONFIG_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ - '__version' => Types::integer(), 'credentials' => Types::object( [ 'type' => Types::string(), 'project_id' => Types::string(), diff --git a/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php b/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php index ea75d2f16..fbc7a31d0 100644 --- a/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php +++ b/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php @@ -10,11 +10,10 @@ class SalesforceD2CDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_SALESFORCE_D2C_SERVICE; - protected const SERVICE_SCHEMA_VERSION = 1; + protected const CONFIG_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ - '__version' => Types::integer(), 'display_name' => Types::string(), 'client_id' => Types::string(), 'client_secret' => Types::string(), diff --git a/inc/Integrations/Shopify/ShopifyDataSource.php b/inc/Integrations/Shopify/ShopifyDataSource.php index 4141d41f8..163f96d70 100644 --- a/inc/Integrations/Shopify/ShopifyDataSource.php +++ b/inc/Integrations/Shopify/ShopifyDataSource.php @@ -10,11 +10,10 @@ class ShopifyDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_SHOPIFY_SERVICE; - protected const SERVICE_SCHEMA_VERSION = 1; + protected const CONFIG_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ - '__version' => Types::integer(), 'access_token' => Types::skip_sanitize( Types::string() ), 'display_name' => Types::string(), 'enable_blocks' => Types::nullable( Types::boolean() ), diff --git a/inc/Store/DataSource/DataSourceConfigManager.php b/inc/Store/DataSource/DataSourceConfigManager.php index 32527a132..e25466063 100644 --- a/inc/Store/DataSource/DataSourceConfigManager.php +++ b/inc/Store/DataSource/DataSourceConfigManager.php @@ -60,18 +60,19 @@ function ( array $acc, array $item ) { /** * Get all data sources from all origins with optional filters. - * + * * Supported filters: * - service: Filter by service name (e.g. 'airtable', 'google-sheets', 'shopify') * - enable_blocks: Filter by blocks enabled status (false matches with null/false and true matches with true) - * + * * Passing an unsupported filter key will return an error. - * + * * @param array{ * service?: string, * enable_blocks?: bool * } $filters Optional filters to apply to the results. * @return array, @@ -89,7 +90,7 @@ public static function get_all( array $filters = [] ): array|WP_Error { /** * De-duplicate configs. - * + * * Precedence (lowest to highest): * - Code-configured data sources * - Constant-configured data sources @@ -152,7 +153,7 @@ function ( array $config ) use ( $filters ): bool { /** * Get a data source by its UUID. - * + * * @param string $uuid The UUID of the data source to get. * @return array{ * uuid: string, @@ -168,9 +169,9 @@ function ( array $config ) use ( $filters ): bool { public static function get( string $uuid ): array|WP_Error { $from_constant = ConstantConfigStore::get_config_by_uuid( $uuid ); if ( ! is_wp_error( $from_constant ) ) { - return array_merge( - $from_constant, - [ 'config_source' => self::CONFIG_SOURCE_CONSTANT ] + return array_merge( + $from_constant, + [ 'config_source' => self::CONFIG_SOURCE_CONSTANT ] ); } @@ -191,7 +192,7 @@ public static function get( string $uuid ): array|WP_Error { /** * Create a new data source. - * + * * @param array $config The configuration for the new data source. * @return array{ * uuid: string, @@ -215,7 +216,7 @@ public static function create( array $config ): array|WP_Error { /** * Update a data source. - * + * * @param string $uuid The UUID of the data source to update. * @param array $config The new configuration for the data source. * @return array{ @@ -231,8 +232,8 @@ public static function create( array $config ): array|WP_Error { */ public static function update( string $uuid, array $config ): array|WP_Error { if ( - isset( $config['config_source'] ) && - ! in_array( $config['config_source'], self::MUTABLE_CONFIG_SOURCES, true ) + isset( $config['config_source'] ) && + ! in_array( $config['config_source'], self::MUTABLE_CONFIG_SOURCES, true ) ) { /** * Only storage-configured data sources are mutable. @@ -254,7 +255,7 @@ public static function update( string $uuid, array $config ): array|WP_Error { /** * Delete a data source. - * + * * @param string $uuid The UUID of the data source to delete. * @return true|WP_Error True on success, WP_Error on failure. */ diff --git a/inc/Validation/ConfigSchemas.php b/inc/Validation/ConfigSchemas.php index 45c5b2a4d..18990fc7a 100644 --- a/inc/Validation/ConfigSchemas.php +++ b/inc/Validation/ConfigSchemas.php @@ -121,6 +121,7 @@ private static function generate_graphql_query_config_schema(): array { private static function generate_http_data_source_config_schema(): array { return Types::object( [ + '__version' => Types::integer(), 'display_name' => Types::string(), 'endpoint' => Types::string(), 'image_url' => Types::nullable( Types::image_url() ), @@ -138,7 +139,6 @@ private static function generate_http_data_source_config_schema(): array { private static function generate_http_data_source_service_config_schema(): array { return Types::object( [ - '__version' => Types::integer(), 'auth' => Types::nullable( Types::object( [ 'add_to' => Types::nullable( Types::enum( 'header', 'query' ) ), diff --git a/src/data-sources/airtable/AirtableSettings.tsx b/src/data-sources/airtable/AirtableSettings.tsx index d6c8b845d..c3262f68a 100644 --- a/src/data-sources/airtable/AirtableSettings.tsx +++ b/src/data-sources/airtable/AirtableSettings.tsx @@ -43,7 +43,6 @@ export const AirtableSettings = ( { const { state, handleOnChange, validState } = useForm< AirtableServiceConfig >( { initialValues: config?.service_config ?? { - __version: SERVICE_CONFIG_VERSION, enable_blocks: true, }, } ); @@ -78,6 +77,7 @@ export const AirtableSettings = ( { service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, + __version: SERVICE_CONFIG_VERSION, }; return onSave( airtableConfig, mode ); diff --git a/src/data-sources/google-sheets/GoogleSheetsSettings.tsx b/src/data-sources/google-sheets/GoogleSheetsSettings.tsx index 1867010ad..a25d04fa1 100644 --- a/src/data-sources/google-sheets/GoogleSheetsSettings.tsx +++ b/src/data-sources/google-sheets/GoogleSheetsSettings.tsx @@ -4,7 +4,7 @@ import { __ } from '@wordpress/i18n'; import { DataSourceForm } from '@/data-sources/components/DataSourceForm'; import { FieldsSelection } from '@/data-sources/components/FieldsSelection'; -import { GOOGLE_SHEETS_API_SCOPES, ConfigSource } from '@/data-sources/constants'; +import { ConfigSource, GOOGLE_SHEETS_API_SCOPES } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; import { useGoogleSheetsWithFields, @@ -61,7 +61,6 @@ export const GoogleSheetsSettings = ( { const { state, errors, handleOnChange, validState } = useForm< GoogleSheetsServiceConfig >( { initialValues: config?.service_config ?? { - __version: SERVICE_CONFIG_VERSION, enable_blocks: true, }, validationRules, @@ -98,6 +97,7 @@ export const GoogleSheetsSettings = ( { service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, + __version: SERVICE_CONFIG_VERSION, }; return onSave( data, mode ); diff --git a/src/data-sources/http/HttpSettings.tsx b/src/data-sources/http/HttpSettings.tsx index ab4f50fdd..65e807eb8 100644 --- a/src/data-sources/http/HttpSettings.tsx +++ b/src/data-sources/http/HttpSettings.tsx @@ -1,7 +1,6 @@ import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { DataSourceForm } from '../components/DataSourceForm'; import { HttpAuthSettingsInput } from '@/data-sources/components/HttpAuthSettingsInput'; import { ConfigSource } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; @@ -9,6 +8,7 @@ import { HttpAuth } from '@/data-sources/http/types'; import { HttpConfig, HttpServiceConfig, SettingsComponentProps } from '@/data-sources/types'; import { useForm } from '@/hooks/useForm'; import HttpIcon from '@/settings/icons/HttpIcon'; +import { DataSourceForm } from '../components/DataSourceForm'; const SERVICE_CONFIG_VERSION = 1; @@ -35,7 +35,6 @@ function computeAuthState( updatedAuth: Partial< HttpServiceConfig[ 'auth' ] > ) export const HttpSettings = ( { mode, uuid, config }: SettingsComponentProps< HttpConfig > ) => { const { state, handleOnChange, validState } = useForm< HttpServiceConfig >( { initialValues: config?.service_config ?? { - __version: SERVICE_CONFIG_VERSION, auth: computeAuthState( {} ), }, } ); @@ -65,6 +64,7 @@ export const HttpSettings = ( { mode, uuid, config }: SettingsComponentProps< Ht service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, + __version: SERVICE_CONFIG_VERSION, }; return onSave( httpConfig, mode ); diff --git a/src/data-sources/salesforce-d2c/SalesforceD2CSettings.tsx b/src/data-sources/salesforce-d2c/SalesforceD2CSettings.tsx index 76671f6fc..3fc64c7ee 100644 --- a/src/data-sources/salesforce-d2c/SalesforceD2CSettings.tsx +++ b/src/data-sources/salesforce-d2c/SalesforceD2CSettings.tsx @@ -62,7 +62,6 @@ export const SalesforceD2CSettings = ( { const { state, handleOnChange, validState } = useForm< SalesforceD2CServiceConfig >( { initialValues: config?.service_config ?? { - __version: SERVICE_CONFIG_VERSION, enable_blocks: true, }, validationRules, @@ -91,6 +90,7 @@ export const SalesforceD2CSettings = ( { service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, + __version: SERVICE_CONFIG_VERSION, }; return onSave( data, mode ); diff --git a/src/data-sources/shopify/ShopifySettings.tsx b/src/data-sources/shopify/ShopifySettings.tsx index e05d83298..09db2b22b 100644 --- a/src/data-sources/shopify/ShopifySettings.tsx +++ b/src/data-sources/shopify/ShopifySettings.tsx @@ -2,7 +2,6 @@ import { TextControl } from '@wordpress/components'; import { useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { DataSourceForm } from '../components/DataSourceForm'; import PasswordInputControl from '@/data-sources/components/PasswordInputControl'; import { ConfigSource } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; @@ -10,6 +9,7 @@ import { useShopifyShopName } from '@/data-sources/hooks/useShopify'; import { SettingsComponentProps, ShopifyConfig, ShopifyServiceConfig } from '@/data-sources/types'; import { useForm } from '@/hooks/useForm'; import { ShopifyIcon, ShopifyIconWithText } from '@/settings/icons/ShopifyIcon'; +import { DataSourceForm } from '../components/DataSourceForm'; const SERVICE_CONFIG_VERSION = 1; @@ -22,7 +22,6 @@ export const ShopifySettings = ( { const { state, handleOnChange, validState } = useForm< ShopifyServiceConfig >( { initialValues: config?.service_config ?? { - __version: SERVICE_CONFIG_VERSION, enable_blocks: true, }, } ); @@ -61,6 +60,7 @@ export const ShopifySettings = ( { service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, + __version: SERVICE_CONFIG_VERSION, }; return onSave( data, mode ); diff --git a/src/data-sources/types.ts b/src/data-sources/types.ts index 1f6d97b10..8cc324ccf 100644 --- a/src/data-sources/types.ts +++ b/src/data-sources/types.ts @@ -1,4 +1,4 @@ -import { SUPPORTED_SERVICES, ConfigSource } from '@/data-sources/constants'; +import { ConfigSource, SUPPORTED_SERVICES } from '@/data-sources/constants'; import { HttpAuth } from '@/data-sources/http/types'; import { StringIdName } from '@/types/common'; import { GoogleServiceAccountKey } from '@/types/google'; @@ -6,7 +6,6 @@ import { GoogleServiceAccountKey } from '@/types/google'; export type DataSourceType = ( typeof SUPPORTED_SERVICES )[ number ]; interface BaseServiceConfig extends Record< string, unknown > { - __version: number; display_name: string; enable_blocks: boolean; } @@ -14,6 +13,7 @@ interface BaseDataSourceConfig< ServiceName extends DataSourceType, ServiceConfig extends BaseServiceConfig > { + __version: number; service: ServiceName; service_config: ServiceConfig; uuid: string | null; diff --git a/tests/inc/Config/HttpDataSourceTest.php b/tests/inc/Config/HttpDataSourceTest.php index a50d4499b..860752ac7 100644 --- a/tests/inc/Config/HttpDataSourceTest.php +++ b/tests/inc/Config/HttpDataSourceTest.php @@ -11,7 +11,6 @@ class HttpDataSourceTest extends TestCase { public function testGetServiceMethodCannotBeOverriddenl(): void { $config = [ 'service_config' => [ - '__version' => 1, 'display_name' => 'Mock Data Source', 'endpoint' => 'http://example.com', ], diff --git a/tests/inc/Editor/ConfigStoreTest.php b/tests/inc/Editor/ConfigStoreTest.php index ffd99caea..f829b166a 100644 --- a/tests/inc/Editor/ConfigStoreTest.php +++ b/tests/inc/Editor/ConfigStoreTest.php @@ -28,7 +28,6 @@ public function testGetDataSourceReturnsDataSource(): void { 'display' => HttpQuery::from_array( [ 'data_source' => AirtableDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'access_token' => 'token', 'base' => [ 'id' => 'foo', diff --git a/tests/inc/Functions/FunctionsTest.php b/tests/inc/Functions/FunctionsTest.php index de2e4be33..5ff02f807 100644 --- a/tests/inc/Functions/FunctionsTest.php +++ b/tests/inc/Functions/FunctionsTest.php @@ -79,7 +79,6 @@ public function testRegisterBlockWithNestedConfig(): void { 'data_source' => [ '__class' => 'RemoteDataBlocks\Tests\Mocks\MockDataSource', 'service_config' => [ - '__version' => 1, 'display_name' => 'Mock Data Source', 'endpoint' => 'https://example.com/api', ], diff --git a/tests/inc/Integrations/Airtable/AirtableDataSourceTest.php b/tests/inc/Integrations/Airtable/AirtableDataSourceTest.php index 99e51af40..1f1488677 100644 --- a/tests/inc/Integrations/Airtable/AirtableDataSourceTest.php +++ b/tests/inc/Integrations/Airtable/AirtableDataSourceTest.php @@ -13,7 +13,6 @@ protected function setUp(): void { $this->data_source = AirtableDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'access_token' => 'test_access_token', 'display_name' => 'Airtable Source', 'base' => [ diff --git a/tests/inc/Integrations/Google/Sheets/GoogleSheetsDataSourceTest.php b/tests/inc/Integrations/Google/Sheets/GoogleSheetsDataSourceTest.php index 119f63050..c8259e35e 100644 --- a/tests/inc/Integrations/Google/Sheets/GoogleSheetsDataSourceTest.php +++ b/tests/inc/Integrations/Google/Sheets/GoogleSheetsDataSourceTest.php @@ -33,7 +33,6 @@ protected function setUp(): void { $this->data_source = GoogleSheetsDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'display_name' => 'Google Sheets Source', 'credentials' => self::MOCK_CREDENTIALS, 'spreadsheet' => [ diff --git a/tests/inc/Mocks/MockDataSource.php b/tests/inc/Mocks/MockDataSource.php index 11b519444..d63b1957f 100644 --- a/tests/inc/Mocks/MockDataSource.php +++ b/tests/inc/Mocks/MockDataSource.php @@ -11,7 +11,6 @@ class MockDataSource extends HttpDataSource { public const MOCK_CONFIG = [ 'service' => 'mock', 'service_config' => [ - '__version' => 1, 'display_name' => 'Mock Data Source', 'endpoint' => 'https://example.com/api', 'request_headers' => [ diff --git a/tests/inc/Store/DataSource/ConstantConfigStoreTest.php b/tests/inc/Store/DataSource/ConstantConfigStoreTest.php index 0d1d473d2..518e7f233 100644 --- a/tests/inc/Store/DataSource/ConstantConfigStoreTest.php +++ b/tests/inc/Store/DataSource/ConstantConfigStoreTest.php @@ -30,7 +30,6 @@ protected function setUp(): void { 'uuid' => self::TEST_UUID, 'service' => self::TEST_SERVICE, 'service_config' => [ - '__version' => 1, 'store_name' => 'test-store', 'access_token' => 'gy56yrtyrtt', 'display_name' => 'Test Store', diff --git a/tests/inc/Store/DataSource/DataSourceConfigManagerTest.php b/tests/inc/Store/DataSource/DataSourceConfigManagerTest.php index 06e717dfe..dd01e6cb4 100644 --- a/tests/inc/Store/DataSource/DataSourceConfigManagerTest.php +++ b/tests/inc/Store/DataSource/DataSourceConfigManagerTest.php @@ -33,7 +33,6 @@ protected function setUp(): void { 'uuid' => self::AIRTABLE_UUID, 'service' => self::AIRTABLE_SERVICE, 'service_config' => [ - '__version' => 1, 'enable_blocks' => true, 'display_name' => 'Test Airtable', 'access_token' => 'test.airtable.access-token', @@ -67,7 +66,6 @@ protected function setUp(): void { 'uuid' => self::SHEETS_UUID, 'service' => self::SHEETS_SERVICE, 'service_config' => [ - '__version' => 1, 'enable_blocks' => true, 'display_name' => 'Test Google Sheets', 'credentials' => [ @@ -109,7 +107,6 @@ protected function setUp(): void { 'uuid' => self::SHOPIFY_UUID, 'service' => self::SHOPIFY_SERVICE, 'service_config' => [ - '__version' => 1, 'access_token' => 'shpat_abc123def456ghi789jkl0', 'store_name' => 'test-shopify-store', 'display_name' => 'Test Shopify Store', @@ -138,7 +135,7 @@ public function testGetAllReturnsConfigsFromAllSources(): void { ->andReturn( [ $this->shopify_code_config ] ); $result = DataSourceConfigManager::get_all(); - + $this->assertCount( 3, $result ); $this->assertContains( $this->airtable_storage_config, $result ); $this->assertContains( $this->sheets_constant_config, $result ); @@ -217,7 +214,7 @@ public function testUpdateReturnsUpdatedConfig(): void { } public function testUpdateReturnsErrorForImmutableConfig(): void { - $immutable_config = array_merge( + $immutable_config = array_merge( $this->sheets_constant_config, [ 'config_source' => DataSourceConfigManager::CONFIG_SOURCE_CONSTANT ] ); @@ -296,7 +293,7 @@ public function testGetAllHandlesConfigPrecedenceCorrectly(): void { // Should only get one config since they share the same UUID $this->assertCount( 1, $result ); - + // Storage should win due to highest precedence $this->assertContains( $storage_sheets, $result ); $this->assertNotContains( $constant_sheets, $result ); @@ -317,7 +314,7 @@ public function testGetAllWithServiceFilter(): void { ->andReturn( [ $this->shopify_code_config ] ); $result = DataSourceConfigManager::get_all( [ 'service' => self::AIRTABLE_SERVICE ] ); - + $this->assertCount( 1, $result ); $this->assertContains( $this->airtable_storage_config, $result ); } @@ -341,7 +338,7 @@ public function testGetAllWithEnableBlocksFilterTrue(): void { ->andReturn( [ $this->shopify_code_config ] ); $result = DataSourceConfigManager::get_all( [ 'enable_blocks' => true ] ); - + $this->assertCount( 2, $result ); $this->assertContains( $this->airtable_storage_config, $result ); $this->assertContains( $this->shopify_code_config, $result ); @@ -366,7 +363,7 @@ public function testGetAllWithEnableBlocksFilterFalse(): void { ->andReturn( [ $shopify_config_blocks_unset ] ); $result = DataSourceConfigManager::get_all( [ 'enable_blocks' => false ] ); - + $this->assertCount( 1, $result ); $this->assertContains( $shopify_config_blocks_unset, $result ); } @@ -388,7 +385,7 @@ public function testGetAllWithMultipleFilters(): void { 'service' => self::AIRTABLE_SERVICE, 'enable_blocks' => true, ] ); - + $this->assertCount( 1, $result ); $this->assertContains( $this->airtable_storage_config, $result ); } @@ -408,7 +405,7 @@ public function testGetAllReturnsEmptyWhenServiceDoesNotMatch(): void { ->andReturn( [] ); $result = DataSourceConfigManager::get_all( [ 'service' => self::AIRTABLE_SERVICE ] ); - + $this->assertCount( 0, $result ); $this->assertEmpty( $result ); } @@ -438,7 +435,7 @@ public function testGetAllReturnsEmptyWhenEnableBlocksDoesNotMatch(): void { ->andReturn( [ $shopify_config ] ); $result = DataSourceConfigManager::get_all( [ 'enable_blocks' => false ] ); - + $this->assertCount( 0, $result ); $this->assertEmpty( $result ); } @@ -460,7 +457,7 @@ public function testGetAllReturnsEmptyWhenMultipleFiltersDoNotMatch(): void { 'service' => self::AIRTABLE_SERVICE, 'enable_blocks' => false, ] ); - + $this->assertCount( 0, $result ); $this->assertEmpty( $result ); } diff --git a/tests/inc/Telemetry/TracksTelemetryTest.php b/tests/inc/Telemetry/TracksTelemetryTest.php index cd3591970..c6c3ff145 100644 --- a/tests/inc/Telemetry/TracksTelemetryTest.php +++ b/tests/inc/Telemetry/TracksTelemetryTest.php @@ -200,7 +200,6 @@ public function testTrackRemoteDataBlocksUsageDoesTrackEventIfPostContentHaveRem 'display' => HttpQuery::from_array( [ 'data_source' => ShopifyDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'access_token' => 'token', 'display_name' => 'Shopify Source', 'store_name' => 'B. Walton', @@ -216,7 +215,6 @@ public function testTrackRemoteDataBlocksUsageDoesTrackEventIfPostContentHaveRem 'display' => HttpQuery::from_array( [ 'data_source' => HttpDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'display_name' => 'HTTP Source', 'endpoint' => 'https://example.com/api/v1', ], diff --git a/tests/inc/WpdbStorage/DataSourceCrudTest.php b/tests/inc/WpdbStorage/DataSourceCrudTest.php index da67e9ac6..523a07e06 100644 --- a/tests/inc/WpdbStorage/DataSourceCrudTest.php +++ b/tests/inc/WpdbStorage/DataSourceCrudTest.php @@ -16,7 +16,6 @@ public function test_register_new_data_source_with_valid_input(): void { $valid_source = [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ - '__version' => 1, 'access_token' => 'valid_token', 'base' => [ 'id' => 'base_id', @@ -59,7 +58,6 @@ public function test_get_configs(): void { $source1 = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ - '__version' => 1, 'access_token' => 'token1', 'display_name' => 'Airtable Source', 'base' => [ @@ -74,7 +72,6 @@ public function test_get_configs(): void { $source2 = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_SHOPIFY_SERVICE, 'service_config' => [ - '__version' => 1, 'access_token' => 'token2', 'display_name' => 'Shopify Source', 'store_name' => 'mystore', @@ -100,7 +97,6 @@ public function test_get_item_by_uuid_with_valid_uuid(): void { $source = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ - '__version' => 1, 'access_token' => 'token1', 'base' => [ 'id' => 'base_id1', @@ -128,7 +124,6 @@ public function test_update_item_by_uuid_with_valid_uuid(): void { $source = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ - '__version' => 1, 'access_token' => 'token1', 'base' => [ 'id' => 'base_id1', @@ -158,7 +153,6 @@ public function test_delete_item_by_uuid(): void { $source = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ - '__version' => 1, 'access_token' => 'token1', 'base' => [ 'id' => 'base_id1', diff --git a/tests/integration/RDBTestCase.php b/tests/integration/RDBTestCase.php index fecf4f933..db5d63f70 100644 --- a/tests/integration/RDBTestCase.php +++ b/tests/integration/RDBTestCase.php @@ -16,7 +16,6 @@ protected function register_mocked_data_block( string $block_title, array $api_r $test_data_source = HttpDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'display_name' => 'Test API', // Mocked query runner will not actually make a request to the endpoint URL. @@ -46,7 +45,6 @@ protected function register_failed_query_data_block( string $block_title ): void $test_data_source = HttpDataSource::from_array( [ 'service_config' => [ - '__version' => 1, 'display_name' => 'Test Failing API', // Mocked query runner will not actually make a request to the endpoint URL. diff --git a/tests/integration/blocks/BlockWithNestedConfigTest.php b/tests/integration/blocks/BlockWithNestedConfigTest.php index 4c232985f..70ca57791 100644 --- a/tests/integration/blocks/BlockWithNestedConfigTest.php +++ b/tests/integration/blocks/BlockWithNestedConfigTest.php @@ -20,7 +20,6 @@ public function testBlockWithNestedConfigRenders(): void { 'data_source' => [ '__class' => 'RemoteDataBlocks\\Config\\DataSource\\HttpDataSource', 'service_config' => [ - '__version' => 1, 'display_name' => 'Test API', // Mocked query runner will not actually make a request to the endpoint URL. 'endpoint' => 'https://example.com/not-a-real-api', From 37979fcfcc119e0f27213b8c1248e1374ee6d8eb Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Tue, 4 Mar 2025 14:42:50 +1100 Subject: [PATCH 13/19] Fix the linting issues --- src/data-sources/http/HttpSettings.tsx | 2 +- src/data-sources/shopify/ShopifySettings.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data-sources/http/HttpSettings.tsx b/src/data-sources/http/HttpSettings.tsx index 65e807eb8..cf4f87eaa 100644 --- a/src/data-sources/http/HttpSettings.tsx +++ b/src/data-sources/http/HttpSettings.tsx @@ -1,6 +1,7 @@ import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; +import { DataSourceForm } from '../components/DataSourceForm'; import { HttpAuthSettingsInput } from '@/data-sources/components/HttpAuthSettingsInput'; import { ConfigSource } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; @@ -8,7 +9,6 @@ import { HttpAuth } from '@/data-sources/http/types'; import { HttpConfig, HttpServiceConfig, SettingsComponentProps } from '@/data-sources/types'; import { useForm } from '@/hooks/useForm'; import HttpIcon from '@/settings/icons/HttpIcon'; -import { DataSourceForm } from '../components/DataSourceForm'; const SERVICE_CONFIG_VERSION = 1; diff --git a/src/data-sources/shopify/ShopifySettings.tsx b/src/data-sources/shopify/ShopifySettings.tsx index 09db2b22b..b72d793bc 100644 --- a/src/data-sources/shopify/ShopifySettings.tsx +++ b/src/data-sources/shopify/ShopifySettings.tsx @@ -2,6 +2,7 @@ import { TextControl } from '@wordpress/components'; import { useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +import { DataSourceForm } from '../components/DataSourceForm'; import PasswordInputControl from '@/data-sources/components/PasswordInputControl'; import { ConfigSource } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; @@ -9,7 +10,6 @@ import { useShopifyShopName } from '@/data-sources/hooks/useShopify'; import { SettingsComponentProps, ShopifyConfig, ShopifyServiceConfig } from '@/data-sources/types'; import { useForm } from '@/hooks/useForm'; import { ShopifyIcon, ShopifyIconWithText } from '@/settings/icons/ShopifyIcon'; -import { DataSourceForm } from '../components/DataSourceForm'; const SERVICE_CONFIG_VERSION = 1; From 79434021ad14f844966fcc72ce76abef41cb913d Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 5 Mar 2025 10:28:46 +1100 Subject: [PATCH 14/19] Revert "Moving __version from the service config to the root config level" This reverts commit 56215aee04f7039db23b8ff3a86e8d3053d258de. --- example/airtable/events/register.php | 1 + .../build/blocks/leaflet-map/render.php | 1 + .../src/blocks/leaflet-map/render.php | 1 + example/github/markdown-file/register.php | 1 + .../westeros-houses/register.php | 1 + .../rest-api/art-institute/art-institute.php | 1 + example/shopify/product/register.php | 1 + inc/Config/ArraySerializable.php | 1 - inc/Config/DataSource/HttpDataSource.php | 14 +--------- inc/ExampleApi/ExampleApi.php | 1 + .../Airtable/AirtableDataSource.php | 3 ++- inc/Integrations/GitHub/GitHubDataSource.php | 3 ++- .../Google/Sheets/GoogleSheetsDataSource.php | 3 ++- .../SalesforceD2C/SalesforceD2CDataSource.php | 3 ++- .../Shopify/ShopifyDataSource.php | 3 ++- .../DataSource/DataSourceConfigManager.php | 27 +++++++++---------- inc/Validation/ConfigSchemas.php | 2 +- .../airtable/AirtableSettings.tsx | 2 +- .../google-sheets/GoogleSheetsSettings.tsx | 4 +-- src/data-sources/http/HttpSettings.tsx | 2 +- .../salesforce-d2c/SalesforceD2CSettings.tsx | 2 +- src/data-sources/shopify/ShopifySettings.tsx | 2 +- src/data-sources/types.ts | 4 +-- tests/inc/Config/HttpDataSourceTest.php | 1 + tests/inc/Editor/ConfigStoreTest.php | 1 + tests/inc/Functions/FunctionsTest.php | 1 + .../Airtable/AirtableDataSourceTest.php | 1 + .../Sheets/GoogleSheetsDataSourceTest.php | 1 + tests/inc/Mocks/MockDataSource.php | 1 + .../DataSource/ConstantConfigStoreTest.php | 1 + .../DataSourceConfigManagerTest.php | 23 +++++++++------- tests/inc/Telemetry/TracksTelemetryTest.php | 2 ++ tests/inc/WpdbStorage/DataSourceCrudTest.php | 6 +++++ tests/integration/RDBTestCase.php | 2 ++ .../blocks/BlockWithNestedConfigTest.php | 1 + 35 files changed, 72 insertions(+), 52 deletions(-) diff --git a/example/airtable/events/register.php b/example/airtable/events/register.php index 7ffb015fe..a731779c2 100644 --- a/example/airtable/events/register.php +++ b/example/airtable/events/register.php @@ -17,6 +17,7 @@ function register_airtable_events_block(): void { // Define the data source $airtable_data_source = AirtableDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'access_token' => $access_token, 'base' => [ 'id' => $base_id, diff --git a/example/airtable/leaflet-map/build/blocks/leaflet-map/render.php b/example/airtable/leaflet-map/build/blocks/leaflet-map/render.php index 05407fe2f..21f3621d8 100644 --- a/example/airtable/leaflet-map/build/blocks/leaflet-map/render.php +++ b/example/airtable/leaflet-map/build/blocks/leaflet-map/render.php @@ -42,6 +42,7 @@ $map_data_source = AirtableDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'access_token' => $access_token, 'base' => [ 'id' => $base_id, diff --git a/example/airtable/leaflet-map/src/blocks/leaflet-map/render.php b/example/airtable/leaflet-map/src/blocks/leaflet-map/render.php index 05407fe2f..21f3621d8 100644 --- a/example/airtable/leaflet-map/src/blocks/leaflet-map/render.php +++ b/example/airtable/leaflet-map/src/blocks/leaflet-map/render.php @@ -42,6 +42,7 @@ $map_data_source = AirtableDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'access_token' => $access_token, 'base' => [ 'id' => $base_id, diff --git a/example/github/markdown-file/register.php b/example/github/markdown-file/register.php index 0dfffd95f..b3f2755ba 100644 --- a/example/github/markdown-file/register.php +++ b/example/github/markdown-file/register.php @@ -11,6 +11,7 @@ function register_github_file_as_html_block(): void { // Note: This repository is public, so GitHub's API does not require authorization. $service_config = [ + '__version' => 1, 'display_name' => 'Automattic/remote-data-blocks#trunk', 'ref' => 'trunk', 'repo_owner' => 'Automattic', diff --git a/example/google-sheets/westeros-houses/register.php b/example/google-sheets/westeros-houses/register.php index 48b31919f..e54803729 100644 --- a/example/google-sheets/westeros-houses/register.php +++ b/example/google-sheets/westeros-houses/register.php @@ -18,6 +18,7 @@ function register_google_sheets_westeros_houses_blocks(): void { $westeros_houses_data_source = GoogleSheetsDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'credentials' => $credentials, 'display_name' => 'Westeros Houses', 'spreadsheet' => [ diff --git a/example/rest-api/art-institute/art-institute.php b/example/rest-api/art-institute/art-institute.php index 6abd6a44a..f0e9c4188 100644 --- a/example/rest-api/art-institute/art-institute.php +++ b/example/rest-api/art-institute/art-institute.php @@ -19,6 +19,7 @@ function register_aic_block(): void { $aic_data_source = HttpDataSource::from_array([ 'service_config' => [ + '__version' => 1, 'display_name' => 'Art Institute of Chicago', 'endpoint' => 'https://api.artic.edu/api/v1/artworks', 'request_headers' => [ diff --git a/example/shopify/product/register.php b/example/shopify/product/register.php index e1c5b088c..2b5caa5f6 100644 --- a/example/shopify/product/register.php +++ b/example/shopify/product/register.php @@ -15,6 +15,7 @@ function register_shopify_block(): void { $shopify_data_source = ShopifyDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'access_token' => $access_token, 'display_name' => 'Shopify Example', 'store_name' => $store_slug, diff --git a/inc/Config/ArraySerializable.php b/inc/Config/ArraySerializable.php index dd7537c6e..ef45ab21a 100644 --- a/inc/Config/ArraySerializable.php +++ b/inc/Config/ArraySerializable.php @@ -29,7 +29,6 @@ protected function get_or_call_from_config( string $property_name, mixed ...$cal * @inheritDoc */ final public static function from_array( array $config, ?ValidatorInterface $validator = null ): static|WP_Error { - /* check if class exists and implements ArraySerializableInterface */ $subclass = static::get_implementor( $config ); if ( null !== $subclass ) { return $subclass::from_array( $config, $validator ); diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index d1d63eb46..1be71bde3 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -15,7 +15,7 @@ */ class HttpDataSource extends ArraySerializable implements HttpDataSourceInterface { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_GENERIC_HTTP_SERVICE; - protected const CONFIG_SCHEMA_VERSION = 1; + protected const SERVICE_SCHEMA_VERSION = 1; final public function get_display_name(): string { return $this->config['display_name']; @@ -37,10 +37,6 @@ final public function get_service_name(): string { return static::SERVICE_NAME; } - final public function get_config_schema_version(): int { - return static::CONFIG_SCHEMA_VERSION; - } - /** * @inheritDoc * @@ -63,7 +59,6 @@ public static function preprocess_config( array $config ): array|WP_Error { 'service' => static::SERVICE_NAME, 'service_config' => $service_config, 'uuid' => $config['uuid'] ?? null, - '__version' => static::CONFIG_SCHEMA_VERSION, ] ); } @@ -89,7 +84,6 @@ final public function to_array(): array { 'service' => static::SERVICE_NAME, 'service_config' => $this->config['service_config'], 'uuid' => $this->config['uuid'], - '__version' => static::CONFIG_SCHEMA_VERSION, ]; } @@ -116,12 +110,6 @@ protected static function map_service_config( array $service_config ): array { * @inheritDoc */ public static function migrate_config( array $config ): array|WP_Error { - // Migration: Move __version from service_config to the root level. - if ( isset( $config['service_config']['__version'] ) ) { - $config['__version'] = $config['service_config']['__version']; - unset( $config['service_config']['__version'] ); - } - return $config; } } diff --git a/inc/ExampleApi/ExampleApi.php b/inc/ExampleApi/ExampleApi.php index 8c94a8554..4f297326e 100644 --- a/inc/ExampleApi/ExampleApi.php +++ b/inc/ExampleApi/ExampleApi.php @@ -41,6 +41,7 @@ public static function register_remote_data_block(): void { $data_source = HttpDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'display_name' => 'Example API (Conference Event)', 'endpoint' => 'https://example.com/api/v1', // dummy URL ], diff --git a/inc/Integrations/Airtable/AirtableDataSource.php b/inc/Integrations/Airtable/AirtableDataSource.php index b67148559..d37f60035 100644 --- a/inc/Integrations/Airtable/AirtableDataSource.php +++ b/inc/Integrations/Airtable/AirtableDataSource.php @@ -7,10 +7,11 @@ class AirtableDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE; - protected const CONFIG_SCHEMA_VERSION = 1; + protected const SERVICE_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ + '__version' => Types::integer(), 'access_token' => Types::string(), 'base' => Types::object( [ 'id' => Types::string(), diff --git a/inc/Integrations/GitHub/GitHubDataSource.php b/inc/Integrations/GitHub/GitHubDataSource.php index 7fe29f2f3..f67406fbd 100644 --- a/inc/Integrations/GitHub/GitHubDataSource.php +++ b/inc/Integrations/GitHub/GitHubDataSource.php @@ -7,10 +7,11 @@ class GitHubDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_GITHUB_SERVICE; - protected const CONFIG_SCHEMA_VERSION = 1; + protected const SERVICE_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ + '__version' => Types::integer(), 'display_name' => Types::string(), 'repo_owner' => Types::string(), 'repo_name' => Types::string(), diff --git a/inc/Integrations/Google/Sheets/GoogleSheetsDataSource.php b/inc/Integrations/Google/Sheets/GoogleSheetsDataSource.php index 188151526..9c7c6977c 100644 --- a/inc/Integrations/Google/Sheets/GoogleSheetsDataSource.php +++ b/inc/Integrations/Google/Sheets/GoogleSheetsDataSource.php @@ -8,10 +8,11 @@ class GoogleSheetsDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_GOOGLE_SHEETS_SERVICE; - protected const CONFIG_SCHEMA_VERSION = 1; + protected const SERVICE_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ + '__version' => Types::integer(), 'credentials' => Types::object( [ 'type' => Types::string(), 'project_id' => Types::string(), diff --git a/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php b/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php index fbc7a31d0..ea75d2f16 100644 --- a/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php +++ b/inc/Integrations/SalesforceD2C/SalesforceD2CDataSource.php @@ -10,10 +10,11 @@ class SalesforceD2CDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_SALESFORCE_D2C_SERVICE; - protected const CONFIG_SCHEMA_VERSION = 1; + protected const SERVICE_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ + '__version' => Types::integer(), 'display_name' => Types::string(), 'client_id' => Types::string(), 'client_secret' => Types::string(), diff --git a/inc/Integrations/Shopify/ShopifyDataSource.php b/inc/Integrations/Shopify/ShopifyDataSource.php index 163f96d70..4141d41f8 100644 --- a/inc/Integrations/Shopify/ShopifyDataSource.php +++ b/inc/Integrations/Shopify/ShopifyDataSource.php @@ -10,10 +10,11 @@ class ShopifyDataSource extends HttpDataSource { protected const SERVICE_NAME = REMOTE_DATA_BLOCKS_SHOPIFY_SERVICE; - protected const CONFIG_SCHEMA_VERSION = 1; + protected const SERVICE_SCHEMA_VERSION = 1; protected static function get_service_config_schema(): array { return Types::object( [ + '__version' => Types::integer(), 'access_token' => Types::skip_sanitize( Types::string() ), 'display_name' => Types::string(), 'enable_blocks' => Types::nullable( Types::boolean() ), diff --git a/inc/Store/DataSource/DataSourceConfigManager.php b/inc/Store/DataSource/DataSourceConfigManager.php index e25466063..32527a132 100644 --- a/inc/Store/DataSource/DataSourceConfigManager.php +++ b/inc/Store/DataSource/DataSourceConfigManager.php @@ -60,19 +60,18 @@ function ( array $acc, array $item ) { /** * Get all data sources from all origins with optional filters. - * + * * Supported filters: * - service: Filter by service name (e.g. 'airtable', 'google-sheets', 'shopify') * - enable_blocks: Filter by blocks enabled status (false matches with null/false and true matches with true) - * + * * Passing an unsupported filter key will return an error. - * + * * @param array{ * service?: string, * enable_blocks?: bool * } $filters Optional filters to apply to the results. * @return array, @@ -90,7 +89,7 @@ public static function get_all( array $filters = [] ): array|WP_Error { /** * De-duplicate configs. - * + * * Precedence (lowest to highest): * - Code-configured data sources * - Constant-configured data sources @@ -153,7 +152,7 @@ function ( array $config ) use ( $filters ): bool { /** * Get a data source by its UUID. - * + * * @param string $uuid The UUID of the data source to get. * @return array{ * uuid: string, @@ -169,9 +168,9 @@ function ( array $config ) use ( $filters ): bool { public static function get( string $uuid ): array|WP_Error { $from_constant = ConstantConfigStore::get_config_by_uuid( $uuid ); if ( ! is_wp_error( $from_constant ) ) { - return array_merge( - $from_constant, - [ 'config_source' => self::CONFIG_SOURCE_CONSTANT ] + return array_merge( + $from_constant, + [ 'config_source' => self::CONFIG_SOURCE_CONSTANT ] ); } @@ -192,7 +191,7 @@ public static function get( string $uuid ): array|WP_Error { /** * Create a new data source. - * + * * @param array $config The configuration for the new data source. * @return array{ * uuid: string, @@ -216,7 +215,7 @@ public static function create( array $config ): array|WP_Error { /** * Update a data source. - * + * * @param string $uuid The UUID of the data source to update. * @param array $config The new configuration for the data source. * @return array{ @@ -232,8 +231,8 @@ public static function create( array $config ): array|WP_Error { */ public static function update( string $uuid, array $config ): array|WP_Error { if ( - isset( $config['config_source'] ) && - ! in_array( $config['config_source'], self::MUTABLE_CONFIG_SOURCES, true ) + isset( $config['config_source'] ) && + ! in_array( $config['config_source'], self::MUTABLE_CONFIG_SOURCES, true ) ) { /** * Only storage-configured data sources are mutable. @@ -255,7 +254,7 @@ public static function update( string $uuid, array $config ): array|WP_Error { /** * Delete a data source. - * + * * @param string $uuid The UUID of the data source to delete. * @return true|WP_Error True on success, WP_Error on failure. */ diff --git a/inc/Validation/ConfigSchemas.php b/inc/Validation/ConfigSchemas.php index 18990fc7a..45c5b2a4d 100644 --- a/inc/Validation/ConfigSchemas.php +++ b/inc/Validation/ConfigSchemas.php @@ -121,7 +121,6 @@ private static function generate_graphql_query_config_schema(): array { private static function generate_http_data_source_config_schema(): array { return Types::object( [ - '__version' => Types::integer(), 'display_name' => Types::string(), 'endpoint' => Types::string(), 'image_url' => Types::nullable( Types::image_url() ), @@ -139,6 +138,7 @@ private static function generate_http_data_source_config_schema(): array { private static function generate_http_data_source_service_config_schema(): array { return Types::object( [ + '__version' => Types::integer(), 'auth' => Types::nullable( Types::object( [ 'add_to' => Types::nullable( Types::enum( 'header', 'query' ) ), diff --git a/src/data-sources/airtable/AirtableSettings.tsx b/src/data-sources/airtable/AirtableSettings.tsx index c3262f68a..d6c8b845d 100644 --- a/src/data-sources/airtable/AirtableSettings.tsx +++ b/src/data-sources/airtable/AirtableSettings.tsx @@ -43,6 +43,7 @@ export const AirtableSettings = ( { const { state, handleOnChange, validState } = useForm< AirtableServiceConfig >( { initialValues: config?.service_config ?? { + __version: SERVICE_CONFIG_VERSION, enable_blocks: true, }, } ); @@ -77,7 +78,6 @@ export const AirtableSettings = ( { service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, - __version: SERVICE_CONFIG_VERSION, }; return onSave( airtableConfig, mode ); diff --git a/src/data-sources/google-sheets/GoogleSheetsSettings.tsx b/src/data-sources/google-sheets/GoogleSheetsSettings.tsx index a25d04fa1..1867010ad 100644 --- a/src/data-sources/google-sheets/GoogleSheetsSettings.tsx +++ b/src/data-sources/google-sheets/GoogleSheetsSettings.tsx @@ -4,7 +4,7 @@ import { __ } from '@wordpress/i18n'; import { DataSourceForm } from '@/data-sources/components/DataSourceForm'; import { FieldsSelection } from '@/data-sources/components/FieldsSelection'; -import { ConfigSource, GOOGLE_SHEETS_API_SCOPES } from '@/data-sources/constants'; +import { GOOGLE_SHEETS_API_SCOPES, ConfigSource } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; import { useGoogleSheetsWithFields, @@ -61,6 +61,7 @@ export const GoogleSheetsSettings = ( { const { state, errors, handleOnChange, validState } = useForm< GoogleSheetsServiceConfig >( { initialValues: config?.service_config ?? { + __version: SERVICE_CONFIG_VERSION, enable_blocks: true, }, validationRules, @@ -97,7 +98,6 @@ export const GoogleSheetsSettings = ( { service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, - __version: SERVICE_CONFIG_VERSION, }; return onSave( data, mode ); diff --git a/src/data-sources/http/HttpSettings.tsx b/src/data-sources/http/HttpSettings.tsx index cf4f87eaa..ab4f50fdd 100644 --- a/src/data-sources/http/HttpSettings.tsx +++ b/src/data-sources/http/HttpSettings.tsx @@ -35,6 +35,7 @@ function computeAuthState( updatedAuth: Partial< HttpServiceConfig[ 'auth' ] > ) export const HttpSettings = ( { mode, uuid, config }: SettingsComponentProps< HttpConfig > ) => { const { state, handleOnChange, validState } = useForm< HttpServiceConfig >( { initialValues: config?.service_config ?? { + __version: SERVICE_CONFIG_VERSION, auth: computeAuthState( {} ), }, } ); @@ -64,7 +65,6 @@ export const HttpSettings = ( { mode, uuid, config }: SettingsComponentProps< Ht service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, - __version: SERVICE_CONFIG_VERSION, }; return onSave( httpConfig, mode ); diff --git a/src/data-sources/salesforce-d2c/SalesforceD2CSettings.tsx b/src/data-sources/salesforce-d2c/SalesforceD2CSettings.tsx index 3fc64c7ee..76671f6fc 100644 --- a/src/data-sources/salesforce-d2c/SalesforceD2CSettings.tsx +++ b/src/data-sources/salesforce-d2c/SalesforceD2CSettings.tsx @@ -62,6 +62,7 @@ export const SalesforceD2CSettings = ( { const { state, handleOnChange, validState } = useForm< SalesforceD2CServiceConfig >( { initialValues: config?.service_config ?? { + __version: SERVICE_CONFIG_VERSION, enable_blocks: true, }, validationRules, @@ -90,7 +91,6 @@ export const SalesforceD2CSettings = ( { service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, - __version: SERVICE_CONFIG_VERSION, }; return onSave( data, mode ); diff --git a/src/data-sources/shopify/ShopifySettings.tsx b/src/data-sources/shopify/ShopifySettings.tsx index b72d793bc..e05d83298 100644 --- a/src/data-sources/shopify/ShopifySettings.tsx +++ b/src/data-sources/shopify/ShopifySettings.tsx @@ -22,6 +22,7 @@ export const ShopifySettings = ( { const { state, handleOnChange, validState } = useForm< ShopifyServiceConfig >( { initialValues: config?.service_config ?? { + __version: SERVICE_CONFIG_VERSION, enable_blocks: true, }, } ); @@ -60,7 +61,6 @@ export const ShopifySettings = ( { service_config: validState, uuid: uuid ?? null, config_source: ConfigSource.STORAGE, - __version: SERVICE_CONFIG_VERSION, }; return onSave( data, mode ); diff --git a/src/data-sources/types.ts b/src/data-sources/types.ts index 8cc324ccf..1f6d97b10 100644 --- a/src/data-sources/types.ts +++ b/src/data-sources/types.ts @@ -1,4 +1,4 @@ -import { ConfigSource, SUPPORTED_SERVICES } from '@/data-sources/constants'; +import { SUPPORTED_SERVICES, ConfigSource } from '@/data-sources/constants'; import { HttpAuth } from '@/data-sources/http/types'; import { StringIdName } from '@/types/common'; import { GoogleServiceAccountKey } from '@/types/google'; @@ -6,6 +6,7 @@ import { GoogleServiceAccountKey } from '@/types/google'; export type DataSourceType = ( typeof SUPPORTED_SERVICES )[ number ]; interface BaseServiceConfig extends Record< string, unknown > { + __version: number; display_name: string; enable_blocks: boolean; } @@ -13,7 +14,6 @@ interface BaseDataSourceConfig< ServiceName extends DataSourceType, ServiceConfig extends BaseServiceConfig > { - __version: number; service: ServiceName; service_config: ServiceConfig; uuid: string | null; diff --git a/tests/inc/Config/HttpDataSourceTest.php b/tests/inc/Config/HttpDataSourceTest.php index 860752ac7..a50d4499b 100644 --- a/tests/inc/Config/HttpDataSourceTest.php +++ b/tests/inc/Config/HttpDataSourceTest.php @@ -11,6 +11,7 @@ class HttpDataSourceTest extends TestCase { public function testGetServiceMethodCannotBeOverriddenl(): void { $config = [ 'service_config' => [ + '__version' => 1, 'display_name' => 'Mock Data Source', 'endpoint' => 'http://example.com', ], diff --git a/tests/inc/Editor/ConfigStoreTest.php b/tests/inc/Editor/ConfigStoreTest.php index f829b166a..ffd99caea 100644 --- a/tests/inc/Editor/ConfigStoreTest.php +++ b/tests/inc/Editor/ConfigStoreTest.php @@ -28,6 +28,7 @@ public function testGetDataSourceReturnsDataSource(): void { 'display' => HttpQuery::from_array( [ 'data_source' => AirtableDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'access_token' => 'token', 'base' => [ 'id' => 'foo', diff --git a/tests/inc/Functions/FunctionsTest.php b/tests/inc/Functions/FunctionsTest.php index 5ff02f807..de2e4be33 100644 --- a/tests/inc/Functions/FunctionsTest.php +++ b/tests/inc/Functions/FunctionsTest.php @@ -79,6 +79,7 @@ public function testRegisterBlockWithNestedConfig(): void { 'data_source' => [ '__class' => 'RemoteDataBlocks\Tests\Mocks\MockDataSource', 'service_config' => [ + '__version' => 1, 'display_name' => 'Mock Data Source', 'endpoint' => 'https://example.com/api', ], diff --git a/tests/inc/Integrations/Airtable/AirtableDataSourceTest.php b/tests/inc/Integrations/Airtable/AirtableDataSourceTest.php index 1f1488677..99e51af40 100644 --- a/tests/inc/Integrations/Airtable/AirtableDataSourceTest.php +++ b/tests/inc/Integrations/Airtable/AirtableDataSourceTest.php @@ -13,6 +13,7 @@ protected function setUp(): void { $this->data_source = AirtableDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'access_token' => 'test_access_token', 'display_name' => 'Airtable Source', 'base' => [ diff --git a/tests/inc/Integrations/Google/Sheets/GoogleSheetsDataSourceTest.php b/tests/inc/Integrations/Google/Sheets/GoogleSheetsDataSourceTest.php index c8259e35e..119f63050 100644 --- a/tests/inc/Integrations/Google/Sheets/GoogleSheetsDataSourceTest.php +++ b/tests/inc/Integrations/Google/Sheets/GoogleSheetsDataSourceTest.php @@ -33,6 +33,7 @@ protected function setUp(): void { $this->data_source = GoogleSheetsDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'display_name' => 'Google Sheets Source', 'credentials' => self::MOCK_CREDENTIALS, 'spreadsheet' => [ diff --git a/tests/inc/Mocks/MockDataSource.php b/tests/inc/Mocks/MockDataSource.php index d63b1957f..11b519444 100644 --- a/tests/inc/Mocks/MockDataSource.php +++ b/tests/inc/Mocks/MockDataSource.php @@ -11,6 +11,7 @@ class MockDataSource extends HttpDataSource { public const MOCK_CONFIG = [ 'service' => 'mock', 'service_config' => [ + '__version' => 1, 'display_name' => 'Mock Data Source', 'endpoint' => 'https://example.com/api', 'request_headers' => [ diff --git a/tests/inc/Store/DataSource/ConstantConfigStoreTest.php b/tests/inc/Store/DataSource/ConstantConfigStoreTest.php index 518e7f233..0d1d473d2 100644 --- a/tests/inc/Store/DataSource/ConstantConfigStoreTest.php +++ b/tests/inc/Store/DataSource/ConstantConfigStoreTest.php @@ -30,6 +30,7 @@ protected function setUp(): void { 'uuid' => self::TEST_UUID, 'service' => self::TEST_SERVICE, 'service_config' => [ + '__version' => 1, 'store_name' => 'test-store', 'access_token' => 'gy56yrtyrtt', 'display_name' => 'Test Store', diff --git a/tests/inc/Store/DataSource/DataSourceConfigManagerTest.php b/tests/inc/Store/DataSource/DataSourceConfigManagerTest.php index dd01e6cb4..06e717dfe 100644 --- a/tests/inc/Store/DataSource/DataSourceConfigManagerTest.php +++ b/tests/inc/Store/DataSource/DataSourceConfigManagerTest.php @@ -33,6 +33,7 @@ protected function setUp(): void { 'uuid' => self::AIRTABLE_UUID, 'service' => self::AIRTABLE_SERVICE, 'service_config' => [ + '__version' => 1, 'enable_blocks' => true, 'display_name' => 'Test Airtable', 'access_token' => 'test.airtable.access-token', @@ -66,6 +67,7 @@ protected function setUp(): void { 'uuid' => self::SHEETS_UUID, 'service' => self::SHEETS_SERVICE, 'service_config' => [ + '__version' => 1, 'enable_blocks' => true, 'display_name' => 'Test Google Sheets', 'credentials' => [ @@ -107,6 +109,7 @@ protected function setUp(): void { 'uuid' => self::SHOPIFY_UUID, 'service' => self::SHOPIFY_SERVICE, 'service_config' => [ + '__version' => 1, 'access_token' => 'shpat_abc123def456ghi789jkl0', 'store_name' => 'test-shopify-store', 'display_name' => 'Test Shopify Store', @@ -135,7 +138,7 @@ public function testGetAllReturnsConfigsFromAllSources(): void { ->andReturn( [ $this->shopify_code_config ] ); $result = DataSourceConfigManager::get_all(); - + $this->assertCount( 3, $result ); $this->assertContains( $this->airtable_storage_config, $result ); $this->assertContains( $this->sheets_constant_config, $result ); @@ -214,7 +217,7 @@ public function testUpdateReturnsUpdatedConfig(): void { } public function testUpdateReturnsErrorForImmutableConfig(): void { - $immutable_config = array_merge( + $immutable_config = array_merge( $this->sheets_constant_config, [ 'config_source' => DataSourceConfigManager::CONFIG_SOURCE_CONSTANT ] ); @@ -293,7 +296,7 @@ public function testGetAllHandlesConfigPrecedenceCorrectly(): void { // Should only get one config since they share the same UUID $this->assertCount( 1, $result ); - + // Storage should win due to highest precedence $this->assertContains( $storage_sheets, $result ); $this->assertNotContains( $constant_sheets, $result ); @@ -314,7 +317,7 @@ public function testGetAllWithServiceFilter(): void { ->andReturn( [ $this->shopify_code_config ] ); $result = DataSourceConfigManager::get_all( [ 'service' => self::AIRTABLE_SERVICE ] ); - + $this->assertCount( 1, $result ); $this->assertContains( $this->airtable_storage_config, $result ); } @@ -338,7 +341,7 @@ public function testGetAllWithEnableBlocksFilterTrue(): void { ->andReturn( [ $this->shopify_code_config ] ); $result = DataSourceConfigManager::get_all( [ 'enable_blocks' => true ] ); - + $this->assertCount( 2, $result ); $this->assertContains( $this->airtable_storage_config, $result ); $this->assertContains( $this->shopify_code_config, $result ); @@ -363,7 +366,7 @@ public function testGetAllWithEnableBlocksFilterFalse(): void { ->andReturn( [ $shopify_config_blocks_unset ] ); $result = DataSourceConfigManager::get_all( [ 'enable_blocks' => false ] ); - + $this->assertCount( 1, $result ); $this->assertContains( $shopify_config_blocks_unset, $result ); } @@ -385,7 +388,7 @@ public function testGetAllWithMultipleFilters(): void { 'service' => self::AIRTABLE_SERVICE, 'enable_blocks' => true, ] ); - + $this->assertCount( 1, $result ); $this->assertContains( $this->airtable_storage_config, $result ); } @@ -405,7 +408,7 @@ public function testGetAllReturnsEmptyWhenServiceDoesNotMatch(): void { ->andReturn( [] ); $result = DataSourceConfigManager::get_all( [ 'service' => self::AIRTABLE_SERVICE ] ); - + $this->assertCount( 0, $result ); $this->assertEmpty( $result ); } @@ -435,7 +438,7 @@ public function testGetAllReturnsEmptyWhenEnableBlocksDoesNotMatch(): void { ->andReturn( [ $shopify_config ] ); $result = DataSourceConfigManager::get_all( [ 'enable_blocks' => false ] ); - + $this->assertCount( 0, $result ); $this->assertEmpty( $result ); } @@ -457,7 +460,7 @@ public function testGetAllReturnsEmptyWhenMultipleFiltersDoNotMatch(): void { 'service' => self::AIRTABLE_SERVICE, 'enable_blocks' => false, ] ); - + $this->assertCount( 0, $result ); $this->assertEmpty( $result ); } diff --git a/tests/inc/Telemetry/TracksTelemetryTest.php b/tests/inc/Telemetry/TracksTelemetryTest.php index c6c3ff145..cd3591970 100644 --- a/tests/inc/Telemetry/TracksTelemetryTest.php +++ b/tests/inc/Telemetry/TracksTelemetryTest.php @@ -200,6 +200,7 @@ public function testTrackRemoteDataBlocksUsageDoesTrackEventIfPostContentHaveRem 'display' => HttpQuery::from_array( [ 'data_source' => ShopifyDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'access_token' => 'token', 'display_name' => 'Shopify Source', 'store_name' => 'B. Walton', @@ -215,6 +216,7 @@ public function testTrackRemoteDataBlocksUsageDoesTrackEventIfPostContentHaveRem 'display' => HttpQuery::from_array( [ 'data_source' => HttpDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'display_name' => 'HTTP Source', 'endpoint' => 'https://example.com/api/v1', ], diff --git a/tests/inc/WpdbStorage/DataSourceCrudTest.php b/tests/inc/WpdbStorage/DataSourceCrudTest.php index 523a07e06..da67e9ac6 100644 --- a/tests/inc/WpdbStorage/DataSourceCrudTest.php +++ b/tests/inc/WpdbStorage/DataSourceCrudTest.php @@ -16,6 +16,7 @@ public function test_register_new_data_source_with_valid_input(): void { $valid_source = [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ + '__version' => 1, 'access_token' => 'valid_token', 'base' => [ 'id' => 'base_id', @@ -58,6 +59,7 @@ public function test_get_configs(): void { $source1 = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ + '__version' => 1, 'access_token' => 'token1', 'display_name' => 'Airtable Source', 'base' => [ @@ -72,6 +74,7 @@ public function test_get_configs(): void { $source2 = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_SHOPIFY_SERVICE, 'service_config' => [ + '__version' => 1, 'access_token' => 'token2', 'display_name' => 'Shopify Source', 'store_name' => 'mystore', @@ -97,6 +100,7 @@ public function test_get_item_by_uuid_with_valid_uuid(): void { $source = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ + '__version' => 1, 'access_token' => 'token1', 'base' => [ 'id' => 'base_id1', @@ -124,6 +128,7 @@ public function test_update_item_by_uuid_with_valid_uuid(): void { $source = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ + '__version' => 1, 'access_token' => 'token1', 'base' => [ 'id' => 'base_id1', @@ -153,6 +158,7 @@ public function test_delete_item_by_uuid(): void { $source = DataSourceCrud::create_config( [ 'service' => REMOTE_DATA_BLOCKS_AIRTABLE_SERVICE, 'service_config' => [ + '__version' => 1, 'access_token' => 'token1', 'base' => [ 'id' => 'base_id1', diff --git a/tests/integration/RDBTestCase.php b/tests/integration/RDBTestCase.php index db5d63f70..fecf4f933 100644 --- a/tests/integration/RDBTestCase.php +++ b/tests/integration/RDBTestCase.php @@ -16,6 +16,7 @@ protected function register_mocked_data_block( string $block_title, array $api_r $test_data_source = HttpDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'display_name' => 'Test API', // Mocked query runner will not actually make a request to the endpoint URL. @@ -45,6 +46,7 @@ protected function register_failed_query_data_block( string $block_title ): void $test_data_source = HttpDataSource::from_array( [ 'service_config' => [ + '__version' => 1, 'display_name' => 'Test Failing API', // Mocked query runner will not actually make a request to the endpoint URL. diff --git a/tests/integration/blocks/BlockWithNestedConfigTest.php b/tests/integration/blocks/BlockWithNestedConfigTest.php index 70ca57791..4c232985f 100644 --- a/tests/integration/blocks/BlockWithNestedConfigTest.php +++ b/tests/integration/blocks/BlockWithNestedConfigTest.php @@ -20,6 +20,7 @@ public function testBlockWithNestedConfigRenders(): void { 'data_source' => [ '__class' => 'RemoteDataBlocks\\Config\\DataSource\\HttpDataSource', 'service_config' => [ + '__version' => 1, 'display_name' => 'Test API', // Mocked query runner will not actually make a request to the endpoint URL. 'endpoint' => 'https://example.com/not-a-real-api', From 4e4b92b089a91b2f3a1ae38ce1e1952a3b599245 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 5 Mar 2025 10:28:57 +1100 Subject: [PATCH 15/19] Revert "Fix the linting issues" This reverts commit 37979fcfcc119e0f27213b8c1248e1374ee6d8eb. --- src/data-sources/http/HttpSettings.tsx | 2 +- src/data-sources/shopify/ShopifySettings.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data-sources/http/HttpSettings.tsx b/src/data-sources/http/HttpSettings.tsx index ab4f50fdd..377345639 100644 --- a/src/data-sources/http/HttpSettings.tsx +++ b/src/data-sources/http/HttpSettings.tsx @@ -1,7 +1,6 @@ import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { DataSourceForm } from '../components/DataSourceForm'; import { HttpAuthSettingsInput } from '@/data-sources/components/HttpAuthSettingsInput'; import { ConfigSource } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; @@ -9,6 +8,7 @@ import { HttpAuth } from '@/data-sources/http/types'; import { HttpConfig, HttpServiceConfig, SettingsComponentProps } from '@/data-sources/types'; import { useForm } from '@/hooks/useForm'; import HttpIcon from '@/settings/icons/HttpIcon'; +import { DataSourceForm } from '../components/DataSourceForm'; const SERVICE_CONFIG_VERSION = 1; diff --git a/src/data-sources/shopify/ShopifySettings.tsx b/src/data-sources/shopify/ShopifySettings.tsx index e05d83298..ce07f71dc 100644 --- a/src/data-sources/shopify/ShopifySettings.tsx +++ b/src/data-sources/shopify/ShopifySettings.tsx @@ -2,7 +2,6 @@ import { TextControl } from '@wordpress/components'; import { useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { DataSourceForm } from '../components/DataSourceForm'; import PasswordInputControl from '@/data-sources/components/PasswordInputControl'; import { ConfigSource } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; @@ -10,6 +9,7 @@ import { useShopifyShopName } from '@/data-sources/hooks/useShopify'; import { SettingsComponentProps, ShopifyConfig, ShopifyServiceConfig } from '@/data-sources/types'; import { useForm } from '@/hooks/useForm'; import { ShopifyIcon, ShopifyIconWithText } from '@/settings/icons/ShopifyIcon'; +import { DataSourceForm } from '../components/DataSourceForm'; const SERVICE_CONFIG_VERSION = 1; From 8090c4740b65f4f9cec8f782cf5894eb902806d5 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 5 Mar 2025 10:41:26 +1100 Subject: [PATCH 16/19] Revert what wasn't revert with the commit revert --- src/data-sources/http/HttpSettings.tsx | 2 +- src/data-sources/shopify/ShopifySettings.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data-sources/http/HttpSettings.tsx b/src/data-sources/http/HttpSettings.tsx index 377345639..ab4f50fdd 100644 --- a/src/data-sources/http/HttpSettings.tsx +++ b/src/data-sources/http/HttpSettings.tsx @@ -1,6 +1,7 @@ import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; +import { DataSourceForm } from '../components/DataSourceForm'; import { HttpAuthSettingsInput } from '@/data-sources/components/HttpAuthSettingsInput'; import { ConfigSource } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; @@ -8,7 +9,6 @@ import { HttpAuth } from '@/data-sources/http/types'; import { HttpConfig, HttpServiceConfig, SettingsComponentProps } from '@/data-sources/types'; import { useForm } from '@/hooks/useForm'; import HttpIcon from '@/settings/icons/HttpIcon'; -import { DataSourceForm } from '../components/DataSourceForm'; const SERVICE_CONFIG_VERSION = 1; diff --git a/src/data-sources/shopify/ShopifySettings.tsx b/src/data-sources/shopify/ShopifySettings.tsx index ce07f71dc..e05d83298 100644 --- a/src/data-sources/shopify/ShopifySettings.tsx +++ b/src/data-sources/shopify/ShopifySettings.tsx @@ -2,6 +2,7 @@ import { TextControl } from '@wordpress/components'; import { useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +import { DataSourceForm } from '../components/DataSourceForm'; import PasswordInputControl from '@/data-sources/components/PasswordInputControl'; import { ConfigSource } from '@/data-sources/constants'; import { useDataSources } from '@/data-sources/hooks/useDataSources'; @@ -9,7 +10,6 @@ import { useShopifyShopName } from '@/data-sources/hooks/useShopify'; import { SettingsComponentProps, ShopifyConfig, ShopifyServiceConfig } from '@/data-sources/types'; import { useForm } from '@/hooks/useForm'; import { ShopifyIcon, ShopifyIconWithText } from '@/settings/icons/ShopifyIcon'; -import { DataSourceForm } from '../components/DataSourceForm'; const SERVICE_CONFIG_VERSION = 1; From f1009dd385607c7a351e8970bfa94d28fc971f2c Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 5 Mar 2025 11:31:06 +1100 Subject: [PATCH 17/19] Add tests for migration --- tests/inc/Config/HttpDataSourceTest.php | 25 ++++++++++++++++++++++++- tests/inc/Mocks/MockDataSource.php | 12 ++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/inc/Config/HttpDataSourceTest.php b/tests/inc/Config/HttpDataSourceTest.php index a50d4499b..2c698ad49 100644 --- a/tests/inc/Config/HttpDataSourceTest.php +++ b/tests/inc/Config/HttpDataSourceTest.php @@ -8,7 +8,7 @@ class HttpDataSourceTest extends TestCase { private MockDataSource $http_data_source; - public function testGetServiceMethodCannotBeOverriddenl(): void { + public function testGetServiceMethodCannotBeOverridden(): void { $config = [ 'service_config' => [ '__version' => 1, @@ -26,4 +26,27 @@ public function testGetServiceMethodReturnsCorrectValue(): void { $this->assertEquals( 'generic-http', $this->http_data_source->get_service_name() ); } + + public function testMigrateConfigMethodCanBeOverridden_user_id_is_added_to_config(): void { + // Migrate config should add a testUserId to the config if it's not already set. + $this->http_data_source = MockDataSource::create(); + + $this->assertEquals( '123', $this->http_data_source->to_array()['service_config']['testUserId'] ); + } + + public function testMigrateConfigMethodCanBeOverridden_user_id_is_not_added_to_config(): void { + // Migrate config should not add a testUserId to the config if it's already set. + $config = [ + 'service_config' => [ + '__version' => 1, + 'display_name' => 'Mock Data Source', + 'endpoint' => 'http://example.com', + 'testUserId' => '456', + ], + ]; + + $this->http_data_source = MockDataSource::create( $config ); + + $this->assertEquals( '456', $this->http_data_source->to_array()['service_config']['testUserId'] ); + } } diff --git a/tests/inc/Mocks/MockDataSource.php b/tests/inc/Mocks/MockDataSource.php index 11b519444..c2a167f2a 100644 --- a/tests/inc/Mocks/MockDataSource.php +++ b/tests/inc/Mocks/MockDataSource.php @@ -30,4 +30,16 @@ public static function create( ?array $config = self::MOCK_CONFIG, ?ValidatorInt public function set_endpoint( string $endpoint ): void { $this->config['endpoint'] = $endpoint; } + + /** + * Override the migrate_config method to adjust the config for testing. + */ + public static function migrate_config( array $config ): array|WP_Error { + // Add a testUserId to the config if it's not already set. + if ( ! isset( $config['service_config']['testUserId'] ) ) { + $config['service_config']['testUserId'] = '123'; + } + + return $config; + } } From 49101dfd68ed097278c3d351788b89fd02ee0621 Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 5 Mar 2025 11:46:36 +1100 Subject: [PATCH 18/19] Add a test for migrations failing --- tests/inc/Config/HttpDataSourceTest.php | 27 ++++++++++++++++++++----- tests/inc/Mocks/MockDataSource.php | 7 ++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/tests/inc/Config/HttpDataSourceTest.php b/tests/inc/Config/HttpDataSourceTest.php index 2c698ad49..b3ce365d3 100644 --- a/tests/inc/Config/HttpDataSourceTest.php +++ b/tests/inc/Config/HttpDataSourceTest.php @@ -4,9 +4,9 @@ use PHPUnit\Framework\TestCase; use RemoteDataBlocks\Tests\Mocks\MockDataSource; - +use WP_Error; class HttpDataSourceTest extends TestCase { - private MockDataSource $http_data_source; + private MockDataSource|WP_Error $http_data_source; public function testGetServiceMethodCannotBeOverridden(): void { $config = [ @@ -31,7 +31,7 @@ public function testMigrateConfigMethodCanBeOverridden_user_id_is_added_to_confi // Migrate config should add a testUserId to the config if it's not already set. $this->http_data_source = MockDataSource::create(); - $this->assertEquals( '123', $this->http_data_source->to_array()['service_config']['testUserId'] ); + $this->assertEquals( 1, $this->http_data_source->to_array()['service_config']['testUserId'] ); } public function testMigrateConfigMethodCanBeOverridden_user_id_is_not_added_to_config(): void { @@ -41,12 +41,29 @@ public function testMigrateConfigMethodCanBeOverridden_user_id_is_not_added_to_c '__version' => 1, 'display_name' => 'Mock Data Source', 'endpoint' => 'http://example.com', - 'testUserId' => '456', + 'testUserId' => 2, + ], + ]; + + $this->http_data_source = MockDataSource::create( $config ); + + $this->assertEquals( 2, $this->http_data_source->to_array()['service_config']['testUserId'] ); + } + + public function testMigrateConfigMethodCanBeOverridden_user_id_is_not_an_integer(): void { + // Migrate config should trigger an error as the testUserId is not an integer. + $config = [ + 'service_config' => [ + '__version' => 1, + 'display_name' => 'Mock Data Source', + 'endpoint' => 'http://example.com', + 'testUserId' => 'not an integer', ], ]; $this->http_data_source = MockDataSource::create( $config ); - $this->assertEquals( '456', $this->http_data_source->to_array()['service_config']['testUserId'] ); + $this->assertInstanceOf( WP_Error::class, $this->http_data_source ); + $this->assertSame( 'testUserId must be an integer', $this->http_data_source->get_error_message() ); } } diff --git a/tests/inc/Mocks/MockDataSource.php b/tests/inc/Mocks/MockDataSource.php index c2a167f2a..142e12d5b 100644 --- a/tests/inc/Mocks/MockDataSource.php +++ b/tests/inc/Mocks/MockDataSource.php @@ -36,8 +36,13 @@ public function set_endpoint( string $endpoint ): void { */ public static function migrate_config( array $config ): array|WP_Error { // Add a testUserId to the config if it's not already set. + // If it is set, ensure it's an integer. + // Throw an error if it's not an integer. + // Together, this correctly simulates the behavior of the HttpDataSource::migrate_config method. if ( ! isset( $config['service_config']['testUserId'] ) ) { - $config['service_config']['testUserId'] = '123'; + $config['service_config']['testUserId'] = 1; + } elseif ( ! is_int( $config['service_config']['testUserId'] ) ) { + return new WP_Error( 'invalid_test_user_id', 'testUserId must be an integer' ); } return $config; From 944e6e33c67ab023ea6d45673388392e5733c20e Mon Sep 17 00:00:00 2001 From: ingeniumed Date: Wed, 5 Mar 2025 11:54:20 +1100 Subject: [PATCH 19/19] Add more comments --- inc/Config/ArraySerializable.php | 4 ++++ tests/inc/Config/HttpDataSourceTest.php | 1 + 2 files changed, 5 insertions(+) diff --git a/inc/Config/ArraySerializable.php b/inc/Config/ArraySerializable.php index ef45ab21a..f5f373638 100644 --- a/inc/Config/ArraySerializable.php +++ b/inc/Config/ArraySerializable.php @@ -29,11 +29,15 @@ protected function get_or_call_from_config( string $property_name, mixed ...$cal * @inheritDoc */ final public static function from_array( array $config, ?ValidatorInterface $validator = null ): static|WP_Error { + // The purpose of this is to ensure that when from_array runs, it is statically bound to the correct child class. + // This is important for ensuring that the correct child class is used for migrations, preprocess_config, etc. $subclass = static::get_implementor( $config ); if ( null !== $subclass ) { return $subclass::from_array( $config, $validator ); } + // If this is above the get_implementor call, it might still be statically bound to ArraySerializable or HttpDataSource + // instead of the actual subclass like ShopifyDataSource. $config = static::migrate_config( $config ); if ( is_wp_error( $config ) ) { return $config; diff --git a/tests/inc/Config/HttpDataSourceTest.php b/tests/inc/Config/HttpDataSourceTest.php index b3ce365d3..2da77cd27 100644 --- a/tests/inc/Config/HttpDataSourceTest.php +++ b/tests/inc/Config/HttpDataSourceTest.php @@ -5,6 +5,7 @@ use PHPUnit\Framework\TestCase; use RemoteDataBlocks\Tests\Mocks\MockDataSource; use WP_Error; + class HttpDataSourceTest extends TestCase { private MockDataSource|WP_Error $http_data_source;