Skip to content

Commit

Permalink
Extract product variant normalizer
Browse files Browse the repository at this point in the history
  • Loading branch information
lruozzi9 committed Sep 30, 2024
1 parent f1d6061 commit ee897d5
Show file tree
Hide file tree
Showing 5 changed files with 487 additions and 130 deletions.
11 changes: 11 additions & 0 deletions config/services/serializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,27 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Webgriffe\SyliusElasticsearchPlugin\Serializer\ProductNormalizer;
use Webgriffe\SyliusElasticsearchPlugin\Serializer\ProductTranslationNormalizer;
use Webgriffe\SyliusElasticsearchPlugin\Serializer\ProductVariantNormalizer;

return static function (ContainerConfigurator $containerConfigurator) {
$services = $containerConfigurator->services();

$services->set('webgriffe.sylius_elasticsearch_plugin.serializer.product_normalizer', ProductNormalizer::class)
->lazy()
->args([
service('sylius.product_variant_resolver.default'),
service('event_dispatcher'),
service('serializer'),
param('kernel.default_locale'),
])
->tag('serializer.normalizer', ['priority' => 200])
;

$services->set('webgriffe.sylius_elasticsearch_plugin.serializer.product_variant_normalizer', ProductVariantNormalizer::class)
->args([
service('event_dispatcher'),
])
->tag('serializer.normalizer', ['priority' => 200])
;
};
137 changes: 8 additions & 129 deletions src/Serializer/ProductNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
use Psr\EventDispatcher\EventDispatcherInterface;
use RuntimeException;
use Sylius\Component\Attribute\Model\AttributeValueInterface;
use Sylius\Component\Core\Model\CatalogPromotionInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\ChannelPricingInterface;
use Sylius\Component\Core\Model\ProductImageInterface;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Component\Core\Model\ProductTaxonInterface;
Expand All @@ -24,17 +22,18 @@
use Sylius\Component\Product\Model\ProductOptionTranslationInterface;
use Sylius\Component\Product\Model\ProductOptionValueInterface;
use Sylius\Component\Product\Model\ProductOptionValueTranslationInterface;
use Sylius\Component\Product\Model\ProductVariantTranslationInterface;
use Sylius\Component\Product\Resolver\ProductVariantResolverInterface;
use Sylius\Component\Promotion\Model\CatalogPromotionTranslationInterface;
use Sylius\Component\Taxonomy\Model\TaxonTranslationInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Webgriffe\SyliusElasticsearchPlugin\Event\ProductDocumentType\ProductDocumentTypeProductNormalizeEvent;
use Webgriffe\SyliusElasticsearchPlugin\Event\ProductDocumentType\ProductDocumentTypeProductVariantNormalizeEvent;
use Webgriffe\SyliusElasticsearchPlugin\Model\FilterableInterface;
use Webmozart\Assert\Assert;

final class ProductNormalizer implements NormalizerInterface
/**
* @final
*/
class ProductNormalizer implements NormalizerInterface
{
/** @var string[] */
private array $localeCodes = [];
Expand All @@ -47,6 +46,7 @@ final class ProductNormalizer implements NormalizerInterface
public function __construct(
private readonly ProductVariantResolverInterface $productVariantResolver,
private readonly EventDispatcherInterface $eventDispatcher,
private readonly SerializerInterface&NormalizerInterface $serializer,
private readonly string $systemDefaultLocaleCode,
) {
}
Expand Down Expand Up @@ -127,7 +127,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
}
$defaultVariant = $this->productVariantResolver->getVariant($product);
if ($defaultVariant instanceof ProductVariantInterface) {
$normalizedProduct['default-variant'] = $this->normalizeProductVariant($defaultVariant, $channel);
$normalizedProduct['default-variant'] = $this->serializer->normalize($defaultVariant, $format, $context);
}
$mainTaxon = $product->getMainTaxon();
if ($mainTaxon instanceof TaxonInterface) {
Expand All @@ -138,7 +138,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
}
/** @var ProductVariantInterface $variant */
foreach ($product->getVariants() as $variant) {
$normalizedProduct['variants'][] = $this->normalizeProductVariant($variant, $channel);
$normalizedProduct['variants'][] = $this->serializer->normalize($variant, $format, $context);
}

// Product attributes indexing for filters
Expand Down Expand Up @@ -277,64 +277,6 @@ private function normalizeProductTaxon(ProductTaxonInterface $productTaxon): arr
);
}

