├── .github ├── CODEOWNERS └── workflows │ ├── build.yml │ └── coding_standard.yml ├── .gitignore ├── README.md ├── README_webpack-config.md ├── assets ├── admin │ ├── entry.js │ ├── js │ │ └── index.js │ └── scss │ │ └── main.scss └── shop │ ├── entry.js │ ├── js │ └── index.js │ └── scss │ └── main.scss ├── behat.yml.dist ├── composer.json ├── config ├── api_resources │ ├── admin │ │ └── ProductBundle.xml │ └── shop │ │ ├── Order.xml │ │ ├── Product.xml │ │ ├── ProductBundle.xml │ │ └── ProductBundleItem.xml ├── config.yml ├── doctrine │ ├── ProductBundle.orm.xml │ ├── ProductBundleItem.orm.xml │ └── ProductBundleOrderItem.orm.xml ├── resources.yml ├── resources │ ├── product_bundle.yml │ ├── product_bundle_item.yml │ └── product_bundle_order_item.yml ├── routes.yml ├── routes │ ├── admin.yml │ └── shop.yml ├── serialization │ ├── AddProductBundleToCartCommand.xml │ ├── AddProductBundleToCartDto.xml │ ├── OrderItem.xml │ ├── Product.xml │ ├── ProductBundle.xml │ ├── ProductBundleItem.xml │ ├── ProductBundleOrderItem.xml │ ├── ProductVariant.xml │ └── ProductVariantTranslation.xml ├── services.xml ├── services │ ├── controller.xml │ ├── event_listener.xml │ ├── factory.xml │ ├── form.xml │ ├── handler.xml │ ├── menu.xml │ ├── processor.xml │ ├── product.xml │ ├── transformer.xml │ ├── twig.xml │ └── validator.xml ├── twig_hooks │ ├── order │ │ └── show.yaml │ ├── product │ │ ├── admin │ │ │ ├── create.yaml │ │ │ └── update.yaml │ │ └── shop │ │ │ └── show.yaml │ └── twig_hooks.yaml └── validation │ ├── AddProductBundleToCartCommand.xml │ ├── AddProductBundleToCartDto.xml │ ├── ProductBundle.xml │ └── ProductBundleItem.xml ├── doc ├── bundle.png ├── bundle_cart.png ├── bundle_productpage.png ├── bundle_taxon.png ├── create_bundle.png └── functionalities.md ├── ecs.php ├── features ├── creating_bundled_product.feature └── having_bundled_product_in_store.feature ├── node_modules ├── phpspec.yml.dist ├── phpstan.neon.dist ├── phpunit.xml.dist ├── spec └── EventListener │ └── AddProductToProductBundleWhenEditNormalProductEventListenerSpec.php ├── src ├── BitBagSyliusProductBundlePlugin.php ├── Command │ ├── AddProductBundleItemToCartCommand.php │ ├── AddProductBundleToCartCommand.php │ ├── OrderIdentityAwareInterface.php │ └── ProductCodeAwareInterface.php ├── Component │ └── Product │ │ └── AddToCartFormComponent.php ├── DataTransformer │ └── AddProductBundleToCartDtoDataTransformer.php ├── DependencyInjection │ └── CompilerPass │ │ └── AuthenticationManagerPolyfillPass.php ├── Dto │ ├── AddProductBundleToCartDto.php │ ├── AddProductBundleToCartDtoInterface.php │ └── Api │ │ └── AddProductBundleToCartDto.php ├── Entity │ ├── OrderItemInterface.php │ ├── ProductBundle.php │ ├── ProductBundleInterface.php │ ├── ProductBundleItem.php │ ├── ProductBundleItemInterface.php │ ├── ProductBundleOrderItem.php │ ├── ProductBundleOrderItemInterface.php │ ├── ProductBundleOrderItemsAwareTrait.php │ ├── ProductBundlesAwareInterface.php │ ├── ProductBundlesAwareTrait.php │ └── ProductInterface.php ├── EventListener │ ├── AddProductToProductBundleWhenEditNormalProductEventListener.php │ └── CartItemAddListener.php ├── Factory │ ├── AddProductBundleItemToCartCommandFactory.php │ ├── AddProductBundleItemToCartCommandFactoryInterface.php │ ├── AddProductBundleToCartCommandFactory.php │ ├── AddProductBundleToCartCommandFactoryInterface.php │ ├── AddProductBundleToCartDtoFactory.php │ ├── AddProductBundleToCartDtoFactoryInterface.php │ ├── OrderItemFactory.php │ ├── OrderItemFactoryInterface.php │ ├── ProductBundleOrderItemFactory.php │ ├── ProductBundleOrderItemFactoryInterface.php │ ├── ProductFactory.php │ └── ProductFactoryInterface.php ├── Form │ ├── Extension │ │ └── ProductTypeExtension.php │ └── Type │ │ ├── AddProductBundleItemToCartType.php │ │ ├── AddProductBundleToCartType.php │ │ ├── ProductBundleItemType.php │ │ └── ProductBundleType.php ├── Handler │ ├── AddProductBundleToCartHandler.php │ ├── AddProductBundleToCartHandler │ │ ├── CartProcessor.php │ │ └── CartProcessorInterface.php │ └── Api │ │ └── AddProductBundleToCartHandler.php ├── Menu │ └── AdminProductFormMenuListener.php ├── Repository │ ├── ProductVariantRepository.php │ └── ProductVariantRepositoryInterface.php ├── Twig │ └── Extension │ │ └── ProductBundleOrderItemExtension.php └── Validator │ ├── HasAvailableProductBundle.php │ ├── HasAvailableProductBundleValidator.php │ ├── HasExistingCart.php │ ├── HasExistingCartValidator.php │ ├── HasProductBundle.php │ ├── HasProductBundleValidator.php │ ├── Sequentially.php │ └── SequentiallyValidator.php ├── templates ├── Admin │ ├── Order │ │ └── Show │ │ │ └── _productBundleOrderItems.html.twig │ └── product │ │ └── form │ │ ├── sections │ │ ├── bundle.html.twig │ │ └── bundle │ │ │ └── productBundleItem.html.twig │ │ └── side_navigation │ │ └── bundle.html.twig └── Shop │ └── product │ └── show │ └── page │ └── info │ └── summary │ └── add_to_cart │ └── addProductBundleToCart.html.twig ├── tests ├── Api │ ├── Admin │ │ ├── OrderTest.php │ │ └── ProductBundleTest.php │ ├── AdminJsonApiTestCase.php │ ├── DataFixtures │ │ └── ORM │ │ │ ├── general │ │ │ ├── authentication.yml │ │ │ └── channels.yml │ │ │ └── shop │ │ │ ├── orders.yml │ │ │ └── product_bundles.yml │ ├── JsonApiTestCase.php │ ├── Responses │ │ ├── admin │ │ │ ├── get_order_with_bundle_response.json │ │ │ ├── get_product_bundle_collection_response.json │ │ │ ├── get_product_bundle_response.json │ │ │ ├── post_product_bundle_response.json │ │ │ └── put_product_bundle_response.json │ │ └── shop │ │ │ ├── get_bundled_product_response.json │ │ │ ├── get_not_bundled_product_response.json │ │ │ ├── get_order_with_bundle_response.json │ │ │ └── get_product_bundle_response.json │ ├── Shop │ │ ├── OrderTest.php │ │ └── ProductTest.php │ └── Utils │ │ └── CartHelperTrait.php ├── Application │ ├── .babelrc │ ├── .env │ ├── .env.test │ ├── .eslintrc.js │ ├── .gitignore │ ├── Kernel.php │ ├── assets │ │ ├── admin │ │ │ ├── entry.js │ │ │ └── product-entry.js │ │ ├── controllers.json │ │ └── shop │ │ │ └── entry.js │ ├── bin │ │ └── console │ ├── composer.json │ ├── config │ │ ├── api_platform │ │ │ └── .gitkeep │ │ ├── bootstrap.php │ │ ├── bundles.php │ │ ├── jwt │ │ │ ├── private.pem │ │ │ └── public.pem │ │ ├── packages │ │ │ ├── _sylius.yaml │ │ │ ├── assets.yaml │ │ │ ├── bitbag_sylius_product_bundle_plugin.yml │ │ │ ├── dev │ │ │ │ ├── framework.yaml │ │ │ │ ├── monolog.yaml │ │ │ │ ├── routing.yaml │ │ │ │ └── web_profiler.yaml │ │ │ ├── doctrine.yaml │ │ │ ├── doctrine_migrations.yaml │ │ │ ├── framework.yaml │ │ │ ├── http_discovery.yaml │ │ │ ├── lexik_jwt_authentication.yaml │ │ │ ├── liip_imagine.yaml │ │ │ ├── mailer.yaml │ │ │ ├── prod │ │ │ │ ├── doctrine.yaml │ │ │ │ └── monolog.yaml │ │ │ ├── routing.yaml │ │ │ ├── security.yaml │ │ │ ├── staging │ │ │ │ └── monolog.yaml │ │ │ ├── stof_doctrine_extensions.yaml │ │ │ ├── test │ │ │ │ ├── framework.yaml │ │ │ │ ├── monolog.yaml │ │ │ │ ├── sylius_theme.yaml │ │ │ │ ├── sylius_uploader.yaml │ │ │ │ └── web_profiler.yaml │ │ │ ├── test_cached │ │ │ │ ├── framework.yaml │ │ │ │ ├── monolog.yaml │ │ │ │ ├── sylius_channel.yaml │ │ │ │ ├── sylius_theme.yaml │ │ │ │ ├── sylius_uploader.yaml │ │ │ │ └── twig.yaml │ │ │ ├── translation.yaml │ │ │ ├── twig.yaml │ │ │ ├── validator.yaml │ │ │ └── webpack_encore.yaml │ │ ├── routes.yaml │ │ ├── routes │ │ │ ├── api_platform.yaml │ │ │ ├── dev │ │ │ │ └── web_profiler.yaml │ │ │ ├── liip_imagine.yaml │ │ │ ├── sylius_admin.yaml │ │ │ ├── sylius_api.yaml │ │ │ ├── sylius_shop.yaml │ │ │ ├── test │ │ │ │ └── sylius_test_plugin.yaml │ │ │ ├── test_cached │ │ │ │ ├── routing.yaml │ │ │ │ └── sylius_test_plugin.yaml │ │ │ └── ux.yaml │ │ ├── secrets │ │ │ ├── dev │ │ │ │ └── .gitignore │ │ │ ├── prod │ │ │ │ └── .gitignore │ │ │ ├── test │ │ │ │ └── .gitignore │ │ │ └── test_cached │ │ │ │ └── .gitignore │ │ ├── services.yaml │ │ ├── services_test.yaml │ │ └── services_test_cached.yaml │ ├── gulpfile.babel.js │ ├── package.json │ ├── public │ │ ├── .htaccess │ │ ├── favicon.ico │ │ ├── index.php │ │ └── robots.txt │ ├── src │ │ ├── Entity │ │ │ ├── OrderItem.php │ │ │ └── Product.php │ │ └── Resources │ │ │ └── config │ │ │ └── doctrine │ │ │ ├── OrderItem.orm.xml │ │ │ └── Product.orm.xml │ ├── templates │ │ └── bundles │ │ │ ├── SyliusAdminBundle │ │ │ ├── Layout │ │ │ │ └── _logo.html.twig │ │ │ ├── _scripts.html.twig │ │ │ ├── _styles.html.twig │ │ │ └── order │ │ │ │ └── show │ │ │ │ └── content │ │ │ │ └── sections │ │ │ │ └── items │ │ │ │ └── body │ │ │ │ └── item.html.twig │ │ │ └── SyliusShopBundle │ │ │ ├── Layout │ │ │ └── Header │ │ │ │ └── _logo.html.twig │ │ │ ├── _scripts.html.twig │ │ │ └── _styles.html.twig │ ├── translations │ │ └── .gitignore │ └── webpack.config.js ├── Behat │ ├── Context │ │ ├── Setup │ │ │ └── ProductBundleContext.php │ │ └── Ui │ │ │ └── ProductBundleContext.php │ ├── Page │ │ └── Admin │ │ │ ├── CreateBundledProductPage.php │ │ │ └── CreateBundledProductPageInterface.php │ └── Resources │ │ ├── services.yml │ │ └── suites.yml └── Unit │ ├── DataTransformer │ └── AddProductBundleToCartDtoDataTransformerTest.php │ ├── Factory │ ├── AddProductBundleItemToCartCommandFactoryTest.php │ ├── AddProductBundleToCartCommandFactoryTest.php │ ├── AddProductBundleToCartDtoFactoryTest.php │ ├── OrderItemFactoryTest.php │ └── ProductBundleOrderItemFactoryTest.php │ ├── Handler │ ├── AddProductBundleToCartHandler │ │ └── CartProcessorTest.php │ ├── AddProductBundleToCartHandlerTest.php │ └── Api │ │ └── AddProductBundleToCartHandlerTest.php │ ├── MotherObject │ ├── AddProductBundleItemToCartCommandMother.php │ ├── AddProductBundleToCartDtoMother.php │ ├── Api │ │ └── AddProductBundleToCartDtoMother.php │ ├── ChannelMother.php │ ├── OrderItemMother.php │ ├── OrderMother.php │ ├── ProductBundleItemMother.php │ ├── ProductBundleMother.php │ ├── ProductMother.php │ └── ProductVariantMother.php │ ├── TypeExceptionMessage.php │ └── Validator │ ├── HasAvailableProductBundleValidatorTest.php │ ├── HasExistingCartValidatorTest.php │ └── HasProductBundleTest.php ├── translations ├── messages.en.yml ├── messages.fr.yml ├── messages.nl.yml ├── validators.en.yml ├── validators.fr.yml └── validators.nl.yml └── webpack.config.js /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @Sylius/core-team 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /node_modules/ 3 | /composer.lock 4 | 5 | /etc/build/* 6 | !/etc/build/.gitignore 7 | 8 | /tests/Application/yarn.lock 9 | 10 | /.phpunit.result.cache 11 | /behat.yml 12 | /phpspec.yml 13 | /phpunit.xml 14 | .phpunit.result.cache 15 | 16 | # Symfony CLI https://symfony.com/doc/current/setup/symfony_server.html#different-php-settings-per-project 17 | /.php-version 18 | /php.ini 19 | -------------------------------------------------------------------------------- /README_webpack-config.md: -------------------------------------------------------------------------------- 1 | # BitBag SyliusProductBundlePlugin 2 | 3 | ## Installation - Import Webpack Config 4 | 5 |
6 | 7 | 1. Import plugin's `webpack.config.js` file 8 | 9 | ```js 10 | // webpack.config.js 11 | const [bitbagproductBundleShop, bitbagproductBundleAdmin] = require('./vendor/bitbag/product-bundle-plugin/webpack.config.js'); 12 | ... 13 | 14 | module.exports = [..., bitbagproductBundleShop, bitbagproductBundleAdmin]; 15 | ``` 16 | 17 | 2. Add new packages in `./config/packages/assets.yaml` 18 | 19 | ```yml 20 | # config/packages/assets.yaml 21 | 22 | framework: 23 | assets: 24 | packages: 25 | # ... 26 | shop: 27 | json_manifest_path: '%kernel.project_dir%/public/build/shop/manifest.json' 28 | product_bundle_shop: 29 | json_manifest_path: '%kernel.project_dir%/public/build/bitbag/productBundle/shop/manifest.json' 30 | product_bundle_admin: 31 | json_manifest_path: '%kernel.project_dir%/public/build/bitbag/productBundle/admin/manifest.json' 32 | ``` 33 | 34 | 3. Add new build paths in `./config/packages/webpack_encore.yml` 35 | 36 | ```yml 37 | # config/packages/webpack_encore.yml 38 | 39 | webpack_encore: 40 | builds: 41 | # ... 42 | product_bundle_shop: '%kernel.project_dir%/public/build/bitbag/productBundle/shop' 43 | product_bundle_admin: '%kernel.project_dir%/public/build/bitbag/productBundle/admin' 44 | ``` 45 | 46 | 4. Add encore functions to your templates 47 | 48 | ```twig 49 | {# @SyliusShopBundle/_scripts.html.twig #} 50 | {{ encore_entry_script_tags('bitbag-productBundle-shop', null, 'product_bundle_shop') }} 51 | 52 | {# @SyliusShopBundle/_styles.html.twig #} 53 | {{ encore_entry_link_tags('bitbag-productBundle-shop', null, 'product_bundle_shop') }} 54 | 55 | {# @SyliusAdminBundle/_scripts.html.twig #} 56 | {{ encore_entry_script_tags('bitbag-productBundle-admin', null, 'product_bundle_admin') }} 57 | 58 | {# @SyliusAdminBundle/_styles.html.twig #} 59 | {{ encore_entry_link_tags('bitbag-productBundle-admin', null, 'product_bundle_admin') }} 60 | ``` 61 | 62 | 5. Run `yarn encore dev` or `yarn encore production` 63 | -------------------------------------------------------------------------------- /assets/admin/entry.js: -------------------------------------------------------------------------------- 1 | import './js'; 2 | import './scss/main.scss'; 3 | -------------------------------------------------------------------------------- /assets/admin/js/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/assets/admin/js/index.js -------------------------------------------------------------------------------- /assets/admin/scss/main.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/assets/admin/scss/main.scss -------------------------------------------------------------------------------- /assets/shop/entry.js: -------------------------------------------------------------------------------- 1 | import './js'; 2 | import './scss/main.scss'; 3 | -------------------------------------------------------------------------------- /assets/shop/js/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/assets/shop/js/index.js -------------------------------------------------------------------------------- /assets/shop/scss/main.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/assets/shop/scss/main.scss -------------------------------------------------------------------------------- /config/api_resources/shop/Product.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | 33 | shop:product_bundle:read 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /config/api_resources/shop/ProductBundleItem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | 16 | 21 | 22 | 23 | 24 | 25 | shop:product_bundle_items:read 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /config/config.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: resources.yml } 3 | - { resource: services.xml } 4 | - { resource: "@BitBagSyliusProductBundlePlugin/config/twig_hooks/twig_hooks.yaml" } 5 | 6 | framework: 7 | messenger: 8 | buses: 9 | bitbag_sylius_product_bundle.command_bus: ~ 10 | -------------------------------------------------------------------------------- /config/doctrine/ProductBundle.orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /config/doctrine/ProductBundleItem.orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /config/doctrine/ProductBundleOrderItem.orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /config/resources.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: resources/product_bundle.yml } 3 | - { resource: resources/product_bundle_item.yml } 4 | - { resource: resources/product_bundle_order_item.yml } 5 | -------------------------------------------------------------------------------- /config/resources/product_bundle.yml: -------------------------------------------------------------------------------- 1 | sylius_resource: 2 | resources: 3 | bitbag_sylius_product_bundle.product_bundle: 4 | driver: doctrine/orm 5 | classes: 6 | model: BitBag\SyliusProductBundlePlugin\Entity\ProductBundle 7 | interface: BitBag\SyliusProductBundlePlugin\Entity\ProductBundleInterface 8 | form: BitBag\SyliusProductBundlePlugin\Form\Type\ProductBundleType 9 | -------------------------------------------------------------------------------- /config/resources/product_bundle_item.yml: -------------------------------------------------------------------------------- 1 | sylius_resource: 2 | resources: 3 | bitbag_sylius_product_bundle.product_bundle_item: 4 | driver: doctrine/orm 5 | classes: 6 | model: BitBag\SyliusProductBundlePlugin\Entity\ProductBundleItem 7 | interface: BitBag\SyliusProductBundlePlugin\Entity\ProductBundleItemInterface 8 | form: BitBag\SyliusProductBundlePlugin\Form\Type\ProductBundleItemType 9 | -------------------------------------------------------------------------------- /config/resources/product_bundle_order_item.yml: -------------------------------------------------------------------------------- 1 | sylius_resource: 2 | resources: 3 | bitbag_sylius_product_bundle.product_bundle_order_item: 4 | driver: doctrine/orm 5 | classes: 6 | model: BitBag\SyliusProductBundlePlugin\Entity\ProductBundleOrderItem 7 | interface: BitBag\SyliusProductBundlePlugin\Entity\ProductBundleOrderItemInterface 8 | -------------------------------------------------------------------------------- /config/routes.yml: -------------------------------------------------------------------------------- 1 | bitbag_sylius_product_bundle_admin: 2 | resource: routes/admin.yml 3 | prefix: '/%sylius_admin.path_name%' 4 | 5 | bitbag_sylius_product_bundle_shop: 6 | resource: routes/shop.yml 7 | prefix: /{_locale} 8 | requirements: 9 | _locale: ^[a-z]{2}(?:_[A-Z]{2})?$ 10 | 11 | -------------------------------------------------------------------------------- /config/routes/admin.yml: -------------------------------------------------------------------------------- 1 | bitbag_product_bundle_admin_product_create_bundle: 2 | path: /products/new/bundle 3 | methods: [GET, POST] 4 | defaults: 5 | _controller: sylius.controller.product::createAction 6 | _sylius: 7 | section: admin 8 | permission: true 9 | factory: 10 | method: createWithVariantAndBundle 11 | template: "@SyliusAdmin/shared/crud/create.html.twig" 12 | redirect: sylius_admin_product_update 13 | form: 14 | type: Sylius\Bundle\AdminBundle\Form\Type\ProductType 15 | options: 16 | validation_groups: 17 | - sylius 18 | - bitbag_sylius_product_bundle 19 | vars: 20 | subheader: sylius.ui.manage_your_product_catalog 21 | templates: 22 | form: "@SyliusAdmin/product/form.html.twig" 23 | route: 24 | name: bitbag_product_bundle_admin_product_create_bundle 25 | 26 | bitbag_product_bundle_admin_ajax_product_variants_by_phrase: 27 | path: /ajax/product-variants/search-by-phrase 28 | methods: [GET] 29 | defaults: 30 | _controller: sylius.controller.product_variant::indexAction 31 | _format: json 32 | _sylius: 33 | serialization_groups: [Autocomplete] 34 | permission: true 35 | repository: 36 | method: findByPhrase 37 | arguments: 38 | phrase: $phrase 39 | locale: expr:service('sylius.context.locale').getLocaleCode() 40 | 41 | bitbag_product_bundle_admin_ajax_product_variants_by_codes: 42 | path: /ajax/product-variants/by-codes 43 | methods: [GET] 44 | defaults: 45 | _controller: sylius.controller.product_variant::indexAction 46 | _format: json 47 | _sylius: 48 | serialization_groups: [Autocomplete] 49 | permission: true 50 | repository: 51 | method: findByCodes 52 | arguments: [$code] 53 | -------------------------------------------------------------------------------- /config/routes/shop.yml: -------------------------------------------------------------------------------- 1 | bitbag_sylius_product_bundle_shop_ajax_cart_add_product_bundle: 2 | path: /ajax/cart/product-bundle/add 3 | methods: [POST] 4 | defaults: 5 | _controller: bitbag_sylius_product_bundle.controller.order_item::addProductBundleAction 6 | _format: json 7 | _sylius: 8 | factory: 9 | method: createForProduct 10 | arguments: [expr:notFoundOnNull(service('sylius.repository.product').find($productId))] 11 | form: 12 | type: BitBag\SyliusProductBundlePlugin\Form\Type\AddProductBundleToCartType 13 | options: 14 | product: expr:notFoundOnNull(service('sylius.repository.product').find($productId)) 15 | redirect: 16 | route: sylius_shop_cart_summary 17 | parameters: {} 18 | flash: sylius.cart.add_item 19 | 20 | bitbag_sylius_product_bundle_shop_partial_cart_add_product_bundle: 21 | path: /_partial/cart/product-bundle/add 22 | methods: [GET] 23 | defaults: 24 | _controller: bitbag_sylius_product_bundle.controller.order_item::addProductBundleAction 25 | _sylius: 26 | template: $template 27 | factory: 28 | method: createForProduct 29 | arguments: [expr:notFoundOnNull(service('sylius.repository.product').find($productId))] 30 | form: 31 | type: BitBag\SyliusProductBundlePlugin\Form\Type\AddProductBundleToCartType 32 | options: 33 | product: expr:notFoundOnNull(service('sylius.repository.product').find($productId)) 34 | redirect: 35 | route: sylius_shop_cart_summary 36 | parameters: {} 37 | -------------------------------------------------------------------------------- /config/serialization/AddProductBundleToCartCommand.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | shop:product_bundle:add_to_cart 16 | 17 | 18 | shop:product_bundle:add_to_cart 19 | 20 | 21 | shop:product_bundle:add_to_cart 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /config/serialization/AddProductBundleToCartDto.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | shop:cart:add_product_bundle 16 | 17 | 18 | shop:cart:add_product_bundle 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /config/serialization/OrderItem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | admin:order:read 16 | admin:order_item:read 17 | shop:order_item:read 18 | shop:cart:read 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /config/serialization/Product.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | sylius:admin:product:index 16 | sylius:admin:product:show 17 | sylius:admin:product:create 18 | sylius:admin:product:update 19 | sylius:shop:product:index 20 | sylius:shop:product:show 21 | 22 | 23 | sylius:admin:product:index 24 | sylius:admin:product:show 25 | sylius:admin:product:create 26 | sylius:admin:product:update 27 | sylius:shop:product:index 28 | sylius:shop:product:show 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /config/serialization/ProductBundleItem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | admin:product_bundle:create 16 | admin:product_bundle:update 17 | shop:product:read 18 | shop:product_bundle:read 19 | 20 | 21 | admin:product_bundle:create 22 | admin:product_bundle:update 23 | shop:product:read 24 | shop:product_bundle:read 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /config/serialization/ProductBundleOrderItem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | admin:order:read 16 | admin:order_item:read 17 | 18 | 19 | admin:order:read 20 | admin:order_item:read 21 | shop:order_item:read 22 | shop:cart:read 23 | 24 | 25 | admin:order:read 26 | admin:order_item:read 27 | shop:order_item:read 28 | shop:cart:read 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /config/serialization/ProductVariant.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | shop:product:read 16 | shop:product_bundle:read 17 | shop:order_item:read 18 | shop:cart:read 19 | 20 | 21 | shop:product_bundle:read 22 | 23 | 24 | shop:product:read 25 | shop:product_bundle:read 26 | 27 | 28 | shop:product:read 29 | shop:product_bundle:read 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /config/serialization/ProductVariantTranslation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | shop:product:read 16 | shop:product_bundle:read 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /config/services.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /config/services/controller.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /config/services/event_listener.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /config/services/form.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | bitbag_sylius_product_bundle 7 | 8 | 9 | 10 | bitbag_sylius_product_bundle 11 | 12 | 13 | 14 | 15 | 16 | %bitbag_sylius_product_bundle.model.product_bundle.class% 17 | %bitbag_sylius_product_bundle.form.type.product_bundle.validation_groups% 18 | 19 | 20 | 21 | 22 | %bitbag_sylius_product_bundle.model.product_bundle_item.class% 23 | %bitbag_sylius_product_bundle.form.type.product_bundle_item.validation_groups% 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /config/services/handler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /config/services/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /config/services/processor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /config/services/product.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | BitBag\SyliusProductBundlePlugin\Form\Type\AddProductBundleToCartType 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /config/services/transformer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /config/services/twig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /config/services/validator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /config/twig_hooks/order/show.yaml: -------------------------------------------------------------------------------- 1 | sylius_twig_hooks: 2 | hooks: 3 | 'sylius_admin.order.show.content.sections.items.body': 4 | item: 5 | template: '@SyliusAdmin/order/show/content/sections/items/body/item.html.twig' 6 | priority: 800 7 | -------------------------------------------------------------------------------- /config/twig_hooks/product/admin/create.yaml: -------------------------------------------------------------------------------- 1 | sylius_twig_hooks: 2 | hooks: 3 | 'sylius_admin.product.create.content.form.side_navigation': 4 | bundle: 5 | template: '@BitBagSyliusProductBundlePlugin/Admin/product/form/side_navigation/bundle.html.twig' 6 | priority: -10 7 | 8 | 'sylius_admin.product.create.content.form.sections': 9 | bundle: 10 | template: '@BitBagSyliusProductBundlePlugin/Admin/product/form/sections/bundle.html.twig' 11 | priority: -10 12 | 13 | 'sylius_admin.product.create.content.form.sections.bundle': 14 | bundle: 15 | template: '@BitBagSyliusProductBundlePlugin/Admin/product/form/sections/bundle/productBundleItem.html.twig' 16 | priority: 0 17 | -------------------------------------------------------------------------------- /config/twig_hooks/product/admin/update.yaml: -------------------------------------------------------------------------------- 1 | sylius_twig_hooks: 2 | hooks: 3 | 'sylius_admin.product.update.content.form.side_navigation': 4 | bundle: 5 | template: '@BitBagSyliusProductBundlePlugin/Admin/product/form/side_navigation/bundle.html.twig' 6 | priority: -10 7 | 8 | 'sylius_admin.product.update.content.form.sections': 9 | bundle: 10 | template: '@BitBagSyliusProductBundlePlugin/Admin/product/form/sections/bundle.html.twig' 11 | priority: -10 12 | 13 | 'sylius_admin.product.update.content.form.sections.bundle': 14 | product_bundle: 15 | template: '@BitBagSyliusProductBundlePlugin/Admin/product/form/sections/bundle/productBundleItem.html.twig' 16 | priority: 0 17 | -------------------------------------------------------------------------------- /config/twig_hooks/product/shop/show.yaml: -------------------------------------------------------------------------------- 1 | sylius_twig_hooks: 2 | hooks: 3 | 'sylius_shop.product.show.content.info.summary.add_to_cart': 4 | bundle: 5 | component: 'sylius_shop:product:add_to_cart_form' 6 | props: 7 | product: '@=_context.product' 8 | template: '@BitBagSyliusProductBundlePlugin/Shop/product/show/page/info/summary/add_to_cart/addProductBundleToCart.html.twig' 9 | priority: 20 10 | -------------------------------------------------------------------------------- /config/twig_hooks/twig_hooks.yaml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: "@BitBagSyliusProductBundlePlugin/config/twig_hooks/product/**/*.yaml" } 3 | - { resource: "@BitBagSyliusProductBundlePlugin/config/twig_hooks/order/*.yaml" } 4 | -------------------------------------------------------------------------------- /config/validation/AddProductBundleToCartCommand.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /config/validation/AddProductBundleToCartDto.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /config/validation/ProductBundle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /config/validation/ProductBundleItem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /doc/bundle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/doc/bundle.png -------------------------------------------------------------------------------- /doc/bundle_cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/doc/bundle_cart.png -------------------------------------------------------------------------------- /doc/bundle_productpage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/doc/bundle_productpage.png -------------------------------------------------------------------------------- /doc/bundle_taxon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/doc/bundle_taxon.png -------------------------------------------------------------------------------- /doc/create_bundle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/doc/create_bundle.png -------------------------------------------------------------------------------- /doc/functionalities.md: -------------------------------------------------------------------------------- 1 | # Functionalities 2 | 3 | --- 4 | **Bundles** 5 | 6 | The plugin gives the user the opportunity to create bundles that contain more than product from the store. Creating a bundle is possible in the admin panel in the Products section. 7 | 8 |
9 | 10 |
11 | 12 | After choosing the right option, the user is taken to the bundle creation page. All the sections are just the same as for the normal products. However, there is a section that is unique for the plugin and it is Bundle section. 13 | 14 |
15 | 16 |
17 | 18 | In there user can add chosen variants of the products to the bundle and decide what should be their quantity per bundle. 19 | 20 | > When the option `is packed product` is `not checked`, the customer, when adding the product bundle to the basket, can change its variants (example in one of the screens below). 21 | 22 | > When the `is packed product` option is `checked`, it is not possible for the customer to change product variants. 23 | 24 | After setting all the other required info, taxonomy and enabling the bundle in the chosen channel, the user can buy the bundle in the shop. 25 | 26 |
27 | 28 |
29 | 30 |
31 | 32 |
33 | 34 |
35 | 36 |
37 | -------------------------------------------------------------------------------- /ecs.php: -------------------------------------------------------------------------------- 1 | import('vendor/bitbag/coding-standard/ecs.php'); 12 | $config->paths(['src', 'tests']); 13 | }; 14 | -------------------------------------------------------------------------------- /features/creating_bundled_product.feature: -------------------------------------------------------------------------------- 1 | @bundled_product 2 | Feature: Creating a product in store which is a bundle of other products 3 | I want to be able to add bundled product to cart 4 | 5 | Background: 6 | Given the store operates on a single channel in "United States" 7 | And I am logged in as an administrator 8 | And the store has a product "Jack Daniels Gentleman" priced at "$10.00" 9 | And the store has a product "Johny Walker Black" priced at "$10.00" 10 | And the store has a product "Jim Beam Double Oak" priced at "$10.00" 11 | 12 | @ui 13 | Scenario: Creating a bundled product 14 | When I want to create a new bundled product 15 | And I specify its code as "WHISKEY_PACK" 16 | And I name it "Whiskey double pack" in "English (United States)" 17 | And I set its slug to "whiskey-double-pack" in "English (United States)" 18 | And I set its price to "$10.00" for "United States" channel 19 | And I set its original price to "$20.00" for "United States" channel 20 | And I add product "Johny Walker Black" and "Jack Daniels Gentleman" to the bundle 21 | And I add it 22 | Then I should be notified that it has been successfully created 23 | 24 | @ui 25 | Scenario: Creating a bundled product with more products 26 | When I want to create a new bundled product 27 | And I specify its code as "WHISKEY_BIG_PACK" 28 | And I name it "Whiskey triple pack" in "English (United States)" 29 | And I set its slug to "whiskey-triple-pack" in "English (United States)" 30 | And I set its price to "$10.00" for "United States" channel 31 | And I set its original price to "$20.00" for "United States" channel 32 | And I add product "Johny Walker Black" and "Jack Daniels Gentleman" and "Jim Beam Double Oak" to the bundle 33 | And I add it 34 | Then I should be notified that it has been successfully created 35 | -------------------------------------------------------------------------------- /node_modules: -------------------------------------------------------------------------------- 1 | tests/Application/node_modules -------------------------------------------------------------------------------- /phpspec.yml.dist: -------------------------------------------------------------------------------- 1 | suites: 2 | main: 3 | namespace: BitBag\SyliusProductBundlePlugin 4 | psr4_prefix: BitBag\SyliusProductBundlePlugin 5 | -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | reportUnmatchedIgnoredErrors: false 3 | checkMissingIterableValueType: false 4 | 5 | level: 7 6 | paths: 7 | - src 8 | 9 | excludes_analyse: 10 | # Makes PHPStan crash 11 | - 'src/DependencyInjection/Configuration.php' 12 | 13 | # Test dependencies 14 | - 'tests/Application/app/**.php' 15 | - 'tests/Application/src/**.php' 16 | 17 | ignoreErrors: 18 | - '/Parameter #1 \$productRepository of method BitBag\\SyliusProductBundlePlugin\\Component\\Product\\AddToCartFormComponent::initializeProduct\(\) expects Sylius\\Component\\Core\\Repository\\ProductRepositoryInterface, Sylius\\Component\\Core\\Repository\\ProductRepositoryInterface given\./' 19 | - '/Parameter #10 \$productRepository of method Sylius\\Bundle\\ShopBundle\\Twig\\Component\\Product\\AddToCartFormComponent::__construct\(\) expects Sylius\\Component\\Core\\Repository\\ProductRepositoryInterface\, Sylius\\Component\\Core\\Repository\\ProductRepositoryInterface\ given\./' 20 | - identifier: missingType.iterableValue 21 | - identifier: missingType.generics 22 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | ./tests/Api 10 | 11 | 12 | ./tests/Api 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /spec/EventListener/AddProductToProductBundleWhenEditNormalProductEventListenerSpec.php: -------------------------------------------------------------------------------- 1 | shouldHaveType(AddProductToProductBundleWhenEditNormalProductEventListener::class); 24 | } 25 | 26 | public function it_should_add_product_to_product_bundle_if_not_exist_on_pre_create_and_update_event( 27 | ResourceControllerEvent $resourceControllerEvent, 28 | ProductInterface $product, 29 | ProductBundleInterface $productBundle 30 | ): void { 31 | $resourceControllerEvent->getSubject()->willReturn($product); 32 | 33 | $product->getProductBundle()->shouldBeCalled(); 34 | 35 | $product->getProductBundle()->willReturn($productBundle); 36 | 37 | $this->addProductToProductBundle($resourceControllerEvent); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/BitBagSyliusProductBundlePlugin.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new AuthenticationManagerPolyfillPass()); 31 | 32 | parent::build($container); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Command/AddProductBundleItemToCartCommand.php: -------------------------------------------------------------------------------- 1 | productVariant = $productBundleItem->getProductVariant(); 25 | $this->quantity = $productBundleItem->getQuantity(); 26 | } 27 | 28 | public function getProductBundleItem(): ProductBundleItemInterface 29 | { 30 | return $this->productBundleItem; 31 | } 32 | 33 | public function getProductVariant(): ?ProductVariantInterface 34 | { 35 | return $this->productVariant; 36 | } 37 | 38 | public function setProductVariant(ProductVariantInterface $productVariant): void 39 | { 40 | $this->productVariant = $productVariant; 41 | } 42 | 43 | public function getQuantity(): ?int 44 | { 45 | return $this->quantity; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Command/AddProductBundleToCartCommand.php: -------------------------------------------------------------------------------- 1 | orderId; 26 | } 27 | 28 | public function getProductCode(): string 29 | { 30 | return $this->productCode; 31 | } 32 | 33 | public function getQuantity(): int 34 | { 35 | return $this->quantity; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Command/OrderIdentityAwareInterface.php: -------------------------------------------------------------------------------- 1 | getProductCode(); 38 | $quantity = $object->getQuantity(); 39 | 40 | return new AddProductBundleToCartCommand($cart->getId(), $productCode, $quantity); 41 | } 42 | 43 | public function supportsTransformation( 44 | mixed $data, 45 | string $to, 46 | array $context = [], 47 | ): bool { 48 | return isset($context['input']['class']) && AddProductBundleToCartDto::class === $context['input']['class']; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/DependencyInjection/CompilerPass/AuthenticationManagerPolyfillPass.php: -------------------------------------------------------------------------------- 1 | has('security.authentication_manager') && 23 | true === $container->has('security.authentication.manager') 24 | ) { 25 | $container->setAlias('security.authentication_manager', 'security.authentication.manager'); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Dto/AddProductBundleToCartDto.php: -------------------------------------------------------------------------------- 1 | productBundleItems = new ArrayCollection($productBundleItems); 31 | } 32 | 33 | public function getCart(): OrderInterface 34 | { 35 | return $this->cart; 36 | } 37 | 38 | public function setCart(OrderInterface $cart): void 39 | { 40 | $this->cart = $cart; 41 | } 42 | 43 | public function getCartItem(): OrderItemInterface 44 | { 45 | return $this->cartItem; 46 | } 47 | 48 | public function setCartItem(OrderItemInterface $cartItem): void 49 | { 50 | $this->cartItem = $cartItem; 51 | } 52 | 53 | public function getProduct(): ProductInterface 54 | { 55 | return $this->product; 56 | } 57 | 58 | public function setProduct(ProductInterface $product): void 59 | { 60 | $this->product = $product; 61 | } 62 | 63 | public function getProductBundleItems(): ArrayCollection 64 | { 65 | return $this->productBundleItems; 66 | } 67 | 68 | public function getProductCode(): string 69 | { 70 | return $this->product->getCode() ?? ''; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Dto/AddProductBundleToCartDtoInterface.php: -------------------------------------------------------------------------------- 1 | orderTokenValue; 30 | } 31 | 32 | public function setOrderTokenValue(string $orderTokenValue): void 33 | { 34 | $this->orderTokenValue = $orderTokenValue; 35 | } 36 | 37 | public function getProductCode(): string 38 | { 39 | return $this->productCode; 40 | } 41 | 42 | public function getQuantity(): int 43 | { 44 | return $this->quantity; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Entity/OrderItemInterface.php: -------------------------------------------------------------------------------- 1 | createdAt = new \DateTime(); 36 | } 37 | 38 | public function getId(): ?int 39 | { 40 | return $this->id; 41 | } 42 | 43 | public function getProductVariant(): ?ProductVariantInterface 44 | { 45 | return $this->productVariant; 46 | } 47 | 48 | public function setProductVariant(?ProductVariantInterface $productVariant): void 49 | { 50 | $this->productVariant = $productVariant; 51 | } 52 | 53 | public function getQuantity(): ?int 54 | { 55 | return $this->quantity; 56 | } 57 | 58 | public function setQuantity(?int $quantity): void 59 | { 60 | $this->quantity = $quantity; 61 | } 62 | 63 | public function getProductBundle(): ?ProductBundleInterface 64 | { 65 | return $this->productBundle; 66 | } 67 | 68 | public function setProductBundle(?ProductBundleInterface $productBundle): void 69 | { 70 | $this->productBundle = $productBundle; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Entity/ProductBundleItemInterface.php: -------------------------------------------------------------------------------- 1 | id; 39 | } 40 | 41 | public function getOrderItem(): ?OrderItemInterface 42 | { 43 | return $this->orderItem; 44 | } 45 | 46 | public function setOrderItem(?OrderItemInterface $orderItem): void 47 | { 48 | $this->orderItem = $orderItem; 49 | } 50 | 51 | public function getProductBundleItem(): ?ProductBundleItemInterface 52 | { 53 | return $this->productBundleItem; 54 | } 55 | 56 | public function setProductBundleItem(?ProductBundleItemInterface $productBundleItem): void 57 | { 58 | $this->productBundleItem = $productBundleItem; 59 | } 60 | 61 | public function getProductVariant(): ?ProductVariantInterface 62 | { 63 | return $this->productVariant; 64 | } 65 | 66 | public function setProductVariant(?ProductVariantInterface $productVariant): void 67 | { 68 | $this->productVariant = $productVariant; 69 | } 70 | 71 | public function getQuantity(): ?int 72 | { 73 | return $this->quantity; 74 | } 75 | 76 | public function setQuantity(?int $quantity): void 77 | { 78 | $this->quantity = $quantity; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Entity/ProductBundleOrderItemInterface.php: -------------------------------------------------------------------------------- 1 | productBundleOrderItems = new ArrayCollection(); 24 | } 25 | 26 | /** @return ProductBundleOrderItemInterface[]|ArrayCollection */ 27 | public function getProductBundleOrderItems() 28 | { 29 | return $this->productBundleOrderItems; 30 | } 31 | 32 | public function addProductBundleOrderItem(ProductBundleOrderItemInterface $productBundleOrderItem): void 33 | { 34 | $this->productBundleOrderItems->add($productBundleOrderItem); 35 | $productBundleOrderItem->setOrderItem($this); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Entity/ProductBundlesAwareInterface.php: -------------------------------------------------------------------------------- 1 | productBundle; 22 | } 23 | 24 | public function setProductBundle(?ProductBundleInterface $productBundle): void 25 | { 26 | $this->productBundle = $productBundle; 27 | } 28 | 29 | public function isBundle(): bool 30 | { 31 | return null !== $this->getProductBundle(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Entity/ProductInterface.php: -------------------------------------------------------------------------------- 1 | getSubject(); 23 | if (null !== $product->getProductBundle() && null === $product->getProductBundle()->getProduct()) { 24 | $product->getProductBundle()->setProduct($product); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/EventListener/CartItemAddListener.php: -------------------------------------------------------------------------------- 1 | getSubject(); 29 | 30 | Assert::isInstanceOf($addToCartCommand, AddProductBundleToCartDtoInterface::class); 31 | 32 | $this->orderModifier->addToOrder($addToCartCommand->getCart(), $addToCartCommand->getCartItem()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Factory/AddProductBundleItemToCartCommandFactory.php: -------------------------------------------------------------------------------- 1 | getCart()->getId(); 30 | $productCode = $dto->getProduct()->getCode() ?? ''; 31 | $quantity = $dto->getCartItem()->getQuantity(); 32 | 33 | return $this->createNew($cartId, $productCode, $quantity); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Factory/AddProductBundleToCartCommandFactoryInterface.php: -------------------------------------------------------------------------------- 1 | decoratedFactory->createNew(); 31 | 32 | return $orderItem; 33 | } 34 | 35 | public function createWithVariant(ProductVariantInterface $productVariant): OrderItemInterface 36 | { 37 | $orderItem = $this->createNew(); 38 | $orderItem->setVariant($productVariant); 39 | 40 | return $orderItem; 41 | } 42 | 43 | public function createForProduct(ProductInterface $product): \Sylius\Component\Core\Model\OrderItemInterface 44 | { 45 | return $this->decoratedFactory->createForProduct($product); 46 | } 47 | 48 | public function createForCart(OrderInterface $order): \Sylius\Component\Core\Model\OrderItemInterface 49 | { 50 | return $this->decoratedFactory->createForCart($order); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Factory/OrderItemFactoryInterface.php: -------------------------------------------------------------------------------- 1 | decoratedFactory->createNew(); 29 | 30 | return $productBundleOrderItem; 31 | } 32 | 33 | public function createFromProductBundleItem(ProductBundleItemInterface $bundleItem): ProductBundleOrderItemInterface 34 | { 35 | /** @var ProductBundleOrderItemInterface $productBundleOrderItem */ 36 | $productBundleOrderItem = $this->decoratedFactory->createNew(); 37 | 38 | $productBundleOrderItem->setProductBundleItem($bundleItem); 39 | $productBundleOrderItem->setProductVariant($bundleItem->getProductVariant()); 40 | $productBundleOrderItem->setQuantity($bundleItem->getQuantity()); 41 | 42 | return $productBundleOrderItem; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Factory/ProductBundleOrderItemFactoryInterface.php: -------------------------------------------------------------------------------- 1 | productBundleFactory->createNew(); 32 | 33 | /** @var ProductInterface $product */ 34 | $product = $this->createWithVariant(); 35 | 36 | $productBundle->setProduct($product); 37 | 38 | $product->setProductBundle($productBundle); 39 | 40 | return $product; 41 | } 42 | 43 | public function createNew(): BaseProductInterface 44 | { 45 | /** @var BaseProductInterface $product */ 46 | $product = $this->decoratedFactory->createNew(); 47 | 48 | return $product; 49 | } 50 | 51 | public function createWithVariant(): BaseProductInterface 52 | { 53 | return $this->decoratedFactory->createWithVariant(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Factory/ProductFactoryInterface.php: -------------------------------------------------------------------------------- 1 | add('productBundle', ProductBundleType::class, [ 26 | 'label' => false, 27 | 'constraints' => [new Valid()], 28 | ]) 29 | ; 30 | } 31 | 32 | public static function getExtendedTypes(): iterable 33 | { 34 | return [ProductType::class]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Form/Type/AddProductBundleToCartType.php: -------------------------------------------------------------------------------- 1 | add('cartItem', CartItemType::class, [ 28 | 'product' => $options['product'], 29 | ]) 30 | ->add('productBundleItems', CollectionType::class, [ 31 | 'entry_type' => AddProductBundleItemToCartType::class, 32 | 'entry_options' => [ 33 | 'product' => $options['product'], 34 | ], 35 | ]) 36 | ; 37 | } 38 | 39 | public function configureOptions(OptionsResolver $resolver): void 40 | { 41 | $resolver 42 | ->setDefined([ 43 | 'product', 44 | ]) 45 | ->setAllowedTypes('product', ProductInterface::class) 46 | ->setDefaults([ 47 | 'data_class' => AddProductBundleToCartDto::class, 48 | ]) 49 | ; 50 | } 51 | 52 | public function getBlockPrefix(): string 53 | { 54 | return 'bitbag_sylius_product_bundle_plugin_add_product_bundle_to_cart'; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Form/Type/ProductBundleItemType.php: -------------------------------------------------------------------------------- 1 | add('quantity', IntegerType::class, [ 25 | 'label' => false, 26 | 'required' => false, 27 | ]) 28 | ->add('productVariant', ProductVariantAutocompleteType::class, [ 29 | 'label' => false, 30 | ]) 31 | ; 32 | } 33 | 34 | public function getBlockPrefix(): string 35 | { 36 | return 'bitbag_sylius_product_bundle_plugin_product_bundle_item'; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Form/Type/ProductBundleType.php: -------------------------------------------------------------------------------- 1 | add('isPackedProduct', CheckboxType::class, [ 26 | 'label' => 'bitbag_sylius_product_bundle.ui.is_packed_product', 27 | ]) 28 | ->add('productBundleItems', LiveCollectionType::class, [ 29 | 'entry_type' => ProductBundleItemType::class, 30 | 'entry_options' => ['label' => false], 31 | 'allow_add' => true, 32 | 'allow_delete' => true, 33 | 'by_reference' => false, 34 | 'label' => false, 35 | 'button_add_type' => AddButtonType::class, 36 | ]) 37 | ; 38 | } 39 | 40 | public function getBlockPrefix(): string 41 | { 42 | return 'bitbag_sylius_product_bundle_plugin_product_bundle'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Handler/AddProductBundleToCartHandler.php: -------------------------------------------------------------------------------- 1 | orderRepository->findCartById($addProductBundleToCartCommand->getOrderId()); 36 | Assert::notNull($cart); 37 | 38 | /** @var ProductInterface|null $product */ 39 | $product = $this->productRepository->findOneByCode($addProductBundleToCartCommand->getProductCode()); 40 | Assert::notNull($product); 41 | Assert::true($product->isBundle()); 42 | 43 | /** @var ProductBundleInterface|null $productBundle */ 44 | $productBundle = $product->getProductBundle(); 45 | Assert::notNull($productBundle); 46 | 47 | $quantity = $addProductBundleToCartCommand->getQuantity(); 48 | Assert::greaterThan($quantity, 0); 49 | 50 | $this->cartProcessor->process($cart, $productBundle, $quantity); 51 | $this->orderRepository->add($cart); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Handler/AddProductBundleToCartHandler/CartProcessorInterface.php: -------------------------------------------------------------------------------- 1 | getMenu(); 21 | 22 | $menu 23 | ->addChild('bundle') 24 | ->setAttribute('template', '@BitBagSyliusProductBundlePlugin/Admin/product/form/side_navigation/bundle.html.twig') 25 | ->setLabel('bitbag_sylius_product_bundle.ui.bundle') 26 | ; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Repository/ProductVariantRepository.php: -------------------------------------------------------------------------------- 1 | getEntityManager()->getExpressionBuilder(); 24 | 25 | return $this->createQueryBuilder('o') 26 | ->leftJoin('o.translations', 'translation', 'WITH', 'translation.locale = :locale') 27 | ->innerJoin('o.product', 'product') 28 | ->andWhere($expr->orX( 29 | 'translation.name LIKE :phrase', 30 | 'o.code LIKE :phrase', 31 | 'product.code LIKE :phrase', 32 | )) 33 | ->setParameter('phrase', '%' . $phrase . '%') 34 | ->setParameter('locale', $locale) 35 | ->setMaxResults(20) 36 | ->getQuery() 37 | ->getResult() 38 | ; 39 | } 40 | 41 | public function findByCodes(array $codes): array 42 | { 43 | return $this->createQueryBuilder('o') 44 | ->andWhere('o.code IN (:codes)') 45 | ->setParameter('codes', $codes) 46 | ->getQuery() 47 | ->getResult() 48 | ; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Repository/ProductVariantRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | ['html']], 33 | ), 34 | ]; 35 | } 36 | 37 | public function renderProductBundleOrderItems(ProductInterface $product): string 38 | { 39 | if (!$product->isBundle()) { 40 | return ''; 41 | } 42 | 43 | $productBundle = $product->getProductBundle(); 44 | 45 | if (null === $productBundle) { 46 | throw new \RuntimeException('Product does not contain a valid product bundle.'); 47 | } 48 | 49 | $items = $productBundle->getProductBundleItems(); 50 | 51 | return $this->twig->render('@BitBagSyliusProductBundlePlugin/Admin/Order/Show/_productBundleOrderItems.html.twig', [ 52 | 'items' => $items, 53 | ]); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Validator/HasAvailableProductBundle.php: -------------------------------------------------------------------------------- 1 | orderRepository->findCartById($value->getOrderId()); 41 | 42 | if (null !== $cart) { 43 | return; 44 | } 45 | 46 | $this->context->addViolation(HasExistingCart::CART_DOESNT_EXIST_MESSAGE); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Validator/HasProductBundle.php: -------------------------------------------------------------------------------- 1 | productRepository->findOneByCode($value->getProductCode()); 43 | 44 | if (null === $product) { 45 | $this->context->addViolation(HasProductBundle::PRODUCT_DOESNT_EXIST_MESSAGE); 46 | 47 | return; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Validator/Sequentially.php: -------------------------------------------------------------------------------- 1 | context; 27 | 28 | $validator = $context->getValidator()->inContext($context); 29 | 30 | $originalCount = $validator->getViolations()->count(); 31 | 32 | if (is_iterable($constraint->constraints)) { 33 | foreach ($constraint->constraints as $c) { 34 | if ($originalCount !== $validator->validate($value, $c)->getViolations()->count()) { 35 | break; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /templates/Admin/product/form/sections/bundle.html.twig: -------------------------------------------------------------------------------- 1 | {% set form = hookable_metadata.context.form %} 2 | {% set product = hookable_metadata.context.resource %} 3 | 4 | {% if product.isBundle %} 5 |
6 |
7 |
8 |

9 | {{ 'bitbag_sylius_product_bundle.ui.bundle'|trans }} 10 |

11 |
12 |
13 | {% hook 'bundle' with { product } %} 14 |
15 |
16 |
17 | {% endif %} 18 | -------------------------------------------------------------------------------- /templates/Admin/product/form/sections/bundle/productBundleItem.html.twig: -------------------------------------------------------------------------------- 1 | {% from '@SyliusResource/Macros/notification.html.twig' import error %} 2 | 3 | {% set form = hookable_metadata.context.form %} 4 | {% set product_bundle_items = hookable_metadata.context.form.productBundle.productBundleItems %} 5 | 6 |
7 | {{ error(form.vars.errors) }} 8 |
9 | {{ form_row(form.productBundle.isPackedProduct) }} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% for product_bundle_form in product_bundle_items %} 20 | 21 | 24 | 27 | 30 | 31 | {% endfor %} 32 | 33 |
{{ 'bitbag_sylius_product_bundle.ui.product_variant'|trans }}{{ 'bitbag_sylius_product_bundle.ui.quantity'|trans }}{{ 'bitbag_sylius_product_bundle.ui.delete'|trans }}
22 | {{ form_row(product_bundle_form.children.productVariant) }} 23 | 25 | {{ form_row(product_bundle_form.children.quantity) }} 26 | 28 | {{ form_widget(product_bundle_form.vars.button_delete, { label: 'sylius.ui.delete'|trans, attr: { class: 'btn btn-outline-danger w-100','data-test-image-delete': '' }}) }} 29 |
34 |
35 | {{ form_widget(product_bundle_items.vars.button_add) }} 36 |
37 |
38 |
39 | -------------------------------------------------------------------------------- /templates/Admin/product/form/side_navigation/bundle.html.twig: -------------------------------------------------------------------------------- 1 | {% set product = hookable_metadata.context.resource %} 2 | 3 | {% if product.isBundle %} 4 | 14 | {% endif %} 15 | -------------------------------------------------------------------------------- /templates/Shop/product/show/page/info/summary/add_to_cart/addProductBundleToCart.html.twig: -------------------------------------------------------------------------------- 1 | {% form_theme form '@SyliusShop/form/theme.html.twig' %} 2 | 3 | {% if product.isBundle %} 4 | {% set product_bundle_items = form.productBundleItems %} 5 |
6 |

{{ 'bitbag_sylius_product_bundle.ui.products_in_bundle'|trans }}

7 | {% for item in product_bundle_items %} 8 | {% set data = item.vars.data %} 9 |
10 |
11 | 12 | {{ data.quantity }} x {{ data.productVariant.product.name }} 13 | 14 | {% if item.productVariant is defined %} 15 | {{ form_row(item.productVariant) }} 16 | {% endif %} 17 |
18 |
19 | {% endfor %} 20 |
21 |
22 | {% endif %} 23 | -------------------------------------------------------------------------------- /tests/Api/Admin/OrderTest.php: -------------------------------------------------------------------------------- 1 | fixtures = $this->loadFixturesFromFiles([ 32 | 'general/channels.yml', 33 | 'general/authentication.yml', 34 | 'shop/product_bundles.yml', 35 | 'shop/orders.yml', 36 | ]); 37 | 38 | $authToken = $this->getAuthToken('api@example.com', 'sylius-api'); 39 | $this->authHeaders = $this->getHeaders($authToken); 40 | } 41 | 42 | /** @test */ 43 | public function it_gets_order_data_containing_info_about_bundled_items(): void 44 | { 45 | /** @var OrderInterface $order */ 46 | $order = $this->fixtures['order_with_bundle']; 47 | 48 | $this->client->request( 49 | Request::METHOD_GET, 50 | sprintf(self::ENDPOINT_ORDERS_ITEM, $order->getTokenValue()), 51 | [], 52 | [], 53 | $this->authHeaders, 54 | ); 55 | $response = $this->client->getResponse(); 56 | 57 | $this->assertResponse($response, 'admin/get_order_with_bundle_response', Response::HTTP_OK); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/Api/AdminJsonApiTestCase.php: -------------------------------------------------------------------------------- 1 | client->request( 21 | 'POST', 22 | $endpoint, 23 | [], 24 | [], 25 | ['CONTENT_TYPE' => 'application/json', 'HTTP_ACCEPT' => 'application/json'], 26 | json_encode(['email' => $email, 'password' => $password]), 27 | ); 28 | 29 | return json_decode($this->client->getResponse()->getContent(), true)['token']; 30 | } 31 | 32 | public function getHeaders($authToken = null): array 33 | { 34 | $headers = ['CONTENT_TYPE' => 'application/ld+json', 'HTTP_ACCEPT' => 'application/ld+json']; 35 | 36 | if (null === $authToken) { 37 | return $headers; 38 | } 39 | 40 | $authorizationHeader = self::getContainer()->getParameter('sylius.api.authorization_header'); 41 | $headers['HTTP_' . $authorizationHeader] = 'Bearer ' . $authToken; 42 | 43 | return $headers; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/Api/DataFixtures/ORM/general/authentication.yml: -------------------------------------------------------------------------------- 1 | Sylius\Component\Core\Model\AdminUser: 2 | admin: 3 | plainPassword: sylius-api 4 | roles: [ROLE_API_ACCESS] 5 | enabled: true 6 | email: api@example.com 7 | username: sylius 8 | localeCode: en_US 9 | -------------------------------------------------------------------------------- /tests/Api/DataFixtures/ORM/general/channels.yml: -------------------------------------------------------------------------------- 1 | Sylius\Component\Core\Model\Channel: 2 | channel_web: 3 | code: "WEB" 4 | name: "Web Channel" 5 | hostname: "localhost" 6 | description: "Lorem ipsum" 7 | baseCurrency: "@currency1" 8 | defaultLocale: "@locale" 9 | locales: ["@locale"] 10 | color: "black" 11 | enabled: true 12 | taxCalculationStrategy: "order_items_based" 13 | 14 | Sylius\Component\Currency\Model\Currency: 15 | currency1: 16 | code: "EUR" 17 | 18 | Sylius\Component\Locale\Model\Locale: 19 | locale: 20 | code: "en_US" 21 | -------------------------------------------------------------------------------- /tests/Api/JsonApiTestCase.php: -------------------------------------------------------------------------------- 1 | 'application/ld+json', 'HTTP_ACCEPT' => 'application/ld+json']; 20 | 21 | public const PATCH_HEADER = ['CONTENT_TYPE' => 'application/merge-patch+json', 'HTTP_ACCEPT' => 'application/ld+json']; 22 | 23 | protected static function getContainer(): Container 24 | { 25 | if (is_callable('parent::getContainer')) { 26 | /* @phpstan-ignore-next-line */ 27 | return parent::getContainer(); 28 | } 29 | 30 | return self::$container; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/Api/Responses/admin/get_order_with_bundle_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "\/api\/v2\/contexts\/Order", 3 | "@id": "\/api\/v2\/admin\/orders\/zszRdAaZIx", 4 | "@type": "Order", 5 | "customer": "@string@", 6 | "channel": "\/api\/v2\/admin\/channels\/WEB", 7 | "shippingAddress": "@...@", 8 | "billingAddress": "@...@", 9 | "payments": "@*@", 10 | "shipments": "@*@", 11 | "currencyCode": "EUR", 12 | "localeCode": "en_US", 13 | "checkoutState": "completed", 14 | "paymentState": "awaiting_payment", 15 | "shippingState": "ready", 16 | "tokenValue": "zszRdAaZIx", 17 | "id": "@integer@", 18 | "number": "@string@", 19 | "items": [ 20 | { 21 | "@id": "@string@", 22 | "@type": "OrderItem", 23 | "variant": "\/api\/v2\/admin\/product-variants\/WHISKEY_DOUBLE_PACK", 24 | "productName": "Whiskey Double Pack", 25 | "id": "@integer@", 26 | "quantity": 1, 27 | "unitPrice": 1800, 28 | "originalUnitPrice": 0, 29 | "total": 1800, 30 | "productBundleOrderItems": [ 31 | { 32 | "@type": "ProductBundleOrderItem", 33 | "@id": "@string@", 34 | "id": "@integer@", 35 | "productVariant": "@string@", 36 | "quantity": 1 37 | }, 38 | { 39 | "@type": "ProductBundleOrderItem", 40 | "@id": "@string@", 41 | "id": "@integer@", 42 | "productVariant": "@string@", 43 | "quantity": 1 44 | } 45 | ], 46 | "subtotal": 1800 47 | } 48 | ], 49 | "itemsTotal": 1800, 50 | "total": 1800, 51 | "state": "new", 52 | "taxTotal": 0, 53 | "shippingTotal": 0, 54 | "orderPromotionTotal": 0 55 | } 56 | -------------------------------------------------------------------------------- /tests/Api/Responses/admin/get_product_bundle_collection_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "\/api\/v2\/contexts\/ProductBundle", 3 | "@id": "\/api\/v2\/admin\/product-bundles", 4 | "@type": "hydra:Collection", 5 | "hydra:totalItems": 1, 6 | "hydra:member": [ 7 | { 8 | "@id": "\/api\/v2\/admin\/product-bundles\/@integer@", 9 | "@type": "ProductBundle", 10 | "id": "@integer@", 11 | "product": "\/api\/v2\/admin\/products\/WHISKEY_DOUBLE_PACK", 12 | "items": [ 13 | "\/api\/v2\/shop\/product-bundle-items\/@integer@", 14 | "\/api\/v2\/shop\/product-bundle-items\/@integer@" 15 | ], 16 | "createdAt": "@datetime@", 17 | "updatedAt": "@datetime@", 18 | "isPacked": true 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tests/Api/Responses/admin/get_product_bundle_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "\/api\/v2\/contexts\/ProductBundle", 3 | "@id": "\/api\/v2\/admin\/product-bundles\/@integer@", 4 | "@type": "ProductBundle", 5 | "id": "@integer@", 6 | "product": "\/api\/v2\/admin\/products\/WHISKEY_DOUBLE_PACK", 7 | "items": [ 8 | "\/api\/v2\/shop\/product-bundle-items\/@integer@", 9 | "\/api\/v2\/shop\/product-bundle-items\/@integer@" 10 | ], 11 | "createdAt": "@datetime@", 12 | "updatedAt": "@datetime@", 13 | "isPacked": true 14 | } 15 | -------------------------------------------------------------------------------- /tests/Api/Responses/admin/post_product_bundle_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "\/api\/v2\/contexts\/ProductBundle", 3 | "@id": "\/api\/v2\/admin\/product-bundles\/@integer@", 4 | "@type": "ProductBundle", 5 | "id": "@integer@", 6 | "product": "\/api\/v2\/admin\/products\/JOHNNY_WALKER_BUNDLE", 7 | "items": [ 8 | "\/api\/v2\/shop\/product-bundle-items\/@integer@", 9 | "\/api\/v2\/shop\/product-bundle-items\/@integer@" 10 | ], 11 | "createdAt": "@datetime@", 12 | "updatedAt": "@datetime@", 13 | "isPacked": true 14 | } 15 | -------------------------------------------------------------------------------- /tests/Api/Responses/admin/put_product_bundle_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "\/api\/v2\/contexts\/ProductBundle", 3 | "@id": "\/api\/v2\/admin\/product-bundles\/@integer@", 4 | "@type": "ProductBundle", 5 | "id": "@integer@", 6 | "product": "\/api\/v2\/admin\/products\/WHISKEY_DOUBLE_PACK", 7 | "items": [ 8 | "\/api\/v2\/shop\/product-bundle-items\/@integer@", 9 | "\/api\/v2\/shop\/product-bundle-items\/@integer@" 10 | ], 11 | "createdAt": "@datetime@", 12 | "updatedAt": "@datetime@", 13 | "isPacked": false 14 | } 15 | -------------------------------------------------------------------------------- /tests/Api/Responses/shop/get_bundled_product_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "\/api\/v2\/contexts\/Product", 3 | "@id": "\/api\/v2\/shop\/products\/WHISKEY_DOUBLE_PACK", 4 | "@type": "Product", 5 | "productTaxons": [], 6 | "mainTaxon": null, 7 | "averageRating": "@integer@", 8 | "images": [], 9 | "id": "@integer@", 10 | "code": "WHISKEY_DOUBLE_PACK", 11 | "variants": ["/api/v2/shop/product-variants/@string@"], 12 | "options": [], 13 | "associations": [], 14 | "createdAt": "@datetime@", 15 | "updatedAt": "@datetime@", 16 | "isBundle": true, 17 | "shortDescription": null, 18 | "reviews": [], 19 | "name": "@string@", 20 | "description": "@string@", 21 | "slug": "@string@", 22 | "bundle": "/api/v2/admin/product-bundles/@integer@", 23 | "defaultVariant": "@string@" 24 | } 25 | -------------------------------------------------------------------------------- /tests/Api/Responses/shop/get_not_bundled_product_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "\/api\/v2\/contexts\/Product", 3 | "@id": "\/api\/v2\/shop\/products\/JOHNNY_WALKER_BLACK", 4 | "@type": "Product", 5 | "productTaxons": "@...@", 6 | "mainTaxon": null, 7 | "reviews": "@...@", 8 | "averageRating": "@integer@", 9 | "images": "@...@", 10 | "id": "@integer@", 11 | "code": "JOHNNY_WALKER_BLACK", 12 | "name": "@string@", 13 | "slug": "@string@", 14 | "variants": "@...@", 15 | "options": "@...@", 16 | "createdAt": "@string@", 17 | "updatedAt": "@string@", 18 | "bundle": null, 19 | "isBundle": false, 20 | "description": "@string@", 21 | "shortDescription": null, 22 | "defaultVariant": "@string@" 23 | } 24 | -------------------------------------------------------------------------------- /tests/Api/Responses/shop/get_product_bundle_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "\/api\/v2\/contexts\/ProductBundle", 3 | "@id": "@string@", 4 | "@type": "Product", 5 | "product": "\/api\/v2\/shop\/products\/WHISKEY_DOUBLE_PACK", 6 | "items": [ 7 | { 8 | "@type": "ProductBundleItem", 9 | "@id": "@string@", 10 | "productVariant": "@...@", 11 | "quantity": 1 12 | }, 13 | { 14 | "@type": "ProductBundleItem", 15 | "@id": "@string@", 16 | "productVariant": "@...@", 17 | "quantity": 1 18 | } 19 | ], 20 | "isPacked": true 21 | } 22 | -------------------------------------------------------------------------------- /tests/Api/Utils/CartHelperTrait.php: -------------------------------------------------------------------------------- 1 | get('sylius.command_bus'); 25 | 26 | $command = new PickupCart('WEB', 'en_US', null, $tokenValue, ); 27 | 28 | $commandBus->dispatch($command); 29 | } 30 | 31 | public function findCart(string $tokenValue): ?OrderInterface 32 | { 33 | /** @var OrderRepositoryInterface $orderManager */ 34 | $orderManager = self::getContainer()->get('sylius.repository.order'); 35 | 36 | return $orderManager->findCartByTokenValue($tokenValue); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/Application/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "targets": { 5 | "node": "6" 6 | }, 7 | "useBuiltIns": true 8 | }] 9 | ], 10 | "plugins": [ 11 | ["transform-object-rest-spread", { 12 | "useBuiltIns": true 13 | }] 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tests/Application/.env: -------------------------------------------------------------------------------- 1 | # This file is a "template" of which env vars needs to be defined in your configuration or in an .env file 2 | # Set variables here that may be different on each deployment target of the app, e.g. development, staging, production. 3 | # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration 4 | 5 | ###> symfony/framework-bundle ### 6 | APP_ENV=dev 7 | APP_DEBUG=1 8 | APP_SECRET=EDITME 9 | ###< symfony/framework-bundle ### 10 | 11 | ###> doctrine/doctrine-bundle ### 12 | # Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url 13 | # For a sqlite database, use: "sqlite:///%kernel.project_dir%/var/data.db" 14 | # Set "serverVersion" to your server version to avoid edge-case exceptions and extra database calls 15 | # DATABASE_URL=sqlite:///%kernel.project_dir%/var/data_%kernel.environment%.db 16 | DATABASE_URL=mysql://root@127.0.0.1/bitbag_product_bundle_plugin_%kernel.environment%?serverVersion=8 17 | ###< doctrine/doctrine-bundle ### 18 | 19 | ###> symfony/messenger ### 20 | # Choose one of the transports below 21 | # MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages 22 | # MESSENGER_TRANSPORT_DSN=doctrine://default 23 | # MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages 24 | MESSENGER_TRANSPORT_DSN=sync:// 25 | ###< symfony/messenger ### 26 | 27 | ###> lexik/jwt-authentication-bundle ### 28 | JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem 29 | JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem 30 | JWT_PASSPHRASE=acme_plugin_development 31 | ###< lexik/jwt-authentication-bundle ### 32 | 33 | ###> symfony/swiftmailer-bundle ### 34 | # For Gmail as a transport, use: "gmail://username:password@localhost" 35 | # For a generic SMTP server, use: "smtp://localhost:25?encryption=&auth_mode=" 36 | # Delivery is disabled by default via "null://localhost" 37 | MAILER_URL=smtp://localhost 38 | ###< symfony/swiftmailer-bundle ### 39 | -------------------------------------------------------------------------------- /tests/Application/.env.test: -------------------------------------------------------------------------------- 1 | APP_SECRET='ch4mb3r0f5ecr3ts' 2 | 3 | KERNEL_CLASS='Tests\BitBag\SyliusProductBundlePlugin\Application\Kernel' 4 | -------------------------------------------------------------------------------- /tests/Application/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'airbnb-base', 3 | env: { 4 | node: true, 5 | }, 6 | rules: { 7 | 'object-shorthand': ['error', 'always', { 8 | avoidQuotes: true, 9 | avoidExplicitReturnArrows: true, 10 | }], 11 | 'function-paren-newline': ['error', 'consistent'], 12 | 'max-len': ['warn', 120, 2, { 13 | ignoreUrls: true, 14 | ignoreComments: false, 15 | ignoreRegExpLiterals: true, 16 | ignoreStrings: true, 17 | ignoreTemplateLiterals: true, 18 | }], 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /tests/Application/.gitignore: -------------------------------------------------------------------------------- 1 | /public/assets 2 | /public/build 3 | /public/css 4 | /public/js 5 | /public/media/* 6 | !/public/media/image/ 7 | /public/media/image/* 8 | !/public/media/image/.gitignore 9 | 10 | /node_modules 11 | 12 | /config/encryption 13 | 14 | ###> symfony/framework-bundle ### 15 | /.env.*.local 16 | /.env.local 17 | /.env.local.php 18 | /public/bundles 19 | /var/ 20 | /vendor/ 21 | ###< symfony/framework-bundle ### 22 | 23 | ###> symfony/web-server-bundle ### 24 | /.web-server-pid 25 | ###< symfony/web-server-bundle ### 26 | -------------------------------------------------------------------------------- /tests/Application/assets/admin/entry.js: -------------------------------------------------------------------------------- 1 | import 'sylius/bundle/AdminBundle/Resources/assets/entrypoint'; 2 | -------------------------------------------------------------------------------- /tests/Application/assets/admin/product-entry.js: -------------------------------------------------------------------------------- 1 | import 'sylius/bundle/AdminBundle/Resources/assets/scripts/product/attribute-tabs-refresher'; 2 | -------------------------------------------------------------------------------- /tests/Application/assets/controllers.json: -------------------------------------------------------------------------------- 1 | { 2 | "controllers": { 3 | "@symfony/ux-autocomplete": { 4 | "autocomplete": { 5 | "main": "dist/controller.js", 6 | "webpackMode": "eager", 7 | "fetch": "eager", 8 | "enabled": true, 9 | "autoimport": { 10 | "tom-select/dist/css/tom-select.default.css": false, 11 | "tom-select/dist/css/tom-select.bootstrap5.css": false 12 | } 13 | } 14 | } 15 | }, 16 | "entrypoints": [] 17 | } 18 | -------------------------------------------------------------------------------- /tests/Application/assets/shop/entry.js: -------------------------------------------------------------------------------- 1 | import 'sylius/bundle/ShopBundle/Resources/assets/entrypoint'; 2 | -------------------------------------------------------------------------------- /tests/Application/bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | getParameterOption(['--env', '-e'], null, true)) { 19 | putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env); 20 | } 21 | 22 | if ($input->hasParameterOption('--no-debug', true)) { 23 | putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); 24 | } 25 | 26 | require dirname(__DIR__).'/config/bootstrap.php'; 27 | 28 | if ($_SERVER['APP_DEBUG']) { 29 | umask(0000); 30 | 31 | if (class_exists(Debug::class)) { 32 | Debug::enable(); 33 | } 34 | } 35 | 36 | $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); 37 | $application = new Application($kernel); 38 | $application->run($input); 39 | -------------------------------------------------------------------------------- /tests/Application/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sylius/plugin-skeleton-test-application", 3 | "description": "Sylius application for plugin testing purposes (composer.json needed for project dir resolving)", 4 | "license": "MIT" 5 | } 6 | -------------------------------------------------------------------------------- /tests/Application/config/api_platform/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/tests/Application/config/api_platform/.gitkeep -------------------------------------------------------------------------------- /tests/Application/config/bootstrap.php: -------------------------------------------------------------------------------- 1 | =1.2) 18 | if (is_array($env = @include dirname(__DIR__) . '/.env.local.php')) { 19 | $_SERVER += $env; 20 | $_ENV += $env; 21 | } elseif (!class_exists(Dotenv::class)) { 22 | throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.'); 23 | } else { 24 | // load all the .env files 25 | (new Dotenv())->loadEnv(dirname(__DIR__) . '/.env'); 26 | } 27 | 28 | $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?? 'dev'; 29 | $_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV']; 30 | $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], \FILTER_VALIDATE_BOOLEAN) ? '1' : '0'; 31 | -------------------------------------------------------------------------------- /tests/Application/config/jwt/public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6QkmF/Xi5nAYb8Kzr7qC 3 | d63V2K+d/nCXbpDUKKDPJAqOtTlMoQSuJRLNnhhp7z1i/Cp4Bhifr20Pu2dq8JYg 4 | 6pRT4ctqvYb/MXxAaPZc3EcBC0S6AhgKO/fDvR3LcqYqGJmQQOXZvxTsgqongdvV 5 | 4XbqFBMMgngyayoBk0VKTaI/s+LQhIce+1QaxbAI0+/zbR0hZ1hWT73orJi3do+1 6 | TBzQol+V7WGa8LlJfmgM56qO3BmVkeTDMBc27pGp6g3+Oufk/l29jEGJlUT9yu7Q 7 | BRhaQTWNVASa2aD+AKjVBzJh53O2zD8slAbjF1M9U7bbWN28Sv+xC/dUz0q9HnPu 8 | RsY2tnwryqTyYn/Hf2xyP3/KvjJ6oslAwemu5JirdJkO7KVQAthWG42gLuhZg3ks 9 | cSZhCLZH7nO2UDsf+2ZZgdbhpYZwR4gDRfNt7GKWXnWZOz9Uw1yVCPgylyZRZwg8 10 | l0y9aABdj3379I22icrwpMZbAgkyxNSV6UNJuxZksLUoP3i9OvXYgPYU9E4tU/Ul 11 | Dm/T1rGSReGoPkU1YQnI50bq7p1byIoUu2scTflvpTVI5a7zULkS1tg60xk7vBRC 12 | aBc7nr4UEtA235N6uLtcGxH11WBMwsKX69sSU0sQdC4Sk25zXM2gc8R1XV9K3qz2 13 | wQorQRlCwrkG44VRDgbFH+8CAwEAAQ== 14 | -----END PUBLIC KEY----- 15 | -------------------------------------------------------------------------------- /tests/Application/config/packages/assets.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | assets: 3 | packages: 4 | shop: 5 | json_manifest_path: '%kernel.project_dir%/public/build/shop/manifest.json' 6 | admin: 7 | json_manifest_path: '%kernel.project_dir%/public/build/admin/manifest.json' 8 | product_bundle_shop: 9 | json_manifest_path: '%kernel.project_dir%/public/build/bitbag/productBundle/shop/manifest.json' 10 | product_bundle_admin: 11 | json_manifest_path: '%kernel.project_dir%/public/build/bitbag/productBundle/admin/manifest.json' 12 | -------------------------------------------------------------------------------- /tests/Application/config/packages/bitbag_sylius_product_bundle_plugin.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: "@BitBagSyliusProductBundlePlugin/config/config.yml" } 3 | -------------------------------------------------------------------------------- /tests/Application/config/packages/dev/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | profiler: { only_exceptions: false } 3 | -------------------------------------------------------------------------------- /tests/Application/config/packages/dev/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: stream 5 | path: "%kernel.logs_dir%/%kernel.environment%.log" 6 | level: debug 7 | firephp: 8 | type: firephp 9 | level: info 10 | -------------------------------------------------------------------------------- /tests/Application/config/packages/dev/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: true 4 | -------------------------------------------------------------------------------- /tests/Application/config/packages/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: true 3 | intercept_redirects: false 4 | -------------------------------------------------------------------------------- /tests/Application/config/packages/doctrine.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | # Adds a fallback DATABASE_URL if the env var is not set. 3 | # This allows you to run cache:warmup even if your 4 | # environment variables are not available yet. 5 | # You should not need to change this value. 6 | env(DATABASE_URL): '' 7 | 8 | doctrine: 9 | dbal: 10 | driver: 'pdo_mysql' 11 | server_version: '5.7' 12 | charset: UTF8 13 | 14 | url: '%env(resolve:DATABASE_URL)%' 15 | 16 | orm: 17 | auto_generate_proxy_classes: '%kernel.debug%' 18 | naming_strategy: doctrine.orm.naming_strategy.underscore 19 | auto_mapping: true 20 | mappings: 21 | App: 22 | is_bundle: false 23 | type: xml 24 | dir: '%kernel.project_dir%/src/Resources/config/doctrine' 25 | prefix: 'Tests\BitBag\SyliusProductBundlePlugin\Entity' 26 | -------------------------------------------------------------------------------- /tests/Application/config/packages/doctrine_migrations.yaml: -------------------------------------------------------------------------------- 1 | doctrine_migrations: 2 | storage: 3 | table_storage: 4 | table_name: sylius_migrations 5 | -------------------------------------------------------------------------------- /tests/Application/config/packages/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | secret: '%env(APP_SECRET)%' 3 | form: true 4 | csrf_protection: true 5 | session: 6 | handler_id: ~ 7 | -------------------------------------------------------------------------------- /tests/Application/config/packages/http_discovery.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | Psr\Http\Message\RequestFactoryInterface: '@http_discovery.psr17_factory' 3 | Psr\Http\Message\ResponseFactoryInterface: '@http_discovery.psr17_factory' 4 | Psr\Http\Message\ServerRequestFactoryInterface: '@http_discovery.psr17_factory' 5 | Psr\Http\Message\StreamFactoryInterface: '@http_discovery.psr17_factory' 6 | Psr\Http\Message\UploadedFileFactoryInterface: '@http_discovery.psr17_factory' 7 | Psr\Http\Message\UriFactoryInterface: '@http_discovery.psr17_factory' 8 | 9 | http_discovery.psr17_factory: 10 | class: Http\Discovery\Psr17Factory 11 | -------------------------------------------------------------------------------- /tests/Application/config/packages/lexik_jwt_authentication.yaml: -------------------------------------------------------------------------------- 1 | lexik_jwt_authentication: 2 | secret_key: '%env(resolve:JWT_SECRET_KEY)%' 3 | public_key: '%env(resolve:JWT_PUBLIC_KEY)%' 4 | pass_phrase: '%env(JWT_PASSPHRASE)%' 5 | -------------------------------------------------------------------------------- /tests/Application/config/packages/liip_imagine.yaml: -------------------------------------------------------------------------------- 1 | liip_imagine: 2 | resolvers: 3 | default: 4 | web_path: 5 | web_root: "%kernel.project_dir%/public" 6 | cache_prefix: "media/cache" 7 | -------------------------------------------------------------------------------- /tests/Application/config/packages/mailer.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | mailer: 3 | dsn: 'null://null' 4 | cache: 5 | pools: 6 | test.mailer_pool: 7 | adapter: cache.adapter.filesystem 8 | -------------------------------------------------------------------------------- /tests/Application/config/packages/prod/doctrine.yaml: -------------------------------------------------------------------------------- 1 | doctrine: 2 | orm: 3 | metadata_cache_driver: 4 | type: service 5 | id: doctrine.system_cache_provider 6 | query_cache_driver: 7 | type: service 8 | id: doctrine.system_cache_provider 9 | result_cache_driver: 10 | type: service 11 | id: doctrine.result_cache_provider 12 | 13 | services: 14 | doctrine.result_cache_provider: 15 | class: Symfony\Component\Cache\DoctrineProvider 16 | public: false 17 | arguments: 18 | - '@doctrine.result_cache_pool' 19 | doctrine.system_cache_provider: 20 | class: Symfony\Component\Cache\DoctrineProvider 21 | public: false 22 | arguments: 23 | - '@doctrine.system_cache_pool' 24 | 25 | framework: 26 | cache: 27 | pools: 28 | doctrine.result_cache_pool: 29 | adapter: cache.app 30 | doctrine.system_cache_pool: 31 | adapter: cache.system 32 | -------------------------------------------------------------------------------- /tests/Application/config/packages/prod/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: fingers_crossed 5 | action_level: error 6 | handler: nested 7 | nested: 8 | type: stream 9 | path: "%kernel.logs_dir%/%kernel.environment%.log" 10 | level: debug 11 | -------------------------------------------------------------------------------- /tests/Application/config/packages/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: ~ 4 | -------------------------------------------------------------------------------- /tests/Application/config/packages/staging/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: fingers_crossed 5 | action_level: error 6 | handler: nested 7 | nested: 8 | type: stream 9 | path: "%kernel.logs_dir%/%kernel.environment%.log" 10 | level: debug 11 | -------------------------------------------------------------------------------- /tests/Application/config/packages/stof_doctrine_extensions.yaml: -------------------------------------------------------------------------------- 1 | # Read the documentation: https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html 2 | # See the official DoctrineExtensions documentation for more details: https://github.com/Atlantic18/DoctrineExtensions/tree/master/doc/ 3 | stof_doctrine_extensions: 4 | default_locale: '%locale%' 5 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | test: ~ 3 | session: 4 | handler_id: ~ 5 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: stream 5 | path: "%kernel.logs_dir%/%kernel.environment%.log" 6 | level: error 7 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test/sylius_theme.yaml: -------------------------------------------------------------------------------- 1 | sylius_theme: 2 | sources: 3 | test: ~ 4 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test/sylius_uploader.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | Sylius\Component\Core\Generator\ImagePathGeneratorInterface: 3 | class: Sylius\Behat\Service\Generator\UploadedImagePathGenerator 4 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: false 3 | intercept_redirects: false 4 | 5 | framework: 6 | profiler: { collect: false } 7 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test_cached/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | test: ~ 3 | session: 4 | handler_id: ~ 5 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test_cached/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: stream 5 | path: "%kernel.logs_dir%/%kernel.environment%.log" 6 | level: error 7 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test_cached/sylius_channel.yaml: -------------------------------------------------------------------------------- 1 | sylius_channel: 2 | debug: true 3 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test_cached/sylius_theme.yaml: -------------------------------------------------------------------------------- 1 | sylius_theme: 2 | sources: 3 | test: ~ 4 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test_cached/sylius_uploader.yaml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: "../test/sylius_uploader.yaml" } 3 | -------------------------------------------------------------------------------- /tests/Application/config/packages/test_cached/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | paths: ['%kernel.project_dir%/templates'] 3 | debug: '%kernel.debug%' 4 | strict_variables: true 5 | 6 | services: 7 | _defaults: 8 | public: false 9 | autowire: true 10 | autoconfigure: true 11 | 12 | Twig\Extra\Intl\IntlExtension: ~ 13 | -------------------------------------------------------------------------------- /tests/Application/config/packages/translation.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | default_locale: '%locale%' 3 | translator: 4 | paths: 5 | - '%kernel.project_dir%/translations' 6 | fallbacks: 7 | - '%locale%' 8 | - 'en' 9 | -------------------------------------------------------------------------------- /tests/Application/config/packages/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | paths: ['%kernel.project_dir%/templates'] 3 | debug: '%kernel.debug%' 4 | strict_variables: '%kernel.debug%' 5 | 6 | services: 7 | _defaults: 8 | public: false 9 | autowire: true 10 | autoconfigure: true 11 | 12 | Twig\Extra\Intl\IntlExtension: ~ 13 | -------------------------------------------------------------------------------- /tests/Application/config/packages/validator.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | validation: 3 | enable_attributes: true 4 | -------------------------------------------------------------------------------- /tests/Application/config/packages/webpack_encore.yaml: -------------------------------------------------------------------------------- 1 | webpack_encore: 2 | output_path: '%kernel.project_dir%/public/build/default' 3 | builds: 4 | shop: '%kernel.project_dir%/public/build/shop' 5 | admin: '%kernel.project_dir%/public/build/admin' 6 | product_bundle_shop: '%kernel.project_dir%/public/build/bitbag/productBundle/shop' 7 | product_bundle_admin: '%kernel.project_dir%/public/build/bitbag/productBundle/admin' 8 | -------------------------------------------------------------------------------- /tests/Application/config/routes.yaml: -------------------------------------------------------------------------------- 1 | bitbag_sylius_product_bundle_plugin: 2 | resource: "@BitBagSyliusProductBundlePlugin/config/routes.yml" 3 | -------------------------------------------------------------------------------- /tests/Application/config/routes/api_platform.yaml: -------------------------------------------------------------------------------- 1 | api_platform: 2 | resource: . 3 | type: api_platform 4 | prefix: /api 5 | -------------------------------------------------------------------------------- /tests/Application/config/routes/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | _wdt: 2 | resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml" 3 | prefix: /_wdt 4 | 5 | _profiler: 6 | resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml" 7 | prefix: /_profiler 8 | -------------------------------------------------------------------------------- /tests/Application/config/routes/liip_imagine.yaml: -------------------------------------------------------------------------------- 1 | _liip_imagine: 2 | resource: "@LiipImagineBundle/Resources/config/routing.yaml" 3 | -------------------------------------------------------------------------------- /tests/Application/config/routes/sylius_admin.yaml: -------------------------------------------------------------------------------- 1 | sylius_admin: 2 | resource: "@SyliusAdminBundle/Resources/config/routing.yml" 3 | prefix: /admin 4 | 5 | live_component: 6 | resource: "@LiveComponentBundle/config/routes.php" 7 | prefix: /_components 8 | -------------------------------------------------------------------------------- /tests/Application/config/routes/sylius_api.yaml: -------------------------------------------------------------------------------- 1 | sylius_api: 2 | resource: "@SyliusApiBundle/Resources/config/routing.yml" 3 | prefix: "%sylius.security.api_route%" 4 | -------------------------------------------------------------------------------- /tests/Application/config/routes/sylius_shop.yaml: -------------------------------------------------------------------------------- 1 | sylius_shop: 2 | resource: "@SyliusShopBundle/Resources/config/routing.yml" 3 | prefix: /{_locale} 4 | requirements: 5 | _locale: ^[A-Za-z]{2,4}(_([A-Za-z]{4}|[0-9]{3}))?(_([A-Za-z]{2}|[0-9]{3}))?$ 6 | 7 | sylius_shop_payum: 8 | resource: "@SyliusPayumBundle/Resources/config/routing/integrations/sylius_shop.yaml" 9 | 10 | sylius_shop_default_locale: 11 | path: / 12 | methods: [GET] 13 | defaults: 14 | _controller: sylius_shop.controller.locale_switch::switchAction 15 | 16 | live_component: 17 | resource: "@LiveComponentBundle/config/routes.php" 18 | prefix: /_components 19 | -------------------------------------------------------------------------------- /tests/Application/config/routes/test/sylius_test_plugin.yaml: -------------------------------------------------------------------------------- 1 | sylius_test_plugin_main: 2 | path: /test/main 3 | controller: FrameworkBundle:Template:template 4 | defaults: 5 | template: "@SyliusTestPlugin/main.html.twig" 6 | -------------------------------------------------------------------------------- /tests/Application/config/routes/test_cached/routing.yaml: -------------------------------------------------------------------------------- 1 | sylius_test_plugin_main: 2 | path: /test/main 3 | controller: FrameworkBundle:Template:template 4 | defaults: 5 | template: "@SyliusTestPlugin/main.html.twig" 6 | -------------------------------------------------------------------------------- /tests/Application/config/routes/test_cached/sylius_test_plugin.yaml: -------------------------------------------------------------------------------- 1 | sylius_test_plugin_main: 2 | path: /test/main 3 | controller: FrameworkBundle:Template:template 4 | defaults: 5 | template: "@SyliusTestPlugin/main.html.twig" 6 | -------------------------------------------------------------------------------- /tests/Application/config/routes/ux.yaml: -------------------------------------------------------------------------------- 1 | live_component: 2 | resource: "@LiveComponentBundle/config/routes.php" 3 | prefix: /_components 4 | -------------------------------------------------------------------------------- /tests/Application/config/secrets/dev/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/tests/Application/config/secrets/dev/.gitignore -------------------------------------------------------------------------------- /tests/Application/config/secrets/prod/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/tests/Application/config/secrets/prod/.gitignore -------------------------------------------------------------------------------- /tests/Application/config/secrets/test/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/tests/Application/config/secrets/test/.gitignore -------------------------------------------------------------------------------- /tests/Application/config/secrets/test_cached/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/tests/Application/config/secrets/test_cached/.gitignore -------------------------------------------------------------------------------- /tests/Application/config/services.yaml: -------------------------------------------------------------------------------- 1 | # Put parameters here that don't need to change on each machine where the app is deployed 2 | # https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration 3 | parameters: 4 | locale: en_US 5 | -------------------------------------------------------------------------------- /tests/Application/config/services_test.yaml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: "../../Behat/Resources/services.yml" } 3 | - { resource: "../../../vendor/sylius/sylius/src/Sylius/Behat/Resources/config/services.xml" } 4 | 5 | # workaround needed for strange "test.client.history" problem 6 | # see https://github.com/FriendsOfBehat/SymfonyExtension/issues/88 7 | services: 8 | Symfony\Component\BrowserKit\AbstractBrowser: '@test.client' 9 | -------------------------------------------------------------------------------- /tests/Application/config/services_test_cached.yaml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: "services_test.yaml" } 3 | -------------------------------------------------------------------------------- /tests/Application/gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | import chug from 'gulp-chug'; 2 | import gulp from 'gulp'; 3 | import yargs from 'yargs'; 4 | 5 | const { argv } = yargs 6 | .options({ 7 | rootPath: { 8 | description: ' path to public assets directory', 9 | type: 'string', 10 | requiresArg: true, 11 | required: false, 12 | }, 13 | nodeModulesPath: { 14 | description: ' path to node_modules directory', 15 | type: 'string', 16 | requiresArg: true, 17 | required: false, 18 | }, 19 | }); 20 | 21 | const config = [ 22 | '--rootPath', 23 | argv.rootPath || '../../../../../../../tests/Application/public/assets', 24 | '--nodeModulesPath', 25 | argv.nodeModulesPath || '../../../../../../../tests/Application/node_modules', 26 | ]; 27 | 28 | export const buildAdmin = function buildAdmin() { 29 | return gulp.src('../../vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/gulpfile.babel.js', { read: false }) 30 | .pipe(chug({ args: config, tasks: 'build' })); 31 | }; 32 | buildAdmin.description = 'Build admin assets.'; 33 | 34 | export const watchAdmin = function watchAdmin() { 35 | return gulp.src('../../vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/gulpfile.babel.js', { read: false }) 36 | .pipe(chug({ args: config, tasks: 'watch' })); 37 | }; 38 | watchAdmin.description = 'Watch admin asset sources and rebuild on changes.'; 39 | 40 | export const buildShop = function buildShop() { 41 | return gulp.src('../../vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/gulpfile.babel.js', { read: false }) 42 | .pipe(chug({ args: config, tasks: 'build' })); 43 | }; 44 | buildShop.description = 'Build shop assets.'; 45 | 46 | export const watchShop = function watchShop() { 47 | return gulp.src('../../vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/gulpfile.babel.js', { read: false }) 48 | .pipe(chug({ args: config, tasks: 'watch' })); 49 | }; 50 | watchShop.description = 'Watch shop asset sources and rebuild on changes.'; 51 | 52 | export const build = gulp.parallel(buildAdmin, buildShop); 53 | build.description = 'Build assets.'; 54 | 55 | gulp.task('admin', buildAdmin); 56 | gulp.task('admin-watch', watchAdmin); 57 | gulp.task('shop', buildShop); 58 | gulp.task('shop-watch', watchShop); 59 | 60 | export default build; 61 | -------------------------------------------------------------------------------- /tests/Application/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "MIT", 3 | "scripts": { 4 | "build": "encore dev", 5 | "build:prod": "encore production", 6 | "watch": "encore dev --watch" 7 | }, 8 | "dependencies": { 9 | "@sylius-ui/admin": "file:../../vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle", 10 | "@sylius-ui/shop": "file:../../vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle", 11 | "@symfony/ux-autocomplete": "file:../../vendor/symfony/ux-autocomplete/assets", 12 | "@symfony/ux-live-component": "file:../../vendor/symfony/ux-live-component/assets" 13 | }, 14 | "devDependencies": { 15 | "@hotwired/stimulus": "^3.0.0", 16 | "@symfony/stimulus-bridge": "^3.2.0", 17 | "@symfony/webpack-encore": "^5.0.1", 18 | "tom-select": "^2.2.2", 19 | "babel-core": "^6.26.3", 20 | "babel-plugin-external-helpers": "^6.22.0", 21 | "babel-plugin-module-resolver": "^3.1.1", 22 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 23 | "babel-preset-env": "^1.7.0", 24 | "babel-register": "^6.26.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Application/public/.htaccess: -------------------------------------------------------------------------------- 1 | DirectoryIndex app.php 2 | 3 | 4 | RewriteEngine On 5 | 6 | RewriteCond %{HTTP:Authorization} ^(.*) 7 | RewriteRule .* - [e=HTTP_AUTHORIZATION:%1] 8 | 9 | RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ 10 | RewriteRule ^(.*) - [E=BASE:%1] 11 | 12 | RewriteCond %{ENV:REDIRECT_STATUS} ^$ 13 | RewriteRule ^index\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L] 14 | 15 | RewriteCond %{REQUEST_FILENAME} -f 16 | RewriteRule .? - [L] 17 | 18 | RewriteRule .? %{ENV:BASE}/index.php [L] 19 | 20 | 21 | 22 | 23 | RedirectMatch 302 ^/$ /index.php/ 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/Application/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/tests/Application/public/favicon.ico -------------------------------------------------------------------------------- /tests/Application/public/index.php: -------------------------------------------------------------------------------- 1 | handle($request); 35 | $response->send(); 36 | $kernel->terminate($request, $response); 37 | -------------------------------------------------------------------------------- /tests/Application/public/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | # www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449 3 | 4 | User-agent: * 5 | -------------------------------------------------------------------------------- /tests/Application/src/Entity/OrderItem.php: -------------------------------------------------------------------------------- 1 | init(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/Application/src/Entity/Product.php: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/Application/src/Resources/config/doctrine/Product.orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/Application/templates/bundles/SyliusAdminBundle/Layout/_logo.html.twig: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 |
6 | -------------------------------------------------------------------------------- /tests/Application/templates/bundles/SyliusAdminBundle/_scripts.html.twig: -------------------------------------------------------------------------------- 1 | {{ encore_entry_script_tags('admin-entry', null, 'admin') }} 2 | {{ encore_entry_script_tags('bitbag-productBundle-admin', null, 'product_bundle_admin') }} 3 | -------------------------------------------------------------------------------- /tests/Application/templates/bundles/SyliusAdminBundle/_styles.html.twig: -------------------------------------------------------------------------------- 1 | {{ encore_entry_link_tags('admin-entry', null, 'admin') }} 2 | {{ encore_entry_link_tags('bitbag-productBundle-admin', null, 'product_bundle_admin') }} 3 | -------------------------------------------------------------------------------- /tests/Application/templates/bundles/SyliusAdminBundle/order/show/content/sections/items/body/item.html.twig: -------------------------------------------------------------------------------- 1 | {% from '@SyliusAdmin/shared/helper/product_image.html.twig' import image %} 2 | 3 | {% set product = hookable_metadata.context.product %} 4 | {% set variant = hookable_metadata.context.variant %} 5 | 6 | 7 |
8 |
9 | {{ image(product) }} 10 |
11 |
12 | 17 |
{{ variant.code }}
18 |
{{ variant.name }}
19 |
20 |
21 | 22 | {{ bitbag_render_product_bundle_order_items(product) }} 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/Application/templates/bundles/SyliusShopBundle/Layout/Header/_logo.html.twig: -------------------------------------------------------------------------------- 1 |
2 | 3 | Sylius logo 4 | 5 |
6 | -------------------------------------------------------------------------------- /tests/Application/templates/bundles/SyliusShopBundle/_scripts.html.twig: -------------------------------------------------------------------------------- 1 | {{ encore_entry_script_tags('shop-entry', null, 'shop') }} 2 | {{ encore_entry_script_tags('bitbag-productBundle-shop', null, 'product_bundle_shop') }} 3 | -------------------------------------------------------------------------------- /tests/Application/templates/bundles/SyliusShopBundle/_styles.html.twig: -------------------------------------------------------------------------------- 1 | {{ encore_entry_link_tags('shop-entry', null, 'shop') }} 2 | {{ encore_entry_link_tags('bitbag-productBundle-shop', null, 'product_bundle_shop') }} 3 | -------------------------------------------------------------------------------- /tests/Application/translations/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitBagCommerce/SyliusProductBundlePlugin/2a3819010ccaee087746f8c113fc58d27327628f/tests/Application/translations/.gitignore -------------------------------------------------------------------------------- /tests/Application/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const Encore = require('@symfony/webpack-encore'); 3 | 4 | const [bitbagProductBundleShop, bitbagProductBundleAdmin] = require('../../webpack.config.js'); 5 | 6 | const syliusBundles = path.resolve(__dirname, '../../vendor/sylius/sylius/src/Sylius/Bundle/'); 7 | const uiBundleScripts = path.resolve(syliusBundles, 'UiBundle/Resources/private/js/'); 8 | const uiBundleResources = path.resolve(syliusBundles, 'UiBundle/Resources/private/'); 9 | 10 | // Shop config 11 | Encore.setOutputPath('public/build/shop/') 12 | .setPublicPath('/build/shop') 13 | .addEntry('shop-entry', './assets/shop/entry.js') 14 | .enableStimulusBridge('./assets/controllers.json') 15 | .disableSingleRuntimeChunk() 16 | .cleanupOutputBeforeBuild() 17 | .enableSourceMaps(!Encore.isProduction()) 18 | .enableVersioning(Encore.isProduction()) 19 | .enableSassLoader(); 20 | 21 | const shopConfig = Encore.getWebpackConfig(); 22 | 23 | shopConfig.resolve.alias['sylius/ui'] = uiBundleScripts; 24 | shopConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources; 25 | shopConfig.resolve.alias['sylius/bundle'] = syliusBundles; 26 | shopConfig.name = 'shop'; 27 | 28 | Encore.reset(); 29 | 30 | // Admin config 31 | Encore.setOutputPath('public/build/admin/') 32 | .setPublicPath('/build/admin') 33 | .addEntry('admin-entry', './assets/admin/entry.js') 34 | .addEntry('admin-product-entry', './assets/admin/product-entry.js') 35 | .enableStimulusBridge('./assets/controllers.json') 36 | .disableSingleRuntimeChunk() 37 | .cleanupOutputBeforeBuild() 38 | .enableSourceMaps(!Encore.isProduction()) 39 | .enableVersioning(Encore.isProduction()) 40 | .enableSassLoader(); 41 | 42 | const adminConfig = Encore.getWebpackConfig(); 43 | 44 | adminConfig.resolve.alias['sylius/ui'] = uiBundleScripts; 45 | adminConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources; 46 | adminConfig.resolve.alias['sylius/bundle'] = syliusBundles; 47 | adminConfig.externals = Object.assign({}, adminConfig.externals, { window: 'window', document: 'document' }); 48 | adminConfig.name = 'admin'; 49 | 50 | module.exports = [shopConfig, adminConfig, bitbagProductBundleShop, bitbagProductBundleAdmin]; 51 | -------------------------------------------------------------------------------- /tests/Behat/Page/Admin/CreateBundledProductPageInterface.php: -------------------------------------------------------------------------------- 1 | createNew($productBundleItem); 27 | 28 | self::assertInstanceOf(AddProductBundleItemToCartCommand::class, $command); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/Unit/Factory/AddProductBundleToCartCommandFactoryTest.php: -------------------------------------------------------------------------------- 1 | createNew(self::ORDER_ID, self::PRODUCT_CODE, self::QUANTITY); 31 | 32 | self::assertInstanceOf(AddProductBundleToCartCommand::class, $command); 33 | self::assertEquals(self::ORDER_ID, $command->getOrderId()); 34 | self::assertEquals(self::PRODUCT_CODE, $command->getProductCode()); 35 | self::assertEquals(self::QUANTITY, $command->getQuantity()); 36 | } 37 | 38 | public function testCreateAddProductBundleToCartCommandObjectFromDto(): void 39 | { 40 | $dto = AddProductBundleToCartDtoMother::createWithOrderIdAndProductCode(self::ORDER_ID, self::PRODUCT_CODE); 41 | 42 | $factory = new AddProductBundleToCartCommandFactory(); 43 | $command = $factory->createFromDto($dto); 44 | 45 | self::assertInstanceOf(AddProductBundleToCartCommand::class, $command); 46 | self::assertEquals(self::ORDER_ID, $command->getOrderId()); 47 | self::assertEquals(self::PRODUCT_CODE, $command->getProductCode()); 48 | self::assertEquals(0, $command->getQuantity()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/Unit/Factory/OrderItemFactoryTest.php: -------------------------------------------------------------------------------- 1 | createMock(CartItemFactoryInterface::class); 28 | $baseFactory->expects(self::once()) 29 | ->method('createNew') 30 | ->willReturn($orderItem) 31 | ; 32 | 33 | $factory = new OrderItemFactory($baseFactory); 34 | $orderItemWithVariant = $factory->createWithVariant($productVariant); 35 | 36 | self::assertSame($productVariant, $orderItemWithVariant->getVariant()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/Unit/MotherObject/AddProductBundleItemToCartCommandMother.php: -------------------------------------------------------------------------------- 1 | setName($name); 29 | 30 | return $channel; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/Unit/MotherObject/OrderItemMother.php: -------------------------------------------------------------------------------- 1 | id = $id; 32 | }; 33 | ($setIdClosure->bindTo($order, $order))($id); 34 | 35 | return $order; 36 | } 37 | 38 | public static function createWithChannel(ChannelInterface $channel): OrderInterface 39 | { 40 | $order = self::create(); 41 | 42 | $order->setChannel($channel); 43 | 44 | return $order; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/Unit/MotherObject/ProductBundleItemMother.php: -------------------------------------------------------------------------------- 1 | addProductBundleItem($bundleItem); 34 | } 35 | 36 | return $productBundle; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/Unit/MotherObject/ProductVariantMother.php: -------------------------------------------------------------------------------- 1 | setCode($code); 29 | 30 | return $productVariant; 31 | } 32 | 33 | public static function createDisabledWithCode(string $code): ProductVariantInterface 34 | { 35 | $productVariant = self::createWithCode($code); 36 | 37 | $productVariant->disable(); 38 | 39 | return $productVariant; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Unit/TypeExceptionMessage.php: -------------------------------------------------------------------------------- 1 | { 6 | Encore.reset(); 7 | 8 | Encore 9 | .setOutputPath(`public/build/bitbag/${pluginName}/${type}/`) 10 | .setPublicPath(`/build/bitbag/${pluginName}/${type}/`) 11 | .addEntry(`bitbag-${pluginName}-${type}`, path.resolve(__dirname, `./assets/${type}/entry.js`)) 12 | .disableSingleRuntimeChunk() 13 | .cleanupOutputBeforeBuild() 14 | .enableSourceMaps(!Encore.isProduction()) 15 | .enableSassLoader(); 16 | 17 | const config = Encore.getWebpackConfig(); 18 | config.name = `bitbag-${pluginName}-${type}`; 19 | 20 | return config; 21 | } 22 | 23 | Encore 24 | .setOutputPath(`src/Resources/public/`) 25 | .setPublicPath(`/public/`) 26 | .addEntry(`bitbag-${pluginName}-shop`, path.resolve(__dirname, `./assets/shop/entry.js`)) 27 | .addEntry(`bitbag-${pluginName}-admin`, path.resolve(__dirname, `./assets/admin/entry.js`)) 28 | .cleanupOutputBeforeBuild() 29 | .disableSingleRuntimeChunk() 30 | .enableSassLoader(); 31 | 32 | const distConfig = Encore.getWebpackConfig(); 33 | distConfig.name = `bitbag-plugin-dist`; 34 | 35 | Encore.reset(); 36 | 37 | const shopConfig = getConfig(pluginName, 'shop') 38 | const adminConfig = getConfig(pluginName, 'admin') 39 | 40 | module.exports = [shopConfig, adminConfig, distConfig]; 41 | --------------------------------------------------------------------------------