-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
🏷️ type:productionProduction codebase (src/, modules/, core functionality)Production codebase (src/, modules/, core functionality)📂 area:blocksLayout Builder block A/B testing featuresLayout Builder block A/B testing features📂 area:coreCore plugin system, interfaces, managers, and base functionalityCore plugin system, interfaces, managers, and base functionality🔥 priority:mediumStandard feature requests, moderate bugs with workaroundsStandard feature requests, moderate bugs with workarounds
Description
Summary
The A/B Blocks feature currently has context serialization/deserialization logic embedded directly in two classes, violating the Single Responsibility Principle and creating code duplication. This issue proposes extracting this logic into a dedicated service.
Current Implementation Problems
Code Location Issues
- Serialization:
TestableBlockComponentRenderArray::serializeSupportedContextValues()(lines 267-302) - Deserialization:
AjaxBlockRender::deserializeContextValues()anddeserializeContextValue()(lines 168-226)
Problems with Current Approach
- Duplicated Logic: Both classes contain similar context handling code
- Mixed Responsibilities: Event subscriber and controller both handle serialization concerns
- Hard to Test: Context logic is buried within larger classes
- Maintenance Overhead: Changes to context handling require touching multiple files
- No Reusability: Other parts of the system can't leverage this functionality
Proposed Solution
New Service: ContextNormalizerService
Create a dedicated service that integrates with Drupal's serialization component to handle context serialization/deserialization:
namespace Drupal\ab_blocks\Service;
use Drupal\Core\Plugin\Context\ContextInterface;
use Drupal\serialization\Normalizer\NormalizerInterface;
use Drupal\serialization\Normalizer\DenormalizerInterface;
class ContextNormalizerService implements NormalizerInterface, DenormalizerInterface {
public function normalize($contexts, $format = NULL, array $context = []): array;
public function denormalize($data, $class, $format = NULL, array $context = []): array;
public function supportsNormalization($data, $format = NULL): bool;
public function supportsDenormalization($data, $type, $format = NULL): bool;
}Service Registration
# ab_blocks.services.yml
services:
ab_blocks.context_normalizer:
class: Drupal\ab_blocks\Service\ContextNormalizerService
arguments:
- '@typed_data_manager'
- '@entity_type.manager'
- '@language_manager'
tags:
- { name: normalizer }Implementation Details
Supported Context Types
- EntityAdapter: Serialize to
entity:{type}={id}format - PrimitiveInterface: JSON encode values
- Language: Serialize language ID
Methods to Implement
normalize(array $contexts): Convert Context objects to serializable arraydenormalize(array $data): Reconstruct Context objects from serialized dataencodeForTransport(array $contexts): Base64 encode for URL transportdecodeFromTransport(string $encoded): Decode from URL transport
Refactored Classes
TestableBlockComponentRenderArray
// Remove serializeSupportedContextValues() method
// Replace with:
$serialized_contexts = $this->contextNormalizer->normalize($event->getContexts());
$encoded_context_values = $this->contextNormalizer->encodeForTransport($serialized_contexts);AjaxBlockRender
// Remove deserializeContextValues() and deserializeContextValue() methods
// Replace with:
$context_values = $this->contextNormalizer->decodeFromTransport($encoded_contexts);Benefits
Separation of Concerns
- Event subscriber focuses on render array modification
- Controller focuses on Ajax response generation
- Context handling isolated in dedicated service
Improved Maintainability
- Single location for context serialization logic
- Easier to test context handling in isolation
- Clear service boundaries and responsibilities
Extensibility
- Other modules can leverage the context normalizer
- Easy to add support for new context types
- Follows Drupal's normalizer pattern for consistency
Integration with Drupal Core
- Uses Drupal's serialization component architecture
- Follows established patterns for normalizers
- Can be tagged and discovered by the serialization system
Implementation Steps
- Create ContextNormalizerService with normalize/denormalize methods
- Add service definition in ab_blocks.services.yml
- Refactor TestableBlockComponentRenderArray to use service
- Refactor AjaxBlockRender to use service
- Add comprehensive unit tests for the new service
- Update documentation reflecting the new architecture
Testing Strategy
Unit Tests
- Test context normalization for all supported types
- Test edge cases (null values, invalid data)
- Test encoding/decoding roundtrips
- Mock dependencies for isolated testing
Integration Tests
- Verify end-to-end context preservation in A/B block testing
- Test with various Layout Builder configurations
- Ensure backwards compatibility
Backward Compatibility
This refactoring maintains full backward compatibility:
- No changes to public APIs
- Same serialization format maintained
- Existing A/B tests continue to work unchanged
Metadata
Metadata
Assignees
Labels
🏷️ type:productionProduction codebase (src/, modules/, core functionality)Production codebase (src/, modules/, core functionality)📂 area:blocksLayout Builder block A/B testing featuresLayout Builder block A/B testing features📂 area:coreCore plugin system, interfaces, managers, and base functionalityCore plugin system, interfaces, managers, and base functionality🔥 priority:mediumStandard feature requests, moderate bugs with workaroundsStandard feature requests, moderate bugs with workarounds