diff --git a/inc/Config/DataSource/DataSourceConnection.php b/inc/Config/DataSource/DataSourceConnection.php new file mode 100644 index 000000000..39447d36a --- /dev/null +++ b/inc/Config/DataSource/DataSourceConnection.php @@ -0,0 +1,108 @@ +validate( $service_config ); + + if ( is_wp_error( $validated ) ) { + return $validated; + } + + return [ + 'service' => static::get_service_name(), + 'uuid' => $config['uuid'] ?? null, + 'service_config' => $service_config, + 'queries' => $config['queries'] ?? [], + ]; + } + + /** + * @inheritDoc + */ + public static function migrate_config( array $config ): array|WP_Error { + return $config; + } + + /** + * @inheritDoc + */ + public function to_array(): array { + return array_merge( + $this->config, + [ + self::CLASS_REF_ATTRIBUTE => static::class, + 'service' => static::get_service_name(), + ] + ); + } + + public function get_service_config(): array { + return $this->config['service_config']; + } + + /** + * Get the schema for validating the data source configuration. + * + * @return array The schema for validating the data source configuration. + */ + public static function get_config_schema(): array { + return ConfigSchemas::get_data_source_connection_config_schema(); + } + + /** + * Get the schema for validating the service-specific configuration. + * + * @return array The schema for validating the service-specific configuration. + */ + abstract public static function get_service_config_schema(): array; + + /** + * Get the UUID of the connection. + * + * @return string The UUID. + */ + public function get_uuid(): string { + return $this->config['uuid']; + } + + /** + * Get the display name of the data source. + * + * @return string The display name. + */ + public function get_display_name(): string { + return $this->config['service_config']['display_name']; + } + + /** + * Get the service name. + * + * @return string The service name. + */ + abstract public static function get_service_name(): string; + + /** + * Get the queries for the data source. + * + * @return array The queries. + */ + abstract public function get_queries(): array; +} diff --git a/inc/Config/DataSource/DataSourceConnectionInterface.php b/inc/Config/DataSource/DataSourceConnectionInterface.php new file mode 100644 index 000000000..83e326649 --- /dev/null +++ b/inc/Config/DataSource/DataSourceConnectionInterface.php @@ -0,0 +1,18 @@ +validate( $service_config ); + + if ( is_wp_error( $validated ) ) { + return $validated; + } + + return [ + 'service' => static::get_service_name(), + 'uuid' => $config['uuid'] ?? null, + 'connection_uuid' => $config['connection_uuid'] ?? null, + 'service_config' => $service_config, + ]; + } + + /** + * @inheritDoc + */ + public static function migrate_config( array $config ): array|WP_Error { + return $config; + } + + /** + * @inheritDoc + */ + public function to_array(): array { + return array_merge( + $this->config, + [ + self::CLASS_REF_ATTRIBUTE => static::class, + 'service' => static::get_service_name(), + ] + ); + } + + /** + * Get the schema for validating the query configuration. + * + * @return array The schema for validating the query configuration. + */ + public static function get_config_schema(): array { + return ConfigSchemas::get_data_source_query_config_schema(); + } + + /** + * Get the schema for validating the service-specific configuration. + * + * @return array The schema for validating the service-specific configuration. + */ + abstract public static function get_service_config_schema(): array; + + /** + * Get the UUID of the query. + * + * @return string The UUID. + */ + public function get_uuid(): string { + return $this->config['uuid']; + } + + /** + * Get the UUID of the associated data source connection. + * + * @return string|null The connection UUID. + */ + public function get_connection_uuid(): string|null { + return $this->config['connection_uuid']; + } + + /** + * Get the display name of the query. + * + * @return string The display name. + */ + public function get_display_name(): string { + return $this->config['service_config']['display_name']; + } + + /** + * Get the service name. + * + * @return string The service name. + */ + abstract public static function get_service_name(): string; +} diff --git a/inc/Config/DataSource/DataSourceQueryInterface.php b/inc/Config/DataSource/DataSourceQueryInterface.php new file mode 100644 index 000000000..2d94267db --- /dev/null +++ b/inc/Config/DataSource/DataSourceQueryInterface.php @@ -0,0 +1,19 @@ + \RemoteDataBlocks\Integrations\Shopify\ShopifyDataSource::class, REMOTE_DATA_BLOCKS_MOCK_SERVICE => \RemoteDataBlocks\Tests\Mocks\MockDataSource::class, ]; + +const REMOTE_DATA_BLOCKS__DATA_SOURCE_CONNECTION_CONFIG_CLASSMAP = []; +const REMOTE_DATA_BLOCKS__DATA_SOURCE_QUERY_CONFIG_CLASSMAP = []; diff --git a/inc/Validation/ConfigSchemas.php b/inc/Validation/ConfigSchemas.php index 4b309bf7a..165367766 100644 --- a/inc/Validation/ConfigSchemas.php +++ b/inc/Validation/ConfigSchemas.php @@ -73,6 +73,26 @@ public static function get_remote_data_block_attribute_config_schema(): array { return $schema; } + public static function get_data_source_connection_config_schema(): array { + static $schema = null; + + if ( null === $schema ) { + $schema = self::generate_data_source_connection_config_schema(); + } + + return $schema; + } + + public static function get_data_source_query_config_schema(): array { + static $schema = null; + + if ( null === $schema ) { + $schema = self::generate_data_source_query_config_schema(); + } + + return $schema; + } + private static function generate_remote_data_block_config_schema(): array { return Types::object( [ 'icon' => Types::nullable( Types::string() ), @@ -401,4 +421,25 @@ private static function generate_remote_data_block_attribute_config_schema(): ar ), ] ); } + + private static function generate_data_source_connection_config_schema(): array { + return Types::object( [ + 'uuid' => Types::nullable( Types::uuid() ), + 'service' => Types::string(), + 'service_config' => Types::record( Types::string(), Types::any() ), + 'queries' => Types::list_of( Types::record( Types::string(), Types::any() ) ), + '__metadata' => Types::nullable( Types::record( Types::string(), Types::any() ) ), + ] ); + } + + private static function generate_data_source_query_config_schema(): array { + return Types::object( [ + 'uuid' => Types::nullable( Types::uuid() ), + 'service' => Types::string(), + 'service_config' => Types::record( Types::string(), Types::any() ), + 'connection_uuid' => Types::nullable( Types::uuid() ), + 'connection' => Types::nullable( Types::record( Types::string(), Types::any() ) ), + '__metadata' => Types::nullable( Types::record( Types::string(), Types::any() ) ), + ] ); + } } diff --git a/inc/WpdbStorage/DataSourceConnectionCrud.php b/inc/WpdbStorage/DataSourceConnectionCrud.php new file mode 100644 index 000000000..4c5fafcd6 --- /dev/null +++ b/inc/WpdbStorage/DataSourceConnectionCrud.php @@ -0,0 +1,28 @@ + 404 ] + ); + } + + /** + * Get configs by service name. + * + * @param string $service_name The service name. + * @return array Array of configs for the specified service. + */ + public static function get_by_service( string $service_name ): array { + return array_values( array_filter( + static::get_all(), + function ( $config ) use ( $service_name ): bool { + return $config['service'] === $service_name; + } + ) ); + } + + /** + * Create a new config. + * + * @param array $config The config data. + * @return array|WP_Error The created config or an error. + */ + public static function create( array $config ): array|WP_Error { + return static::save( $config ); + } + + /** + * Update an existing config. + * + * @param string $uuid The UUID of the config to update. + * @param array $config_data The updated config data. + * @return array|WP_Error The updated config or an error. + */ + public static function update( string $uuid, array $config_data ): array|WP_Error { + $existing = static::get_by_uuid( $uuid ); + if ( is_wp_error( $existing ) ) { + return $existing; + } + + $config = array_merge( $existing, $config_data ); + $config['uuid'] = $uuid; // Ensure UUID remains the same + + return static::save( $config ); + } + + /** + * Save a config to the database. + * + * @param array $config The config data. + * @return array|WP_Error The saved config or an error. + */ + protected static function save( array $config ): array|WP_Error { + // Create a validated config instance + $config_instance = static::validate_and_instantiate( $config ); + if ( is_wp_error( $config_instance ) ) { + return $config_instance; + } + + // Convert the instance back to an array + $new_config = $config_instance->to_array(); + + // Ensure metadata is set + $now = gmdate( 'Y-m-d H:i:s' ); + $new_config['__metadata'] = [ + 'created_at' => $config['__metadata']['created_at'] ?? $now, + 'updated_at' => $now, + ]; + + // Ensure UUID is set + $new_config['uuid'] = $config['uuid'] ?? wp_generate_uuid4(); + + // Create or update the config + $configs = array_values( array_filter( + static::get_all(), + function ( $existing ) use ( $new_config ) { + return $existing['uuid'] !== $new_config['uuid']; + } + ) ); + $configs[] = $new_config; + + if ( true !== static::save_all( $configs ) ) { + return new WP_Error( + static::get_save_failed_error_code(), + static::get_save_failed_error_message() + ); + } + + return $new_config; + } + + /** + * Delete a config by UUID. + * + * @param string $uuid The UUID of the config to delete. + * @return bool|WP_Error True on success, WP_Error on failure. + */ + public static function delete( string $uuid ): bool|WP_Error { + $configs = array_values( array_filter( + static::get_all(), + function ( $config ) use ( $uuid ) { + return $config['uuid'] !== $uuid; + } + ) ); + + if ( true !== static::save_all( $configs ) ) { + return new WP_Error( + static::get_delete_failed_error_code(), + static::get_delete_failed_error_message() + ); + } + + return true; + } + + /** + * Save all configs to the database. + */ + protected static function save_all( array $configs ): bool { + return update_option( static::get_option_name(), $configs ); + } +}