├── .docker
├── nginx
│ └── nginx.conf
└── php
│ └── php.ini
├── .editorconfig
├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── Makefile
├── README.md
├── behat.yml.dist
├── bin
└── create_node_symlink.php
├── composer.json
├── docker-compose.yml
├── e2e-test-server.sh
├── easy-coding-standard.yml
├── ecs.php
├── etc
└── build
│ └── .gitignore
├── features
├── managing_shipping_methods_with_table_rate.feature
├── managing_table_rates.feature
└── seeing_correct_shipping_fees_for_table_rate_based_method.feature
├── node_modules
├── phpspec.yml.dist
├── phpstan.neon
├── phpunit.xml.dist
├── psalm-baseline.xml
├── psalm.xml
├── roave-bc-check.yaml
├── spec
├── Calculator
│ └── TableRateShippingCalculatorSpec.php
├── Checker
│ └── TableRateShippingMethodEligibilityCheckerSpec.php
├── Entity
│ └── ShippingTableRateSpec.php
├── EventSubscriber
│ └── TableRateDeleteSubscriberSpec.php
├── Form
│ └── EventSubscriber
│ │ └── AddCurrencySubscriberSpec.php
└── Resolver
│ └── TableRateResolverSpec.php
├── src
├── Calculator
│ └── TableRateShippingCalculator.php
├── Checker
│ └── TableRateShippingMethodEligibilityChecker.php
├── DependencyInjection
│ ├── Configuration.php
│ └── WebgriffeSyliusTableRateShippingExtension.php
├── Entity
│ └── ShippingTableRate.php
├── EventSubscriber
│ └── TableRateDeleteSubscriber.php
├── Exception
│ └── RateNotFoundException.php
├── Form
│ ├── EventSubscriber
│ │ └── AddCurrencySubscriber.php
│ └── Type
│ │ ├── Shipping
│ │ └── Calculator
│ │ │ ├── ChannelBasedTableRateConfigurationType.php
│ │ │ └── TableRateConfigurationType.php
│ │ ├── ShippingTableRateType.php
│ │ └── WeightLimitToRateType.php
├── Menu
│ └── AdminMenuListener.php
├── Resolver
│ ├── TableRateResolver.php
│ └── TableRateResolverInterface.php
├── Resources
│ ├── config
│ │ ├── admin_routing.yml
│ │ ├── config.yml
│ │ ├── doctrine
│ │ │ └── ShippingTableRate.orm.yml
│ │ ├── services.yml
│ │ └── shop_routing.yml
│ ├── translations
│ │ ├── flashes.en.yml
│ │ ├── flashes.fr.yml
│ │ ├── messages.en.yml
│ │ ├── messages.fr.yml
│ │ ├── validators.en.yml
│ │ └── validators.fr.yml
│ └── views
│ │ └── TableRateCrud
│ │ ├── _form.html.twig
│ │ ├── _weightLimitToRateTheme.html.twig
│ │ ├── create.html.twig
│ │ ├── index.html.twig
│ │ └── update.html.twig
└── WebgriffeSyliusTableRateShippingPlugin.php
├── symfony.lock
└── tests
├── Application
├── .env
├── .env.test
├── .eslintrc.js
├── .gitignore
├── Kernel.php
├── assets
│ ├── admin
│ │ └── entry.js
│ └── shop
│ │ └── entry.js
├── bin
│ └── console
├── composer.json
├── config
│ ├── api_platform
│ │ └── .gitignore
│ ├── bootstrap.php
│ ├── bundles.php
│ ├── jwt
│ │ ├── private.pem
│ │ └── public.pem
│ ├── packages
│ │ ├── _sylius.yaml
│ │ ├── api_platform.yaml
│ │ ├── assets.yaml
│ │ ├── dev
│ │ │ ├── framework.yaml
│ │ │ ├── jms_serializer.yaml
│ │ │ ├── monolog.yaml
│ │ │ ├── routing.yaml
│ │ │ └── web_profiler.yaml
│ │ ├── doctrine.yaml
│ │ ├── doctrine_migrations.yaml
│ │ ├── fos_rest.yaml
│ │ ├── framework.yaml
│ │ ├── jms_serializer.yaml
│ │ ├── lexik_jwt_authentication.yaml
│ │ ├── liip_imagine.yaml
│ │ ├── mailer.yaml
│ │ ├── prod
│ │ │ ├── doctrine.yaml
│ │ │ ├── jms_serializer.yaml
│ │ │ └── monolog.yaml
│ │ ├── routing.yaml
│ │ ├── security.yaml
│ │ ├── staging
│ │ │ └── monolog.yaml
│ │ ├── stof_doctrine_extensions.yaml
│ │ ├── test
│ │ │ ├── framework.yaml
│ │ │ ├── mailer.yaml
│ │ │ ├── monolog.yaml
│ │ │ ├── security.yaml
│ │ │ ├── sylius_theme.yaml
│ │ │ ├── sylius_uploader.yaml
│ │ │ └── web_profiler.yaml
│ │ ├── test_cached
│ │ │ ├── doctrine.yaml
│ │ │ ├── fos_rest.yaml
│ │ │ ├── framework.yaml
│ │ │ ├── mailer.yaml
│ │ │ ├── monolog.yaml
│ │ │ ├── security.yaml
│ │ │ ├── sylius_channel.yaml
│ │ │ ├── sylius_theme.yaml
│ │ │ ├── sylius_uploader.yaml
│ │ │ └── twig.yaml
│ │ ├── translation.yaml
│ │ ├── twig.yaml
│ │ ├── validator.yaml
│ │ ├── webgriffe_sylius_table_rate_shipping_plugin.yaml
│ │ └── webpack_encore.yaml
│ ├── routes
│ │ ├── dev
│ │ │ └── web_profiler.yaml
│ │ ├── liip_imagine.yaml
│ │ ├── sylius_admin.yaml
│ │ ├── sylius_api.yaml
│ │ ├── sylius_shop.yaml
│ │ ├── test
│ │ │ ├── routing.yaml
│ │ │ └── sylius_test_plugin.yaml
│ │ ├── test_cached
│ │ │ ├── routing.yaml
│ │ │ └── sylius_test_plugin.yaml
│ │ └── webgriffe_sylius_table_rate_shipping_plugin.yaml
│ ├── secrets
│ │ ├── dev
│ │ │ └── .gitignore
│ │ ├── prod
│ │ │ └── .gitignore
│ │ ├── test
│ │ │ └── .gitignore
│ │ └── test_cached
│ │ │ └── .gitignore
│ ├── serialization
│ │ └── .gitignore
│ ├── services.yaml
│ ├── services_test.yaml
│ └── services_test_cached.yaml
├── package.json
├── public
│ ├── .htaccess
│ ├── favicon.ico
│ ├── index.php
│ └── robots.txt
├── src
│ └── Entity
│ │ └── .gitignore
├── templates
│ ├── .gitignore
│ └── bundles
│ │ ├── SyliusAdminBundle
│ │ ├── Layout
│ │ │ └── _logo.html.twig
│ │ ├── Security
│ │ │ └── _content.html.twig
│ │ ├── _scripts.html.twig
│ │ └── _styles.html.twig
│ │ └── SyliusShopBundle
│ │ ├── Homepage
│ │ └── _banner.html.twig
│ │ ├── Layout
│ │ └── Header
│ │ │ └── _logo.html.twig
│ │ ├── _scripts.html.twig
│ │ └── _styles.html.twig
├── translations
│ └── .gitignore
└── webpack.config.js
└── Behat
├── Context
├── Setup
│ ├── ProductContext.php
│ └── ShippingTableRateContext.php
├── Transform
│ └── NumberContext.php
└── Ui
│ ├── ManagingShippingMethodsWithTableRateContext.php
│ ├── ManagingTableRatesContext.php
│ └── ShippingTableRateContext.php
├── Page
├── ShippingMethod
│ ├── UpdatePage.php
│ └── UpdatePageInterface.php
└── TableRate
│ ├── CreatePage.php
│ ├── CreatePageInterface.php
│ ├── IndexPage.php
│ ├── IndexPageInterface.php
│ ├── UpdatePage.php
│ └── UpdatePageInterface.php
└── Resources
├── services.yml
└── suites.yml
/.docker/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 | user www-data;
2 | worker_processes auto;
3 | daemon off;
4 | pid /run/nginx.pid;
5 |
6 | include /etc/nginx/modules-enabled/*.conf;
7 |
8 | events {
9 | worker_connections 1024;
10 | }
11 |
12 | http {
13 | include /etc/nginx/mime.types;
14 | default_type application/octet-stream;
15 |
16 | server_tokens off;
17 |
18 | client_max_body_size 64m;
19 | sendfile on;
20 | tcp_nodelay on;
21 | tcp_nopush on;
22 |
23 | gzip_vary on;
24 |
25 | access_log /var/log/nginx/access.log;
26 | error_log /var/log/nginx/error.log;
27 |
28 | server {
29 | listen 80;
30 |
31 | root /app/tests/Application/public;
32 | index index.php;
33 |
34 | location / {
35 | try_files $uri /index.php$is_args$args;
36 | }
37 |
38 | location ~ \.php$ {
39 | include fastcgi_params;
40 |
41 | fastcgi_pass unix:/var/run/php8-fpm.sock;
42 | fastcgi_split_path_info ^(.+\.php)(/.*)$;
43 |
44 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
45 | fastcgi_param DOCUMENT_ROOT $realpath_root;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/.docker/php/php.ini:
--------------------------------------------------------------------------------
1 | [PHP]
2 | memory_limit=512M
3 |
4 | [date]
5 | date.timezone=${PHP_DATE_TIMEZONE}
6 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 | # Change these settings to your own preference
9 | indent_style = space
10 | indent_size = 4
11 |
12 | # We recommend you to keep these unchanged
13 | end_of_line = lf
14 | charset = utf-8
15 | trim_trailing_whitespace = true
16 | insert_final_newline = true
17 |
18 | [*.feature]
19 | indent_style = space
20 | indent_size = 4
21 |
22 | [*.js]
23 | indent_style = space
24 | indent_size = 2
25 |
26 | [*.json]
27 | indent_style = space
28 | indent_size = 2
29 |
30 | [*.md]
31 | indent_style = space
32 | indent_size = 4
33 | trim_trailing_whitespace = false
34 |
35 | [*.neon]
36 | indent_style = space
37 | indent_size = 4
38 |
39 | [*.php]
40 | indent_style = space
41 | indent_size = 4
42 |
43 | [*.sh]
44 | indent_style = space
45 | indent_size = 4
46 |
47 | [*.{yaml,yml}]
48 | indent_style = space
49 | indent_size = 4
50 | trim_trailing_whitespace = false
51 |
52 | [.babelrc]
53 | indent_style = space
54 | indent_size = 2
55 |
56 | [.gitmodules]
57 | indent_style = tab
58 | indent_size = 4
59 |
60 | [.php_cs{,.dist}]
61 | indent_style = space
62 | indent_size = 4
63 |
64 | [composer.json]
65 | indent_style = space
66 | indent_size = 4
67 |
68 | [package.json]
69 | indent_style = space
70 | indent_size = 2
71 |
72 | [phpspec.yml{,.dist}]
73 | indent_style = space
74 | indent_size = 4
75 |
76 | [phpstan.neon]
77 | indent_style = space
78 | indent_size = 4
79 |
80 | [phpunit.xml{,.dist}]
81 | indent_style = space
82 | indent_size = 4
83 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches-ignore:
6 | - 'dependabot/**'
7 | pull_request: ~
8 | release:
9 | types: [created]
10 | schedule:
11 | -
12 | cron: "0 1 * * 6" # Run at 1am every Saturday
13 | workflow_dispatch: ~
14 |
15 | jobs:
16 | tests:
17 | runs-on: ubuntu-latest
18 |
19 | name: "Sylius ${{ matrix.sylius }}, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MySQL ${{ matrix.mysql }}"
20 |
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | php: [ "8.1", "8.2", "8.3" ]
25 | symfony: [ "5.4.*", "^6.4" ]
26 | sylius: ["1.13.3"]
27 | node: ["18.x"]
28 | mysql: ["8.0"]
29 |
30 | env:
31 | APP_ENV: test
32 | DATABASE_URL: "mysql://root:root@127.0.0.1/sylius?serverVersion=${{ matrix.mysql }}"
33 |
34 | steps:
35 | -
36 | uses: actions/checkout@v2
37 |
38 | -
39 | name: Setup PHP
40 | uses: shivammathur/setup-php@v2
41 | with:
42 | php-version: "${{ matrix.php }}"
43 | extensions: intl
44 | tools: flex,symfony
45 | coverage: none
46 |
47 | -
48 | name: Setup Node
49 | uses: actions/setup-node@v4
50 | with:
51 | node-version: "${{ matrix.node }}"
52 |
53 | -
54 | name: Shutdown default MySQL
55 | run: sudo service mysql stop
56 |
57 | -
58 | name: Setup MySQL
59 | uses: mirromutth/mysql-action@v1.1
60 | with:
61 | mysql version: "${{ matrix.mysql }}"
62 | mysql root password: "root"
63 |
64 | -
65 | name: Output PHP version for Symfony CLI
66 | run: php -v | head -n 1 | awk '{ print $2 }' > .php-version
67 |
68 | -
69 | name: Install certificates
70 | run: symfony server:ca:install
71 |
72 | -
73 | name: Run Chrome Headless
74 | run: google-chrome-stable --enable-automation --disable-background-networking --no-default-browser-check --no-first-run --disable-popup-blocking --disable-default-apps --allow-insecure-localhost --disable-translate --disable-extensions --no-sandbox --enable-features=Metal --headless --remote-debugging-port=9222 --window-size=2880,1800 --proxy-server='direct://' --proxy-bypass-list='*' http://127.0.0.1 > /dev/null 2>&1 &
75 |
76 | -
77 | name: Run webserver
78 | run: (cd tests/Application && symfony server:start --port=8080 --dir=public --daemon)
79 |
80 | -
81 | name: Validate composer.json
82 | run: composer validate --ansi --strict
83 |
84 | -
85 | name: Get Composer cache directory
86 | id: composer-cache
87 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
88 |
89 | -
90 | name: Cache Composer
91 | uses: actions/cache@v4
92 | with:
93 | path: ${{ steps.composer-cache.outputs.dir }}
94 | key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json **/composer.lock') }}
95 | restore-keys: |
96 | ${{ runner.os }}-php-${{ matrix.php }}-composer-
97 |
98 | -
99 | name: Configure global composer
100 | run: |
101 | composer global config --no-plugins allow-plugins.symfony/flex true
102 | composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^2.2.2"
103 |
104 | -
105 | name: Restrict Symfony version
106 | if: matrix.symfony != ''
107 | run: |
108 | composer config extra.symfony.require "${{ matrix.symfony }}"
109 |
110 | -
111 | name: Restrict Sylius version
112 | if: matrix.sylius != ''
113 | run: composer require "sylius/sylius:${{ matrix.sylius }}" --no-update --no-scripts --no-interaction
114 |
115 | -
116 | name: Install PHP dependencies
117 | run: composer install --no-interaction
118 | env:
119 | SYMFONY_REQUIRE: ${{ matrix.symfony }}
120 |
121 | -
122 | name: Get Yarn cache directory
123 | id: yarn-cache
124 | run: echo "::set-output name=dir::$(yarn cache dir)"
125 |
126 | -
127 | name: Cache Yarn
128 | uses: actions/cache@v4
129 | with:
130 | path: ${{ steps.yarn-cache.outputs.dir }}
131 | key: ${{ runner.os }}-node-${{ matrix.node }}-yarn-${{ hashFiles('**/package.json **/yarn.lock') }}
132 | restore-keys: |
133 | ${{ runner.os }}-node-${{ matrix.node }}-yarn-
134 |
135 | -
136 | name: Install JS dependencies
137 | run: (cd tests/Application && yarn install)
138 |
139 | -
140 | name: Prepare test application database
141 | run: |
142 | (cd tests/Application && bin/console doctrine:database:create -vvv)
143 | (cd tests/Application && bin/console doctrine:schema:create -vvv)
144 |
145 | -
146 | name: Prepare test application assets
147 | run: |
148 | (cd tests/Application && bin/console assets:install public -vvv)
149 | (cd tests/Application && yarn build:prod)
150 |
151 | -
152 | name: Prepare test application cache
153 | run: (cd tests/Application && bin/console cache:warmup -vvv)
154 |
155 | -
156 | name: Load fixtures in test application
157 | run: (cd tests/Application && bin/console sylius:fixtures:load -n)
158 |
159 | -
160 | name: Validate database schema
161 | run: (cd tests/Application && bin/console doctrine:schema:validate)
162 |
163 | -
164 | name: Run PHPStan
165 | run: vendor/bin/phpstan analyse -c phpstan.neon -l max src/
166 |
167 | -
168 | name: Run Psalm
169 | run: vendor/bin/psalm
170 |
171 | -
172 | name: Run PHPSpec
173 | run: vendor/bin/phpspec run --ansi -f progress --no-interaction
174 |
175 | -
176 | name: Run PHPUnit
177 | run: vendor/bin/phpunit --colors=always
178 |
179 | -
180 | name: Run Behat
181 | run: vendor/bin/behat --colors --strict -vvv --no-interaction || vendor/bin/behat --colors --strict -vvv --no-interaction --rerun
182 |
183 | -
184 | name: Upload Behat logs
185 | uses: actions/upload-artifact@v4
186 | if: failure()
187 | with:
188 | name: Behat logs
189 | path: etc/build/
190 | if-no-files-found: ignore
191 |
192 | roave_bc_check:
193 | name: Roave BC Check
194 | runs-on: ubuntu-latest
195 | env:
196 | PHP_VERSION: 8.2
197 | steps:
198 | - name: Checkout code
199 | uses: actions/checkout@v3
200 | with:
201 | fetch-depth: 0
202 |
203 | - name: Setup PHP
204 | uses: shivammathur/setup-php@v2
205 | with:
206 | php-version: "${{ env.PHP_VERSION }}"
207 | extensions: intl
208 | tools: flex,symfony
209 | coverage: none
210 |
211 | - name: Install roave/backward-compatibility-check.
212 | run: composer require --dev roave/backward-compatibility-check --no-plugins
213 |
214 | - name: Run roave/backward-compatibility-check.
215 | run: vendor/bin/roave-backward-compatibility-check --format=github-actions
216 |
--------------------------------------------------------------------------------
/.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 |
15 | # Symfony CLI https://symfony.com/doc/current/setup/symfony_server.html#different-php-settings-per-project
16 | /.php-version
17 | /php.ini
18 | docker-compose.override.yml
19 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | phpunit:
2 | vendor/bin/phpunit
3 |
4 | phpspec:
5 | vendor/bin/phpspec run --ansi --no-interaction -f dot
6 |
7 | phpstan:
8 | vendor/bin/phpstan analyse
9 |
10 | psalm:
11 | vendor/bin/psalm
12 |
13 | behat-js:
14 | APP_ENV=test vendor/bin/behat --colors --strict --no-interaction -vvv -f progress
15 |
16 | install:
17 | composer install --no-interaction --no-scripts
18 |
19 | backend:
20 | tests/Application/bin/console sylius:install --no-interaction
21 | tests/Application/bin/console sylius:fixtures:load default --no-interaction
22 |
23 | frontend:
24 | (cd tests/Application && yarn install --pure-lockfile)
25 | (cd tests/Application && GULP_ENV=prod yarn build)
26 |
27 | behat:
28 | APP_ENV=test vendor/bin/behat --colors --strict --no-interaction -vvv -f progress
29 |
30 | init: install backend frontend
31 |
32 | ci: init phpstan psalm phpunit phpspec behat
33 |
34 | integration: init phpunit behat
35 |
36 | static: install phpspec phpstan psalm
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Table Rate Shipping Plugin
8 |
9 | 
10 | This plugin allows to define shipping rates using weight tables.
11 | 
12 |
13 | ## Installation
14 |
15 | 1. Run `composer require --no-scripts webgriffe/sylius-table-rate-shipping-plugin`.
16 |
17 | 2. Add the plugin to the `config/bundles.php` file:
18 |
19 | ```php
20 | Webgriffe\SyliusTableRateShippingPlugin\WebgriffeSyliusTableRateShippingPlugin::class => ['all' => true],
21 | ```
22 |
23 | 3. Add the plugin's config to by creating the file `config/packages/webgriffe_sylius_table_rate_shipping_plugin.yaml` with the following content:
24 |
25 | ```yaml
26 | imports:
27 | - { resource: "@WebgriffeSyliusTableRateShippingPlugin/Resources/config/config.yml" }
28 | ```
29 |
30 | 4. Add the plugin's routing by creating the file `config/routes/webgriffe_sylius_table_rate_shipping_plugin.yaml` with the following content:
31 |
32 | ```yaml
33 | webgriffe_sylius_table_rate_shipping_plugin_shop:
34 | resource: "@WebgriffeSyliusTableRateShippingPlugin/Resources/config/shop_routing.yml"
35 | prefix: /{_locale}
36 | requirements:
37 | _locale: ^[A-Za-z]{2,4}(_([A-Za-z]{4}|[0-9]{3}))?(_([A-Za-z]{2}|[0-9]{3}))?$
38 |
39 | webgriffe_sylius_table_rate_shipping_plugin_admin:
40 | resource: "@WebgriffeSyliusTableRateShippingPlugin/Resources/config/admin_routing.yml"
41 | prefix: /%sylius_admin.path_name%
42 |
43 | ```
44 |
45 | 5. Finish the installation by updating the database schema and installing assets:
46 |
47 | ```bash
48 | bin/console cache:clear
49 | bin/console doctrine:migrations:diff
50 | bin/console doctrine:migrations:migrate
51 | bin/console assets:install
52 | bin/console sylius:theme:assets:install
53 | ```
54 |
55 | ## Contributing
56 |
57 | To contribute you need to:
58 |
59 | 1. Clone this repository into you development environment and go to the plugin's root directory,
60 |
61 | 2. Then, from the plugin's root directory, run the following commands:
62 |
63 | ```bash
64 | composer install
65 | ```
66 |
67 | 3. Copy `tests/Application/.env` in `tests/Application/.env.local` and set configuration specific for your development environment.
68 |
69 | 4. Then, from the plugin's root directory, run the following commands:
70 |
71 | ```bash
72 | (cd tests/Application && yarn install)
73 | (cd tests/Application && yarn build)
74 | (cd tests/Application && bin/console assets:install public)
75 | (cd tests/Application && bin/console doctrine:database:create)
76 | (cd tests/Application && bin/console doctrine:schema:create)
77 | (cd tests/Application && bin/console sylius:fixtures:load)
78 | (cd tests/Application && symfony server:start -d) # Requires Symfony CLI (https://symfony.com/download)
79 | ```
80 |
81 | 5. Now at http://localhost:8080/ you have a full Sylius testing application which runs the plugin
82 |
83 | ### Testing
84 |
85 | After your changes you must ensure that the tests are still passing.
86 |
87 | First setup your test database:
88 |
89 | ```bash
90 | (cd tests/Application && bin/console -e test doctrine:database:create)
91 | (cd tests/Application && bin/console -e test doctrine:schema:create)
92 | ```
93 |
94 | This plugin's test application already comes with a test configuration that uses SQLite as test database.
95 | If you don't want this you can create a `tests/Application/.env.test.local` with a different `DATABASE_URL`.
96 |
97 | The current CI suite runs the following tests:
98 |
99 | * Easy Coding Standard
100 |
101 | ```bash
102 | vendor/bin/ecs check src/ tests/Behat/
103 | ```
104 |
105 | * PHPStan
106 |
107 | ```bash
108 | vendor/bin/phpstan analyse -c phpstan.neon -l max src/
109 | ```
110 |
111 | * PHPUnit
112 |
113 | ```bash
114 | vendor/bin/phpunit
115 | ```
116 |
117 | * PHPSpec
118 |
119 | ```bash
120 | vendor/bin/phpspec run
121 | ```
122 |
123 | * Behat (without Javascript)
124 |
125 | ```bash
126 | vendor/bin/behat --tags="~@javascript"
127 | ```
128 |
129 | * Behat (only Javascript)
130 |
131 | ```bash
132 | vendor/bin/behat --tags="@javascript"
133 | ```
134 |
135 | To run them all with a single command run:
136 |
137 | ```bash
138 | composer suite
139 | ```
140 |
141 | To run Behat's Javascript scenarios you need to setup Selenium and Chromedriver. Do the following:
142 |
143 | 1. Start Headless Chrome:
144 |
145 | ```bash
146 | google-chrome-stable --enable-automation --disable-background-networking --no-default-browser-check --no-first-run --disable-popup-blocking --disable-default-apps --allow-insecure-localhost --disable-translate --disable-extensions --no-sandbox --enable-features=Metal --headless --remote-debugging-port=9222 --window-size=2880,1800 --proxy-server='direct://' --proxy-bypass-list='*' http://127.0.0.1
147 | ```
148 |
149 | 2. Install SSL certificates (only once needed) and run test application's webserver on `127.0.0.1:8080`:
150 |
151 | ```bash
152 | symfony server:ca:install
153 | APP_ENV=test symfony server:start --port=8080 --dir=tests/Application/public --daemon
154 | ```
155 |
156 | License
157 | -------
158 | This library is under the MIT license. See the complete license in the LICENSE file.
159 |
160 | Credits
161 | -------
162 | Developed by [Webgriffe®](http://www.webgriffe.com/).
163 |
--------------------------------------------------------------------------------
/behat.yml.dist:
--------------------------------------------------------------------------------
1 | imports:
2 | - vendor/sylius/sylius/src/Sylius/Behat/Resources/config/suites.yml
3 | - tests/Behat/Resources/suites.yml
4 |
5 | default:
6 | formatters:
7 | pretty:
8 | verbose: true
9 | paths: false
10 | snippets: false
11 |
12 | extensions:
13 | DMore\ChromeExtension\Behat\ServiceContainer\ChromeExtension: ~
14 | Robertfausk\Behat\PantherExtension: ~
15 |
16 | FriendsOfBehat\MinkDebugExtension:
17 | directory: etc/build
18 | clean_start: false
19 | screenshot: true
20 |
21 | Behat\MinkExtension:
22 | files_path: "%paths.base%/vendor/sylius/sylius/src/Sylius/Behat/Resources/fixtures/"
23 | base_url: "https://127.0.0.1:8080/"
24 | default_session: symfony
25 | javascript_session: chromedriver
26 | sessions:
27 | symfony:
28 | symfony: ~
29 | chromedriver:
30 | chrome:
31 | api_url: http://127.0.0.1:9222
32 | validate_certificate: false
33 | chrome_headless_second_session:
34 | chrome:
35 | api_url: http://127.0.0.1:9222
36 | validate_certificate: false
37 | panther:
38 | panther:
39 | manager_options:
40 | connection_timeout_in_ms: 5000
41 | request_timeout_in_ms: 120000
42 | chromedriver_arguments:
43 | - --log-path=etc/build/chromedriver.log
44 | - --verbose
45 | capabilities:
46 | acceptSslCerts: true
47 | acceptInsecureCerts: true
48 | unexpectedAlertBehaviour: accept
49 | show_auto: false
50 |
51 | FriendsOfBehat\SymfonyExtension:
52 | bootstrap: tests/Application/config/bootstrap.php
53 | kernel:
54 | class: Tests\Webgriffe\SyliusTableRateShippingPlugin\Application\Kernel
55 |
56 | FriendsOfBehat\VariadicExtension: ~
57 |
58 | FriendsOfBehat\SuiteSettingsExtension:
59 | paths:
60 | - "features"
61 |
62 | SyliusLabs\SuiteTagsExtension: ~
63 |
--------------------------------------------------------------------------------
/bin/create_node_symlink.php:
--------------------------------------------------------------------------------
1 | `' . NODE_MODULES_FOLDER_NAME . '` already exists as a link or folder, keeping existing as may be intentional.' . PHP_EOL;
11 | exit(0);
12 | } else {
13 | echo '> Invalid symlink `' . NODE_MODULES_FOLDER_NAME . '` detected, recreating...' . PHP_EOL;
14 | if (!@unlink(NODE_MODULES_FOLDER_NAME)) {
15 | echo '> Could not delete file `' . NODE_MODULES_FOLDER_NAME . '`.' . PHP_EOL;
16 | exit(1);
17 | }
18 | }
19 | }
20 |
21 | /* try to create the symlink using PHP internals... */
22 | $success = @symlink(PATH_TO_NODE_MODULES, NODE_MODULES_FOLDER_NAME);
23 |
24 | /* if case it has failed, but OS is Windows... */
25 | if (!$success && strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
26 | /* ...then try a different approach which does not require elevated permissions and folder to exist */
27 | echo '> This system is running Windows, creation of links requires elevated privileges,' . PHP_EOL;
28 | echo '> and target path to exist. Fallback to NTFS Junction:' . PHP_EOL;
29 | exec(sprintf('mklink /J %s %s 2> NUL', NODE_MODULES_FOLDER_NAME, PATH_TO_NODE_MODULES), $output, $returnCode);
30 | $success = $returnCode === 0;
31 | if (!$success) {
32 | echo '> Failed o create the required symlink' . PHP_EOL;
33 | exit(2);
34 | }
35 | }
36 |
37 | $path = @readlink(NODE_MODULES_FOLDER_NAME);
38 | /* check if link points to the intended directory */
39 | if ($path && realpath($path) === realpath(PATH_TO_NODE_MODULES)) {
40 | echo '> Successfully created the symlink.' . PHP_EOL;
41 | exit(0);
42 | }
43 |
44 | echo '> Failed to create the symlink to `' . NODE_MODULES_FOLDER_NAME . '`.' . PHP_EOL;
45 | exit(3);
46 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webgriffe/sylius-table-rate-shipping-plugin",
3 | "type": "sylius-plugin",
4 | "description": "Provides table rate shipping calculator.",
5 | "keywords": [
6 | "sylius",
7 | "sylius-plugin"
8 | ],
9 | "license": "MIT",
10 | "require": {
11 | "php": "^8.1",
12 | "sylius/sylius": "^1.13.3",
13 | "symfony/webpack-encore-bundle": "^1.15"
14 | },
15 | "require-dev": {
16 | "behat/behat": "^3.6.1",
17 | "behat/mink-selenium2-driver": "^1.6",
18 | "dbrekelmans/bdi": "^1.1",
19 | "dmore/behat-chrome-extension": "^1.3",
20 | "dmore/chrome-mink-driver": "^2.7",
21 | "friends-of-behat/mink": "^1.8",
22 | "friends-of-behat/mink-browserkit-driver": "^1.4",
23 | "friends-of-behat/mink-debug-extension": "^2.0.0",
24 | "friends-of-behat/mink-extension": "^2.4",
25 | "friends-of-behat/page-object-extension": "^0.3",
26 | "friends-of-behat/suite-settings-extension": "^1.0",
27 | "friends-of-behat/symfony-extension": "^2.1",
28 | "friends-of-behat/variadic-extension": "^1.3",
29 | "phpspec/phpspec": "^7.2",
30 | "phpstan/extension-installer": "^1.0",
31 | "phpstan/phpstan": "^1.8.1",
32 | "phpstan/phpstan-doctrine": "1.3.16",
33 | "phpstan/phpstan-strict-rules": "^1.3.0",
34 | "phpstan/phpstan-webmozart-assert": "^1.2.0",
35 | "phpunit/phpunit": "^9.6 || ^10.5",
36 | "polishsymfonycommunity/symfony-mocker-container": "^1.0",
37 | "robertfausk/behat-panther-extension": "^1.1",
38 | "sylius-labs/coding-standard": "^4.2",
39 | "sylius-labs/suite-tags-extension": "^0.2",
40 | "symfony/browser-kit": "^5.4 || ^6.0",
41 | "symfony/debug-bundle": "^5.4 || ^6.0",
42 | "symfony/dotenv": "^5.4 || ^6.0",
43 | "symfony/flex": "^2.2.2",
44 | "symfony/intl": "^5.4 || ^6.0",
45 | "symfony/web-profiler-bundle": "^5.4 || ^6.0",
46 | "vimeo/psalm": "4.27.0"
47 | },
48 | "config": {
49 | "sort-packages": true,
50 | "allow-plugins": {
51 | "dealerdirect/phpcodesniffer-composer-installer": false,
52 | "phpstan/extension-installer": true,
53 | "symfony/flex": true,
54 | "symfony/thanks": true
55 | }
56 | },
57 | "extra": {
58 | "branch-alias": {
59 | "dev-master": "1.12-dev"
60 | }
61 | },
62 | "autoload": {
63 | "psr-4": {
64 | "Webgriffe\\SyliusTableRateShippingPlugin\\": "src/",
65 | "Tests\\Webgriffe\\SyliusTableRateShippingPlugin\\": "tests/"
66 | }
67 | },
68 | "autoload-dev": {
69 | "classmap": [
70 | "tests/Application/Kernel.php"
71 | ]
72 | },
73 | "scripts": {
74 | "post-install-cmd": [
75 | "php bin/create_node_symlink.php"
76 | ],
77 | "post-update-cmd": [
78 | "php bin/create_node_symlink.php"
79 | ],
80 | "post-create-project-cmd": [
81 | "php bin/create_node_symlink.php"
82 | ],
83 | "ecs": "ecs check src/ tests/Behat/",
84 | "phpstan": "phpstan analyse -c phpstan.neon -l max src/",
85 | "phpunit": "phpunit",
86 | "phpspec": "phpspec run",
87 | "behat": "behat --strict -vvv --no-interaction || behat --strict -vvv --no-interaction --rerun",
88 | "suite": [
89 | "@ecs",
90 | "@phpstan",
91 | "@phpunit",
92 | "@phpspec",
93 | "@behat"
94 | ],
95 | "auto-scripts": {
96 | "cache:clear": "symfony-cmd",
97 | "assets:install %PUBLIC_DIR%": "symfony-cmd",
98 | "security-checker security:check": "script"
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | app:
3 | image: sylius/standard:1.11-traditional-alpine
4 | environment:
5 | APP_ENV: "dev"
6 | DATABASE_URL: "mysql://root:mysql@mysql/sylius_%kernel.environment%?charset=utf8mb4"
7 | # DATABASE_URL: "pgsql://root:postgres@postgres/sylius_%kernel.environment%?charset=utf8" # When using postgres
8 | PHP_DATE_TIMEZONE: "Europe/Warsaw"
9 | volumes:
10 | - ./:/app:delegated
11 | - ./.docker/php/php.ini:/etc/php8/php.ini:delegated
12 | - ./.docker/nginx/nginx.conf:/etc/nginx/nginx.conf:delegated
13 | ports:
14 | - 80:80
15 | depends_on:
16 | - mysql
17 | networks:
18 | - sylius
19 |
20 | mysql:
21 | image: mysql:8.0
22 | platform: linux/amd64
23 | environment:
24 | MYSQL_ROOT_PASSWORD: mysql
25 | ports:
26 | - ${MYSQL_PORT:-3306}:3306
27 | networks:
28 | - sylius
29 |
30 | # postgres:
31 | # image: postgres:14-alpine
32 | # environment:
33 | # POSTGRES_USER: root
34 | # POSTGRES_PASSWORD: postgres
35 | # ports:
36 | # - ${POSTGRES_PORT:-5432}:5432
37 | # networks:
38 | # - sylius
39 |
40 | networks:
41 | sylius:
42 | driver: bridge
43 |
--------------------------------------------------------------------------------
/e2e-test-server.sh:
--------------------------------------------------------------------------------
1 | # Make sure to set GOOGLE_CHROME env variable pointing to your Google Chrome binary. For example on macOS:
2 | # GOOGLE_CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ./e2e-test-server.sh
3 |
4 | trap 'kill %1; kill %2' SIGINT
5 | cd tests/Application && APP_ENV=test symfony server:start --port=8080 --dir=public & "${GOOGLE_CHROME}" --enable-automation --disable-background-networking --no-default-browser-check --no-first-run --disable-popup-blocking --disable-default-apps --allow-insecure-localhost --disable-translate --disable-extensions --no-sandbox --enable-features=Metal --headless --remote-debugging-port=9222 --disable-gpu --window-size=2880,1800 --proxy-server='direct://' --proxy-bypass-list='*' --crash-dumps-dir=/tmp https://127.0.0.1 & tee
6 |
--------------------------------------------------------------------------------
/easy-coding-standard.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: 'vendor/sylius-labs/coding-standard/easy-coding-standard.yml' }
3 |
--------------------------------------------------------------------------------
/ecs.php:
--------------------------------------------------------------------------------
1 | paths([
10 | __DIR__ . '/src',
11 | __DIR__ . '/tests/Behat',
12 | __DIR__ . '/ecs.php',
13 | ]);
14 |
15 | $ecsConfig->import('vendor/sylius-labs/coding-standard/ecs.php');
16 |
17 | $ecsConfig->skip([
18 | VisibilityRequiredFixer::class => ['*Spec.php'],
19 | ]);
20 | };
21 |
--------------------------------------------------------------------------------
/etc/build/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/etc/build/.gitignore
--------------------------------------------------------------------------------
/features/managing_shipping_methods_with_table_rate.feature:
--------------------------------------------------------------------------------
1 | @managing_shipping_methods_with_table_rate
2 | Feature: Managing shipping methods with table rates
3 | In order to be able to effectively use already defined table rates
4 | As an Administrator
5 | I want to be able to assign table rates to shipping methods
6 |
7 | @ui @javascript
8 | Scenario: Assigning a table rate to a shipping method
9 | Given I am logged in as an administrator
10 | And the store operates on a single channel in "United States"
11 | And the store also operates on another channel named "Europe" in "EUR" currency
12 | And the store has a shipping table rate "United States Rates" for currency "USD"
13 | And the store has a shipping table rate "Europe Rates" for currency "EUR"
14 | When I want to create a new shipping method
15 | And I choose "Table rate" calculator
16 | Then I should be able to choose only the table rate "United States Rates" for the "United States" channel
17 | And I should be able to choose only the table rate "Europe Rates" for the "Europe" channel
18 |
--------------------------------------------------------------------------------
/features/managing_table_rates.feature:
--------------------------------------------------------------------------------
1 | @managing_table_rates
2 | Feature: Managing table rates
3 | In order to define shipping table rates
4 | As an Administrator
5 | I want to browse, create, update and delete table rates
6 |
7 | Background:
8 | Given I am logged in as an administrator
9 | And the store operates on a single channel in "United States"
10 |
11 | @ui
12 | Scenario: Browsing an empty list of table rates
13 | When I am browsing the list of table rates
14 | Then I should see zero table rates in the list
15 |
16 | @ui
17 | Scenario: Browsing the list of table rates
18 | Given the store has a shipping table rate "East Coast Rates" for currency "USD"
19 | And the store has also a shipping table rate "West Coast Rates" for currency "USD"
20 | When I am browsing the list of table rates
21 | Then I should see 2 table rates in the list
22 | And I should see the "East Coast Rates" table rate in the list
23 | And I should see the "West Coast Rates" table rate in the list
24 |
25 | @ui @javascript
26 | Scenario: Adding a new table rate
27 | When I add a shipping table rate named "New Rates" for currency "USD"
28 | And I am browsing the list of table rates
29 | Then I should see 1 table rate in the list
30 | And I should see the "New Rates" table rate in the list
31 |
32 | @ui
33 | Scenario: Deleting a table rate
34 | Given the store has a shipping table rate "East Coast Rates" for currency "USD"
35 | When I am browsing the list of table rates
36 | Then I should see 1 table rate in the list
37 | When I delete the "East Coast Rates" table rate
38 | And I am browsing the list of table rates
39 | Then I should see zero table rates in the list
40 |
41 | @ui
42 | Scenario: Updating a table rate
43 | Given the store has a shipping table rate "East Coast Rates" for currency "USD"
44 | And this shipping table rate has a rate "$5.00" for shipments up to 1000 kg
45 | And I want to modify the "East Coast Rates" table rate
46 | When I change its name to "Edited Rates"
47 | And I save my changes
48 | Then I should be notified that it has been successfully edited
49 | And this shipping table rate name should be "Edited Rates"
50 |
51 | @ui @javascript
52 | Scenario: Adding weight rates into a table rate
53 | Given the store has a shipping table rate "East Coast Rates" for currency "USD"
54 | And I want to modify the "East Coast Rates" table rate
55 | When I add a new rate of "$5.00" for shipments up to 5 kg
56 | And I add a new rate of "$10.00" for shipments up to 20 kg
57 | And I save my changes
58 | Then I should be notified that it has been successfully edited
59 | And this shipping table rate should have 2 rates
60 |
61 | @ui @javascript
62 | Scenario: Validating a table rate
63 | When I try to add a new shipping table
64 | And I specify its code as "VALIDATE_ME"
65 | And I specify its currency as "USD"
66 | And I add a new rate of "$10.00" for shipments up to 20 kg
67 | But I do not specify its name
68 | And I try to add it
69 | Then I should be notified that name is required
70 | When I try to add a new shipping table
71 | And I specify its name as "Validate Me"
72 | And I specify its currency as "USD"
73 | And I add a new rate of "$10.00" for shipments up to 20 kg
74 | But I do not specify its code
75 | And I try to add it
76 | Then I should be notified that code is required
77 | When I try to add a new shipping table
78 | And I specify its code as "VALIDATE_ME"
79 | And I specify its name as "Validate Me"
80 | And I add a new rate of "$10.00" for shipments up to 20 kg
81 | But I do not specify its currency
82 | And I try to add it
83 | Then I should be notified that currency is required
84 | When I try to add a new shipping table
85 | And I specify its code as "VALIDATE_ME"
86 | And I specify its name as "Validate Me"
87 | And I specify its currency as "USD"
88 | But I do not specify any rate
89 | And I try to add it
90 | Then I should be notified that at least one rate is required
91 |
92 | @ui
93 | Scenario: Trying to change table rate code (even if its field is disabled)
94 | Given the store has a shipping table rate "East Coast Rates" for currency "USD"
95 | And this shipping table rate has a rate "$5.00" for shipments up to 1000 kg
96 | And I want to modify the "East Coast Rates" table rate
97 | Then the code field should be disabled
98 | When I change its code to "ANOTHER_CODE"
99 | And I save my changes
100 | Then the "East Coast Rates" table rate should still have code "EAST_COAST_RATES"
101 |
102 | @ui
103 | Scenario: Trying to change table rate currency (even if its field is disabled)
104 | Given the store also operates on another channel named "Europe" in "EUR" currency
105 | And the store has a shipping table rate "East Coast Rates" for currency "USD"
106 | And this shipping table rate has a rate "$5.00" for shipments up to 1000 kg
107 | And I want to modify the "East Coast Rates" table rate
108 | Then the currency field should be disabled
109 | When I change its currency to "EUR"
110 | And I save my changes
111 | Then the "East Coast Rates" table rate should still have "USD" currency
112 |
113 | @ui @javascript
114 | Scenario: Creating two table rates with the same code
115 | Given the store has a shipping table rate "East Coast Rates" for currency "USD"
116 | When I add a shipping table rate named "East Coast Rates" for currency "USD"
117 | Then I should be notified that code has to be unique
118 |
119 | @ui
120 | Scenario: Deleting a table rate which is already in use
121 | Given the store has a shipping table rate "East Coast Rates" for currency "USD"
122 | And the store has "East Coast Shipping" shipping method using "East Coast Rates" table rate for "United States" channel
123 | When I am browsing the list of table rates
124 | Then I should see 1 table rate in the list
125 | When I delete the "East Coast Rates" table rate
126 | Then I should be notified that the table rate couldn't be deleted because is already used by the "East Coast Shipping" shipping method
127 | And the "East Coast Rates" shipping table rate should still be there
128 |
--------------------------------------------------------------------------------
/features/seeing_correct_shipping_fees_for_table_rate_based_method.feature:
--------------------------------------------------------------------------------
1 | @table_rate_shipping_fee
2 | Feature: Seeing correct shipping fees for table rate based shipping methods
3 | In order to get a proper margin on shipping cost
4 | As a Store Owner
5 | I want to charge different fees for different shipment weights
6 |
7 | Background:
8 | Given the store operates on a single channel in "United States"
9 | And the store has a product "Bottle of water" which weights 1 kg
10 | And the store has a shipping table rate "Weight-based" for currency "USD"
11 | And it has a rate "$5.00" for shipments up to 5 kg
12 | And it has a rate "$10.00" for shipments up to 20 kg
13 | And the store has "Basic" shipping method using "Weight-based" table rate for "United States" channel
14 | And I am a logged in customer
15 |
16 | @ui
17 | Scenario: Seeing correct shipping fee for the light shipment
18 | When I add product "Bottle of water" to the cart
19 | Then my cart shipping total should be "$5.00"
20 |
21 | @ui
22 | Scenario: Seeing correct shipping fee for the exact upper limit of the lighter shipment
23 | When I add 5 products "Bottle of water" to the cart
24 | Then my cart shipping total should be "$5.00"
25 |
26 | @ui
27 | Scenario: Seeing correct shipping fee for the heavier shipment
28 | When I add 15 products "Bottle of water" to the cart
29 | Then my cart shipping total should be "$10.00"
30 |
31 | @ui
32 | Scenario: Seeing no shipping methods for too heavy shipment
33 | When I add 25 products "Bottle of water" to the cart
34 | Then I should not see shipping total for my cart
35 | And I should have no shipping methods available to choose from
36 |
37 | @ui
38 | Scenario: Seeing no shipping methods for too heavy shipment when increasing product quantity from the shopping cart
39 | When I add product "Bottle of water" to the cart
40 | Then my cart shipping total should be "$5.00"
41 | When I change "Bottle of water" quantity to "25"
42 | Then my cart shipping total should be "$0.00"
43 | And I should have no shipping methods available to choose from
44 |
--------------------------------------------------------------------------------
/node_modules:
--------------------------------------------------------------------------------
1 | tests/Application/node_modules
--------------------------------------------------------------------------------
/phpspec.yml.dist:
--------------------------------------------------------------------------------
1 | suites:
2 | main:
3 | namespace: Webgriffe\SyliusTableRateShippingPlugin
4 | psr4_prefix: Webgriffe\SyliusTableRateShippingPlugin
5 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: max
3 | reportUnmatchedIgnoredErrors: false
4 | paths:
5 | - src
6 | - tests/Behat
7 |
8 | excludePaths:
9 | # Makes PHPStan crash
10 | - 'src/DependencyInjection/Configuration.php'
11 |
12 | # Test dependencies
13 | - 'tests/Application/app/**.php'
14 | - 'tests/Application/src/**.php'
15 |
16 | ignoreErrors:
17 | -
18 | identifier: missingType.generics
19 | -
20 | identifier: missingType.iterableValue
21 | - '/Parameter #1 \$configuration of method Symfony\\Component\\DependencyInjection\\Extension\\Extension::processConfiguration\(\) expects Symfony\\Component\\Config\\Definition\\ConfigurationInterface, Symfony\\Component\\Config\\Definition\\ConfigurationInterface\|null given\./'
22 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 | tests
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/psalm-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $shipment
6 |
7 |
8 |
9 |
10 | ShippingMethodEligibilityCheckerInterface
11 | ShippingMethodEligibilityCheckerInterface
12 |
13 |
14 | TableRateShippingMethodEligibilityChecker
15 |
16 |
17 | $method
18 | $subject
19 |
20 |
21 |
22 |
23 | $config
24 |
25 |
26 | $this->getConfiguration([], $container)
27 |
28 |
29 |
30 |
31 |
32 | $array['rate']
33 | $array['weightLimit']
34 |
35 |
36 | $array
37 |
38 |
39 | int
40 |
41 |
42 | $array['rate']
43 |
44 |
45 |
46 |
47 | $channelConfiguration['table_rate']
48 |
49 |
50 | $channelConfiguration
51 |
52 |
53 |
54 |
55 | $shippingTableRate->getCode()
56 |
57 |
58 |
59 |
60 | $resource
61 |
62 |
63 | $resource
64 |
65 |
66 |
67 |
68 | $currency
69 |
70 |
71 |
72 |
73 | $calculatorConfig[$channelCode][TableRateConfigurationType::TABLE_RATE_FIELD_NAME]
74 |
75 |
76 | $channel->getName()
77 | $channel->getName()
78 | $shippingMethod->getName()
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/psalm.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/roave-bc-check.yaml:
--------------------------------------------------------------------------------
1 | parameters:
2 | ignoreErrors:
3 | - '#\[BC\] SKIPPED: Roave\\BetterReflection\\Reflection\\ReflectionClass ".*?" could not be found in the located source#'
4 |
--------------------------------------------------------------------------------
/spec/Calculator/TableRateShippingCalculatorSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($tableRateResolver);
21 | }
22 |
23 | function it_calculates_the_rate_based_on_the_table_rate(
24 | ShipmentInterface $shipment,
25 | TableRateResolverInterface $tableRateResolver,
26 | ShippingTableRate $tableRate
27 | ): void {
28 | $configuration = ['CHANNEL_CODE' => ['table_rate' => $tableRate]];
29 | $shipment->getShippingWeight()->willReturn(15.5);
30 | $tableRateResolver->resolve($shipment, $configuration)->willReturn($tableRate);
31 | $tableRate->getRate(15.5)->willReturn(1000);
32 |
33 | $this
34 | ->calculate($shipment, $configuration)
35 | ->shouldReturn(1000)
36 | ;
37 | }
38 |
39 | function it_should_return_zero_if_no_rate_is_found_for_a_given_shipment(
40 | ShipmentInterface $shipment,
41 | TableRateResolverInterface $tableRateResolver,
42 | ShippingTableRate $tableRate
43 | ) {
44 | $configuration = ['CHANNEL_CODE' => ['table_rate' => $tableRate]];
45 | $shipment->getShippingWeight()->willReturn(1000);
46 | $tableRateResolver->resolve($shipment, $configuration)->willReturn($tableRate);
47 | $tableRate->getRate(1000)->willThrow(RateNotFoundException::class);
48 |
49 | $this
50 | ->calculate($shipment, $configuration)
51 | ->shouldReturn(0)
52 | ;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/spec/Checker/TableRateShippingMethodEligibilityCheckerSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($eligibilityChecker, $tableRateResolver);
22 | }
23 |
24 | function it_returns_false_if_the_decorated_checker_returns_false(
25 | ShippingMethodEligibilityCheckerInterface $eligibilityChecker,
26 | ShipmentInterface $shipment,
27 | ShippingMethodInterface $shippingMethod
28 | ): void {
29 | $eligibilityChecker->isEligible($shipment, $shippingMethod)->willReturn(false);
30 |
31 | $this->isEligible($shipment, $shippingMethod)->shouldReturn(false);
32 | }
33 |
34 | function it_returns_true_if_the_decorated_checker_returns_true_and_other_calculator_is_used(
35 | ShippingMethodEligibilityCheckerInterface $eligibilityChecker,
36 | ShipmentInterface $shipment,
37 | ShippingMethodInterface $shippingMethod
38 | ): void {
39 | $eligibilityChecker->isEligible($shipment, $shippingMethod)->willReturn(true);
40 |
41 | $shippingMethod->getCalculator()->willReturn('ananas');
42 |
43 | $this->isEligible($shipment, $shippingMethod)->shouldReturn(true);
44 | }
45 |
46 | function it_returns_true_if_the_decorated_checker_returns_true_and_a_rate_can_be_found(
47 | ShippingMethodEligibilityCheckerInterface $eligibilityChecker,
48 | ShipmentInterface $shipment,
49 | ShippingMethodInterface $shippingMethod,
50 | TableRateResolverInterface $tableRateResolver,
51 | ShippingTableRate $tableRate
52 | ): void {
53 | $eligibilityChecker->isEligible($shipment, $shippingMethod)->willReturn(true);
54 | $shippingMethod->getCalculator()->willReturn(TableRateShippingCalculator::TYPE);
55 | $shippingMethod->getConfiguration()->willReturn(['some' => 'config']);
56 | $shipment->getShippingWeight()->willReturn(15.5);
57 | $tableRateResolver->resolve($shipment, ['some' => 'config'])->willReturn($tableRate);
58 | $tableRate->getRate(15.5)->willReturn(1000);
59 |
60 | $this->isEligible($shipment, $shippingMethod)->shouldReturn(true);
61 | }
62 |
63 | function it_returns_false_if_the_decorated_checker_returns_true_and_a_rate_cannot_be_found(
64 | ShippingMethodEligibilityCheckerInterface $eligibilityChecker,
65 | ShipmentInterface $shipment,
66 | ShippingMethodInterface $shippingMethod,
67 | TableRateResolverInterface $tableRateResolver,
68 | ShippingTableRate $tableRate
69 | ): void {
70 | $eligibilityChecker->isEligible($shipment, $shippingMethod)->willReturn(true);
71 | $shippingMethod->getCalculator()->willReturn(TableRateShippingCalculator::TYPE);
72 | $shippingMethod->getConfiguration()->willReturn(['some' => 'config']);
73 | $shipment->getShippingWeight()->willReturn(15.5);
74 | $tableRateResolver->resolve($shipment, ['some' => 'config'])->willReturn($tableRate);
75 | $tableRate->getRate(15.5)->willThrow(RateNotFoundException::class);
76 |
77 | $this->isEligible($shipment, $shippingMethod)->shouldReturn(false);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/spec/Entity/ShippingTableRateSpec.php:
--------------------------------------------------------------------------------
1 | addRate(20.0, 10);
17 | $this->addRate(5.0, 5);
18 | $this->addRate(10.0, 7);
19 |
20 | $this->getRate(2.0)->shouldReturn(5);
21 | $this->getRate(5.0)->shouldReturn(5);
22 | $this->getRate(7.0)->shouldReturn(7);
23 | $this->getRate(10.0)->shouldReturn(7);
24 | $this->getRate(15.0)->shouldReturn(10);
25 | $this->getRate(20.0)->shouldReturn(10);
26 | $this->shouldThrow(RateNotFoundException::class)->during('getRate', [25.0]);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/spec/EventSubscriber/TableRateDeleteSubscriberSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($shippingMethodRepository);
23 | }
24 |
25 | public function it_is_initializable(): void
26 | {
27 | $this->shouldHaveType(TableRateDeleteSubscriber::class);
28 | }
29 |
30 | public function it_should_implement_event_subscriber_interface(): void
31 | {
32 | $this->shouldImplement(EventSubscriberInterface::class);
33 | }
34 |
35 | public function it_should_subscribe_to_table_rate_pre_delete_event(): void
36 | {
37 | self::getSubscribedEvents()->shouldReturn(
38 | ['webgriffe.shipping_table_rate.pre_delete' => 'onTableRatePreDelete']
39 | );
40 | }
41 |
42 | public function it_should_stop_event_if_table_rate_is_already_in_use(
43 | ResourceControllerEvent $event,
44 | ShippingMethodRepositoryInterface $shippingMethodRepository
45 | ): void {
46 | $tableRate = new ShippingTableRate();
47 | $tableRate->setCode('TABLE_RATE');
48 | $anotherTableRate = new ShippingTableRate();
49 | $anotherTableRate->setCode('ANOTHER_RATE');
50 | $shippingMethod1 = new ShippingMethod();
51 | $shippingMethod1->setCode('METHOD1');
52 | $shippingMethod1->setConfiguration(['WEB-US' => ['table_rate' => 'TABLE_RATE']]);
53 | $shippingMethod2 = new ShippingMethod();
54 | $shippingMethod2->setCode('METHOD2');
55 | $shippingMethod2->setConfiguration(['WEB-US' => ['table_rate' => 'ANOTHER_RATE']]);
56 | $shippingMethod3 = new ShippingMethod();
57 | $shippingMethod3->setCode('METHOD3');
58 | $shippingMethod3->setConfiguration(
59 | ['WEB-US' => ['table_rate' => 'ANOTHER_RATE'], 'WEB-EU' => ['table_rate' => 'TABLE_RATE']]
60 | );
61 | $shippingMethodRepository
62 | ->findBy(['calculator' => TableRateShippingCalculator::TYPE])
63 | ->willReturn([$shippingMethod1, $shippingMethod2, $shippingMethod3])
64 | ;
65 | $event->getSubject()->willReturn($tableRate);
66 | $event
67 | ->stop(
68 | 'webgriffe_sylius_table_rate_plugin.ui.shipping_table_rate.already_used_by_shipping_methods',
69 | ResourceControllerEvent::TYPE_ERROR,
70 | ['%shipping_methods%' => 'METHOD1, METHOD3'],
71 | 400
72 | )
73 | ->shouldBeCalled()
74 | ;
75 |
76 | $this->onTableRatePreDelete($event);
77 | }
78 |
79 | public function it_should_not_stop_event_if_table_rate_is_not_in_use(
80 | ShippingTableRate $shippingTableRate,
81 | ResourceControllerEvent $event,
82 | ShippingMethodRepositoryInterface $shippingMethodRepository
83 | ): void {
84 | $event->getSubject()->willReturn($shippingTableRate);
85 | $shippingMethodRepository
86 | ->findBy(['calculator' => TableRateShippingCalculator::TYPE])
87 | ->willReturn([])
88 | ;
89 | $event
90 | ->stop()
91 | ->shouldNotBeCalled()
92 | ;
93 |
94 | $this->onTableRatePreDelete($event);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/spec/Form/EventSubscriber/AddCurrencySubscriberSpec.php:
--------------------------------------------------------------------------------
1 | shouldImplement(EventSubscriberInterface::class);
19 | }
20 |
21 | function it_subscribes_to_event(): void
22 | {
23 | $this::getSubscribedEvents()->shouldReturn([FormEvents::PRE_SET_DATA => 'preSetData']);
24 | }
25 |
26 | function it_sets_currency_as_disabled_when_table_rate_is_not_new(
27 | FormEvent $event,
28 | ShippingTableRate $shippingTableRate,
29 | FormInterface $form
30 | ): void {
31 | $event->getData()->willReturn($shippingTableRate);
32 | $event->getForm()->willReturn($form);
33 |
34 | $shippingTableRate->getId()->willReturn(2);
35 |
36 | $form
37 | ->add('currency', Argument::type('string'), Argument::withEntry('disabled', true))
38 | ->shouldBeCalled()
39 | ->willReturn($form)
40 | ;
41 |
42 | $this->preSetData($event);
43 | }
44 |
45 | function it_does_not_set_currency_as_disabled_when_table_rate_is_new(
46 | FormEvent $event,
47 | ShippingTableRate $shippingTableRate,
48 | FormInterface $form
49 | ): void {
50 | $event->getData()->willReturn($shippingTableRate);
51 | $event->getForm()->willReturn($form);
52 |
53 | $shippingTableRate->getId()->willReturn(null);
54 |
55 | $form
56 | ->add('currency', Argument::type('string'), Argument::withEntry('disabled', false))
57 | ->shouldBeCalled()
58 | ->willReturn($form)
59 | ;
60 |
61 | $this->preSetData($event);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/spec/Resolver/TableRateResolverSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($tableRateRepository);
22 | }
23 |
24 | public function it_should_implement_table_rate_resolver_interface(): void
25 | {
26 | $this->shouldImplement(TableRateResolverInterface::class);
27 | }
28 |
29 | public function it_should_resolve_table_rate_from_shipment(
30 | ShipmentInterface $shipment,
31 | OrderInterface $order,
32 | ChannelInterface $channel,
33 | RepositoryInterface $tableRateRepository,
34 | ShippingTableRate $tableRate
35 | ): void {
36 | $shipment->getOrder()->willReturn($order);
37 | $order->getChannel()->willReturn($channel);
38 | $channel->getCode()->willReturn('CHANNEL_CODE');
39 | $tableRate->getCode()->willReturn('TABLE_RATE_CODE');
40 | $tableRateRepository->findOneBy(['code' => 'TABLE_RATE_CODE'])->willReturn($tableRate);
41 | $calculatorConfig = ['CHANNEL_CODE' => ['table_rate' => 'TABLE_RATE_CODE']];
42 |
43 | $this->resolve($shipment, $calculatorConfig)->shouldReturn($tableRate);
44 | }
45 |
46 | public function it_throws_a_missing_channel_configuration_exception_if_the_order_channel_is_not_configured(
47 | ShipmentInterface $shipment,
48 | OrderInterface $order,
49 | ChannelInterface $channel,
50 | ShippingMethodInterface $shippingMethod,
51 | ShippingTableRate $shippingTableRate
52 | ): void {
53 | $shipment->getOrder()->willReturn($order);
54 | $order->getChannel()->willReturn($channel);
55 | $channel->getCode()->willReturn('ANOTHER_CHANNEL_CODE');
56 | $channel->getName()->willReturn('Another channel');
57 |
58 | $shipment->getMethod()->willReturn($shippingMethod);
59 | $shippingMethod->getName()->willReturn('Table rate based');
60 | $shippingTableRate->getCode()->willReturn('TABLE_RATE_CODE');
61 |
62 | $this
63 | ->shouldThrow(
64 | new MissingChannelConfigurationException(
65 | 'Shipping method "Table rate based" has no configuration for channel "Another channel".'
66 | )
67 | )
68 | ->during('resolve', [$shipment, ['CHANNEL_CODE' => ['table_rate' => $shippingTableRate]]])
69 | ;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Calculator/TableRateShippingCalculator.php:
--------------------------------------------------------------------------------
1 | tableRateResolver->resolve($shipment, $configuration);
28 |
29 | try {
30 | return $tableRate->getRate($shipment->getShippingWeight());
31 | } catch (RateNotFoundException $e) {
32 | return 0;
33 | }
34 | }
35 |
36 | public function getType(): string
37 | {
38 | return self::TYPE;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Checker/TableRateShippingMethodEligibilityChecker.php:
--------------------------------------------------------------------------------
1 | eligibilityChecker->isEligible($subject, $method)) {
29 | return false;
30 | }
31 |
32 | if ($method->getCalculator() !== TableRateShippingCalculator::TYPE) {
33 | return true;
34 | }
35 |
36 | Assert::isInstanceOf($subject, ShipmentInterface::class);
37 |
38 | $weight = $subject->getShippingWeight();
39 | /** @noinspection PhpParamsInspection */
40 | $tableRate = $this->tableRateResolver->resolve($subject, $method->getConfiguration());
41 |
42 | try {
43 | $tableRate->getRate($weight);
44 | } catch (RateNotFoundException $e) {
45 | return false;
46 | }
47 |
48 | return true;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/DependencyInjection/Configuration.php:
--------------------------------------------------------------------------------
1 | processConfiguration($this->getConfiguration([], $container), $configs);
18 | $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
19 |
20 | $loader->load('services.yml');
21 | }
22 |
23 | public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface
24 | {
25 | return new Configuration();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Entity/ShippingTableRate.php:
--------------------------------------------------------------------------------
1 | id;
56 | }
57 |
58 | public function getCode(): ?string
59 | {
60 | return $this->code;
61 | }
62 |
63 | public function setCode(?string $code): void
64 | {
65 | $this->code = $code;
66 | }
67 |
68 | public function getName(): ?string
69 | {
70 | return $this->name;
71 | }
72 |
73 | public function setName(?string $name): void
74 | {
75 | $this->name = $name;
76 | }
77 |
78 | public function getCurrency(): ?CurrencyInterface
79 | {
80 | return $this->currency;
81 | }
82 |
83 | public function setCurrency(?CurrencyInterface $currency): void
84 | {
85 | $this->currency = $currency;
86 | }
87 |
88 | public function addRate(float $weightLimit, int $rate): void
89 | {
90 | $this->weightLimitToRate[] = ['weightLimit' => $weightLimit, 'rate' => $rate];
91 | }
92 |
93 | public function getRate(float $weight): int
94 | {
95 | usort($this->weightLimitToRate, function (array $a, array $b): int {
96 | return $a['weightLimit'] <=> $b['weightLimit'];
97 | });
98 |
99 | foreach ($this->weightLimitToRate as $array) {
100 | if ($weight <= $array['weightLimit']) {
101 | return $array['rate'];
102 | }
103 | }
104 |
105 | throw new RateNotFoundException($this, $weight);
106 | }
107 |
108 | public function getRatesCount(): int
109 | {
110 | return count($this->weightLimitToRate);
111 | }
112 |
113 | /**
114 | * @internal
115 | */
116 | public function getWeightLimitToRate(): array
117 | {
118 | return $this->weightLimitToRate;
119 | }
120 |
121 | /**
122 | * @internal
123 | */
124 | public function setWeightLimitToRate(array $weightLimitToRate): void
125 | {
126 | $this->weightLimitToRate = $weightLimitToRate;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/EventSubscriber/TableRateDeleteSubscriber.php:
--------------------------------------------------------------------------------
1 | 'onTableRatePreDelete'];
24 | }
25 |
26 | public function onTableRatePreDelete(ResourceControllerEvent $event): void
27 | {
28 | $shippingTableRate = $event->getSubject();
29 | Assert::isInstanceOf($shippingTableRate, ShippingTableRate::class);
30 |
31 | $shippingMethods = $this->shippingMethodRepository->findBy(['calculator' => TableRateShippingCalculator::TYPE]);
32 | $foundMethods = [];
33 | /** @var ShippingMethod $shippingMethod */
34 | foreach ($shippingMethods as $shippingMethod) {
35 | foreach ($shippingMethod->getConfiguration() as $channelConfiguration) {
36 | /** @var string|null $channelTableRateCode */
37 | $channelTableRateCode = $channelConfiguration['table_rate'] ?? null;
38 | if ($channelTableRateCode !== null && $channelTableRateCode === $shippingTableRate->getCode()) {
39 | $foundMethods[] = $shippingMethod->getCode();
40 | }
41 | }
42 | }
43 |
44 | if (count($foundMethods) > 0) {
45 | $event->stop(
46 | 'webgriffe_sylius_table_rate_plugin.ui.shipping_table_rate.already_used_by_shipping_methods',
47 | ResourceControllerEvent::TYPE_ERROR,
48 | ['%shipping_methods%' => implode(', ', $foundMethods)],
49 | 400,
50 | );
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Exception/RateNotFoundException.php:
--------------------------------------------------------------------------------
1 | getCode(),
21 | $weight,
22 | );
23 | parent::__construct($message, $code, $previous);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Form/EventSubscriber/AddCurrencySubscriber.php:
--------------------------------------------------------------------------------
1 | 'preSetData'];
19 | }
20 |
21 | public function preSetData(FormEvent $event): void
22 | {
23 | $messagesNamespace = 'webgriffe_sylius_table_rate_plugin.ui.shipping_table_rate.';
24 | $form = $event->getForm();
25 | $resource = $event->getData();
26 | Assert::nullOrIsInstanceOf($resource, ResourceInterface::class);
27 |
28 | $form->add(
29 | 'currency',
30 | CurrencyChoiceType::class,
31 | [
32 | 'label' => $messagesNamespace . 'currency.label',
33 | 'required' => true,
34 | 'placeholder' => $messagesNamespace . 'currency.placeholder',
35 | 'disabled' => $this->shouldCurrencyBeDisabled($resource),
36 | ],
37 | );
38 | }
39 |
40 | private function shouldCurrencyBeDisabled(?ResourceInterface $resource): bool
41 | {
42 | if (null === $resource) {
43 | return false;
44 | }
45 |
46 | return $resource->getId() !== null;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Form/Type/Shipping/Calculator/ChannelBasedTableRateConfigurationType.php:
--------------------------------------------------------------------------------
1 | setDefaults(
17 | [
18 | 'entry_type' => TableRateConfigurationType::class,
19 | 'entry_options' => function (ChannelInterface $channel): array {
20 | return ['label' => $channel->getName(), 'currency' => $channel->getBaseCurrency()];
21 | },
22 | ],
23 | );
24 | }
25 |
26 | public function getParent(): string
27 | {
28 | return ChannelCollectionType::class;
29 | }
30 |
31 | public function getBlockPrefix(): string
32 | {
33 | return 'webgriffe_sylius_table_rate_shipping_plugin_calculator_channel_based_table_rate';
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Form/Type/Shipping/Calculator/TableRateConfigurationType.php:
--------------------------------------------------------------------------------
1 | add(
34 | self::TABLE_RATE_FIELD_NAME,
35 | EntityType::class,
36 | [
37 | 'label' => $messagesNamespace . 'table_rate.label',
38 | 'placeholder' => $messagesNamespace . 'table_rate.placeholder',
39 | 'class' => ShippingTableRate::class,
40 | 'query_builder' => function (EntityRepository $entityRepository) use ($currency): QueryBuilder {
41 | return $entityRepository
42 | ->createQueryBuilder('tr')
43 | ->where('tr.currency = :currency')
44 | ->setParameter('currency', $currency)
45 | ;
46 | },
47 | 'choice_label' => 'name',
48 | 'choice_value' => 'code',
49 | 'constraints' => [new NotBlank(['groups' => ['sylius']])],
50 | ],
51 | )->setDataMapper($this);
52 | }
53 |
54 | public function configureOptions(OptionsResolver $resolver): void
55 | {
56 | $resolver
57 | ->setDefaults(['data_class' => null])
58 | ->setRequired('currency')
59 | ;
60 | }
61 |
62 | public function getBlockPrefix(): string
63 | {
64 | return 'webgriffe_sylius_table_rate_shipping_plugin_calculator_table_rate';
65 | }
66 |
67 | /**
68 | * @psalm-suppress MoreSpecificImplementedParamType
69 | * @psalm-suppress PossiblyInvalidArgument
70 | * @psalm-suppress UnnecessaryVarAnnotation
71 | */
72 | public function mapDataToForms(mixed $viewData, \Traversable $forms): void
73 | {
74 | // there is no data yet, so nothing to prepopulate
75 | if (null === $viewData) {
76 | return;
77 | }
78 |
79 | // invalid data type
80 | if (!is_array($viewData)) {
81 | throw new UnexpectedTypeException($viewData, 'array');
82 | }
83 |
84 | /** @var FormInterface[] $forms */
85 | $forms = iterator_to_array($forms);
86 |
87 | if (!array_key_exists(self::TABLE_RATE_FIELD_NAME, $viewData)) {
88 | return;
89 | }
90 |
91 | // initialize form field values
92 | $forms['table_rate']->setData($this->tableRateRepository->findOneBy(['code' => $viewData[self::TABLE_RATE_FIELD_NAME]]));
93 | }
94 |
95 | /**
96 | * @psalm-suppress MoreSpecificImplementedParamType
97 | * @psalm-suppress PossiblyInvalidArgument
98 | * @psalm-suppress UnnecessaryVarAnnotation
99 | */
100 | public function mapFormsToData(\Traversable $forms, mixed &$viewData): void
101 | {
102 | /** @var FormInterface[] $forms */
103 | $forms = iterator_to_array($forms);
104 |
105 | // as data is passed by reference, overriding it will change it in
106 | // the form object as well
107 | // beware of type inconsistency, see caution below
108 | $tableRateSelected = $forms[self::TABLE_RATE_FIELD_NAME]->getData();
109 | if (!$tableRateSelected instanceof ShippingTableRate) {
110 | $viewData = [];
111 |
112 | return;
113 | }
114 |
115 | $viewData = [self::TABLE_RATE_FIELD_NAME => $tableRateSelected->getCode()];
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/Form/Type/ShippingTableRateType.php:
--------------------------------------------------------------------------------
1 | addEventSubscriber(new AddCodeFormSubscriber())
21 | ->addEventSubscriber(new AddCurrencySubscriber())
22 | ->add('name', TextType::class, ['label' => $messagesNamespace . 'name'])
23 | ->add(
24 | 'weightLimitToRate',
25 | CollectionType::class,
26 | [
27 | 'label' => $messagesNamespace . 'weightLimitToRate.label',
28 | 'allow_add' => true,
29 | 'allow_delete' => true,
30 | 'entry_type' => WeightLimitToRateType::class,
31 | ],
32 | )
33 | ;
34 | }
35 |
36 | public function getBlockPrefix(): string
37 | {
38 | return 'webgriffe_sylius_table_rate_plugin_shipping_table_rate';
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Form/Type/WeightLimitToRateType.php:
--------------------------------------------------------------------------------
1 | add(
20 | 'weightLimit',
21 | NumberType::class,
22 | [
23 | 'label' => $messagesNamespace . 'weightLimit',
24 | 'scale' => 2,
25 | 'required' => true,
26 | 'constraints' => [new NotBlank(['groups' => 'sylius'])],
27 | ],
28 | )
29 | ->add(
30 | 'rate',
31 | MoneyType::class,
32 | [
33 | 'label' => $messagesNamespace . 'rate',
34 | 'required' => true,
35 | 'constraints' => [new NotBlank(['groups' => 'sylius'])],
36 | ],
37 | )
38 | ;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Menu/AdminMenuListener.php:
--------------------------------------------------------------------------------
1 | getMenu();
14 | $configuration = $menu->getChild('configuration');
15 | if (null === $configuration) {
16 | return;
17 | }
18 | $configuration
19 | ->addChild(
20 | 'webgriffe-sylius-table-rate-plugin-table-rates',
21 | ['route' => 'webgriffe_admin_shipping_table_rate_index'],
22 | )
23 | ->setLabel('webgriffe.ui.shipping_table_rates')
24 | ->setLabelAttribute('icon', 'pallet')
25 | ;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Resolver/TableRateResolver.php:
--------------------------------------------------------------------------------
1 | $tableRateRepository
21 | */
22 | public function __construct(private RepositoryInterface $tableRateRepository)
23 | {
24 | }
25 |
26 | public function resolve(ShipmentInterface $shipment, array $calculatorConfig): ShippingTableRate
27 | {
28 | $order = $shipment->getOrder();
29 | if (null === $order) {
30 | throw new \RuntimeException('Cannot resolve a table rate, there\'s no order for this shipment.');
31 | }
32 | $channel = $order->getChannel();
33 | if (null === $channel) {
34 | throw new \RuntimeException(
35 | 'Cannot resolve a table rate, there\'s no channel for this shipment\'s order.',
36 | );
37 | }
38 | $channelCode = $channel->getCode();
39 |
40 | if (!isset($calculatorConfig[$channelCode])) {
41 | $shippingMethod = $shipment->getMethod();
42 | if (null === $shippingMethod) {
43 | throw new MissingChannelConfigurationException(
44 | sprintf(
45 | 'This shipment has no configuration for channel "%s".',
46 | $channel->getName(),
47 | ),
48 | );
49 | }
50 |
51 | throw new MissingChannelConfigurationException(
52 | sprintf(
53 | 'Shipping method "%s" has no configuration for channel "%s".',
54 | $shippingMethod->getName(),
55 | $channel->getName(),
56 | ),
57 | );
58 | }
59 |
60 | /** @var string $tableRateCode */
61 | $tableRateCode = $calculatorConfig[$channelCode][TableRateConfigurationType::TABLE_RATE_FIELD_NAME];
62 | $tableRate = $this->tableRateRepository->findOneBy(['code' => $tableRateCode]);
63 | Assert::isInstanceOf($tableRate, ShippingTableRate::class);
64 |
65 | return $tableRate;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Resolver/TableRateResolverInterface.php:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
17 |
18 | {{ error(form.vars.errors) }}
19 |
20 | {% if prototypes|default is iterable %}
21 | {% for key, subPrototype in prototypes %}
22 |
25 | {% endfor %}
26 | {% endif %}
27 |
28 |
29 | {% for child in form %}
30 | {{ _self.collectionItem(child, allow_delete, button_delete_label, loop.index0) }}
31 | {% endfor %}
32 |
33 |
34 | {% if prototype is defined and allow_add %}
35 |
36 |
37 | {{ button_add_label|trans }}
38 |
39 | {% endif %}
40 |
41 | {% endblock %}
42 |
43 | {% macro collectionItem(form, allow_delete, button_delete_label, index) %}
44 |
45 | {{ form_widget(form) }}
46 | {% if allow_delete %}
47 |
54 | {% endif %}
55 |
56 | {% endmacro %}
57 |
58 | {% block _webgriffe_sylius_table_rate_plugin_shipping_table_rate_weightLimitToRate_entry_widget %}
59 | {%- if form is rootform -%}
60 | {{ form_errors(form) }}
61 | {%- endif -%}
62 | {{- block('form_rows') -}}
63 | {{- form_rest(form) -}}
64 | {% endblock %}
65 |
66 | {% block _webgriffe_sylius_table_rate_plugin_shipping_table_rate_weightLimitToRate_entry_weightLimit_row %}
67 |
68 | {{ block('form_row') }}
69 |
70 | {% endblock %}
71 | {% block _webgriffe_sylius_table_rate_plugin_shipping_table_rate_weightLimitToRate_entry_rate_row %}
72 |
73 | {{ block('form_row') }}
74 |
75 | {% endblock %}
76 |
--------------------------------------------------------------------------------
/src/Resources/views/TableRateCrud/create.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@SyliusAdmin/Crud/create.html.twig' %}
2 |
3 | {% form_theme form.weightLimitToRate '@WebgriffeSyliusTableRateShippingPlugin/TableRateCrud/_weightLimitToRateTheme.html.twig' %}
4 |
5 |
--------------------------------------------------------------------------------
/src/Resources/views/TableRateCrud/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@SyliusAdmin/Crud/index.html.twig' %}
2 |
--------------------------------------------------------------------------------
/src/Resources/views/TableRateCrud/update.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@SyliusAdmin/Crud/update.html.twig' %}
2 |
3 | {% form_theme form.weightLimitToRate '@WebgriffeSyliusTableRateShippingPlugin/TableRateCrud/_weightLimitToRateTheme.html.twig' %}
4 |
--------------------------------------------------------------------------------
/src/WebgriffeSyliusTableRateShippingPlugin.php:
--------------------------------------------------------------------------------
1 | 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=mysql://root@127.0.0.1/sylius_table_rate_shipping_%kernel.environment%?serverVersion=5.5
16 | ###< doctrine/doctrine-bundle ###
17 |
18 | ###> lexik/jwt-authentication-bundle ###
19 | JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
20 | JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
21 | JWT_PASSPHRASE=acme_plugin_development
22 | ###< lexik/jwt-authentication-bundle ###
23 |
24 | ###> symfony/mailer ###
25 | MAILER_DSN=null://null
26 | ###< symfony/mailer ###
27 |
28 | ###> symfony/messenger ###
29 | # Choose one of the transports below
30 | # MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
31 | MESSENGER_TRANSPORT_DSN=doctrine://default
32 | # MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
33 | ###< symfony/messenger ###
34 |
--------------------------------------------------------------------------------
/tests/Application/.env.test:
--------------------------------------------------------------------------------
1 | APP_SECRET='ch4mb3r0f5ecr3ts'
2 |
3 | KERNEL_CLASS='Tests\Webgriffe\SyliusTableRateShippingPlugin\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 | ###> symfony/framework-bundle ###
13 | /.env.*.local
14 | /.env.local
15 | /.env.local.php
16 | /public/bundles
17 | /var/
18 | /vendor/
19 | ###< symfony/framework-bundle ###
20 |
21 | ###> symfony/web-server-bundle ###
22 | /.web-server-pid
23 | ###< symfony/web-server-bundle ###
24 |
--------------------------------------------------------------------------------
/tests/Application/Kernel.php:
--------------------------------------------------------------------------------
1 | getProjectDir() . '/var/cache/' . $this->environment;
23 | }
24 |
25 | public function getLogDir(): string
26 | {
27 | return $this->getProjectDir() . '/var/log';
28 | }
29 |
30 | public function registerBundles(): iterable
31 | {
32 | foreach ($this->getConfigurationDirectories() as $confDir) {
33 | $bundlesFile = $confDir . '/bundles.php';
34 | if (false === is_file($bundlesFile)) {
35 | continue;
36 | }
37 | yield from $this->registerBundlesFromFile($bundlesFile);
38 | }
39 | }
40 |
41 | protected function configureRoutes(RoutingConfigurator $routes): void
42 | {
43 | foreach ($this->getConfigurationDirectories() as $confDir) {
44 | $this->loadRoutesConfiguration($routes, $confDir);
45 | }
46 | }
47 |
48 | protected function getContainerBaseClass(): string
49 | {
50 | if ($this->isTestEnvironment() && class_exists(MockerContainer::class)) {
51 | return MockerContainer::class;
52 | }
53 |
54 | return parent::getContainerBaseClass();
55 | }
56 |
57 | private function isTestEnvironment(): bool
58 | {
59 | return 0 === strpos($this->getEnvironment(), 'test');
60 | }
61 |
62 | private function loadRoutesConfiguration(RoutingConfigurator $routes, string $confDir): void
63 | {
64 | $routes->import($confDir . '/{routes}/*' . self::CONFIG_EXTS);
65 | $routes->import($confDir . '/{routes}/' . $this->environment . '/**/*' . self::CONFIG_EXTS);
66 | $routes->import($confDir . '/{routes}' . self::CONFIG_EXTS);
67 | }
68 |
69 | /**
70 | * @return BundleInterface[]
71 | */
72 | private function registerBundlesFromFile(string $bundlesFile): iterable
73 | {
74 | $contents = require $bundlesFile;
75 | foreach ($contents as $class => $envs) {
76 | if (isset($envs['all']) || isset($envs[$this->environment])) {
77 | yield new $class();
78 | }
79 | }
80 | }
81 |
82 | /**
83 | * @return string[]
84 | */
85 | private function getConfigurationDirectories(): iterable
86 | {
87 | yield $this->getProjectDir() . '/config';
88 | $syliusConfigDir = $this->getProjectDir() . '/config/sylius/' . SyliusKernel::MAJOR_VERSION . '.' . SyliusKernel::MINOR_VERSION;
89 | if (is_dir($syliusConfigDir)) {
90 | yield $syliusConfigDir;
91 | }
92 | $symfonyConfigDir = $this->getProjectDir() . '/config/symfony/' . BaseKernel::MAJOR_VERSION . '.' . BaseKernel::MINOR_VERSION;
93 | if (is_dir($symfonyConfigDir)) {
94 | yield $symfonyConfigDir;
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/tests/Application/assets/admin/entry.js:
--------------------------------------------------------------------------------
1 | import 'sylius/bundle/AdminBundle/Resources/private/entry';
2 |
--------------------------------------------------------------------------------
/tests/Application/assets/shop/entry.js:
--------------------------------------------------------------------------------
1 | import 'sylius/bundle/ShopBundle/Resources/private/entry';
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/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/config/api_platform/.gitignore
--------------------------------------------------------------------------------
/tests/Application/config/bootstrap.php:
--------------------------------------------------------------------------------
1 | =1.2)
11 | if (is_array($env = @include dirname(__DIR__) . '/.env.local.php')) {
12 | $_SERVER += $env;
13 | $_ENV += $env;
14 | } elseif (!class_exists(Dotenv::class)) {
15 | throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
16 | } elseif (method_exists(Dotenv::class, 'bootEnv')) {
17 | (new Dotenv())->bootEnv(dirname(__DIR__) . '/.env');
18 |
19 | return;
20 | } else {
21 | // load all the .env files
22 | (new Dotenv(true))->loadEnv(dirname(__DIR__) . '/.env');
23 | }
24 |
25 | $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
26 | $_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
27 | $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], \FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
28 |
--------------------------------------------------------------------------------
/tests/Application/config/bundles.php:
--------------------------------------------------------------------------------
1 | ['all' => true],
5 | Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
6 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
7 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
8 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
9 | Sylius\Bundle\OrderBundle\SyliusOrderBundle::class => ['all' => true],
10 | Sylius\Bundle\MoneyBundle\SyliusMoneyBundle::class => ['all' => true],
11 | Sylius\Bundle\CurrencyBundle\SyliusCurrencyBundle::class => ['all' => true],
12 | Sylius\Bundle\LocaleBundle\SyliusLocaleBundle::class => ['all' => true],
13 | Sylius\Bundle\ProductBundle\SyliusProductBundle::class => ['all' => true],
14 | Sylius\Bundle\ChannelBundle\SyliusChannelBundle::class => ['all' => true],
15 | Sylius\Bundle\AttributeBundle\SyliusAttributeBundle::class => ['all' => true],
16 | Sylius\Bundle\TaxationBundle\SyliusTaxationBundle::class => ['all' => true],
17 | Sylius\Bundle\ShippingBundle\SyliusShippingBundle::class => ['all' => true],
18 | Sylius\Bundle\PaymentBundle\SyliusPaymentBundle::class => ['all' => true],
19 | Sylius\Bundle\MailerBundle\SyliusMailerBundle::class => ['all' => true],
20 | Sylius\Bundle\PromotionBundle\SyliusPromotionBundle::class => ['all' => true],
21 | Sylius\Bundle\AddressingBundle\SyliusAddressingBundle::class => ['all' => true],
22 | Sylius\Bundle\InventoryBundle\SyliusInventoryBundle::class => ['all' => true],
23 | Sylius\Bundle\TaxonomyBundle\SyliusTaxonomyBundle::class => ['all' => true],
24 | Sylius\Bundle\UserBundle\SyliusUserBundle::class => ['all' => true],
25 | Sylius\Bundle\CustomerBundle\SyliusCustomerBundle::class => ['all' => true],
26 | Sylius\Bundle\UiBundle\SyliusUiBundle::class => ['all' => true],
27 | Sylius\Bundle\ReviewBundle\SyliusReviewBundle::class => ['all' => true],
28 | Sylius\Bundle\CoreBundle\SyliusCoreBundle::class => ['all' => true],
29 | Sylius\Bundle\ResourceBundle\SyliusResourceBundle::class => ['all' => true],
30 | Sylius\Bundle\GridBundle\SyliusGridBundle::class => ['all' => true],
31 | winzou\Bundle\StateMachineBundle\winzouStateMachineBundle::class => ['all' => true],
32 | Sonata\BlockBundle\SonataBlockBundle::class => ['all' => true],
33 | Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle::class => ['all' => true],
34 | JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
35 | FOS\RestBundle\FOSRestBundle::class => ['all' => true],
36 | Knp\Bundle\GaufretteBundle\KnpGaufretteBundle::class => ['all' => true],
37 | Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true],
38 | Liip\ImagineBundle\LiipImagineBundle::class => ['all' => true],
39 | Payum\Bundle\PayumBundle\PayumBundle::class => ['all' => true],
40 | Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],
41 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
42 | Sylius\Bundle\FixturesBundle\SyliusFixturesBundle::class => ['all' => true],
43 | Sylius\Bundle\PayumBundle\SyliusPayumBundle::class => ['all' => true],
44 | Sylius\Bundle\ThemeBundle\SyliusThemeBundle::class => ['all' => true],
45 | Sylius\Bundle\AdminBundle\SyliusAdminBundle::class => ['all' => true],
46 | Sylius\Bundle\ShopBundle\SyliusShopBundle::class => ['all' => true],
47 | Webgriffe\SyliusTableRateShippingPlugin\WebgriffeSyliusTableRateShippingPlugin::class => ['all' => true],
48 | Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true, 'test_cached' => true],
49 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true, 'test_cached' => true],
50 | FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle::class => ['test' => true, 'test_cached' => true],
51 | Sylius\Behat\Application\SyliusTestPlugin\SyliusTestPlugin::class => ['test' => true, 'test_cached' => true],
52 | ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
53 | Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
54 | Sylius\Bundle\ApiBundle\SyliusApiBundle::class => ['all' => true],
55 | SyliusLabs\DoctrineMigrationsExtraBundle\SyliusLabsDoctrineMigrationsExtraBundle::class => ['all' => true],
56 | BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true],
57 | SyliusLabs\Polyfill\Symfony\Security\Bundle\SyliusLabsPolyfillSymfonySecurityBundle::class => ['all' => true],
58 | Sylius\Calendar\SyliusCalendarBundle::class => ['all' => true],
59 | Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
60 | League\FlysystemBundle\FlysystemBundle::class => ['all' => true],
61 | ];
62 | if (class_exists(Sylius\Abstraction\StateMachine\SyliusStateMachineAbstractionBundle::class)) {
63 | $bundles[Sylius\Abstraction\StateMachine\SyliusStateMachineAbstractionBundle::class] = ['all' => true];
64 | }
65 |
66 | return $bundles;
67 |
--------------------------------------------------------------------------------
/tests/Application/config/jwt/private.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN ENCRYPTED PRIVATE KEY-----
2 | MIIJrTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIDbthk+aF5EACAggA
3 | MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBA3DYfh2mXByUxFNke/Wf5SBIIJ
4 | UBckIgXeXBWPLQAAq07pN8uNFMUcUirFuEvbmxVe1PupCCAqriNxi1DqeSu/M7c1
5 | h66y0BqKZu/0G9SVTg63iCKDEiRAM3hLyD2CsjYg8h2LAaqQ9dFYGV0cHRhCXagZ
6 | Sdt9YTfn2rarRbxauMSt0z9zwCaiUrBU4JwSM3g+tD7W0lxAm9TeaqBZek5DIX+j
7 | 3Gom5tPYQe8jvfGMGdMPuanoEwH4WbWzGcqypWriy4JwaggwKCQ4ituWfa9kqMMC
8 | 8HRmBBDg0gtafmQP910RZh18JL2ewF5Pl7GDsLtOj5gNLNuAiQxDCcYRnD4/Cdsl
9 | bH91btmGX1nUVIFViUTW93eBsjBgdgqOMRVxUKkSSX6CmIZWlE3AazgwSbvOvNrN
10 | JGa8X21UwfuS/JHLmfRmgdti0YxRjJkBYLPpcd3ILsi+MMhSHy0uycAM/dB80Q1B
11 | vkW1UXGbCw/PzA5yHrzULzAl69E3Tt5nTVMIIcBGxw2rf+ej+AVjsuOl7etwecdC
12 | gnA90ViNlGOACLVnhsjd4WVF9Oircosf0UYoblwcT6gw1GSVF9pWuu7k5hy/7Pt/
13 | o1BvonUgz/4VHG+K58qvtnlto+JE0XWzPvukNUyggtekTLyoQCI3ZKge6ui3qLax
14 | N6whHpzFnFVF3GJAisTk5naHFawHNvH7t85pmc+UnjNUUmyl9RStl9LMYDSBKNlR
15 | LzPlJK27E5SLhhyJCni4+UYjH6PdlJuKXJ0365fufJ+5ajHRatwt039xLnK0W+oa
16 | L35NxCuXrn8YxOgJIomt7IrkV3AuxoWxcx4lRFoM0WCdn9SWZVtfFFiyX/Xr1qDg
17 | dUysw3/bePEkOKr5JWx09hT0OKDpkwLFo2Ljtvjln4EMXYEvvVqFciKw0kqF73Dw
18 | NyoSubwR4qs6FQclKW1TAP6UW4B6ffq1iagKOCTZ5bBtsPBZk8UGCJb57q4fUj4P
19 | nJy0hnSdlOH4Am+US4HF4ayOGuaV1Be1taurdJnt5cNnUYRah0wg4nG+wVdG5HJk
20 | f4dJ4nih9d6WA/8LfxdpB7NCwdR+KK6lky+GgLSdhmIT9lzjj2GDsU4lBf29TkBn
21 | lyt98/LWGrgCQgZAQ/obxLT8CZtY+tNejGoMppY+ub8DIaLBFID+fcz13kgA9x7a
22 | TeVB8RPok+S3yHXP9a4WSFe9DGjjN+m7EnRtte7MEjyMoekXVnT04gNbTMoGAjNb
23 | lrR4g3ICygZtsoGSB2VEu7o3azAspXNBMOuJfRCuC0LDXcjH3TbvjX0da5wHBoK9
24 | clRxu+CDo9A849HMkmSje8wED7ysZnkvSX0OdPjXahVd4t1tDRI6jSlzFo9fGcjp
25 | S8Ikm9iMrHXaWcDdtcq4C63CjSynIBr4mNIxe/f2e9nynm3AIv+aOan891RWHqrd
26 | DdpSSPShtzATI9PbB+b+S0Gw58Y8fpO7yoZ87VW1BMpadmFZ87YY78jdB7BwInNI
27 | JqtnivinM6qCsvbdMoGinUyL6PUcfQGiEAibouKr3zNRDC4aesBZZmj7w0dnf+HK
28 | YC905aR0cddlc6DBo/ed3o9krMcZ6oY/vruemPTc5G7Cg3t4H3mInRgURw22X1wo
29 | FsioU1yOdkK+MYxvmGsQvQuSJhp7h1Uz37t/olkPRafZgy2nEtw6DQO0Dm4UfSsD
30 | nysq6dn1WeZPkOipGBRgQmY1FTRzwPoCxi7+/EuHhD8hr962rHOglSuNqPG89J8r
31 | wdbTDr8kgXj2A9p+jI3TVKEX+h6FEhrCHW9SHUqATOZ7RiNL6hKld9j0U4D9gQwZ
32 | dflA0TxpVsHXm7pd1idkr46jIFgw7HA89Erm0Ty7RolfHkqlRca805AVmsKkviIz
33 | sbF5uv4WzIE3ViO8P1KMUhCyElm72mpyNTXBhkxkup9hJ4fQieaN6pET6dQ2xyjs
34 | SBIvQoXI0JQKpespcyAdoh88ULQjRUXEOaNFfN7q+itTcocwmPZfzW2nXORJT2p8
35 | SXLqSE73nYZdqzSYFq1hLcnlubJ7yPBYYG1fI0IydjSGKfnjtB0DReR32OToRZ7m
36 | laduZ8O+IaBUY4Sp6QdYcVbGGpG/wsPmTQyScc/O2bfSI7AiPnL9EnwebI9sPSWQ
37 | R0t0QMXZOSSqNY6jkYjsOCxeekRIdY6havo2Y52Ywti0QNrkT4BQ+175VVTmRMdy
38 | LNaMFeEq6ehSEdaHaozvjHvP50HQT43tCK+RJiL+Gf9FqawoQRt693yO5LFbQsuw
39 | QsUSMi41txpINMa+HEc2K5FvGoPr7FmajLK7X2fr+3c/yZ4fahoMKEAVFWl5kRYx
40 | Fe1smlw1Vxl/qNQ32LFWsBIK+XnYBteYmlpVyYrTgXyjnp1rK2zz0118DPFuYiAP
41 | O0r6nnBz0NbwnSKb7S4CjxBKDvDbWTzP35Q5L/vySnO2zRbM64Gw7sjeLiJittWS
42 | gQfbFpEk9k8KVndKM4H50Jp0WznmYpm1Tman8hUOiCvmq0qdI3bJ5Bnj0K+q2zFV
43 | +noGpMFdq1+8WaUFLQFGCPM+yJgCqDgT1RAgfsGcomckGcmenDtHaTbcSFabEdpM
44 | Tsa2qLdg/Kju+7JyGrkmobXl/azuyjYTHfRvSZrvO5WUDFzhChrJpIL4nA3ZGRlS
45 | gvy+OzyyBh4sRyHwLItwUwE81aya3W4llAkhQ7OycmqniJgjtJzLwnxv2RQsB8bF
46 | pyoqQdKVxkqHdbUFeh9igI4ffRAK+8xDER5J+RUoZ4mO8qJebxar54XTb6I/Lepc
47 | g8ITX8bJ/GH+M6JdP7tLCikDTSGS+i1ReMQXE5XuEajYOVbzQdyWU5jleZIx0f6X
48 | mTa4WvMEGNyNxKZZXsy9FAaBkZqrNzEv8k0uFgFMNWQcMMtiqbei86yACdqe+jiW
49 | HqHv8wfoBHR+eIARub2itOJ/cI+oKv96d4it4FqQ9Lml8RUFFZj7Hrd6EjDb6Nq4
50 | P9ti7eku/xZvS0saBNChvv44GhP6FZJS0i/gidVffLna7Wua98tPZEAXp57k+XUL
51 | PzsRJ4a+hFuQjkyXFoz/v8YuUdyCFUSVVr9ArVu0v4+4euFWpQLav5sXv0Gh9X58
52 | Ek1KIf7Z/tZAJnSjTjFuSbDX/AoTMTxpRBKKnFW6zY0Nw2pjTVMtTVDkv9xkBpBK
53 | wod7FPD5f0T7y9YOARVZnBxVRSkkcYpEJFy5pLNeadg9
54 | -----END ENCRYPTED PRIVATE KEY-----
55 |
--------------------------------------------------------------------------------
/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/_sylius.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: "@SyliusCoreBundle/Resources/config/app/config.yml" }
3 |
4 | - { resource: "@SyliusAdminBundle/Resources/config/app/config.yml" }
5 |
6 | - { resource: "@SyliusShopBundle/Resources/config/app/config.yml" }
7 |
8 | - { resource: "@SyliusApiBundle/Resources/config/app/config.yaml" }
9 |
10 | parameters:
11 | sylius_core.public_dir: '%kernel.project_dir%/public'
12 |
13 | sylius_shop:
14 | product_grid:
15 | include_all_descendants: true
16 |
17 | sylius_api:
18 | enabled: true
19 |
--------------------------------------------------------------------------------
/tests/Application/config/packages/api_platform.yaml:
--------------------------------------------------------------------------------
1 | api_platform:
2 | mapping:
3 | paths:
4 | - '%kernel.project_dir%/../../vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources'
5 | - '%kernel.project_dir%/config/api_platform'
6 | - '%kernel.project_dir%/src/Entity'
7 | patch_formats:
8 | json: ['application/merge-patch+json']
9 | swagger:
10 | versions: [3]
11 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tests/Application/config/packages/dev/framework.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | profiler: { only_exceptions: false }
3 |
--------------------------------------------------------------------------------
/tests/Application/config/packages/dev/jms_serializer.yaml:
--------------------------------------------------------------------------------
1 | jms_serializer:
2 | visitors:
3 | json_serialization:
4 | options:
5 | - JSON_PRETTY_PRINT
6 | - JSON_UNESCAPED_SLASHES
7 | - JSON_PRESERVE_ZERO_FRACTION
8 | json_deserialization:
9 | options:
10 | - JSON_PRETTY_PRINT
11 | - JSON_UNESCAPED_SLASHES
12 | - JSON_PRESERVE_ZERO_FRACTION
13 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/fos_rest.yaml:
--------------------------------------------------------------------------------
1 | fos_rest:
2 | exception: true
3 | view:
4 | formats:
5 | json: true
6 | xml: true
7 | empty_content: 204
8 | format_listener:
9 | rules:
10 | - { path: '^/api/v1/.*', priorities: ['json', 'xml'], fallback_format: json, prefer_extension: true }
11 | - { path: '^/', stop: true }
12 |
--------------------------------------------------------------------------------
/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 | serializer:
8 | mapping:
9 | paths: [ '%kernel.project_dir%/config/serialization' ]
10 |
--------------------------------------------------------------------------------
/tests/Application/config/packages/jms_serializer.yaml:
--------------------------------------------------------------------------------
1 | jms_serializer:
2 | visitors:
3 | xml_serialization:
4 | format_output: '%kernel.debug%'
5 |
--------------------------------------------------------------------------------
/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: '%env(MAILER_DSN)%'
4 |
--------------------------------------------------------------------------------
/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/jms_serializer.yaml:
--------------------------------------------------------------------------------
1 | jms_serializer:
2 | visitors:
3 | json_serialization:
4 | options:
5 | - JSON_UNESCAPED_SLASHES
6 | - JSON_PRESERVE_ZERO_FRACTION
7 | json_deserialization:
8 | options:
9 | - JSON_UNESCAPED_SLASHES
10 | - JSON_PRESERVE_ZERO_FRACTION
11 |
--------------------------------------------------------------------------------
/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/security.yaml:
--------------------------------------------------------------------------------
1 | security:
2 | enable_authenticator_manager: true
3 | providers:
4 | sylius_admin_user_provider:
5 | id: sylius.admin_user_provider.email_or_name_based
6 | sylius_api_admin_user_provider:
7 | id: sylius.admin_user_provider.email_or_name_based
8 | sylius_shop_user_provider:
9 | id: sylius.shop_user_provider.email_or_name_based
10 | sylius_api_shop_user_provider:
11 | id: sylius.shop_user_provider.email_or_name_based
12 |
13 | password_hashers:
14 | Sylius\Component\User\Model\UserInterface: argon2i
15 | firewalls:
16 | admin:
17 | switch_user: true
18 | context: admin
19 | pattern: "%sylius.security.admin_regex%"
20 | provider: sylius_admin_user_provider
21 | form_login:
22 | provider: sylius_admin_user_provider
23 | login_path: sylius_admin_login
24 | check_path: sylius_admin_login_check
25 | failure_path: sylius_admin_login
26 | default_target_path: sylius_admin_dashboard
27 | use_forward: false
28 | use_referer: true
29 | enable_csrf: true
30 | csrf_parameter: _csrf_admin_security_token
31 | csrf_token_id: admin_authenticate
32 | remember_me:
33 | secret: "%env(APP_SECRET)%"
34 | path: "/%sylius_admin.path_name%"
35 | name: APP_ADMIN_REMEMBER_ME
36 | lifetime: 31536000
37 | remember_me_parameter: _remember_me
38 | logout:
39 | path: sylius_admin_logout
40 | target: sylius_admin_login
41 |
42 | new_api_admin_user:
43 | pattern: "%sylius.security.new_api_admin_regex%/.*"
44 | provider: sylius_api_admin_user_provider
45 | stateless: true
46 | entry_point: jwt
47 | json_login:
48 | check_path: "%sylius.security.new_api_admin_route%/authentication-token"
49 | username_path: email
50 | password_path: password
51 | success_handler: lexik_jwt_authentication.handler.authentication_success
52 | failure_handler: lexik_jwt_authentication.handler.authentication_failure
53 | jwt: true
54 |
55 | new_api_shop_user:
56 | pattern: "%sylius.security.new_api_shop_regex%/.*"
57 | provider: sylius_api_shop_user_provider
58 | stateless: true
59 | entry_point: jwt
60 | json_login:
61 | check_path: "%sylius.security.new_api_shop_route%/authentication-token"
62 | username_path: email
63 | password_path: password
64 | success_handler: lexik_jwt_authentication.handler.authentication_success
65 | failure_handler: lexik_jwt_authentication.handler.authentication_failure
66 | jwt: true
67 |
68 | shop:
69 | switch_user: { role: ROLE_ALLOWED_TO_SWITCH }
70 | context: shop
71 | pattern: "%sylius.security.shop_regex%"
72 | provider: sylius_shop_user_provider
73 | form_login:
74 | success_handler: sylius.authentication.success_handler
75 | failure_handler: sylius.authentication.failure_handler
76 | provider: sylius_shop_user_provider
77 | login_path: sylius_shop_login
78 | check_path: sylius_shop_login_check
79 | failure_path: sylius_shop_login
80 | default_target_path: sylius_shop_homepage
81 | use_forward: false
82 | use_referer: true
83 | enable_csrf: true
84 | csrf_parameter: _csrf_shop_security_token
85 | csrf_token_id: shop_authenticate
86 | remember_me:
87 | secret: "%env(APP_SECRET)%"
88 | name: APP_SHOP_REMEMBER_ME
89 | lifetime: 31536000
90 | remember_me_parameter: _remember_me
91 | logout:
92 | path: sylius_shop_logout
93 | target: sylius_shop_homepage
94 | invalidate_session: false
95 |
96 | dev:
97 | pattern: ^/(_(profiler|wdt)|css|images|js)/
98 | security: false
99 |
100 | image_resolver:
101 | pattern: ^/media/cache/resolve
102 | security: false
103 |
104 | access_control:
105 | - { path: "%sylius.security.admin_regex%/_partial", role: PUBLIC_ACCESS, ips: [127.0.0.1, ::1] }
106 | - { path: "%sylius.security.admin_regex%/_partial", role: ROLE_NO_ACCESS }
107 | - { path: "%sylius.security.shop_regex%/_partial", role: PUBLIC_ACCESS, ips: [127.0.0.1, ::1] }
108 | - { path: "%sylius.security.shop_regex%/_partial", role: ROLE_NO_ACCESS }
109 |
110 | - { path: "%sylius.security.admin_regex%/login", role: PUBLIC_ACCESS }
111 | - { path: "%sylius.security.shop_regex%/login", role: PUBLIC_ACCESS }
112 |
113 | - { path: "%sylius.security.shop_regex%/register", role: PUBLIC_ACCESS }
114 | - { path: "%sylius.security.shop_regex%/verify", role: PUBLIC_ACCESS }
115 |
116 | - { path: "%sylius.security.admin_regex%", role: ROLE_ADMINISTRATION_ACCESS }
117 | - { path: "%sylius.security.shop_regex%/account", role: ROLE_USER }
118 |
119 | - { path: "%sylius.security.new_api_admin_route%/reset-password-requests", role: PUBLIC_ACCESS }
120 | - { path: "%sylius.security.new_api_admin_regex%/.*", role: ROLE_API_ACCESS }
121 | - { path: "%sylius.security.new_api_admin_route%/authentication-token", role: PUBLIC_ACCESS }
122 | - { path: "%sylius.security.new_api_user_account_regex%/.*", role: ROLE_USER }
123 | - { path: "%sylius.security.new_api_shop_route%/authentication-token", role: PUBLIC_ACCESS }
124 | - { path: "%sylius.security.new_api_shop_regex%/.*", role: PUBLIC_ACCESS }
125 |
--------------------------------------------------------------------------------
/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 | storage_factory_id: session.storage.factory.mock_file
5 |
--------------------------------------------------------------------------------
/tests/Application/config/packages/test/mailer.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | cache:
3 | pools:
4 | test.mailer_pool:
5 | adapter: cache.adapter.filesystem
6 |
--------------------------------------------------------------------------------
/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/security.yaml:
--------------------------------------------------------------------------------
1 | security:
2 | password_hashers:
3 | Sylius\Component\User\Model\UserInterface:
4 | algorithm: argon2i
5 | time_cost: 3
6 | memory_cost: 10
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/doctrine.yaml:
--------------------------------------------------------------------------------
1 | doctrine:
2 | orm:
3 | entity_managers:
4 | default:
5 | result_cache_driver:
6 | type: memcached
7 | host: localhost
8 | port: 11211
9 | query_cache_driver:
10 | type: memcached
11 | host: localhost
12 | port: 11211
13 | metadata_cache_driver:
14 | type: memcached
15 | host: localhost
16 | port: 11211
17 |
--------------------------------------------------------------------------------
/tests/Application/config/packages/test_cached/fos_rest.yaml:
--------------------------------------------------------------------------------
1 | fos_rest:
2 | exception:
3 | debug: true
4 |
--------------------------------------------------------------------------------
/tests/Application/config/packages/test_cached/framework.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: ../test/framework.yaml }
3 |
--------------------------------------------------------------------------------
/tests/Application/config/packages/test_cached/mailer.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: "../test/mailer.yaml" }
3 |
--------------------------------------------------------------------------------
/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/security.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: ../test/security.yaml }
3 |
--------------------------------------------------------------------------------
/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 | strict_variables: true
3 |
--------------------------------------------------------------------------------
/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_annotations: true
4 |
--------------------------------------------------------------------------------
/tests/Application/config/packages/webgriffe_sylius_table_rate_shipping_plugin.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: "@WebgriffeSyliusTableRateShippingPlugin/Resources/config/config.yml" }
3 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tests/Application/config/routes/sylius_api.yaml:
--------------------------------------------------------------------------------
1 | sylius_api:
2 | resource: "@SyliusApiBundle/Resources/config/routing.yml"
3 | prefix: "%sylius.security.new_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: "@SyliusShopBundle/Resources/config/routing/payum.yml"
9 |
10 | sylius_shop_default_locale:
11 | path: /
12 | methods: [GET]
13 | defaults:
14 | _controller: sylius.controller.shop.locale_switch::switchAction
15 |
--------------------------------------------------------------------------------
/tests/Application/config/routes/test/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/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/webgriffe_sylius_table_rate_shipping_plugin.yaml:
--------------------------------------------------------------------------------
1 | webgriffe_sylius_table_rate_shipping_plugin_shop:
2 | resource: "@WebgriffeSyliusTableRateShippingPlugin/Resources/config/shop_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 | webgriffe_sylius_table_rate_shipping_plugin_admina:
8 | resource: "@WebgriffeSyliusTableRateShippingPlugin/Resources/config/admin_routing.yml"
9 | prefix: /admin
10 |
--------------------------------------------------------------------------------
/tests/Application/config/secrets/dev/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/config/secrets/dev/.gitignore
--------------------------------------------------------------------------------
/tests/Application/config/secrets/prod/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/config/secrets/prod/.gitignore
--------------------------------------------------------------------------------
/tests/Application/config/secrets/test/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/config/secrets/test/.gitignore
--------------------------------------------------------------------------------
/tests/Application/config/secrets/test_cached/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/config/secrets/test_cached/.gitignore
--------------------------------------------------------------------------------
/tests/Application/config/serialization/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/config/serialization/.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/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@babel/polyfill": "^7.0.0",
4 | "chart.js": "^3.7.1",
5 | "jquery": "^3.5.0",
6 | "jquery.dirtyforms": "^2.0.0",
7 | "lightbox2": "^2.9.0",
8 | "semantic-ui-css": "^2.2.0",
9 | "slick-carousel": "^1.8.1"
10 | },
11 | "devDependencies": {
12 | "@babel/core": "^7.0.0",
13 | "@babel/plugin-external-helpers": "^7.0.0",
14 | "@babel/plugin-proposal-object-rest-spread": "^7.18.9",
15 | "@babel/preset-env": "^7.18.10",
16 | "@babel/register": "^7.0.0",
17 | "@rollup/plugin-babel": "^5.3.1",
18 | "@rollup/plugin-commonjs": "^22.0.2",
19 | "@rollup/plugin-inject": "^4.0.4",
20 | "@rollup/plugin-node-resolve": "^13.3.0",
21 | "@semantic-ui-react/css-patch": "^1.1.2",
22 | "@symfony/webpack-encore": "^3.1.0",
23 | "babel-plugin-fast-async": "^6.1.2",
24 | "babel-plugin-module-resolver": "^4.1.0",
25 | "dedent": "^0.7.0",
26 | "eslint": "^8.23.0",
27 | "eslint-config-airbnb-base": "^15.0.0",
28 | "eslint-import-resolver-babel-module": "^5.3.1",
29 | "eslint-plugin-import": "^2.26.0",
30 | "fast-async": "^6.3.8",
31 | "gulp": "^4.0.2",
32 | "gulp-chug": "^0.5.1",
33 | "gulp-concat": "^2.6.1",
34 | "gulp-debug": "^4.0.0",
35 | "gulp-if": "^3.0.0",
36 | "gulp-livereload": "^4.0.2",
37 | "gulp-order": "^1.2.0",
38 | "gulp-sass": "^5.1.0",
39 | "gulp-sourcemaps": "^3.0.0",
40 | "gulp-uglifycss": "^1.1.0",
41 | "merge-stream": "^2.0.0",
42 | "rollup": "^2.79.0",
43 | "rollup-plugin-terser": "^7.0.2",
44 | "sass": "^1.54.8",
45 | "sass-loader": "^13.0.0",
46 | "upath": "^2.0.1",
47 | "yargs": "^17.5.1"
48 | },
49 | "engines": {
50 | "node": "^14 || ^16 || ^18"
51 | },
52 | "engineStrict": true,
53 | "scripts": {
54 | "watch": "encore dev --watch",
55 | "build": "encore dev",
56 | "build:prod": "encore production",
57 | "gulp": "gulp build",
58 | "lint": "yarn lint:js",
59 | "lint:js": "eslint gulpfile.babel.js src/Sylius/Bundle/AdminBundle/gulpfile.babel.js src/Sylius/Bundle/ShopBundle/gulpfile.babel.js src/Sylius/Bundle/UiBundle/Resources/private/js src/Sylius/Bundle/AdminBundle/Resources/private/js src/Sylius/Bundle/ShopBundle/Resources/private/js",
60 | "postinstall": "semantic-ui-css-patch"
61 | },
62 | "repository": {
63 | "type": "git",
64 | "url": "git+https://github.com/Sylius/Sylius.git"
65 | },
66 | "author": "Paweł Jędrzejewski",
67 | "license": "MIT"
68 | }
69 |
--------------------------------------------------------------------------------
/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/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/public/favicon.ico
--------------------------------------------------------------------------------
/tests/Application/public/index.php:
--------------------------------------------------------------------------------
1 | handle($request);
28 | $response->send();
29 | $kernel->terminate($request, $response);
30 |
--------------------------------------------------------------------------------
/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/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/src/Entity/.gitignore
--------------------------------------------------------------------------------
/tests/Application/templates/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/templates/.gitignore
--------------------------------------------------------------------------------
/tests/Application/templates/bundles/SyliusAdminBundle/Layout/_logo.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
 }})
