diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8679beed..cd7e13b3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -24,7 +24,7 @@ jobs:
php: [8.0]
symfony: [^5.4, ^6.0]
sylius: [~1.11.0, ~1.12.0]
- node: [14.x]
+ node: [14.17.x]
mysql: [5.7, 8.0]
exclude:
@@ -124,6 +124,11 @@ jobs:
restore-keys: |
${{ runner.os }}-node-${{ matrix.node }}-yarn-
+ -
+ name: Copy package.json.dist to package.json
+ if: matrix.sylius != ''
+ run: (cd tests/Application && cp package.json.\${{ matrix.sylius }}.dist package.json)
+
-
name: Install JS dependencies
run: (cd tests/Application && yarn install)
diff --git a/.gitignore b/.gitignore
index 5f8e7464..5cefda9b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,7 +7,12 @@
/tests/Application/yarn.lock
+/.phpunit.result.cache
/behat.yml
/phpspec.yml
/phpunit.xml
-/.phpunit.result.cache
+.phpunit.result.cache
+
+# Symfony CLI https://symfony.com/doc/current/setup/symfony_server.html#different-php-settings-per-project
+/.php-version
+/php.ini
diff --git a/composer.json b/composer.json
index 3130125e..813a3167 100644
--- a/composer.json
+++ b/composer.json
@@ -6,11 +6,11 @@
"license": "MIT",
"require": {
"php": "^8.0",
- "sylius/sylius": "~1.11.0 || ~1.12.0"
+ "sylius/sylius": "~1.11.0 || ~1.12.0",
+ "symfony/webpack-encore-bundle": "^1.12"
},
"require-dev": {
"ext-json": "*",
- "symfony/webpack-encore-bundle": "^1.15",
"behat/behat": "^3.6.1",
"behat/mink-selenium2-driver": "^1.4",
"dmore/behat-chrome-extension": "^1.3",
@@ -41,7 +41,8 @@
"friendsofphp/php-cs-fixer": "^3.0",
"bitbag/coding-standard": "^1.0",
"lchrusciel/api-test-case": "^5.1",
- "polishsymfonycommunity/symfony-mocker-container": "^1.0"
+ "polishsymfonycommunity/symfony-mocker-container": "^1.0",
+ "php-http/message-factory": "^1.1"
},
"conflict": {
"symfony/symfony": "4.1.8",
diff --git a/features/creating_bundled_product.feature b/features/creating_bundled_product.feature
new file mode 100644
index 00000000..be965851
--- /dev/null
+++ b/features/creating_bundled_product.feature
@@ -0,0 +1,34 @@
+@bundled_product
+Feature: Creating a product in store which is a bundle of other products
+ I want to be able to add bundled product to cart
+
+ Background:
+ Given the store operates on a single channel in "United States"
+ And I am logged in as an administrator
+ And the store has a product "Jack Daniels Gentleman" priced at "$10.00"
+ And the store has a product "Johny Walker Black" priced at "$10.00"
+ And the store has a product "Jim Beam Double Oak" priced at "$10.00"
+
+ @ui @javascript
+ Scenario: Creating a bundled product
+ When I want to create a new bundled product
+ And I specify its code as "WHISKEY_PACK"
+ And I name it "Whiskey double pack" in "English (United States)"
+ And I set its slug to "whiskey-double-pack" in "English (United States)"
+ And I set its price to "$10.00" for "United States" channel
+ And I set its original price to "$20.00" for "United States" channel
+ And I add product "Johny Walker Black" and "Jack Daniels Gentleman" to the bundle
+ And I add it
+ Then I should be notified that it has been successfully created
+
+ @ui @javascript
+ Scenario: Creating a bundled product with more products
+ When I want to create a new bundled product
+ And I specify its code as "WHISKEY_BIG_PACK"
+ And I name it "Whiskey triple pack" in "English (United States)"
+ And I set its slug to "whiskey-triple-pack" in "English (United States)"
+ And I set its price to "$10.00" for "United States" channel
+ And I set its original price to "$20.00" for "United States" channel
+ And I add product "Johny Walker Black" and "Jack Daniels Gentleman" and "Jim Beam Double Oak" to the bundle
+ And I add it
+ Then I should be notified that it has been successfully created
diff --git a/features/having_bundled_product_in_store.feature b/features/having_bundled_product_in_store.feature
index d1bdc501..1e9031d2 100644
--- a/features/having_bundled_product_in_store.feature
+++ b/features/having_bundled_product_in_store.feature
@@ -4,15 +4,37 @@ Feature: Having a product in store which is a bundle of other products
Background:
Given the store operates on a single channel in "United States"
- And the store has locale en_US
+ And I am a logged in customer
+ And the store ships everywhere for Free
+ And the store allows paying Offline
@ui
- Scenario: Adding a product to cart
- Given I am a logged in customer
- And the store has a product "Jack Daniels Gentleman" priced at "$10.00"
+ Scenario: Adding a product bundle to the cart
+ Given the store has a product "Jack Daniels Gentleman" priced at "$10.00"
And the store has a product "Johny Walker Black" priced at "$10.00"
And the store has bundled product "Whiskey double pack" priced at "$18.00" which contains "Jack Daniels Gentleman" and "Johny Walker Black"
And all store products appear under a main taxonomy
Then I added product "Whiskey double pack" to the cart
And I should be on my cart summary page
And there should be one item in my cart
+
+ @ui
+ Scenario: Adding a few product bundles to the cart
+ Given the store has a product "Jim Beam" priced at "$10.00"
+ And the store has a product "Jim Beam Double Oak" priced at "$10.00"
+ And the store has bundled product "Jim Beam double pack" priced at "$18.00" which contains "Jim Beam" and "Jim Beam Double Oak"
+ And all store products appear under a main taxonomy
+ Then I added product "Jim Beam double pack" to the cart
+ And I change product "Jim Beam double pack" quantity to 5 in my cart
+ And I should see "Jim Beam double pack" with quantity 5 in my cart
+
+ @ui
+ Scenario: Placing an order for a bundled product
+ Given the store has a product "Jim Beam" priced at "$10.00"
+ And the store has a product "Jim Beam Double Oak" priced at "$10.00"
+ And the store has bundled product "Jim Beam double pack" priced at "$18.00" which contains "Jim Beam" and "Jim Beam Double Oak"
+ Given I have product "Jim Beam double pack" in the cart
+ And I specified the billing address as "Ankh Morpork", "Frost Alley", "90210", "United States" for "Jon Snow"
+ And I proceed with "Free" shipping method and "Offline" payment
+ And I confirm my order
+ Then I should see the thank you page
diff --git a/src/Command/AddProductBundleItemToCartCommand.php b/src/Command/AddProductBundleItemToCartCommand.php
index d2a8149d..f2cca7b8 100644
--- a/src/Command/AddProductBundleItemToCartCommand.php
+++ b/src/Command/AddProductBundleItemToCartCommand.php
@@ -15,18 +15,11 @@
final class AddProductBundleItemToCartCommand
{
- /** @var ProductBundleItemInterface */
- private $productBundleItem;
-
- /** @var ProductVariantInterface|null */
- private $productVariant;
-
- /** @var int|null */
- private $quantity;
-
- public function __construct(ProductBundleItemInterface $productBundleItem)
- {
- $this->productBundleItem = $productBundleItem;
+ public function __construct(
+ private ProductBundleItemInterface $productBundleItem,
+ private ?ProductVariantInterface $productVariant = null,
+ private ?int $quantity = null
+ ) {
$this->productVariant = $productBundleItem->getProductVariant();
$this->quantity = $productBundleItem->getQuantity();
}
diff --git a/src/Command/AddProductBundleToCartCommand.php b/src/Command/AddProductBundleToCartCommand.php
index 7ef3e44c..6e100b6b 100644
--- a/src/Command/AddProductBundleToCartCommand.php
+++ b/src/Command/AddProductBundleToCartCommand.php
@@ -12,23 +12,11 @@
final class AddProductBundleToCartCommand implements OrderIdentityAwareInterface, ProductCodeAwareInterface
{
- /** @var int */
- private $orderId;
-
- /** @var string */
- private $productCode;
-
- /** @var int */
- private $quantity;
-
public function __construct(
- int $orderId,
- string $productCode,
- int $quantity = 1
+ private int $orderId,
+ private string $productCode,
+ private int $quantity = 1
) {
- $this->orderId = $orderId;
- $this->productCode = $productCode;
- $this->quantity = $quantity;
}
public function getOrderId(): int
diff --git a/src/Controller/OrderItemController.php b/src/Controller/OrderItemController.php
index 48859b53..f13d9e82 100644
--- a/src/Controller/OrderItemController.php
+++ b/src/Controller/OrderItemController.php
@@ -32,18 +32,6 @@
class OrderItemController extends BaseOrderItemController
{
- /** @var MessageBusInterface */
- protected $messageBus;
-
- /** @var OrderRepositoryInterface */
- protected $orderRepository;
-
- /** @var AddProductBundleToCartDtoFactoryInterface */
- private $addProductBundleToCartDtoFactory;
-
- /** @var AddProductBundleToCartCommandFactoryInterface */
- private $addProductBundleToCartCommandFactory;
-
public function __construct(
MetadataInterface $metadata,
Controller\RequestConfigurationFactoryInterface $requestConfigurationFactory,
@@ -62,10 +50,10 @@ public function __construct(
Controller\StateMachineInterface $stateMachine,
Controller\ResourceUpdateHandlerInterface $resourceUpdateHandler,
Controller\ResourceDeleteHandlerInterface $resourceDeleteHandler,
- MessageBusInterface $messageBus,
- OrderRepositoryInterface $orderRepository,
- AddProductBundleToCartDtoFactoryInterface $addProductBundleToCartDtoFactory,
- AddProductBundleToCartCommandFactoryInterface $addProductBundleToCartCommandFactory
+ private MessageBusInterface $messageBus,
+ private OrderRepositoryInterface $orderRepository,
+ private AddProductBundleToCartDtoFactoryInterface $addProductBundleToCartDtoFactory,
+ private AddProductBundleToCartCommandFactoryInterface $addProductBundleToCartCommandFactory
) {
parent::__construct(
$metadata,
@@ -86,11 +74,6 @@ public function __construct(
$resourceUpdateHandler,
$resourceDeleteHandler
);
-
- $this->messageBus = $messageBus;
- $this->orderRepository = $orderRepository;
- $this->addProductBundleToCartDtoFactory = $addProductBundleToCartDtoFactory;
- $this->addProductBundleToCartCommandFactory = $addProductBundleToCartCommandFactory;
}
public function addProductBundleAction(Request $request): ?Response
diff --git a/src/Dto/AddProductBundleToCartDto.php b/src/Dto/AddProductBundleToCartDto.php
index 6a320a13..fb40c854 100644
--- a/src/Dto/AddProductBundleToCartDto.php
+++ b/src/Dto/AddProductBundleToCartDto.php
@@ -10,7 +10,6 @@
namespace BitBag\SyliusProductBundlePlugin\Dto;
-use BitBag\SyliusProductBundlePlugin\Command\AddProductBundleItemToCartCommand;
use BitBag\SyliusProductBundlePlugin\Command\ProductCodeAwareInterface;
use BitBag\SyliusProductBundlePlugin\Entity\ProductInterface;
use Doctrine\Common\Collections\ArrayCollection;
@@ -19,30 +18,14 @@
final class AddProductBundleToCartDto implements AddProductBundleToCartDtoInterface, ProductCodeAwareInterface
{
- /** @var OrderInterface */
- private $cart;
+ private ArrayCollection $productBundleItems;
- /** @var OrderItemInterface */
- private $cartItem;
-
- /** @var ProductInterface */
- private $product;
-
- /** @var ArrayCollection */
- private $productBundleItems;
-
- /**
- * @param AddProductBundleItemToCartCommand[] $productBundleItems
- */
public function __construct(
- OrderInterface $cart,
- OrderItemInterface $cartItem,
- ProductInterface $product,
+ private OrderInterface $cart,
+ private OrderItemInterface $cartItem,
+ private ProductInterface $product,
array $productBundleItems
) {
- $this->cart = $cart;
- $this->cartItem = $cartItem;
- $this->product = $product;
$this->productBundleItems = new ArrayCollection($productBundleItems);
}
diff --git a/src/Dto/Api/AddProductBundleToCartDto.php b/src/Dto/Api/AddProductBundleToCartDto.php
index dd8d2e85..4d96771c 100644
--- a/src/Dto/Api/AddProductBundleToCartDto.php
+++ b/src/Dto/Api/AddProductBundleToCartDto.php
@@ -14,19 +14,11 @@
final class AddProductBundleToCartDto implements OrderTokenValueAwareInterface
{
- /** @var string|null */
- private $orderTokenValue;
-
- /** @var string */
- private $productCode;
-
- /** @var int */
- private $quantity;
-
- public function __construct(string $productCode, int $quantity = 1)
- {
- $this->productCode = $productCode;
- $this->quantity = $quantity;
+ public function __construct(
+ private string $productCode,
+ private int $quantity = 1,
+ private ?string $orderTokenValue = null
+ ) {
}
public function getOrderTokenValue(): ?string
diff --git a/src/Factory/AddProductBundleToCartDtoFactory.php b/src/Factory/AddProductBundleToCartDtoFactory.php
index b53e2012..b5277347 100644
--- a/src/Factory/AddProductBundleToCartDtoFactory.php
+++ b/src/Factory/AddProductBundleToCartDtoFactory.php
@@ -20,12 +20,9 @@
final class AddProductBundleToCartDtoFactory implements AddProductBundleToCartDtoFactoryInterface
{
- /** @var AddProductBundleItemToCartCommandFactoryInterface */
- private $addProductBundleItemToCartCommandFactory;
-
- public function __construct(AddProductBundleItemToCartCommandFactoryInterface $addProductBundleItemToCartCommandFactory)
- {
- $this->addProductBundleItemToCartCommandFactory = $addProductBundleItemToCartCommandFactory;
+ public function __construct(
+ private AddProductBundleItemToCartCommandFactoryInterface $addProductBundleItemToCartCommandFactory
+ ) {
}
public function createNew(
diff --git a/src/Factory/OrderItemFactory.php b/src/Factory/OrderItemFactory.php
index 38978397..b959ff98 100644
--- a/src/Factory/OrderItemFactory.php
+++ b/src/Factory/OrderItemFactory.php
@@ -18,12 +18,9 @@
final class OrderItemFactory implements OrderItemFactoryInterface
{
- /** @var CartItemFactoryInterface */
- private $decoratedFactory;
-
- public function __construct(CartItemFactoryInterface $decoratedFactory)
- {
- $this->decoratedFactory = $decoratedFactory;
+ public function __construct(
+ private CartItemFactoryInterface $decoratedFactory
+ ) {
}
public function createNew(): OrderItemInterface
diff --git a/src/Factory/ProductBundleOrderItemFactory.php b/src/Factory/ProductBundleOrderItemFactory.php
index cbc883cd..c54bc5b5 100644
--- a/src/Factory/ProductBundleOrderItemFactory.php
+++ b/src/Factory/ProductBundleOrderItemFactory.php
@@ -16,12 +16,9 @@
final class ProductBundleOrderItemFactory implements ProductBundleOrderItemFactoryInterface
{
- /** @var FactoryInterface */
- private $decoratedFactory;
-
- public function __construct(FactoryInterface $decoratedFactory)
- {
- $this->decoratedFactory = $decoratedFactory;
+ public function __construct(
+ private FactoryInterface $decoratedFactory
+ ) {
}
public function createNew(): ProductBundleOrderItemInterface
diff --git a/src/Factory/ProductFactory.php b/src/Factory/ProductFactory.php
index 65e6eef5..08507701 100644
--- a/src/Factory/ProductFactory.php
+++ b/src/Factory/ProductFactory.php
@@ -18,16 +18,10 @@
final class ProductFactory implements ProductFactoryInterface
{
- /** @var DecoratedProductFactoryInterface */
- private $decoratedFactory;
-
- /** @var FactoryInterface */
- private $productBundleFactory;
-
- public function __construct(DecoratedProductFactoryInterface $decoratedFactory, FactoryInterface $productBundleFactory)
- {
- $this->decoratedFactory = $decoratedFactory;
- $this->productBundleFactory = $productBundleFactory;
+ public function __construct(
+ private DecoratedProductFactoryInterface $decoratedFactory,
+ private FactoryInterface $productBundleFactory
+ ) {
}
public function createWithVariantAndBundle(): BaseProductInterface
diff --git a/src/Handler/AddProductBundleToCartHandler.php b/src/Handler/AddProductBundleToCartHandler.php
index 5ae0af0c..e0caed6d 100644
--- a/src/Handler/AddProductBundleToCartHandler.php
+++ b/src/Handler/AddProductBundleToCartHandler.php
@@ -21,23 +21,11 @@
final class AddProductBundleToCartHandler implements MessageHandlerInterface
{
- /** @var OrderRepositoryInterface */
- private $orderRepository;
-
- /** @var ProductRepositoryInterface */
- private $productRepository;
-
- /** @var CartProcessorInterface */
- private $cartProcessor;
-
public function __construct(
- OrderRepositoryInterface $orderRepository,
- ProductRepositoryInterface $productRepository,
- CartProcessorInterface $cartItemProcessor
+ private OrderRepositoryInterface $orderRepository,
+ private ProductRepositoryInterface $productRepository,
+ private CartProcessorInterface $cartProcessor
) {
- $this->orderRepository = $orderRepository;
- $this->productRepository = $productRepository;
- $this->cartProcessor = $cartItemProcessor;
}
public function __invoke(AddProductBundleToCartCommand $addProductBundleToCartCommand): void
diff --git a/src/Handler/AddProductBundleToCartHandler/CartProcessor.php b/src/Handler/AddProductBundleToCartHandler/CartProcessor.php
index bb2ffe32..9cb4dd87 100644
--- a/src/Handler/AddProductBundleToCartHandler/CartProcessor.php
+++ b/src/Handler/AddProductBundleToCartHandler/CartProcessor.php
@@ -21,28 +21,12 @@
final class CartProcessor implements CartProcessorInterface
{
- /** @var OrderItemQuantityModifierInterface */
- private $orderItemQuantityModifier;
-
- /** @var ProductBundleOrderItemFactoryInterface */
- private $productBundleOrderItemFactory;
-
- /** @var OrderModifierInterface */
- private $orderModifier;
-
- /** @var OrderItemFactoryInterface */
- private $cartItemFactory;
-
public function __construct(
- OrderItemQuantityModifierInterface $orderItemQuantityModifier,
- ProductBundleOrderItemFactoryInterface $productBundleOrderItemFactory,
- OrderModifierInterface $orderModifier,
- OrderItemFactoryInterface $cartItemFactory
+ private OrderItemQuantityModifierInterface $orderItemQuantityModifier,
+ private ProductBundleOrderItemFactoryInterface $productBundleOrderItemFactory,
+ private OrderModifierInterface $orderModifier,
+ private OrderItemFactoryInterface $cartItemFactory
) {
- $this->orderItemQuantityModifier = $orderItemQuantityModifier;
- $this->productBundleOrderItemFactory = $productBundleOrderItemFactory;
- $this->orderModifier = $orderModifier;
- $this->cartItemFactory = $cartItemFactory;
}
public function process(
diff --git a/src/Resources/views/Admin/Form/productBundleItem.html.twig b/src/Resources/views/Admin/Form/productBundleItem.html.twig
index 12786be3..60d9deb8 100644
--- a/src/Resources/views/Admin/Form/productBundleItem.html.twig
+++ b/src/Resources/views/Admin/Form/productBundleItem.html.twig
@@ -36,7 +36,7 @@
{% if prototype is defined and allow_add %}
-
+
{{ button_add_label|trans }}
@@ -49,7 +49,7 @@
{% apply spaceless %}
- {{ form_row(form.productVariant, {'remote_url': path('bitbag_product_bundle_admin_ajax_product_variants_by_phrase'), 'remote_criteria_type': 'contains', 'remote_criteria_name': 'phrase', 'load_edit_url': path('bitbag_product_bundle_admin_ajax_product_variants_by_codes')}) }}
+ {{ form_row(form.productVariant, {'remote_url': path('bitbag_product_bundle_admin_ajax_product_variants_by_phrase'), 'remote_criteria_type': 'contains', 'remote_criteria_name': 'phrase', 'load_edit_url': path('bitbag_product_bundle_admin_ajax_product_variants_by_codes')}) }}
|
{{ form_row(form.quantity) }}
diff --git a/src/Twig/Extension/ProductBundleOrderItemExtension.php b/src/Twig/Extension/ProductBundleOrderItemExtension.php
index d43eb70f..fcb3fd2f 100644
--- a/src/Twig/Extension/ProductBundleOrderItemExtension.php
+++ b/src/Twig/Extension/ProductBundleOrderItemExtension.php
@@ -19,16 +19,10 @@
final class ProductBundleOrderItemExtension extends AbstractExtension
{
- /** @var RepositoryInterface */
- private $productBundleOrderItemRepository;
-
- /** @var Environment */
- private $twig;
-
- public function __construct(RepositoryInterface $productBundleOrderItemRepository, Environment $twig)
- {
- $this->productBundleOrderItemRepository = $productBundleOrderItemRepository;
- $this->twig = $twig;
+ public function __construct(
+ private RepositoryInterface $productBundleOrderItemRepository,
+ private Environment $twig
+ ) {
}
public function getFunctions(): array
diff --git a/src/Validator/HasAvailableProductBundleValidator.php b/src/Validator/HasAvailableProductBundleValidator.php
index 9aa902d2..c22a119e 100644
--- a/src/Validator/HasAvailableProductBundleValidator.php
+++ b/src/Validator/HasAvailableProductBundleValidator.php
@@ -25,23 +25,11 @@
final class HasAvailableProductBundleValidator extends ConstraintValidator
{
- /** @var ProductRepositoryInterface */
- private $productRepository;
-
- /** @var OrderRepositoryInterface */
- private $orderRepository;
-
- /** @var AvailabilityCheckerInterface */
- private $availabilityChecker;
-
public function __construct(
- ProductRepositoryInterface $productRepository,
- OrderRepositoryInterface $orderRepository,
- AvailabilityCheckerInterface $availabilityChecker
+ private ProductRepositoryInterface $productRepository,
+ private OrderRepositoryInterface $orderRepository,
+ private AvailabilityCheckerInterface $availabilityChecker
) {
- $this->productRepository = $productRepository;
- $this->orderRepository = $orderRepository;
- $this->availabilityChecker = $availabilityChecker;
}
/**
diff --git a/src/Validator/HasExistingCartValidator.php b/src/Validator/HasExistingCartValidator.php
index 94861df2..75d39d0c 100644
--- a/src/Validator/HasExistingCartValidator.php
+++ b/src/Validator/HasExistingCartValidator.php
@@ -19,12 +19,9 @@
final class HasExistingCartValidator extends ConstraintValidator
{
- /** @var OrderRepositoryInterface */
- private $orderRepository;
-
- public function __construct(OrderRepositoryInterface $orderRepository)
- {
- $this->orderRepository = $orderRepository;
+ public function __construct(
+ private OrderRepositoryInterface $orderRepository
+ ) {
}
/**
diff --git a/src/Validator/HasProductBundleValidator.php b/src/Validator/HasProductBundleValidator.php
index 0b53ee55..58a4c4cb 100644
--- a/src/Validator/HasProductBundleValidator.php
+++ b/src/Validator/HasProductBundleValidator.php
@@ -20,12 +20,9 @@
final class HasProductBundleValidator extends ConstraintValidator
{
- /** @var ProductRepositoryInterface */
- private $productRepository;
-
- public function __construct(ProductRepositoryInterface $productRepository)
- {
- $this->productRepository = $productRepository;
+ public function __construct(
+ private ProductRepositoryInterface $productRepository
+ ) {
}
/**
diff --git a/src/Validator/Sequentially.php b/src/Validator/Sequentially.php
index c92c6c42..ce95d6f9 100644
--- a/src/Validator/Sequentially.php
+++ b/src/Validator/Sequentially.php
@@ -14,10 +14,7 @@
final class Sequentially extends Composite
{
- /** @var array */
- public $constraints = [];
-
- public function __construct(?array $constraints = null)
+ public function __construct(public ?array $constraints = null)
{
parent::__construct($constraints ?? []);
}
diff --git a/src/Validator/SequentiallyValidator.php b/src/Validator/SequentiallyValidator.php
index de83a512..057eeb58 100644
--- a/src/Validator/SequentiallyValidator.php
+++ b/src/Validator/SequentiallyValidator.php
@@ -28,9 +28,11 @@ public function validate(mixed $value, Constraint $constraint): void
$originalCount = $validator->getViolations()->count();
- foreach ($constraint->constraints as $c) {
- if ($originalCount !== $validator->validate($value, $c)->getViolations()->count()) {
- break;
+ if (is_iterable($constraint->constraints)) {
+ foreach ($constraint->constraints as $c) {
+ if ($originalCount !== $validator->validate($value, $c)->getViolations()->count()) {
+ break;
+ }
}
}
}
diff --git a/tests/Application/.gitignore b/tests/Application/.gitignore
index 8ad1225e..bc600a8c 100644
--- a/tests/Application/.gitignore
+++ b/tests/Application/.gitignore
@@ -1,4 +1,5 @@
/public/assets
+/public/build
/public/css
/public/js
/public/media/*
diff --git a/tests/Application/config/bundles.php b/tests/Application/config/bundles.php
index 414b2e59..18e508fd 100644
--- a/tests/Application/config/bundles.php
+++ b/tests/Application/config/bundles.php
@@ -1,11 +1,5 @@
['all' => true],
Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => ['test' => true],
Fidry\AliceDataFixtures\Bridge\Symfony\FidryAliceDataFixturesBundle::class => ['test' => true],
+ Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
+ Sylius\Calendar\SyliusCalendarBundle::class => ['all' => true],
+ BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true],
+ SyliusLabs\Polyfill\Symfony\Security\Bundle\SyliusLabsPolyfillSymfonySecurityBundle::class => ['all' => true],
];
diff --git a/tests/Application/config/packages/assets.yaml b/tests/Application/config/packages/assets.yaml
new file mode 100644
index 00000000..a7b133d0
--- /dev/null
+++ b/tests/Application/config/packages/assets.yaml
@@ -0,0 +1,11 @@
+framework:
+ assets:
+ packages:
+ shop:
+ json_manifest_path: '%kernel.project_dir%/public/build/shop/manifest.json'
+ admin:
+ json_manifest_path: '%kernel.project_dir%/public/build/admin/manifest.json'
+ product_bundle_shop:
+ json_manifest_path: '%kernel.project_dir%/public/build/bitbag/productBundle/shop/manifest.json'
+ product_bundle_admin:
+ json_manifest_path: '%kernel.project_dir%/public/build/bitbag/productBundle/admin/manifest.json'
diff --git a/tests/Application/config/packages/webpack_encore.yaml b/tests/Application/config/packages/webpack_encore.yaml
index 80beb76c..33196059 100644
--- a/tests/Application/config/packages/webpack_encore.yaml
+++ b/tests/Application/config/packages/webpack_encore.yaml
@@ -3,5 +3,5 @@ webpack_encore:
builds:
shop: '%kernel.project_dir%/public/build/shop'
admin: '%kernel.project_dir%/public/build/admin'
- cs_shop: '%kernel.project_dir%/public/build/bitbag/cs/shop'
- cs_admin: '%kernel.project_dir%/public/build/bitbag/cs/admin'
+ product_bundle_shop: '%kernel.project_dir%/public/build/bitbag/productBundle/shop'
+ product_bundle_admin: '%kernel.project_dir%/public/build/bitbag/productBundle/admin'
diff --git a/tests/Application/config/sylius/1.11/bundles.php b/tests/Application/config/sylius/1.11/bundles.php
index aa8974a9..b8da49fb 100644
--- a/tests/Application/config/sylius/1.11/bundles.php
+++ b/tests/Application/config/sylius/1.11/bundles.php
@@ -1,26 +1,7 @@
['all' => true],
- Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
];
-
-if (class_exists('BabDev\PagerfantaBundle\BabDevPagerfantaBundle')) {
- $bundles[BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class] = ['all' => true];
-}
-if (class_exists('SyliusLabs\Polyfill\Symfony\Security\Bundle\SyliusLabsPolyfillSymfonySecurityBundle')) {
- $bundles[SyliusLabs\Polyfill\Symfony\Security\Bundle\SyliusLabsPolyfillSymfonySecurityBundle::class] = ['all' => true];
-}
-if (class_exists('Sylius\Calendar\SyliusCalendarBundle')) {
- $bundles[Sylius\Calendar\SyliusCalendarBundle::class] = ['all' => true];
-}
-
-return $bundles;
diff --git a/tests/Application/config/sylius/1.12/bundles.php b/tests/Application/config/sylius/1.12/bundles.php
index 82a796e6..5f922a2d 100644
--- a/tests/Application/config/sylius/1.12/bundles.php
+++ b/tests/Application/config/sylius/1.12/bundles.php
@@ -1,17 +1,7 @@
['all' => true],
- Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
- Sylius\Calendar\SyliusCalendarBundle::class => ['all' => true],
- BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true],
- SyliusLabs\Polyfill\Symfony\Security\Bundle\SyliusLabsPolyfillSymfonySecurityBundle::class => ['all' => true],
];
diff --git a/tests/Application/package.json.~1.11.0.dist b/tests/Application/package.json.~1.11.0.dist
new file mode 100644
index 00000000..36e6c1f0
--- /dev/null
+++ b/tests/Application/package.json.~1.11.0.dist
@@ -0,0 +1,41 @@
+{
+ "dependencies": {
+ "@babel/polyfill": "^7.0.0",
+ "chart.js": "^3.7.1",
+ "jquery": "^3.5.0",
+ "jquery.dirtyforms": "^2.0.0",
+ "lightbox2": "^2.9.0",
+ "semantic-ui-css": "^2.2.0",
+ "slick-carousel": "^1.8.1"
+ },
+ "devDependencies": {
+ "@symfony/webpack-encore": "^1.6.1",
+ "babel-core": "^6.26.3",
+ "babel-plugin-external-helpers": "^6.22.0",
+ "babel-plugin-module-resolver": "^3.1.1",
+ "babel-plugin-transform-object-rest-spread": "^6.26.0",
+ "babel-preset-env": "^1.7.0",
+ "babel-register": "^6.26.0",
+ "dedent": "^0.7.0",
+ "eslint": "^4.19.1",
+ "eslint-config-airbnb-base": "^12.1.0",
+ "eslint-import-resolver-babel-module": "^4.0.0",
+ "eslint-plugin-import": "^2.11.0",
+ "merge-stream": "^1.0.0",
+ "sass": "^1.39.2",
+ "sass-loader": "^12.1.0"
+ },
+ "scripts": {
+ "dev": "yarn encore dev",
+ "watch": "yarn encore dev --watch",
+ "prod": "yarn encore prod",
+ "lint": "yarn lint:js",
+ "lint:js": "eslint gulpfile.babel.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/Sylius/Sylius.git"
+ },
+ "author": "Paweł Jędrzejewski",
+ "license": "MIT"
+}
diff --git a/tests/Application/package.json b/tests/Application/package.json.~1.12.0.dist
similarity index 100%
rename from tests/Application/package.json
rename to tests/Application/package.json.~1.12.0.dist
diff --git a/tests/Application/templates/bundles/SyliusAdminBundle/Layout/_logo.html.twig b/tests/Application/templates/bundles/SyliusAdminBundle/Layout/_logo.html.twig
new file mode 100644
index 00000000..1d9fa7d0
--- /dev/null
+++ b/tests/Application/templates/bundles/SyliusAdminBundle/Layout/_logo.html.twig
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/tests/Application/templates/bundles/SyliusAdminBundle/_scripts.html.twig b/tests/Application/templates/bundles/SyliusAdminBundle/_scripts.html.twig
new file mode 100644
index 00000000..54be86fa
--- /dev/null
+++ b/tests/Application/templates/bundles/SyliusAdminBundle/_scripts.html.twig
@@ -0,0 +1,2 @@
+{{ encore_entry_script_tags('admin-entry', null, 'admin') }}
+{{ encore_entry_script_tags('bitbag-productBundle-admin', null, 'product_bundle_admin') }}
diff --git a/tests/Application/templates/bundles/SyliusAdminBundle/_styles.html.twig b/tests/Application/templates/bundles/SyliusAdminBundle/_styles.html.twig
new file mode 100644
index 00000000..d87343da
--- /dev/null
+++ b/tests/Application/templates/bundles/SyliusAdminBundle/_styles.html.twig
@@ -0,0 +1,2 @@
+{{ encore_entry_link_tags('admin-entry', null, 'admin') }}
+{{ encore_entry_link_tags('bitbag-productBundle-admin', null, 'product_bundle_admin') }}
diff --git a/tests/Application/templates/bundles/SyliusShopBundle/Layout/Header/_logo.html.twig b/tests/Application/templates/bundles/SyliusShopBundle/Layout/Header/_logo.html.twig
new file mode 100644
index 00000000..84b8df56
--- /dev/null
+++ b/tests/Application/templates/bundles/SyliusShopBundle/Layout/Header/_logo.html.twig
@@ -0,0 +1,5 @@
+
diff --git a/tests/Application/templates/bundles/SyliusShopBundle/_scripts.html.twig b/tests/Application/templates/bundles/SyliusShopBundle/_scripts.html.twig
new file mode 100644
index 00000000..278c091e
--- /dev/null
+++ b/tests/Application/templates/bundles/SyliusShopBundle/_scripts.html.twig
@@ -0,0 +1,2 @@
+{{ encore_entry_script_tags('shop-entry', null, 'shop') }}
+{{ encore_entry_script_tags('bitbag-productBundle-shop', null, 'product_bundle_shop') }}
diff --git a/tests/Application/templates/bundles/SyliusShopBundle/_styles.html.twig b/tests/Application/templates/bundles/SyliusShopBundle/_styles.html.twig
new file mode 100644
index 00000000..5365a60e
--- /dev/null
+++ b/tests/Application/templates/bundles/SyliusShopBundle/_styles.html.twig
@@ -0,0 +1,2 @@
+{{ encore_entry_link_tags('shop-entry', null, 'shop') }}
+{{ encore_entry_link_tags('bitbag-productBundle-shop', null, 'product_bundle_shop') }}
diff --git a/tests/Application/webpack.config.js b/tests/Application/webpack.config.js
index be0fe917..8bbcb1a9 100644
--- a/tests/Application/webpack.config.js
+++ b/tests/Application/webpack.config.js
@@ -1,6 +1,6 @@
const path = require('path');
const Encore = require('@symfony/webpack-encore');
-const [bitbagCsShop, bitbagCsAdmin] = require('../../webpack.config.js');
+const [bitbagProductBundleShop, bitbagProductBundleAdmin] = require('../../webpack.config.js');
const syliusBundles = path.resolve(__dirname, '../../vendor/sylius/sylius/src/Sylius/Bundle/');
const uiBundleScripts = path.resolve(syliusBundles, 'UiBundle/Resources/private/js/');
@@ -44,4 +44,4 @@ adminConfig.resolve.alias['chart.js/dist/Chart.min'] = path.resolve(__dirname, '
adminConfig.externals = Object.assign({}, adminConfig.externals, {window: 'window', document: 'document'});
adminConfig.name = 'admin';
-module.exports = [shopConfig, adminConfig, bitbagCsShop, bitbagCsAdmin];
+module.exports = [shopConfig, adminConfig, bitbagProductBundleShop, bitbagProductBundleAdmin];
diff --git a/tests/Behat/Context/Setup/ProductBundleContext.php b/tests/Behat/Context/Setup/ProductBundleContext.php
index e36ae923..cbd157f6 100644
--- a/tests/Behat/Context/Setup/ProductBundleContext.php
+++ b/tests/Behat/Context/Setup/ProductBundleContext.php
@@ -29,58 +29,18 @@
final class ProductBundleContext implements Context
{
- /** @var SharedStorageInterface */
- private $sharedStorage;
-
- /** @var FactoryInterface */
- private $taxonFactory;
-
- /** @var ProductRepositoryInterface */
- private $productRepository;
-
- /** @var FactoryInterface */
- private $productTaxonFactory;
-
- /** @var EntityManagerInterface */
- private $productTaxonManager;
-
- /** @var ProductFactory */
- private $productFactory;
-
- /** @var FactoryInterface */
- private $productBundleItemFactory;
-
- /** @var FactoryInterface */
- private $channelPricingFactory;
-
- /** @var ProductVariantResolverInterface */
- private $productVariantResolver;
-
- /** @var SlugGeneratorInterface */
- private $slugGenerator;
-
public function __construct(
- SharedStorageInterface $sharedStorage,
- FactoryInterface $taxonFactory,
- ProductRepositoryInterface $productRepository,
- FactoryInterface $productTaxonFactory,
- EntityManagerInterface $productTaxonManager,
- ProductFactory $productFactory,
- FactoryInterface $productBundleItemFactory,
- FactoryInterface $channelPricingFactory,
- ProductVariantResolverInterface $productVariantResolver,
- SlugGeneratorInterface $slugGenerator
+ private SharedStorageInterface $sharedStorage,
+ private FactoryInterface $taxonFactory,
+ private ProductRepositoryInterface $productRepository,
+ private FactoryInterface $productTaxonFactory,
+ private EntityManagerInterface $productTaxonManager,
+ private ProductFactory $productFactory,
+ private FactoryInterface $productBundleItemFactory,
+ private FactoryInterface $channelPricingFactory,
+ private ProductVariantResolverInterface $productVariantResolver,
+ private SlugGeneratorInterface $slugGenerator
) {
- $this->sharedStorage = $sharedStorage;
- $this->taxonFactory = $taxonFactory;
- $this->productRepository = $productRepository;
- $this->productTaxonFactory = $productTaxonFactory;
- $this->productTaxonManager = $productTaxonManager;
- $this->productFactory = $productFactory;
- $this->productBundleItemFactory = $productBundleItemFactory;
- $this->channelPricingFactory = $channelPricingFactory;
- $this->productVariantResolver = $productVariantResolver;
- $this->slugGenerator = $slugGenerator;
}
/**
diff --git a/tests/Behat/Context/Ui/ProductBundleContext.php b/tests/Behat/Context/Ui/ProductBundleContext.php
new file mode 100644
index 00000000..85f4429d
--- /dev/null
+++ b/tests/Behat/Context/Ui/ProductBundleContext.php
@@ -0,0 +1,92 @@
+createBundledProductPage->open();
+ }
+
+ /**
+ * @When I specify its code as :code
+ */
+ public function iSpecifyItsCode(string $code): void
+ {
+ $this->createBundledProductPage->specifyCode($code);
+ }
+
+ /**
+ * @When I name it :name in :language
+ */
+ public function iRenameItToIn(?string $name = null, ?string $language = null): void
+ {
+ if (null !== $name && null !== $language) {
+ $this->createBundledProductPage->nameItIn($name, $language);
+ }
+ }
+
+ /**
+ * @When I set its slug to :slug
+ * @When I set its slug to :slug in :language
+ */
+ public function iSetItsSlugToIn(?string $slug = null, $language = 'en_US')
+ {
+ $this->createBundledProductPage->specifySlugIn($slug, $language);
+ }
+
+ /**
+ * @When /^I set its(?:| default) price to "(?:€|£|\$)([^"]+)" for ("([^"]+)" channel)$/
+ */
+ public function iSetItsPriceTo(string $price, ChannelInterface $channel)
+ {
+ $this->createBundledProductPage->specifyPrice($channel, $price);
+ }
+
+ /**
+ * @When /^I set its original price to "(?:€|£|\$)([^"]+)" for ("([^"]+)" channel)$/
+ */
+ public function iSetItsOriginalPriceTo(int $originalPrice, ChannelInterface $channel)
+ {
+ $this->createBundledProductPage->specifyOriginalPrice($channel, $originalPrice);
+ }
+
+ /**
+ * @When I add it
+ */
+ public function iAddIt()
+ {
+ $this->createBundledProductPage->create();
+ }
+
+ /**
+ * @When I add product :productName to the bundle
+ * @When I add product :firstProductName and :secondProductName to the bundle
+ * @When I add product :firstProductName and :secondProductName and :thirdProductName to the bundle
+ */
+ public function iAddProductsToBundledProduct(...$productsNames)
+ {
+ $this->createBundledProductPage->addProductsToBundle($productsNames);
+ }
+}
diff --git a/tests/Behat/Page/Admin/CreateBundledProductPage.php b/tests/Behat/Page/Admin/CreateBundledProductPage.php
new file mode 100644
index 00000000..5d83e714
--- /dev/null
+++ b/tests/Behat/Page/Admin/CreateBundledProductPage.php
@@ -0,0 +1,121 @@
+getDocument()->fillField('Code', $code);
+ }
+
+ public function nameItIn(string $name, string $localeCode): void
+ {
+ $this->clickTabIfItsNotActive('details');
+ $this->activateLanguageTab($localeCode);
+ $this->getElement('name', ['%locale%' => $localeCode])->setValue($name);
+ }
+
+ public function specifySlugIn(?string $slug, string $locale): void
+ {
+ $this->activateLanguageTab($locale);
+
+ $this->getElement('slug', ['%locale%' => $locale])->setValue($slug);
+ }
+
+ public function activateLanguageTab(string $locale): void
+ {
+ if (DriverHelper::isNotJavascript($this->getDriver())) {
+ return;
+ }
+
+ $languageTabTitle = $this->getElement('language_tab', ['%locale%' => $locale]);
+ if (!$languageTabTitle->hasClass('active')) {
+ $languageTabTitle->click();
+ }
+ }
+
+ public function specifyPrice(ChannelInterface $channel, string $price): void
+ {
+ $this->getElement('price', ['%channelCode%' => $channel->getCode()])->setValue($price);
+ }
+
+ public function specifyOriginalPrice(ChannelInterface $channel, int $originalPrice): void
+ {
+ $this->getElement('original_price', ['%channelCode%' => $channel->getCode()])->setValue($originalPrice);
+ }
+
+ public function addProductsToBundle(array $productsNames): void
+ {
+ $this->clickTabIfItsNotActive('bundle');
+
+ $productCounter = 0;
+
+ foreach ($productsNames as $productName) {
+ $addSelector = $this->getElement('add_product_to_bundle_button');
+ $addSelector->click();
+ $addSelector->waitFor(5, fn () => $this->hasElement('product_selector_dropdown'));
+
+ $dropdown = $this->getLastProductAutocomplete();
+ $dropdown->click();
+ $dropdown->waitFor(5, fn () => $this->hasElement('product_selector_dropdown_item'));
+
+ $item = $this->getElement('product_selector_dropdown_item', [
+ '%item%' => $productName,
+ ]);
+ $item->click();
+
+ $this->getElement('product_selector_quantity', ['%productCounter%' => $productCounter])->setValue('1');
+
+ ++$productCounter;
+ }
+ }
+
+ protected function getDefinedElements(): array
+ {
+ return array_merge(parent::getDefinedElements(), [
+ 'product_selector_quantity' => '#sylius_product_productBundle_productBundleItems_%productCounter%_quantity',
+ 'product_selector_dropdown_item' => '#add_product_to_bundle_autocomplete > div > div > div.menu.transition.visible > div.item:contains("%item%")',
+ 'product_selector_dropdown' => '#add_product_to_bundle_autocomplete',
+ 'add_product_to_bundle_button' => '#bitbag_add_product_to_bundle_button',
+ 'code' => '#sylius_product_code',
+ 'language_tab' => '[data-locale="%locale%"] .title',
+ 'name' => '#sylius_product_translations_%locale%_name',
+ 'original_price' => '#sylius_product_variant_channelPricings_%channelCode%_originalPrice',
+ 'price' => '#sylius_product_variant_channelPricings_%channelCode%_price',
+ 'slug' => '#sylius_product_translations_%locale%_slug',
+ 'tab' => '.menu [data-tab="%name%"]',
+ ]);
+ }
+
+ private function clickTabIfItsNotActive(string $tabName): void
+ {
+ $attributesTab = $this->getElement('tab', ['%name%' => $tabName]);
+ if (!$attributesTab->hasClass('active')) {
+ $attributesTab->click();
+ }
+ }
+
+ private function getLastProductAutocomplete(): NodeElement
+ {
+ $items = $this->getDocument()->findAll('css', '#add_product_to_bundle_autocomplete');
+
+ Assert::notEmpty($items);
+
+ return end($items);
+ }
+}
diff --git a/tests/Behat/Page/Admin/CreateBundledProductPageInterface.php b/tests/Behat/Page/Admin/CreateBundledProductPageInterface.php
new file mode 100644
index 00000000..d7c4250a
--- /dev/null
+++ b/tests/Behat/Page/Admin/CreateBundledProductPageInterface.php
@@ -0,0 +1,23 @@
+ {
Encore.reset();
|