Skip to content

Commit

Permalink
Ensure product option values are synchronized from the variant to its…
Browse files Browse the repository at this point in the history
… sample
  • Loading branch information
mbabker committed Sep 6, 2022
1 parent 88e2cf7 commit 34d04b0
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 15 deletions.
9 changes: 2 additions & 7 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,10 @@ parameters:
-
message: "#^Call to static method Webmozart\\\\Assert\\\\Assert\\:\\:isInstanceOf\\(\\) with BabDev\\\\SyliusProductSamplesPlugin\\\\Model\\\\ProductVariantInterface and 'BabDev\\\\\\\\SyliusProductSamplesPlugin\\\\\\\\Model\\\\\\\\ProductVariantInterface' will always evaluate to true\\.$#"
count: 1
path: src/Form/EventSubscriber/SynchronizeSampleProductVariantTranslationsFormSubscriber.php

-
message: "#^Cannot call method getTranslations\\(\\) on Sylius\\\\Component\\\\Product\\\\Model\\\\ProductVariantInterface\\|null\\.$#"
count: 1
path: src/Form/EventSubscriber/SynchronizeSampleProductVariantTranslationsFormSubscriber.php
path: src/Form/EventSubscriber/SynchronizeSampleProductVariantOptionValuesFormSubscriber.php

-
message: "#^Cannot call method hasTranslation\\(\\) on Sylius\\\\Component\\\\Product\\\\Model\\\\ProductVariantInterface\\|null\\.$#"
message: "#^Call to static method Webmozart\\\\Assert\\\\Assert\\:\\:isInstanceOf\\(\\) with BabDev\\\\SyliusProductSamplesPlugin\\\\Model\\\\ProductVariantInterface and 'BabDev\\\\\\\\SyliusProductSamplesPlugin\\\\\\\\Model\\\\\\\\ProductVariantInterface' will always evaluate to true\\.$#"
count: 1
path: src/Form/EventSubscriber/SynchronizeSampleProductVariantTranslationsFormSubscriber.php

Expand Down
7 changes: 6 additions & 1 deletion spec/EventListener/SampleVariantGeneratorListenerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use BabDev\SyliusProductSamplesPlugin\Model\ChannelInterface;
use BabDev\SyliusProductSamplesPlugin\Model\ProductInterface;
use BabDev\SyliusProductSamplesPlugin\Model\ProductVariantInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantOptionValuesSynchronizerInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantTranslationsSynchronizerInterface;
use Doctrine\Common\Collections\ArrayCollection;
use PhpSpec\ObjectBehavior;
Expand All @@ -24,9 +25,10 @@ public function let(
FactoryInterface $channelPricingFactory,
ProductVariantFactoryInterface $productVariantFactory,
SampleVariantCodeGeneratorInterface $codeGenerator,
ProductVariantOptionValuesSynchronizerInterface $optionValuesSynchronizer,
ProductVariantTranslationsSynchronizerInterface $translationsSynchronizer,
): void {
$this->beConstructedWith($channelPricingFactory, $productVariantFactory, $codeGenerator, $translationsSynchronizer);
$this->beConstructedWith($channelPricingFactory, $productVariantFactory, $codeGenerator, $optionValuesSynchronizer, $translationsSynchronizer);
}