4 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/Application/templates/bundles/SyliusAdminBundle/Security/_content.html.twig:
--------------------------------------------------------------------------------
1 | {% include '@SyliusUi/Security/_login.html.twig'
2 | with {
3 | 'action': path('sylius_admin_login_check'),
4 | 'paths': {'logo': asset('build/admin/images/logo.png', 'admin')}
5 | }
6 | %}
7 |
--------------------------------------------------------------------------------
/tests/Application/templates/bundles/SyliusAdminBundle/_scripts.html.twig:
--------------------------------------------------------------------------------
1 | {{ encore_entry_script_tags('admin-entry', null, 'admin') }}
2 |
--------------------------------------------------------------------------------
/tests/Application/templates/bundles/SyliusAdminBundle/_styles.html.twig:
--------------------------------------------------------------------------------
1 | {{ encore_entry_link_tags('admin-entry', null, 'admin') }}
2 |
--------------------------------------------------------------------------------
/tests/Application/templates/bundles/SyliusShopBundle/Homepage/_banner.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
 }})
4 |
5 |
6 |
{{ 'sylius.homepage.banner_content'|trans }}
7 |
{{ 'sylius.homepage.banner_button'|trans }}
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/Application/templates/bundles/SyliusShopBundle/Layout/Header/_logo.html.twig:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/tests/Application/templates/bundles/SyliusShopBundle/_scripts.html.twig:
--------------------------------------------------------------------------------
1 | {{ encore_entry_script_tags('shop-entry', null, 'shop') }}
2 |
--------------------------------------------------------------------------------
/tests/Application/templates/bundles/SyliusShopBundle/_styles.html.twig:
--------------------------------------------------------------------------------
1 | {{ encore_entry_link_tags('shop-entry', null, 'shop') }}
2 |
--------------------------------------------------------------------------------
/tests/Application/translations/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webgriffe/WebgriffeSyliusTableRateShippingPlugin/f94f6c1b985927d11fdf38972365f920a8d1d6f5/tests/Application/translations/.gitignore
--------------------------------------------------------------------------------
/tests/Application/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const Encore = require('@symfony/webpack-encore');
3 |
4 | const syliusBundles = path.resolve(__dirname, '../../vendor/sylius/sylius/src/Sylius/Bundle/');
5 | const uiBundleScripts = path.resolve(syliusBundles, 'UiBundle/Resources/private/js/');
6 | const uiBundleResources = path.resolve(syliusBundles, 'UiBundle/Resources/private/');
7 |
8 | // Shop config
9 | Encore
10 | .setOutputPath('public/build/shop/')
11 | .setPublicPath('/build/shop')
12 | .addEntry('shop-entry', './assets/shop/entry.js')
13 | .disableSingleRuntimeChunk()
14 | .cleanupOutputBeforeBuild()
15 | .enableSourceMaps(!Encore.isProduction())
16 | .enableVersioning(Encore.isProduction())
17 | .enableSassLoader();
18 |
19 | const shopConfig = Encore.getWebpackConfig();
20 |
21 | shopConfig.resolve.alias['sylius/ui'] = uiBundleScripts;
22 | shopConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources;
23 | shopConfig.resolve.alias['sylius/bundle'] = syliusBundles;
24 | shopConfig.resolve.alias['chart.js/dist/Chart.min'] = path.resolve(__dirname, 'node_modules/chart.js/dist/chart.min.js');
25 | shopConfig.name = 'shop';
26 |
27 | Encore.reset();
28 |
29 | // Admin config
30 | Encore
31 | .setOutputPath('public/build/admin/')
32 | .setPublicPath('/build/admin')
33 | .addEntry('admin-entry', './assets/admin/entry.js')
34 | .disableSingleRuntimeChunk()
35 | .cleanupOutputBeforeBuild()
36 | .enableSourceMaps(!Encore.isProduction())
37 | .enableVersioning(Encore.isProduction())
38 | .enableSassLoader();
39 |
40 | const adminConfig = Encore.getWebpackConfig();
41 |
42 | adminConfig.resolve.alias['sylius/ui'] = uiBundleScripts;
43 | adminConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources;
44 | adminConfig.resolve.alias['sylius/bundle'] = syliusBundles;
45 | adminConfig.resolve.alias['chart.js/dist/Chart.min'] = path.resolve(__dirname, 'node_modules/chart.js/dist/chart.min.js');
46 | adminConfig.externals = Object.assign({}, adminConfig.externals, { window: 'window', document: 'document' });
47 | adminConfig.name = 'admin';
48 |
49 | module.exports = [shopConfig, adminConfig];
50 |
--------------------------------------------------------------------------------
/tests/Behat/Context/Setup/ProductContext.php:
--------------------------------------------------------------------------------
1 | productExampleFactory->create([
38 | 'name' => $productName,
39 | 'enabled' => true,
40 | 'main_taxon' => null,
41 | ]);
42 |
43 | /** @var ProductVariantInterface $productVariant */
44 | $productVariant = $product->getVariants()->first();
45 |
46 | $productVariant->setWeight((float) $weight);
47 |
48 | $this->productRepository->add($product);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/Behat/Context/Setup/ShippingTableRateContext.php:
--------------------------------------------------------------------------------
1 | shippingTableRateRepository->findBy(['name' => $name]);
40 |
41 | Assert::count(
42 | $shippingTableRates,
43 | 1,
44 | sprintf('%d shipping table rates has been found with name "%s".', count($shippingTableRates), $name),
45 | );
46 |
47 | return $shippingTableRates[0];
48 | }
49 |
50 | /**
51 | * @Given the store has (also) a shipping table rate :name for currency :currency
52 | */
53 | public function theStoreHasShippingTableRateForCurrency(string $name, CurrencyInterface $currency): void
54 | {
55 | /** @var ShippingTableRate $shippingTableRate */
56 | $shippingTableRate = $this->shippingTableRateFactory->createNew();
57 | $shippingTableRate->setName($name);
58 | $shippingTableRate->setCode(StringInflector::nameToUppercaseCode($name));
59 | $shippingTableRate->setCurrency($currency);
60 |
61 | $this->shippingTableRateRepository->add($shippingTableRate);
62 |
63 | $this->sharedStorage->set('shipping_table_rate', $shippingTableRate);
64 | }
65 |
66 | /**
67 | * @Given /^(this shipping table rate) has a rate ("[^"]+") for shipments up to (\d+) kg$/
68 | * @Given /^(it) has a rate ("[^"]+") for shipments up to (\d+) kg$/
69 | */
70 | public function thisShippingTableRateHasRateForShipmentsUpToKg(ShippingTableRate $shippingTableRate, int $rate, int $weightLimit): void
71 | {
72 | $shippingTableRate->addRate($weightLimit, $rate);
73 |
74 | $this->shippingTableRateManager->flush();
75 | }
76 |
77 | /**
78 | * @Given the store has :shippingMethodName shipping method using :shippingTableRate table rate for :channel channel
79 | */
80 | public function theStoreHasShippingMethodUsingTableRateForChannel(
81 | string $shippingMethodName,
82 | ShippingTableRate $shippingTableRate,
83 | ChannelInterface $channel,
84 | ): void {
85 | /** @var ShippingMethodInterface $shippingMethod */
86 | $shippingMethod = $this->shippingMethodExampleFactory->create([
87 | 'name' => $shippingMethodName,
88 | 'enabled' => true,
89 | 'zone' => $this->getShippingZone(),
90 | 'calculator' => [
91 | 'type' => TableRateShippingCalculator::TYPE,
92 | 'configuration' => [$channel->getCode() => [TableRateShippingCalculator::TYPE => $shippingTableRate->getCode()]],
93 | ],
94 | 'channels' => [$channel],
95 | ]);
96 |
97 | $this->shippingMethodRepository->add($shippingMethod);
98 | }
99 |
100 | private function getShippingZone(): ZoneInterface
101 | {
102 | if ($this->sharedStorage->has('shipping_zone')) {
103 | return $this->sharedStorage->get('shipping_zone');
104 | }
105 |
106 | return $this->sharedStorage->get('zone');
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/tests/Behat/Context/Transform/NumberContext.php:
--------------------------------------------------------------------------------
1 | 0,
13 | 'one' => 1,
14 | 'two' => 2,
15 | 'three' => 3,
16 | ];
17 |
18 | /**
19 | * @Transform :number
20 | */
21 | public function transformNumber(string $number): int
22 | {
23 | if (is_numeric($number)) {
24 | return (int) $number;
25 | }
26 | if (!\array_key_exists($number, self::STRING_TO_INT)) {
27 | throw new \RuntimeException("Can't transform the number '$number' to integer. It's to big.");
28 | }
29 |
30 | return self::STRING_TO_INT[$number];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Behat/Context/Ui/ManagingShippingMethodsWithTableRateContext.php:
--------------------------------------------------------------------------------
1 | updatePage->getTableRateOptions($channel->getCode());
29 | Assert::count($options, 1);
30 | Assert::eq($options[0]->getAttribute('value'), $shippingTableRate->getCode());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Behat/Context/Ui/ManagingTableRatesContext.php:
--------------------------------------------------------------------------------
1 | indexPage->open();
35 | }
36 |
37 | /**
38 | * @Then I should see :number table rate(s) in the list
39 | */
40 | public function iShouldSeeZeroTableRatesInTheList(int $number = 0)
41 | {
42 | Assert::same($number, $this->indexPage->countItems());
43 | }
44 |
45 | /**
46 | * @Then I should see the :shippingTableRate table rate in the list
47 | */
48 | public function iShouldSeeTheTableRateInTheList(ShippingTableRate $shippingTableRate)
49 | {
50 | Assert::true($this->indexPage->isSingleResourceOnPage(['name' => $shippingTableRate->getName()]));
51 | }
52 |
53 | /**
54 | * @When I add a shipping table rate named :name for currency :currency
55 | */
56 | public function iAddAShippingTableRateNamedForCurrency(string $name, CurrencyInterface $currency)
57 | {
58 | $this->createPage->open();
59 | $this->createPage->fillCode(StringInflector::nameToUppercaseCode($name));
60 | $this->createPage->fillName($name);
61 | $this->createPage->fillCurrency($currency);
62 | $this->createPage->addRate(random_int(1, 10), random_int(500, 1000));
63 | $this->createPage->create();
64 | }
65 |
66 | /**
67 | * @When I delete the :shippingTableRate table rate
68 | */
69 | public function iDeleteTheTableRate(ShippingTableRate $shippingTableRate)
70 | {
71 | $this->indexPage->deleteResourceOnPage(['name' => $shippingTableRate->getName()]);
72 | }
73 |
74 | /**
75 | * @Given I want to modify the :shippingTableRate table rate
76 | */
77 | public function iWantToModifyTheTableRate(ShippingTableRate $shippingTableRate): void
78 | {
79 | $this->updatePage->open(['id' => $shippingTableRate->getId()]);
80 | }
81 |
82 | /**
83 | * @When I save my changes
84 | */
85 | public function iSaveMyChanges()
86 | {
87 | $this->updatePage->saveChanges();
88 | }
89 |
90 | /**
91 | * @When I change its code to :code
92 | */
93 | public function iChangeItsCodeTo(string $code)
94 | {
95 | $this->createPage->fillCode($code);
96 | }
97 |
98 | /**
99 | * @When I change its name to :name
100 | */
101 | public function iChangeItsNameTo(string $name)
102 | {
103 | $this->createPage->fillName($name);
104 | }
105 |
106 | /**
107 | * @Then /^(this shipping table rate) name should be "([^"]+)"$/
108 | */
109 | public function thisShippingTableRateNameShouldBe(ShippingTableRate $shippingTableRate, string $code)
110 | {
111 | $this->updatePage->open(['id' => $shippingTableRate->getId()]);
112 | $this->updatePage->hasResourceValues(['name' => $code]);
113 | }
114 |
115 | /**
116 | * @When /^I add a new rate of ("[^"]+") for shipments up to (\d+) kg$/
117 | */
118 | public function iAddANewRateOfForShipmentsUpToKg(int $rate, int $weightLimit): void
119 | {
120 | $this->updatePage->addRate($rate, $weightLimit);
121 | }
122 |
123 | /**
124 | * @Then /^(this shipping table rate) should have (\d+) rates$/
125 | */
126 | public function thisShippingTableRateShouldHaveRates(ShippingTableRate $shippingTableRate, int $count)
127 | {
128 | $this->indexPage->open();
129 |
130 | Assert::eq($this->indexPage->getTableRateRatesCount($shippingTableRate), $count);
131 | }
132 |
133 | /**
134 | * @When I try to add a new shipping table
135 | */
136 | public function iTryToAddANewShippingTable()
137 | {
138 | $this->createPage->open();
139 | }
140 |
141 | /**
142 | * @When I specify its code as :code
143 | */
144 | public function iSpecifyItsCodeAs(string $code)
145 | {
146 | $this->createPage->fillCode($code);
147 | }
148 |
149 | /**
150 | * @When I specify its currency as :currency
151 | */
152 | public function iSpecifyItsCurrencyAs(CurrencyInterface $currency)
153 | {
154 | $this->createPage->fillCurrency($currency);
155 | }
156 |
157 | /**
158 | * @When I do not specify its name
159 | */
160 | public function iDoNotSpecifyItsName()
161 | {
162 | $this->createPage->fillName('');
163 | }
164 |
165 | /**
166 | * @When I try to add it
167 | */
168 | public function iTryToAddIt()
169 | {
170 | $this->createPage->create();
171 | }
172 |
173 | /**
174 | * @Then I should be notified that :element is required
175 | */
176 | public function iShouldBeNotifiedThatIsRequired($element)
177 | {
178 | Assert::same($this->createPage->getValidationMessage($element), 'This value should not be blank.');
179 | }
180 |
181 | /**
182 | * @When I specify its name as :name
183 | */
184 | public function iSpecifyItsNameAs(string $name)
185 | {
186 | $this->createPage->fillName($name);
187 | }
188 |
189 | /**
190 | * @When I do not specify its code
191 | */
192 | public function iDoNotSpecifyItsCode()
193 | {
194 | $this->createPage->fillCode('');
195 | }
196 |
197 | /**
198 | * @When I do not specify its currency
199 | */
200 | public function iDoNotSpecifyItsCurrency()
201 | {
202 | $this->createPage->fillCurrency(null);
203 | }
204 |
205 | /**
206 | * @When I do not specify any rate
207 | */
208 | public function iDoNotSpecifyAnyRate()
209 | {
210 | // Simply we don't add the rate
211 | }
212 |
213 | /**
214 | * @Then I should be notified that at least one rate is required
215 | */
216 | public function iShouldBeNotifiedThatAtLeastOneRateIsRequired()
217 | {
218 | Assert::same(
219 | $this->createPage->getFormValidationMessage(),
220 | 'You should specify at least one rate for this table rate.',
221 | );
222 | }
223 |
224 | /**
225 | * @Then the code field should be disabled
226 | */
227 | public function theCodeFieldShouldBeDisabled()
228 | {
229 | Assert::true($this->updatePage->isCodeDisabled());
230 | }
231 |
232 | /**
233 | * @Then the :shippingTableRate table rate should still have code :code
234 | */
235 | public function theShippingTableRateShouldStillHaveCode(ShippingTableRate $shippingTableRate, string $code)
236 | {
237 | Assert::eq($shippingTableRate->getCode(), $code);
238 | }
239 |
240 | /**
241 | * @Then the currency field should be disabled
242 | */
243 | public function theCurrencyFieldShouldBeDisabled()
244 | {
245 | Assert::true($this->updatePage->isCurrencyDisabled());
246 | }
247 |
248 | /**
249 | * @When I change its currency to :currency
250 | */
251 | public function iChangeItsCurrencyTo(CurrencyInterface $currency)
252 | {
253 | $this->createPage->fillCurrency($currency);
254 | }
255 |
256 | /**
257 | * @Then the :shippingTableRate table rate should still have :currency currency
258 | */
259 | public function theTableRateShouldStillHaveCurrency(
260 | ShippingTableRate $shippingTableRate,
261 | CurrencyInterface $currency,
262 | ) {
263 | Assert::same($shippingTableRate->getCurrency()->getCode(), $currency->getCode());
264 | }
265 |
266 | /**
267 | * @Then I should be notified that code has to be unique
268 | */
269 | public function iShouldBeNotifiedThatCodeHasToBeUnique()
270 | {
271 | $this->createPage->getValidationMessage(
272 | 'code',
273 | 'There\'s another shipping table rate with the same code. The code has to be unique.',
274 | );
275 | }
276 |
277 | /**
278 | * @Then I should be notified that the table rate couldn't be deleted because is already used by the :shippingMethod shipping method
279 | */
280 | public function iShouldBeNotifiedThatTheTableRateCouldntBeDeletedBecauseIsAlreadyUsedByTheShippingMethod(
281 | ShippingMethod $shippingMethod,
282 | ) {
283 | Assert::contains(
284 | $this->indexPage->getValidationMessage(),
285 | 'The table rate cannot be deleted because is currently used by the following shipping methods: ' .
286 | $shippingMethod->getCode(),
287 | );
288 | }
289 |
290 | /**
291 | * @Then the :shippingTableRate shipping table rate should still be there
292 | */
293 | public function theShippingTableRateShouldStillBeThere(ShippingTableRate $shippingTableRate)
294 | {
295 | Assert::true($this->indexPage->isSingleResourceOnPage(['name' => $shippingTableRate->getName()]));
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/tests/Behat/Context/Ui/ShippingTableRateContext.php:
--------------------------------------------------------------------------------
1 | addressPage->open();
29 | $this->addressPage->specifyBillingAddress($this->createDefaultAddress());
30 | $this->addressPage->nextStep();
31 |
32 | $this->selectShippingPage->verify();
33 | Assert::true($this->selectShippingPage->hasNoShippingMethodsMessage());
34 | }
35 |
36 | private function createDefaultAddress(): AddressInterface
37 | {
38 | /** @var AddressInterface $address */
39 | $address = $this->addressFactory->createNew();
40 | $address->setFirstName('John');
41 | $address->setLastName('Doe');
42 | $address->setCountryCode('US');
43 | $address->setCity('North Bridget');
44 | $address->setPostcode('93-554');
45 | $address->setStreet('0635 Myron Hollow Apt. 711');
46 | $address->setPhoneNumber('321123456');
47 |
48 | return $address;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/Behat/Page/ShippingMethod/UpdatePage.php:
--------------------------------------------------------------------------------
1 | getElement('table_rate', ['%channelCode%' => $channelCode])->findAll(
14 | 'css',
15 | 'option[value!=""]',
16 | );
17 | }
18 |
19 | protected function getDefinedElements(): array
20 | {
21 | return array_merge(
22 | parent::getDefinedElements(),
23 | ['table_rate' => '#sylius_shipping_method_configuration_%channelCode%_table_rate'],
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Behat/Page/ShippingMethod/UpdatePageInterface.php:
--------------------------------------------------------------------------------
1 | 'form[name="webgriffe_sylius_table_rate_plugin_shipping_table_rate"]',
16 | 'code' => '#webgriffe_sylius_table_rate_plugin_shipping_table_rate_code',
17 | 'name' => '#webgriffe_sylius_table_rate_plugin_shipping_table_rate_name',
18 | 'currency' => '#webgriffe_sylius_table_rate_plugin_shipping_table_rate_currency',
19 | 'weightLimitToRate' => '#webgriffe_sylius_table_rate_plugin_shipping_table_rate_weightLimitToRate',
20 | ];
21 | }
22 |
23 | protected function getDefinedElements(): array
24 | {
25 | return array_merge(
26 | parent::getDefinedElements(),
27 | self::getCreateUpdatePageDefinedElements(),
28 | );
29 | }
30 |
31 | public function fillCode(string $code)
32 | {
33 | $this->getDocument()->fillField('Code', $code);
34 | }
35 |
36 | public function fillName(string $name)
37 | {
38 | $this->getDocument()->fillField('Name', $name);
39 | }
40 |
41 | public function fillCurrency(?CurrencyInterface $currency)
42 | {
43 | $this->getDocument()->selectFieldOption('Currency', $currency ? $currency->getCode() : '');
44 | }
45 |
46 | public function getFormValidationMessage(): string
47 | {
48 | return trim($this->getElement('form')->find('css', '.sylius-validation-error')->getText());
49 | }
50 |
51 | public function addRate(int $rate, int $weightLimit)
52 | {
53 | $weightLimitToRateField = $this->getDocument()->findById(
54 | 'webgriffe_sylius_table_rate_plugin_shipping_table_rate_weightLimitToRate',
55 | );
56 | $addRateButton = $weightLimitToRateField->findLink('Add');
57 | $addRateButton->click();
58 | $item = $weightLimitToRateField->find('css', '[data-form-collection=item]:last-child');
59 | $item->fillField('Weight limit', $weightLimit);
60 | $item->fillField('Rate', $rate / 100);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tests/Behat/Page/TableRate/CreatePageInterface.php:
--------------------------------------------------------------------------------
1 | getTableAccessor();
15 | $table = $this->getElement('table');
16 |
17 | $row = $tableAccessor->getRowWithFields($table, ['code' => $shippingTableRate->getCode()]);
18 | $rates = $tableAccessor->getFieldFromRow($table, $row, 'rates_count');
19 |
20 | return (int) $rates->getText();
21 | }
22 |
23 | public function getValidationMessage(): string
24 | {
25 | return $this->getDocument()->find('css', '.sylius-flash-message.negative')->getText();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Behat/Page/TableRate/IndexPageInterface.php:
--------------------------------------------------------------------------------
1 | getDocument()->findById(
26 | 'webgriffe_sylius_table_rate_plugin_shipping_table_rate_weightLimitToRate',
27 | );
28 | $addRateButton = $weightLimitToRateField->findLink('Add');
29 | $addRateButton->click();
30 | $item = $weightLimitToRateField->find('css', '[data-form-collection=item]:last-child');
31 | $item->fillField('Weight limit', $weightLimit);
32 | $item->fillField('Rate', $rate / 100);
33 | }
34 |
35 | /**
36 | * @throws \Behat\Mink\Exception\ElementNotFoundException
37 | */
38 | protected function getCodeElement(): NodeElement
39 | {
40 | return $this->getElement('code');
41 | }
42 |
43 | /**
44 | * @throws \Behat\Mink\Exception\ElementNotFoundException
45 | */
46 | public function isCurrencyDisabled(): bool
47 | {
48 | return $this->getElement('currency')->getAttribute('disabled') === 'disabled';
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/Behat/Page/TableRate/UpdatePageInterface.php:
--------------------------------------------------------------------------------
1 |