private function normalizeProductVariant(ProductVariantInterface $variant, ChannelInterface $channel): array
{
$normalizedVariant = [
'sylius-id' => $variant->getId(),
'code' => $variant->getCode(),
'enabled' => $variant->isEnabled(),
'position' => $variant->getPosition(),
'weight' => $variant->getWeight(),
'width' => $variant->getWidth(),
'height' => $variant->getHeight(),
'depth' => $variant->getDepth(),
'shipping-required' => $variant->isShippingRequired(),
'name' => [],
'on-hand' => $variant->getOnHand(),
'on-hold' => $variant->getOnHold(),
'is-tracked' => $variant->isTracked(),
'price' => $this->normalizeChannelPricing($variant->getChannelPricingForChannel($channel)),
'options' => [],
];
/** @var array<array-key, array{option: ProductOptionInterface, value: ProductOptionValueInterface}> $variantOptionsWithValue */
$variantOptionsWithValue = [];
foreach ($variant->getOptionValues() as $optionValue) {
$option = $optionValue->getOption();
Assert::isInstanceOf($option, ProductOptionInterface::class);
$optionId = $option->getId();
if (!is_string($optionId) && !is_int($optionId)) {
throw new RuntimeException('Option ID different from string or integer is not supported.');
}
if (array_key_exists($optionId, $variantOptionsWithValue)) {
throw new RuntimeException('Multiple values for the same option are not supported.');
}
$variantOptionsWithValue[$optionId] = [
'option' => $option,
'value' => $optionValue,
];
}
foreach ($variantOptionsWithValue as $optionAndValue) {
$normalizedVariant['options'][] = $this->normalizeProductOptionAndProductOptionValue(
$optionAndValue['option'],
$optionAndValue['value'],
);
}

/** @var ProductVariantTranslationInterface $variantTranslation */
foreach ($variant->getTranslations() as $variantTranslation) {
$localeCode = $variantTranslation->getLocale();
Assert::string($localeCode);
$normalizedVariant['name'][] = [
$localeCode => $variantTranslation->getName(),
];
}

$event = new ProductDocumentTypeProductVariantNormalizeEvent($variant, $channel, $normalizedVariant);
$this->eventDispatcher->dispatch($event);

return $event->getNormalizedProductVariant();
}

/**
* @param array{attribute: ProductAttributeInterface, values: ProductAttributeValueInterface[]} $attributeWithValues
*/
Expand Down Expand Up @@ -479,69 +421,6 @@ private function normalizeOptionWithValues(array $optionWithValues): array
return $normalizedOptionValue;
}

private function normalizeProductOptionAndProductOptionValue(
ProductOptionInterface $option,
ProductOptionValueInterface $optionValue,
): array {
$filterable = false;
if ($option instanceof FilterableInterface) {
$filterable = $option->isFilterable();
}
$normalizedOption = [
'sylius-id' => $option->getId(),
'code' => $option->getCode(),
'name' => [],
'filterable' => $filterable,
'value' => $this->normalizeProductOptionValue($optionValue),
];
/** @var ProductOptionTranslationInterface $optionTranslation */
foreach ($option->getTranslations() as $optionTranslation) {
$localeCode = $optionTranslation->getLocale();
Assert::string($localeCode);
$normalizedOption['name'][] = [
$localeCode => $optionTranslation->getName(),
];
}

return $normalizedOption;
}

private function normalizeChannelPricing(?ChannelPricingInterface $channelPricing): ?array
{
if ($channelPricing === null) {
return null;
}
$normalizedChannelPricing = [
'price' => $channelPricing->getPrice(),
'original-price' => $channelPricing->getOriginalPrice(),
'applied-promotions' => [],
];
/** @var CatalogPromotionInterface $catalogPromotion */
foreach ($channelPricing->getAppliedPromotions() as $catalogPromotion) {
$normalizedCatalogPromotion = [
'sylius-id' => $catalogPromotion->getId(),
'code' => $catalogPromotion->getCode(),
'label' => [],
'description' => [],
];
/** @var CatalogPromotionTranslationInterface $catalogPromotionTranslation */
foreach ($catalogPromotion->getTranslations() as $catalogPromotionTranslation) {
$localeCode = $catalogPromotionTranslation->getLocale();
Assert::string($localeCode);
$normalizedCatalogPromotion['label'][] = [
$localeCode => $catalogPromotionTranslation->getLabel(),
];
$normalizedCatalogPromotion['description'][] = [
$localeCode => $catalogPromotionTranslation->getDescription(),
];
}

$normalizedChannelPricing['applied-promotions'][] = $normalizedCatalogPromotion;
}

return $normalizedChannelPricing;
}

private function normalizeProductImage(ProductImageInterface $image): array
{
$normalizedImage = [
Expand Down
Loading

0 comments on commit ee897d5

Please sign in to comment.