public function it_does_not_generate_sample_variants_if_product_samples_are_disabled(
Expand All @@ -43,6 +45,7 @@ public function it_generates_sample_variants_if_product_samples_are_enabled_for_
FactoryInterface $channelPricingFactory,
ProductVariantFactoryInterface $productVariantFactory,
SampleVariantCodeGeneratorInterface $codeGenerator,
ProductVariantOptionValuesSynchronizerInterface $optionValuesSynchronizer,
ProductVariantTranslationsSynchronizerInterface $translationsSynchronizer,
ResourceControllerEvent $event,
ProductInterface $product,
Expand Down Expand Up @@ -91,6 +94,7 @@ public function it_generates_sample_variants_if_product_samples_are_enabled_for_

$newSampleOfVariant1->addChannelPricing($newChannelPricingForSampleOfVariant1)->shouldBeCalled();

$optionValuesSynchronizer->synchronize($newSampleOfVariant1)->shouldBeCalled();
$translationsSynchronizer->synchronize($newSampleOfVariant1)->shouldBeCalled();

/*
Expand Down Expand Up @@ -125,6 +129,7 @@ public function it_generates_sample_variants_if_product_samples_are_enabled_for_

$newSampleOfVariant3->addChannelPricing($newChannelPricingForSampleOfVariant3)->shouldBeCalled();

$optionValuesSynchronizer->synchronize($newSampleOfVariant3)->shouldBeCalled();
$translationsSynchronizer->synchronize($newSampleOfVariant3)->shouldBeCalled();

$this->ensureSampleVariantsExist($event);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace spec\BabDev\SyliusProductSamplesPlugin\Form\EventSubscriber;

use BabDev\SyliusProductSamplesPlugin\Model\ProductVariantInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantOptionValuesSynchronizerInterface;
use PhpSpec\ObjectBehavior;
use Symfony\Component\Form\FormEvent;

final class SynchronizeSampleProductVariantOptionValuesFormSubscriberSpec extends ObjectBehavior
{
public function let(ProductVariantOptionValuesSynchronizerInterface $optionValuesSynchronizer): void
{
$this->beConstructedWith($optionValuesSynchronizer);
}

public function it_does_nothing_when_there_is_no_data(FormEvent $event): void
{
$event->getData()->willReturn(null);

$this->onSubmit($event);
}

public function it_synchronizes_option_values_from_the_variant_to_its_sample(
ProductVariantOptionValuesSynchronizerInterface $optionValuesSynchronizer,
FormEvent $event,
ProductVariantInterface $sampleVariant,
): void {
$event->getData()->willReturn($sampleVariant);

$optionValuesSynchronizer->synchronize($sampleVariant)->shouldBeCalled();

$this->onSubmit($event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use BabDev\SyliusProductSamplesPlugin\Model\ProductVariantInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantTranslationsSynchronizerInterface;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Product\Model\ProductVariantTranslationInterface;
use Symfony\Component\Form\FormEvent;

final class SynchronizeSampleProductVariantTranslationsFormSubscriberSpec extends ObjectBehavior
Expand All @@ -28,12 +27,6 @@ public function it_synchronizes_translations_from_the_variant_to_its_sample(
ProductVariantTranslationsSynchronizerInterface $translationsSynchronizer,
FormEvent $event,
ProductVariantInterface $sampleVariant,
ProductVariantInterface $actualVariant,
ProductVariantTranslationInterface $sampleVariantEnglishTranslation,
ProductVariantTranslationInterface $sampleVariantGermanTranslation,
ProductVariantTranslationInterface $sampleVariantFrenchTranslation,
ProductVariantTranslationInterface $actualVariantEnglishTranslation,
ProductVariantTranslationInterface $actualVariantFrenchTranslation,
): void {
$event->getData()->willReturn($sampleVariant);

Expand Down
37 changes: 37 additions & 0 deletions spec/Synchronizer/ProductVariantOptionValuesSynchronizerSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace spec\BabDev\SyliusProductSamplesPlugin\Synchronizer;

use BabDev\SyliusProductSamplesPlugin\Generator\SampleVariantNameGeneratorInterface;
use BabDev\SyliusProductSamplesPlugin\Model\ProductVariantInterface;
use Doctrine\Common\Collections\ArrayCollection;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Product\Model\ProductOptionValueInterface;

final class ProductVariantOptionValuesSynchronizerSpec extends ObjectBehavior
{
public function it_synchronizes_option_values_from_the_variant_to_its_sample(
SampleVariantNameGeneratorInterface $nameGenerator,
ProductVariantInterface $sampleVariant,
ProductVariantInterface $actualVariant,
ProductOptionValueInterface $smallOptionValue,
ProductOptionValueInterface $mediumOptionValue,
ProductOptionValueInterface $largeOptionValue,
): void {
$sampleVariant->getSampleOf()->willReturn($actualVariant);
$sampleVariant->getOptionValues()->willReturn(new ArrayCollection([$smallOptionValue->getWrappedObject(), $mediumOptionValue->getWrappedObject()]));

$actualVariant->hasOptionValue($smallOptionValue)->willReturn(true);
$actualVariant->hasOptionValue($mediumOptionValue)->willReturn(false);
$sampleVariant->removeOptionValue($mediumOptionValue)->shouldBeCalled();

$actualVariant->getOptionValues()->willReturn(new ArrayCollection([$smallOptionValue->getWrappedObject(), $largeOptionValue->getWrappedObject()]));
$sampleVariant->hasOptionValue($smallOptionValue)->willReturn(true);
$sampleVariant->hasOptionValue($largeOptionValue)->willReturn(false);
$sampleVariant->addOptionValue($largeOptionValue)->shouldBeCalled();

$this->synchronize($sampleVariant);
}
}
3 changes: 3 additions & 0 deletions src/EventListener/SampleVariantGeneratorListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use BabDev\SyliusProductSamplesPlugin\Generator\SampleVariantCodeGeneratorInterface;
use BabDev\SyliusProductSamplesPlugin\Model\ProductInterface;
use BabDev\SyliusProductSamplesPlugin\Model\ProductVariantInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantOptionValuesSynchronizerInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantTranslationsSynchronizerInterface;
use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent;
use Sylius\Component\Core\Model\ChannelInterface;
Expand All @@ -21,6 +22,7 @@ public function __construct(
private FactoryInterface $channelPricingFactory,
private ProductVariantFactoryInterface $productVariantFactory,
private SampleVariantCodeGeneratorInterface $codeGenerator,
private ProductVariantOptionValuesSynchronizerInterface $optionValuesSynchronizer,
private ProductVariantTranslationsSynchronizerInterface $translationsSynchronizer,
) {
}
Expand Down Expand Up @@ -68,6 +70,7 @@ private function generateSampleVariant(ProductInterface $product, ProductVariant
$sample->addChannelPricing($this->createChannelPricingForChannel(0, $channel));
}

$this->optionValuesSynchronizer->synchronize($sample);
$this->translationsSynchronizer->synchronize($sample);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace BabDev\SyliusProductSamplesPlugin\Form\EventSubscriber;

use BabDev\SyliusProductSamplesPlugin\Model\ProductVariantInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantOptionValuesSynchronizerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Webmozart\Assert\Assert;

final class SynchronizeSampleProductVariantOptionValuesFormSubscriber implements EventSubscriberInterface
{
public function __construct(
private ProductVariantOptionValuesSynchronizerInterface $optionValuesSynchronizer,
) {
}

public static function getSubscribedEvents(): array
{
return [
FormEvents::SUBMIT => ['onSubmit', -10],
];
}

/**
* @note This listener *MUST* run after {@see ManageSampleProductVariantAssignmentsFormSubscriber::onSubmit()} to ensure
* the relationships between the variant and its sample have been set
*/
public function onSubmit(FormEvent $event): void
{
/** @var ProductVariantInterface|null $sampleVariant */
$sampleVariant = $event->getData();

if (null === $sampleVariant) {
return;
}

Assert::isInstanceOf($sampleVariant, ProductVariantInterface::class);

$this->optionValuesSynchronizer->synchronize($sampleVariant);
}
}
4 changes: 4 additions & 0 deletions src/Form/Type/SampleProductVariantType.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
namespace BabDev\SyliusProductSamplesPlugin\Form\Type;

