Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Product] Composite variant resolver #15099

Merged
21 changes: 15 additions & 6 deletions UPGRADE-1.13.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@
1. Not passing `Doctrine\Persistence\ObjectManager` to `Sylius\Component\Core\Updater\UnpaidOrdersStateUpdater`
as a fifth argument is deprecated.

1. To allow to autoconfigure order processors and cart context and define a priority for them in `1.13` we have introduced
`Sylius\Bundle\OrderBundle\Attribute\AsCartContext` and `Sylius\Bundle\OrderBundle\Attribute\AsOrderProcessor` attributes. By default, Sylius still configures them using interfaces, but this way you cannot define a priority.
1. To ease customization we've introduces attributes for some services in `1.13`:
- `Sylius\Bundle\OrderBundle\Attribute\AsCartContext` for cart contexts
- `Sylius\Bundle\OrderBundle\Attribute\AsOrderProcessor` for order processors
- `Sylius\Bundle\ProductBundle\Attribute\AsProductVariantResolver` for product variant resolvers

By default, Sylius still configures them using interfaces, but this way you cannot define a priority.
If you want to define a priority, you need to set the following configuration in your `_sylius.yaml` file:
```yaml
sylius_core:
autoconfigure_with_attributes: true
```
and use one of the new attributes accordingly to a type of your class, e.g.:
and use one of the new attributes accordingly to the type of your class, e.g.:
```php
<?php

Expand All @@ -35,8 +39,7 @@
use Sylius\Component\Order\Model\OrderInterface;
use Sylius\Component\Order\Processor\OrderProcessorInterface;

#[AsOrderProcessor(priority: 10)] //priority is optional
//#[AsOrderProcessor] can be used as well
#[AsOrderProcessor(/*priority: 10*/)] //priority is optional
final class OrderProcessorWithAttributeStub implements OrderProcessorInterface
{
public function process(OrderInterface $order): void
Expand Down Expand Up @@ -72,7 +75,7 @@
depending on your Guzzle version.
Subsequently, you need to register the adapter as a `Psr\Http\Client\ClientInterface` service as the following:
```yaml
services:
services:
Psr\Http\Client\ClientInterface:
class: Http\Adapter\Guzzle7\Client # for Guzzle 6 use Http\Adapter\Guzzle6\Client instead
```
Expand Down Expand Up @@ -105,3 +108,9 @@

1. PostgreSQL migration support has been introduced. If you are using PostgreSQL, we assume that you have already created a database schema in some way.
All you need to do is run migrations, which will mark all migrations created before Sylius 1.13 as executed.

1. Product variants resolving has been refactored for better extendability.
The tag `sylius.product_variant_resolver.default` has been removed as it was never used.

All internal usages of service `sylius.product_variant_resolver.default` have been switched to `Sylius\Component\Product\Resolver\ProductVariantResolverInterface`, if you have been using the
`sylius.product_variant_resolver.default` service apply this change accordingly.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<argument type="service" id="sylius.behat.api_platform_client.admin" />
<argument type="service" id="Sylius\Behat\Client\ResponseCheckerInterface" />
<argument type="service" id="sylius.behat.shared_storage" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
<argument type="service" id="api_platform.iri_converter" />
<argument type="service" id="sylius.behat.request_factory" />
<argument>%sylius.security.new_api_route%</argument>
Expand Down Expand Up @@ -77,7 +77,7 @@
<argument type="service" id="sylius.repository.shipping_method" />
<argument type="service" id="sylius.repository.order" />
<argument type="service" id="sylius.repository.payment_method" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
<argument type="service" id="api_platform.iri_converter" />
<argument type="service" id="sylius.behat.shared_storage" />
<argument type="service" id="sylius.behat.request_factory" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<argument type="service" id="sylius.repository.address"/>
<argument type="service" id="sylius.repository.adjustment"/>
<argument type="service" id="sylius.manager.order"/>
<argument type="service" id="sylius.product_variant_resolver.default"/>
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface"/>
<argument type="service" id="sylius.unpaid_orders_state_updater" />
</service>

Expand All @@ -35,7 +35,7 @@

<service id="Sylius\Behat\Context\Domain\ManagingPriceHistoryContext">
<argument type="service" id="sylius.repository.channel_pricing_log_entry" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PriceHistory\Remover\ChannelPricingLogEntriesRemoverInterface" />
</service>

Expand Down
10 changes: 5 additions & 5 deletions src/Sylius/Behat/Resources/config/services/contexts/setup.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

<service id="sylius.behat.context.setup.cart" class="Sylius\Behat\Context\Setup\CartContext">
<argument type="service" id="sylius.command_bus" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
<argument type="service" id="sylius.random_generator" />
<argument type="service" id="sylius.behat.shared_storage" />
</service>
Expand Down Expand Up @@ -115,7 +115,7 @@
<argument type="service" id="sylius.repository.order" />
<argument type="service" id="sylius.repository.payment_method" />
<argument type="service" id="sylius.repository.shipping_method" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
<argument type="service" id="sylius.order_item_quantity_modifier" />
<argument type="service" id="doctrine.orm.entity_manager" />
</service>
Expand All @@ -137,7 +137,7 @@
<service id="Sylius\Behat\Context\Setup\PriceHistoryContext">
<argument type="service" id="Sylius\Calendar\Tests\Behat\Context\Setup\CalendarContext" />
<argument type="service" id="sylius.manager.channel_pricing" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
</service>

<service id="sylius.behat.context.setup.product" class="Sylius\Behat\Context\Setup\ProductContext">
Expand All @@ -154,7 +154,7 @@
<argument type="service" id="doctrine.orm.entity_manager" />
<argument type="service" id="sylius.generator.product_variant" />
<argument type="service" id="sylius.repository.product_variant" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
<argument type="service" id="sylius.image_uploader" />
<argument type="service" id="sylius.generator.slug" />
<argument type="service" id="behat.mink.parameters" />
Expand Down Expand Up @@ -311,7 +311,7 @@
<service id="Sylius\Behat\Context\Setup\PriceHistoryContext" public="true">
<argument type="service" id="Sylius\Calendar\Tests\Behat\Context\Setup\CalendarContext" />
<argument type="service" id="sylius.manager.channel_pricing" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
</service>
</services>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@

<service id="sylius.behat.context.ui.admin.browsing_product_variants" class="Sylius\Behat\Context\Ui\Admin\BrowsingProductVariantsContext">
<argument type="service" id="sylius.behat.page.admin.product_variant.index" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
</service>

<service id="sylius.behat.context.ui.admin.managing_promotions" class="Sylius\Behat\Context\Ui\Admin\ManagingPromotionsContext">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
</service>

<service id="Sylius\Bundle\ApiBundle\Serializer\ProductNormalizer">
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
<argument type="service" id="api_platform.iri_converter" />
<tag name="serializer.normalizer" priority="64" />
</service>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@

<service id="sylius.custom_factory.order_item" class="Sylius\Component\Core\Factory\CartItemFactory" decorates="sylius.factory.order_item" decoration-priority="256" public="false">
<argument type="service" id="sylius.custom_factory.order_item.inner" />
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
</service>
<service id="sylius.factory.cart_item" alias="sylius.custom_factory.order_item" />
<service id="sylius.custom_factory.address" class="Sylius\Component\Core\Factory\AddressFactory" decorates="sylius.factory.address" decoration-priority="256" public="false">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
</service>

<service id="sylius.templating.helper.variant_resolver" class="Sylius\Bundle\CoreBundle\Templating\Helper\VariantResolverHelper">
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
<tag name="templating.helper" alias="sylius_resolve_variant" />
</service>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\DefinitionHasTagConstraint;
use Sylius\Bundle\CoreBundle\DependencyInjection\SyliusCoreExtension;
use Sylius\Bundle\OrderBundle\DependencyInjection\SyliusOrderExtension;
use Sylius\Bundle\ProductBundle\DependencyInjection\SyliusProductExtension;
use Sylius\Component\Core\Filesystem\Adapter\FilesystemAdapterInterface;
use Sylius\Component\Core\Filesystem\Adapter\FlysystemFilesystemAdapter;
use Sylius\Component\Core\Filesystem\Adapter\GaufretteFilesystemAdapter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\ProductBundle\Attribute;

#[\Attribute(\Attribute::TARGET_CLASS)]
final class AsProductVariantResolver
{
public function __construct(private int $priority = 0)
{
}

public function getPriority(): int
{
return $this->priority;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\ProductBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class DefaultProductVariantResolverCompilerPass implements CompilerPassInterface
{
private const DEFAULT_PRIORITY = -999;

public function process(ContainerBuilder $container): void
{
if (!$container->has('sylius.product_variant_resolver.default')) {
return;
}

// In case someone overwritten the service, we need to make sure it's tagged
$defaultResolver = $container->getDefinition('sylius.product_variant_resolver.default');
if (!$defaultResolver->hasTag('sylius.product_variant_resolver')) {
$defaultResolver->addTag('sylius.product_variant_resolver', ['priority' => self::DEFAULT_PRIORITY]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace Sylius\Bundle\ProductBundle\DependencyInjection;

use Sylius\Bundle\ProductBundle\Attribute\AsProductVariantResolver;
use Sylius\Bundle\ProductBundle\Controller\ProductAttributeController;
use Sylius\Bundle\ProductBundle\Doctrine\ORM\ProductAttributeValueRepository;
use Sylius\Bundle\ProductBundle\Form\Type\ProductAttributeTranslationType;
Expand All @@ -26,6 +27,7 @@
use Sylius\Component\Product\Model\ProductAttributeValue;
use Sylius\Component\Product\Model\ProductAttributeValueInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
Expand All @@ -42,6 +44,8 @@ public function load(array $configs, ContainerBuilder $container): void
$this->registerResources('sylius', $config['driver'], $config['resources'], $container);

$loader->load('services.xml');

$this->registerAutoconfiguration($container);
}

public function prepend(ContainerBuilder $container): void
Expand All @@ -51,6 +55,16 @@ public function prepend(ContainerBuilder $container): void
$this->prependAttribute($container, $config);
}

private function registerAutoconfiguration(ContainerBuilder $container): void
{
$container->registerAttributeForAutoconfiguration(
AsProductVariantResolver::class,
static function (ChildDefinition $definition, AsProductVariantResolver $attribute): void {
$definition->addTag('sylius.product_variant_resolver', ['priority' => $attribute->getPriority()]);
},
);
}

private function prependAttribute(ContainerBuilder $container, array $config): void
{
if (!$container->hasExtension('sylius_attribute')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,13 @@
<service id="sylius.generator.slug" class="Sylius\Component\Product\Generator\SlugGenerator" />
<service id="Sylius\Component\Product\Generator\SlugGeneratorInterface" alias="sylius.generator.slug" />

<service id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" class="Sylius\Component\Product\Resolver\CompositeProductVariantResolver">
<argument type="tagged_iterator" tag="sylius.product_variant_resolver" />
</service>

<service id="sylius.product_variant_resolver.default" class="Sylius\Component\Product\Resolver\DefaultProductVariantResolver">
<tag name="sylius.product_variant_resolver.default" type="default" />
<tag name="sylius.product_variant_resolver" priority="-999" />
</service>
<service id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" alias="sylius.product_variant_resolver.default" />

<service id="sylius.listener.select_product_attribute_choice_remove" class="Sylius\Bundle\ProductBundle\EventListener\SelectProductAttributeChoiceRemoveListener">
<argument>%sylius.model.product_attribute_value.class%</argument>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
<service id="sylius.form.type.product" class="Sylius\Bundle\ProductBundle\Form\Type\ProductType">
<argument>%sylius.model.product.class%</argument>
<argument>%sylius.form.type.product.validation_groups%</argument>
<argument type="service" id="sylius.product_variant_resolver.default" />
<argument type="service" id="Sylius\Component\Product\Resolver\ProductVariantResolverInterface" />
<argument type="service" id="sylius.factory.product_attribute_value" />
<argument type="service" id="sylius.translation_locale_provider" />
<tag name="form.type" />
Expand Down
9 changes: 9 additions & 0 deletions src/Sylius/Bundle/ProductBundle/SyliusProductBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,20 @@

namespace Sylius\Bundle\ProductBundle;

use Sylius\Bundle\ProductBundle\DependencyInjection\Compiler\DefaultProductVariantResolverCompilerPass;
use Sylius\Bundle\ResourceBundle\AbstractResourceBundle;
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class SyliusProductBundle extends AbstractResourceBundle
{
public function build(ContainerBuilder $container): void
{
parent::build($container);

$container->addCompilerPass(new DefaultProductVariantResolverCompilerPass());
}

public function getSupportedDrivers(): array
{
return [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\ProductBundle\Tests\DependencyInjection\Compiler;

use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractCompilerPassTestCase;
use Sylius\Bundle\ProductBundle\DependencyInjection\Compiler\DefaultProductVariantResolverCompilerPass;
use Sylius\Component\Product\Resolver\ProductVariantResolverInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;

final class DefaultProductVariantResolverCompilerPassTest extends AbstractCompilerPassTestCase
{
/** @test */
public function it_does_nothing_when_default_resolver_is_not_present(): void
{
$this->compile();

$this->assertContainerBuilderNotHasService('sylius.product_variant_resolver.default');
}

/** @test */
public function it_does_nothing_when_default_resolver_already_has_the_tag(): void
{
$defaultResolver = $this->registerService(
'sylius.product_variant_resolver.default',
ProductVariantResolverInterface::class,
);
$defaultResolver->addTag('sylius.product_variant_resolver');

$this->compile();

$this->assertContainerBuilderHasServiceDefinitionWithTag(
'sylius.product_variant_resolver.default',
'sylius.product_variant_resolver',
);
}

/** @test */
public function it_adds_variant_resolver_tag_with_very_low_priority_to_the_default_resolver(): void
{
$this->setDefinition('sylius.product_variant_resolver.default', new Definition());

$this->compile();

$this->assertContainerBuilderHasServiceDefinitionWithTag(
'sylius.product_variant_resolver.default',
'sylius.product_variant_resolver',
['priority' => -999],
);
}

protected function registerCompilerPass(ContainerBuilder $container): void
{
$container->addCompilerPass(new DefaultProductVariantResolverCompilerPass());
}
}