diff --git a/composer-require-checker.json b/composer-require-checker.json index 787da84..b5c6888 100644 --- a/composer-require-checker.json +++ b/composer-require-checker.json @@ -21,6 +21,7 @@ "Sylius\\Component\\Channel\\Context\\ChannelContextInterface", "Sylius\\Component\\Channel\\Model\\ChannelInterface", "Sylius\\Component\\Channel\\Model\\ChannelsAwareInterface", + "Sylius\\Component\\Core\\Calculator\\ProductVariantPricesCalculatorInterface", "Sylius\\Component\\Core\\Model\\ChannelInterface", "Sylius\\Component\\Core\\Model\\OrderInterface", "Sylius\\Component\\Core\\Model\\OrderItemInterface", @@ -29,6 +30,6 @@ "Sylius\\Component\\Order\\Context\\CartContextInterface", "Sylius\\Component\\Order\\Repository\\OrderRepositoryInterface", "Sylius\\Component\\Product\\Resolver\\ProductVariantResolverInterface", - "Sylius\\Component\\Core\\Calculator\\ProductVariantPricesCalculatorInterface" + "Sylius\\Component\\Taxonomy\\Model\\TaxonInterface" ] } diff --git a/composer.json b/composer.json index 4fdd298..fa34ce5 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ "knplabs/knp-menu": "^3.3", "psr/event-dispatcher": "^1.0", "psr/log": "^2.0 || ^3.0", + "setono/composite-compiler-pass": "^1.0", "setono/google-analytics-bundle": "^1.0@alpha", "setono/google-analytics-measurement-protocol": "^1.0@alpha", "sylius/resource-bundle": "^1.8", @@ -34,6 +35,7 @@ "behat/behat": "^3.12", "matthiasnoback/symfony-config-test": "^4.3", "matthiasnoback/symfony-dependency-injection-test": "^4.3", + "phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9.5", "psalm/plugin-phpunit": "^0.18", "psalm/plugin-symfony": "^5.0", diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index bb6b0c7..69322e7 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -20,7 +20,7 @@ public function getConfigTreeBuilder(): TreeBuilder $treeBuilder = new TreeBuilder('setono_sylius_analytics'); $rootNode = $treeBuilder->getRootNode(); - /** @psalm-suppress MixedMethodCall,PossiblyNullReference,PossiblyUndefinedMethod */ + /** @psalm-suppress MixedMethodCall,PossiblyNullReference,PossiblyUndefinedMethod,UndefinedInterfaceMethod */ $rootNode ->addDefaultsIfNotSet() ->children() @@ -43,7 +43,7 @@ public function getConfigTreeBuilder(): TreeBuilder private function addResourcesSection(ArrayNodeDefinition $node): void { - /** @psalm-suppress MixedMethodCall,PossiblyNullReference,PossiblyUndefinedMethod */ + /** @psalm-suppress MixedMethodCall,PossiblyNullReference,PossiblyUndefinedMethod,UndefinedInterfaceMethod */ $node ->children() ->arrayNode('resources') diff --git a/src/DependencyInjection/SetonoSyliusAnalyticsExtension.php b/src/DependencyInjection/SetonoSyliusAnalyticsExtension.php index 8d7fd2a..6478d3b 100644 --- a/src/DependencyInjection/SetonoSyliusAnalyticsExtension.php +++ b/src/DependencyInjection/SetonoSyliusAnalyticsExtension.php @@ -4,6 +4,8 @@ namespace Setono\SyliusAnalyticsPlugin\DependencyInjection; +use Setono\SyliusAnalyticsPlugin\Resolver\Brand\BrandResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Variant\VariantResolverInterface; use Sylius\Bundle\ResourceBundle\DependencyInjection\Extension\AbstractResourceExtension; use Sylius\Bundle\ResourceBundle\SyliusResourceBundle; use Symfony\Component\Config\FileLocator; @@ -34,5 +36,13 @@ public function load(array $configs, ContainerBuilder $container): void } $this->registerResources('setono_sylius_analytics', SyliusResourceBundle::DRIVER_DOCTRINE_ORM, $config['resources'], $container); + + $container->registerForAutoconfiguration(BrandResolverInterface::class) + ->addTag('setono_sylius_analytics.brand_resolver') + ; + + $container->registerForAutoconfiguration(VariantResolverInterface::class) + ->addTag('setono_sylius_analytics.variant_resolver') + ; } } diff --git a/src/Event/ItemResolved.php b/src/Event/ItemResolved.php new file mode 100644 index 0000000..b972873 --- /dev/null +++ b/src/Event/ItemResolved.php @@ -0,0 +1,20 @@ + $context */ + public array $context = [], + ) { + } +} diff --git a/src/EventSubscriber/AddPaymentInfoSubscriber.php b/src/EventSubscriber/AddPaymentInfoSubscriber.php index 679614a..33cacf3 100644 --- a/src/EventSubscriber/AddPaymentInfoSubscriber.php +++ b/src/EventSubscriber/AddPaymentInfoSubscriber.php @@ -10,7 +10,7 @@ use Psr\Log\NullLogger; use Setono\GoogleAnalyticsBundle\Event\ClientSideEvent; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\AddPaymentInfoEvent; -use Setono\SyliusAnalyticsPlugin\Resolver\ItemsResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Items\ItemsResolverInterface; use Setono\SyliusAnalyticsPlugin\Util\FormatAmountTrait; use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent; use Sylius\Component\Core\Model\OrderInterface; diff --git a/src/EventSubscriber/AddShippingInfoSubscriber.php b/src/EventSubscriber/AddShippingInfoSubscriber.php index 3875cca..fbe204f 100644 --- a/src/EventSubscriber/AddShippingInfoSubscriber.php +++ b/src/EventSubscriber/AddShippingInfoSubscriber.php @@ -10,7 +10,7 @@ use Psr\Log\NullLogger; use Setono\GoogleAnalyticsBundle\Event\ClientSideEvent; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\AddShippingInfoEvent; -use Setono\SyliusAnalyticsPlugin\Resolver\ItemsResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Items\ItemsResolverInterface; use Setono\SyliusAnalyticsPlugin\Util\FormatAmountTrait; use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent; use Sylius\Component\Core\Model\OrderInterface; diff --git a/src/EventSubscriber/AddToCartSubscriber.php b/src/EventSubscriber/AddToCartSubscriber.php index d01d534..c47ffb6 100644 --- a/src/EventSubscriber/AddToCartSubscriber.php +++ b/src/EventSubscriber/AddToCartSubscriber.php @@ -10,7 +10,7 @@ use Psr\Log\NullLogger; use Setono\GoogleAnalyticsBundle\Event\ClientSideEvent; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\AddToCartEvent; -use Setono\SyliusAnalyticsPlugin\Resolver\ItemResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Item\ItemResolverInterface; use Setono\SyliusAnalyticsPlugin\Util\FormatAmountTrait; use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent; use Sylius\Component\Core\Model\OrderInterface; @@ -52,7 +52,7 @@ public function track(ResourceControllerEvent $resourceControllerEvent): void * https://github.com/Sylius/Sylius/issues/9407 * * That issue was fixed in Sylius 1.12, but we can't require the order bundle because Sylius doesn't handle - * GitHub repository subtree splits the correct way with regards to packagist therefore we are keeping this + * GitHub repository subtree splits the correct way with regard to packagist therefore we are keeping this */ $order = $this->cartContext->getCart(); if (!$order instanceof OrderInterface) { diff --git a/src/EventSubscriber/BeginCheckoutSubscriber.php b/src/EventSubscriber/BeginCheckoutSubscriber.php index 9329974..c4f5b07 100644 --- a/src/EventSubscriber/BeginCheckoutSubscriber.php +++ b/src/EventSubscriber/BeginCheckoutSubscriber.php @@ -10,7 +10,7 @@ use Psr\Log\NullLogger; use Setono\GoogleAnalyticsBundle\Event\ClientSideEvent; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\BeginCheckoutEvent; -use Setono\SyliusAnalyticsPlugin\Resolver\ItemsResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Items\ItemsResolverInterface; use Setono\SyliusAnalyticsPlugin\Util\FormatAmountTrait; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Order\Context\CartContextInterface; diff --git a/src/EventSubscriber/PurchaseSubscriber.php b/src/EventSubscriber/PurchaseSubscriber.php index 5903f25..7b4361d 100644 --- a/src/EventSubscriber/PurchaseSubscriber.php +++ b/src/EventSubscriber/PurchaseSubscriber.php @@ -10,7 +10,7 @@ use Psr\Log\NullLogger; use Setono\GoogleAnalyticsBundle\Event\ClientSideEvent; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\PurchaseEvent; -use Setono\SyliusAnalyticsPlugin\Resolver\ItemsResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Items\ItemsResolverInterface; use Setono\SyliusAnalyticsPlugin\Util\FormatAmountTrait; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Order\Repository\OrderRepositoryInterface; diff --git a/src/EventSubscriber/ViewCartSubscriber.php b/src/EventSubscriber/ViewCartSubscriber.php index 09fd58d..dcc76e4 100644 --- a/src/EventSubscriber/ViewCartSubscriber.php +++ b/src/EventSubscriber/ViewCartSubscriber.php @@ -10,7 +10,7 @@ use Psr\Log\NullLogger; use Setono\GoogleAnalyticsBundle\Event\ClientSideEvent; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\ViewCartEvent; -use Setono\SyliusAnalyticsPlugin\Resolver\ItemsResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Items\ItemsResolverInterface; use Setono\SyliusAnalyticsPlugin\Util\FormatAmountTrait; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Order\Context\CartContextInterface; diff --git a/src/EventSubscriber/ViewItemSubscriber.php b/src/EventSubscriber/ViewItemSubscriber.php index 95de7f0..3b4e7ff 100644 --- a/src/EventSubscriber/ViewItemSubscriber.php +++ b/src/EventSubscriber/ViewItemSubscriber.php @@ -10,7 +10,7 @@ use Psr\Log\NullLogger; use Setono\GoogleAnalyticsBundle\Event\ClientSideEvent; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\ViewItemEvent; -use Setono\SyliusAnalyticsPlugin\Resolver\ItemResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Item\ItemResolverInterface; use Setono\SyliusAnalyticsPlugin\Util\FormatAmountTrait; use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent; use Sylius\Component\Core\Model\ProductInterface; diff --git a/src/Resolver/Brand/BrandResolverInterface.php b/src/Resolver/Brand/BrandResolverInterface.php new file mode 100644 index 0000000..ec61aaa --- /dev/null +++ b/src/Resolver/Brand/BrandResolverInterface.php @@ -0,0 +1,15 @@ + $services + * + * @extends CompositeService + */ +final class CompositeBrandResolver extends CompositeService implements BrandResolverInterface +{ + public function resolveFromProduct(ProductInterface $product): ?string + { + foreach ($this->services as $brandResolver) { + $val = $brandResolver->resolveFromProduct($product); + if (null !== $val) { + return $val; + } + } + + return null; + } + + public function resolveFromProductVariant(ProductVariantInterface $productVariant): ?string + { + foreach ($this->services as $brandResolver) { + $val = $brandResolver->resolveFromProductVariant($productVariant); + if (null !== $val) { + return $val; + } + } + + return null; + } +} diff --git a/src/Resolver/Category/CategoryResolver.php b/src/Resolver/Category/CategoryResolver.php new file mode 100644 index 0000000..93ebe7c --- /dev/null +++ b/src/Resolver/Category/CategoryResolver.php @@ -0,0 +1,54 @@ +getMainTaxon() ?? $product->getTaxons()->first(); + if (!$taxon instanceof TaxonInterface) { + return []; + } + + /** + * Presume the $product has this taxon hierarchy: Apparel > Shirts > Crew > Short sleeve + * After the call below, $hierarchy will be ['Crew', 'Shirts', 'Apparel']. Notice that the values will + * actually still be taxon objects and not strings yet, but I am just showing it like this for readability + */ + $hierarchy = $taxon->getAncestors()->toArray(); + + /** + * Now we prepend the 'Short sleeve' to the $hierarchy variable, so the resulting array is now: + * ['Short sleeve', 'Crew', 'Shirts', 'Apparel'] + */ + array_unshift($hierarchy, $taxon); + + /** + * Now we just need to reverse the array to make sure the top level taxon is first and so on, + * and finally map the taxon objects to strings and the returned array will be ['Apparel', 'Shirts', 'Crew', 'Short sleeve'] + */ + return array_values(array_map( + static function (TaxonInterface $taxon): string { + return (string) $taxon->getName(); + }, + array_reverse($hierarchy), + )); + } + + public function resolveFromProductVariant(ProductVariantInterface $productVariant): array + { + $product = $productVariant->getProduct(); + if (!$product instanceof ProductInterface) { + return []; + } + + return $this->resolveFromProduct($product); + } +} diff --git a/src/Resolver/Category/CategoryResolverInterface.php b/src/Resolver/Category/CategoryResolverInterface.php new file mode 100644 index 0000000..7498ae9 --- /dev/null +++ b/src/Resolver/Category/CategoryResolverInterface.php @@ -0,0 +1,33 @@ + Shirts > Crew > Short sleeve the resulting array would + * look like this: + * + * [ + * 'Apparel', 'Shirts', 'Crew', 'Short sleeve' + * ] + */ +interface CategoryResolverInterface +{ + /** + * @return list + */ + public function resolveFromProduct(ProductInterface $product): array; + + /** + * @return list + */ + public function resolveFromProductVariant(ProductVariantInterface $productVariant): array; +} diff --git a/src/Resolver/ItemResolver.php b/src/Resolver/Item/ItemResolver.php similarity index 51% rename from src/Resolver/ItemResolver.php rename to src/Resolver/Item/ItemResolver.php index 83656dd..59a7a7a 100644 --- a/src/Resolver/ItemResolver.php +++ b/src/Resolver/Item/ItemResolver.php @@ -2,16 +2,20 @@ declare(strict_types=1); -namespace Setono\SyliusAnalyticsPlugin\Resolver; +namespace Setono\SyliusAnalyticsPlugin\Resolver\Item; +use Psr\EventDispatcher\EventDispatcherInterface; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\Item\Item; +use Setono\SyliusAnalyticsPlugin\Event\ItemResolved; +use Setono\SyliusAnalyticsPlugin\Resolver\Brand\BrandResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Category\CategoryResolverInterface; +use Setono\SyliusAnalyticsPlugin\Resolver\Variant\VariantResolverInterface; use Setono\SyliusAnalyticsPlugin\Util\FormatAmountTrait; use Sylius\Component\Channel\Context\ChannelContextInterface; use Sylius\Component\Core\Calculator\ProductVariantPricesCalculatorInterface; use Sylius\Component\Core\Model\OrderItemInterface; use Sylius\Component\Core\Model\ProductInterface; use Sylius\Component\Core\Model\ProductVariantInterface; -use Sylius\Component\Product\Model\ProductOptionValueInterface; use Sylius\Component\Product\Resolver\ProductVariantResolverInterface; use Webmozart\Assert\Assert; @@ -20,9 +24,13 @@ final class ItemResolver implements ItemResolverInterface use FormatAmountTrait; public function __construct( + private readonly EventDispatcherInterface $eventDispatcher, private readonly ProductVariantResolverInterface $productVariantResolver, private readonly ChannelContextInterface $channelContext, private readonly ProductVariantPricesCalculatorInterface $productVariantPricesCalculator, + private readonly VariantResolverInterface $variantResolver, + private readonly CategoryResolverInterface $categoryResolver, + private readonly BrandResolverInterface $brandResolver, ) { } @@ -31,21 +39,23 @@ public function resolveFromOrderItem(OrderItemInterface $orderItem): Item $variant = $orderItem->getVariant(); Assert::notNull($variant); - $variantStr = implode( - '-', - $variant - ->getOptionValues() - ->map(static fn (ProductOptionValueInterface $productOptionValue) => $productOptionValue->getValue()) - ->toArray(), - ); - - return Item::create() + $item = Item::create() ->setId($variant->getCode()) ->setName($orderItem->getProductName()) - ->setVariant($variantStr) + ->setVariant($this->variantResolver->resolve($variant)) + ->setBrand($this->brandResolver->resolveFromProductVariant($variant)) ->setQuantity($orderItem->getQuantity()) ->setPrice(self::formatAmount($orderItem->getFullDiscountedUnitPrice())) ; + + $this->populateCategories($item, $this->categoryResolver->resolveFromProductVariant($variant)); + + $this->eventDispatcher->dispatch(new ItemResolved($item, [ + 'orderItem' => $orderItem, + 'variant' => $variant, + ])); + + return $item; } public function resolveFromProduct(ProductInterface $product): Item @@ -57,6 +67,7 @@ public function resolveFromProduct(ProductInterface $product): Item $item = Item::create() ->setId($product->getCode()) ->setName($product->getName()) + ->setBrand($this->brandResolver->resolveFromProduct($product)) ; try { @@ -66,6 +77,29 @@ public function resolveFromProduct(ProductInterface $product): Item } catch (\Throwable) { } + $this->populateCategories($item, $this->categoryResolver->resolveFromProduct($product)); + + $this->eventDispatcher->dispatch(new ItemResolved($item, [ + 'product' => $product, + 'variant' => $variant, + ])); + return $item; } + + /** + * @param list $categories + */ + private function populateCategories(Item $item, array $categories): void + { + foreach ($categories as $idx => $category) { + // an item only have five categories available + if ($idx > 4) { + break; + } + + $method = sprintf('setCategory%s', 0 === $idx ? '' : (string) ($idx + 1)); + $item->{$method}($category); + } + } } diff --git a/src/Resolver/ItemResolverInterface.php b/src/Resolver/Item/ItemResolverInterface.php similarity index 88% rename from src/Resolver/ItemResolverInterface.php rename to src/Resolver/Item/ItemResolverInterface.php index d763716..0368e58 100644 --- a/src/Resolver/ItemResolverInterface.php +++ b/src/Resolver/Item/ItemResolverInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Setono\SyliusAnalyticsPlugin\Resolver; +namespace Setono\SyliusAnalyticsPlugin\Resolver\Item; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\Item\Item; use Sylius\Component\Core\Model\OrderItemInterface; diff --git a/src/Resolver/ItemsResolver.php b/src/Resolver/Items/ItemsResolver.php similarity index 80% rename from src/Resolver/ItemsResolver.php rename to src/Resolver/Items/ItemsResolver.php index 30be91d..b03de1e 100644 --- a/src/Resolver/ItemsResolver.php +++ b/src/Resolver/Items/ItemsResolver.php @@ -2,8 +2,9 @@ declare(strict_types=1); -namespace Setono\SyliusAnalyticsPlugin\Resolver; +namespace Setono\SyliusAnalyticsPlugin\Resolver\Items; +use Setono\SyliusAnalyticsPlugin\Resolver\Item\ItemResolverInterface; use Sylius\Component\Core\Model\OrderInterface; final class ItemsResolver implements ItemsResolverInterface diff --git a/src/Resolver/ItemsResolverInterface.php b/src/Resolver/Items/ItemsResolverInterface.php similarity index 84% rename from src/Resolver/ItemsResolverInterface.php rename to src/Resolver/Items/ItemsResolverInterface.php index 91481a0..63543ca 100644 --- a/src/Resolver/ItemsResolverInterface.php +++ b/src/Resolver/Items/ItemsResolverInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Setono\SyliusAnalyticsPlugin\Resolver; +namespace Setono\SyliusAnalyticsPlugin\Resolver\Items; use Setono\GoogleAnalyticsMeasurementProtocol\Request\Body\Event\Item\Item; use Sylius\Component\Core\Model\OrderInterface; diff --git a/src/Resolver/Variant/CompositeVariantResolver.php b/src/Resolver/Variant/CompositeVariantResolver.php new file mode 100644 index 0000000..ff41738 --- /dev/null +++ b/src/Resolver/Variant/CompositeVariantResolver.php @@ -0,0 +1,28 @@ + $services + * + * @extends CompositeService + */ +final class CompositeVariantResolver extends CompositeService implements VariantResolverInterface +{ + public function resolve(ProductVariantInterface $productVariant): ?string + { + foreach ($this->services as $variantResolver) { + $val = $variantResolver->resolve($productVariant); + if (null !== $val) { + return $val; + } + } + + return null; + } +} diff --git a/src/Resolver/Variant/NameBasedVariantResolver.php b/src/Resolver/Variant/NameBasedVariantResolver.php new file mode 100644 index 0000000..3f30053 --- /dev/null +++ b/src/Resolver/Variant/NameBasedVariantResolver.php @@ -0,0 +1,15 @@ +getName(); + } +} diff --git a/src/Resolver/Variant/OptionBasedVariantResolver.php b/src/Resolver/Variant/OptionBasedVariantResolver.php new file mode 100644 index 0000000..c41139f --- /dev/null +++ b/src/Resolver/Variant/OptionBasedVariantResolver.php @@ -0,0 +1,26 @@ +getOptionValues(); + if ($optionValues->isEmpty()) { + return null; + } + + return implode( + '-', + $optionValues + ->map(static fn (ProductOptionValueInterface $productOptionValue) => $productOptionValue->getValue()) + ->toArray(), + ); + } +} diff --git a/src/Resolver/Variant/VariantResolverInterface.php b/src/Resolver/Variant/VariantResolverInterface.php new file mode 100644 index 0000000..8db3a2b --- /dev/null +++ b/src/Resolver/Variant/VariantResolverInterface.php @@ -0,0 +1,12 @@ + + + + class="Setono\SyliusAnalyticsPlugin\Resolver\Item\ItemResolver"> + + + + + class="Setono\SyliusAnalyticsPlugin\Resolver\Items\ItemsResolver"> + + + + + + + + + + + + diff --git a/src/SetonoSyliusAnalyticsPlugin.php b/src/SetonoSyliusAnalyticsPlugin.php index b0cab9c..b763c23 100644 --- a/src/SetonoSyliusAnalyticsPlugin.php +++ b/src/SetonoSyliusAnalyticsPlugin.php @@ -4,6 +4,7 @@ namespace Setono\SyliusAnalyticsPlugin; +use Setono\CompositeCompilerPass\CompositeCompilerPass; use Setono\SyliusAnalyticsPlugin\DependencyInjection\Compiler\OverrideDefaultPropertyProviderPass; use Sylius\Bundle\CoreBundle\Application\SyliusPluginTrait; use Sylius\Bundle\ResourceBundle\AbstractResourceBundle; @@ -26,5 +27,13 @@ public function build(ContainerBuilder $container): void parent::build($container); $container->addCompilerPass(new OverrideDefaultPropertyProviderPass()); + $container->addCompilerPass(new CompositeCompilerPass( + 'setono_sylius_analytics.resolver.brand.composite', + 'setono_sylius_analytics.brand_resolver', + )); + $container->addCompilerPass(new CompositeCompilerPass( + 'setono_sylius_analytics.resolver.variant.composite', + 'setono_sylius_analytics.variant_resolver', + )); } } diff --git a/tests/Resolver/CategoryResolverTest.php b/tests/Resolver/CategoryResolverTest.php new file mode 100644 index 0000000..7444602 --- /dev/null +++ b/tests/Resolver/CategoryResolverTest.php @@ -0,0 +1,44 @@ += 1; --$i) { + $taxon = $this->prophesize(TaxonInterface::class); + $taxon->getName()->willReturn(sprintf('Level %d', $i)); + + $ancestors->add($taxon->reveal()); + } + + $mainTaxon = $this->prophesize(TaxonInterface::class); + $mainTaxon->getAncestors()->willReturn($ancestors); + $mainTaxon->getName()->willReturn('Level 4'); + + $product = $this->prophesize(ProductInterface::class); + $product->getMainTaxon()->willReturn($mainTaxon->reveal()); + + $resolver = new CategoryResolver(); + self::assertSame(['Level 1', 'Level 2', 'Level 3', 'Level 4'], $resolver->resolveFromProduct($product->reveal())); + } +} diff --git a/tests/Resolver/ItemResolverTest.php b/tests/Resolver/ItemResolverTest.php new file mode 100644 index 0000000..825ff44 --- /dev/null +++ b/tests/Resolver/ItemResolverTest.php @@ -0,0 +1,72 @@ +prophesize(EventDispatcherInterface::class); + $productVariantResolver = $this->prophesize(ProductVariantResolverInterface::class); + $channelContext = $this->prophesize(ChannelContextInterface::class); + $productVariantPricesCalculator = $this->prophesize(ProductVariantPricesCalculatorInterface::class); + $variantResolver = $this->prophesize(\Setono\SyliusAnalyticsPlugin\Resolver\Variant\VariantResolverInterface::class); + $variantResolver->resolve(Argument::type(ProductVariantInterface::class))->willReturn('Large'); + $categoryResolver = $this->prophesize(\Setono\SyliusAnalyticsPlugin\Resolver\Category\CategoryResolverInterface::class); + $categoryResolver->resolveFromProductVariant(Argument::type(ProductVariantInterface::class))->willReturn([ + 'Apparel', 'T-shirts', + ]); + $brandResolver = $this->prophesize(BrandResolverInterface::class); + $brandResolver->resolveFromProductVariant(Argument::type(ProductVariantInterface::class))->willReturn('PHP'); + + $resolver = new ItemResolver( + $eventDispatcher->reveal(), + $productVariantResolver->reveal(), + $channelContext->reveal(), + $productVariantPricesCalculator->reveal(), + $variantResolver->reveal(), + $categoryResolver->reveal(), + $brandResolver->reveal(), + ); + + $productVariant = $this->prophesize(ProductVariantInterface::class); + $productVariant->getCode()->willReturn('T_SHIRT'); + + $orderItem = $this->prophesize(OrderItemInterface::class); + $orderItem->getProductName()->willReturn('PHP T-shirt'); + $orderItem->getQuantity()->willReturn(2); + $orderItem->getFullDiscountedUnitPrice()->willReturn(12345); + $orderItem->getVariant()->willReturn($productVariant->reveal()); + $item = $resolver->resolveFromOrderItem($orderItem->reveal()); + + self::assertSame('T_SHIRT', $item->getId()); + self::assertSame('PHP T-shirt', $item->getName()); + self::assertSame(2, $item->getQuantity()); + self::assertSame('Large', $item->getVariant()); + self::assertSame('PHP', $item->getBrand()); + self::assertSame('Apparel', $item->getCategory()); + self::assertSame('T-shirts', $item->getCategory2()); + } +}