use BabDev\SyliusProductSamplesPlugin\Form\EventSubscriber\ManageSampleProductVariantAssignmentsFormSubscriber;
use BabDev\SyliusProductSamplesPlugin\Form\EventSubscriber\SynchronizeSampleProductVariantOptionValuesFormSubscriber;
use BabDev\SyliusProductSamplesPlugin\Form\EventSubscriber\SynchronizeSampleProductVariantTranslationsFormSubscriber;
use BabDev\SyliusProductSamplesPlugin\Model\ProductVariantInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantOptionValuesSynchronizerInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantTranslationsSynchronizerInterface;
use Sylius\Bundle\CoreBundle\Form\Type\ChannelCollectionType;
use Sylius\Bundle\CoreBundle\Form\Type\Product\ChannelPricingType;
Expand All @@ -27,6 +29,7 @@ final class SampleProductVariantType extends AbstractResourceType
* @phpstan-param class-string $dataClass
*/
public function __construct(
private ProductVariantOptionValuesSynchronizerInterface $optionValuesSynchronizer,
private ProductVariantTranslationsSynchronizerInterface $translationsSynchronizer,
string $dataClass,
array $validationGroups = [],
Expand All @@ -38,6 +41,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->addEventSubscriber(new ManageSampleProductVariantAssignmentsFormSubscriber())
->addEventSubscriber(new SynchronizeSampleProductVariantOptionValuesFormSubscriber($this->optionValuesSynchronizer))
->addEventSubscriber(new SynchronizeSampleProductVariantTranslationsFormSubscriber($this->translationsSynchronizer))
->add('shippingCategory', ShippingCategoryChoiceType::class, [
'required' => false,
Expand Down
8 changes: 8 additions & 0 deletions src/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use BabDev\SyliusProductSamplesPlugin\Menu\ProductFormMenuBuilder;
use BabDev\SyliusProductSamplesPlugin\Menu\ProductVariantFormMenuBuilder;
use BabDev\SyliusProductSamplesPlugin\Provider\SampleAwareProductVariantPricesProvider;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantOptionValuesSynchronizer;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantOptionValuesSynchronizerInterface;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantTranslationsSynchronizer;
use BabDev\SyliusProductSamplesPlugin\Synchronizer\ProductVariantTranslationsSynchronizerInterface;
use Sylius\Bundle\AdminBundle\Menu\ProductFormMenuBuilder as RootProductFormMenuBuilder;
Expand All @@ -39,6 +41,7 @@
service('sylius.factory.channel_pricing'),
service('sylius.factory.product_variant'),
service(SampleVariantCodeGeneratorInterface::class),
service(ProductVariantOptionValuesSynchronizerInterface::class),
service(ProductVariantTranslationsSynchronizerInterface::class),
])
->tag('kernel.event_listener', ['event' => 'sylius.product.pre_create', 'method' => 'ensureSampleVariantsExist'])
Expand Down Expand Up @@ -85,6 +88,7 @@

$services->set('babdev_sylius_product_samples.form.type.sample_product_variant', SampleProductVariantType::class)
->args([
service(ProductVariantOptionValuesSynchronizerInterface::class),
service(ProductVariantTranslationsSynchronizerInterface::class),
param('sylius.model.product_variant.class'),
param('sylius.form.type.product_variant.validation_groups'),
Expand Down Expand Up @@ -124,6 +128,10 @@
->tag('kernel.event_listener', ['event' => RootProductVariantFormMenuBuilder::EVENT_NAME, 'method' => 'addProductSamplesMenu'])
;

$services->set('babdev_sylius_product_samples.synchronizer.product_variant.option_values', ProductVariantOptionValuesSynchronizer::class);

$services->alias(ProductVariantOptionValuesSynchronizerInterface::class, 'babdev_sylius_product_samples.synchronizer.product_variant.option_values');

$services->set('babdev_sylius_product_samples.synchronizer.product_variant.translations', ProductVariantTranslationsSynchronizer::class)
->args([
service(SampleVariantNameGeneratorInterface::class),
Expand Down
36 changes: 36 additions & 0 deletions src/Synchronizer/ProductVariantOptionValuesSynchronizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace BabDev\SyliusProductSamplesPlugin\Synchronizer;

use BabDev\SyliusProductSamplesPlugin\Model\ProductVariantInterface;
use Sylius\Component\Product\Model\ProductOptionValueInterface;

final class ProductVariantOptionValuesSynchronizer implements ProductVariantOptionValuesSynchronizerInterface
{
public function synchronize(ProductVariantInterface $sampleVariant): void
{
$actualVariant = $sampleVariant->getSampleOf();

if (null === $actualVariant) {
return;
}

// First, remove outdated option values from the sample
/** @var ProductOptionValueInterface $optionValue */
foreach ($sampleVariant->getOptionValues() as $optionValue) {
if (!$actualVariant->hasOptionValue($optionValue)) {
$sampleVariant->removeOptionValue($optionValue);
}
}

// Next, add missing option values to the sample
/** @var ProductOptionValueInterface $optionValue */
foreach ($actualVariant->getOptionValues() as $optionValue) {
if (!$sampleVariant->hasOptionValue($optionValue)) {
$sampleVariant->addOptionValue($optionValue);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace BabDev\SyliusProductSamplesPlugin\Synchronizer;

use BabDev\SyliusProductSamplesPlugin\Model\ProductVariantInterface;

interface ProductVariantOptionValuesSynchronizerInterface
{
public function synchronize(ProductVariantInterface $sampleVariant): void;
}

0 comments on commit 34d04b0

Please sign in to comment.