├── .docker ├── nginx │ └── nginx.conf └── php │ └── php.ini ├── .editorconfig ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ └── build.yml ├── .gitignore ├── CHANGELOG-1.0.md ├── Makefile ├── README.md ├── behat.yml.dist ├── bin └── create_node_symlink.php ├── composer.json ├── config ├── admin_routing.yaml ├── config.yaml ├── doctrine │ ├── AttachedFile.orm.xml │ ├── Comment.orm.xml │ └── Email.orm.xml ├── routing │ ├── admin │ │ └── order_comments.yaml │ └── shop │ │ └── order_comments.yaml ├── services.xml └── shop_routing.yaml ├── docker-compose.yml ├── ecs.php ├── etc └── build │ └── .gitignore ├── features ├── attaching_file_to_comment.feature ├── commenting_an_order_by_a_customer.feature ├── commenting_an_order_by_an_administrator.feature ├── sorting_administrator_comments.feature └── sorting_customer_comments.feature ├── node_modules ├── phpspec.yml.dist ├── phpstan.neon ├── phpunit.xml.dist ├── psalm.xml ├── src ├── Application │ ├── Command │ │ └── CommentOrder.php │ ├── CommandHandler │ │ └── CommentOrderHandler.php │ └── Process │ │ ├── SendUnreadCommentEmailNotification.php │ │ ├── SendUnreadCommentEmailNotificationInterface.php │ │ └── Sender │ │ ├── ChanneledEmailSender.php │ │ └── ChanneledEmailSenderInterface.php ├── Brille24SyliusOrderCommentsPlugin.php ├── DependencyInjection │ ├── Brille24SyliusOrderCommentsExtension.php │ └── Configuration.php ├── Domain │ ├── Event │ │ ├── FileAttached.php │ │ └── OrderCommented.php │ └── Model │ │ ├── AttachedFile.php │ │ ├── Comment.php │ │ └── Email.php └── Infrastructure │ ├── Controller │ └── Ui │ │ ├── OrderCommentAction.php │ │ └── RenderOrderCommentAction.php │ ├── Form │ ├── DTO │ │ └── OrderComment.php │ └── Type │ │ └── OrderCommentType.php │ └── Migrations │ └── Version20230317140309.php ├── templates ├── Email │ └── unread_comment.html.twig ├── _form.html.twig ├── index.html.twig └── injected │ ├── admin_order_comments.html.twig │ └── shop_order_comments.html.twig ├── 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 │ │ │ └── webpack_encore.yaml │ │ ├── routes.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 │ │ ├── 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 │ ├── templates │ │ └── .gitignore │ ├── translations │ │ └── .gitignore │ └── webpack.config.js ├── Behat │ ├── Context │ │ ├── Application │ │ │ ├── AdministratorOrderCommentsContext.php │ │ │ └── CustomerOrderCommentsContext.php │ │ ├── Common │ │ │ └── ChannelContext.php │ │ ├── Domain │ │ │ ├── AdministratorOrderCommentsContext.php │ │ │ └── CustomerOrderCommentsContext.php │ │ └── UI │ │ │ ├── AdministratorOrderCommentsContext.php │ │ │ └── CustomerOrderCommentsContext.php │ ├── Element │ │ ├── Element.php │ │ ├── OrderCommentFormElement.php │ │ ├── OrderCommentFormElementInterface.php │ │ ├── OrderCommentsElement.php │ │ └── OrderCommentsElementInterface.php │ └── Resources │ │ ├── services.xml │ │ ├── suites.yml │ │ └── suites │ │ ├── application │ │ ├── administrator_order_comments.yml │ │ └── customer_order_comments.yml │ │ ├── domain │ │ ├── administrator_order_comments.yml │ │ └── customer_order_comments.yml │ │ └── ui │ │ ├── administrator_order_comments.yml │ │ └── customer_order_comments.yml └── Comments │ ├── Application │ ├── Command │ │ └── CommentOrderTest.php │ └── Process │ │ └── ChanneledEmailSenderTest.php │ ├── Domain │ ├── Event │ │ ├── FileAttachedTest.php │ │ └── OrderCommentedTest.php │ └── Model │ │ ├── AttachedFileTest.php │ │ ├── CommentTest.php │ │ └── EmailTest.php │ └── Infrastructure │ └── Form │ └── Type │ ├── file.pdf │ └── text.txt └── translations ├── messages.de.yml └── messages.en.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 | 2 | # EditorConfig helps developers define and maintain consistent 3 | # coding styles between different editors and IDEs 4 | # editorconfig.org 5 | 6 | root = true 7 | 8 | [*] 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 4 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.feature] 20 | indent_style = space 21 | indent_size = 4 22 | 23 | [*.js] 24 | indent_style = space 25 | indent_size = 2 26 | 27 | [*.json] 28 | indent_style = space 29 | indent_size = 2 30 | 31 | [*.md] 32 | indent_style = space 33 | indent_size = 4 34 | trim_trailing_whitespace = false 35 | 36 | [*.neon] 37 | indent_style = space 38 | indent_size = 4 39 | 40 | [*.php] 41 | indent_style = space 42 | indent_size = 4 43 | 44 | [*.sh] 45 | indent_style = space 46 | indent_size = 4 47 | 48 | [*.{yaml,yml}] 49 | indent_style = space 50 | indent_size = 4 51 | trim_trailing_whitespace = false 52 | 53 | [.babelrc] 54 | indent_style = space 55 | indent_size = 2 56 | 57 | [.gitmodules] 58 | indent_style = tab 59 | indent_size = 4 60 | 61 | [.php_cs{,.dist}] 62 | indent_style = space 63 | indent_size = 4 64 | 65 | [composer.json] 66 | indent_style = space 67 | indent_size = 4 68 | 69 | [package.json] 70 | indent_style = space 71 | indent_size = 2 72 | 73 | [phpspec.yml{,.dist}] 74 | indent_style = space 75 | indent_size = 4 76 | 77 | [phpstan.neon] 78 | indent_style = space 79 | indent_size = 4 80 | 81 | [phpunit.xml{,.dist}] 82 | indent_style = space 83 | indent_size = 4 84 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @Sylius/core-team 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: composer 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: vimeo/psalm 11 | versions: 12 | - 4.5.0 13 | - 4.5.1 14 | - 4.5.2 15 | - 4.6.0 16 | - 4.6.1 17 | - 4.6.2 18 | - 4.6.3 19 | - 4.7.0 20 | - 4.7.1 21 | - dependency-name: phpstan/phpstan 22 | versions: 23 | - 0.12.70 24 | - 0.12.71 25 | - 0.12.73 26 | - 0.12.75 27 | - 0.12.76 28 | - 0.12.77 29 | - 0.12.78 30 | - 0.12.80 31 | - 0.12.81 32 | - 0.12.83 33 | - 0.12.84 34 | - dependency-name: sylius-labs/coding-standard 35 | versions: 36 | - 4.0.2 37 | - dependency-name: phpstan/phpstan-doctrine 38 | versions: 39 | - 0.12.32 40 | - dependency-name: phpstan/phpstan-webmozart-assert 41 | versions: 42 | - 0.12.10 43 | - 0.12.11 44 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - 'dependabot/**' 7 | pull_request: 8 | branches: 9 | - master 10 | release: 11 | types: [created] 12 | schedule: 13 | - 14 | cron: "0 1 * * 6" # Run at 1am every Saturday 15 | workflow_dispatch: ~ 16 | 17 | jobs: 18 | tests: 19 | runs-on: ubuntu-latest 20 | 21 | name: "Sylius ${{ matrix.sylius }}, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MySQL ${{ matrix.mysql }}" 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | php: ["8.0", "8.1"] 27 | symfony: ["5.4.*", "^6.0"] 28 | sylius: ["^1.11"] 29 | node: ["14.x", "16.x", "18.x"] 30 | mysql: ["5.7", "8.0"] 31 | 32 | env: 33 | APP_ENV: test 34 | DATABASE_URL: "mysql://root:root@127.0.0.1/sylius?serverVersion=${{ matrix.mysql }}" 35 | 36 | steps: 37 | - 38 | uses: actions/checkout@v2 39 | 40 | - 41 | name: Setup PHP 42 | uses: shivammathur/setup-php@v2 43 | with: 44 | php-version: "${{ matrix.php }}" 45 | extensions: intl 46 | tools: flex,symfony 47 | coverage: none 48 | 49 | - 50 | name: Setup Node 51 | uses: actions/setup-node@v1 52 | with: 53 | node-version: "${{ matrix.node }}" 54 | 55 | - 56 | name: Shutdown default MySQL 57 | run: sudo service mysql stop 58 | 59 | - 60 | name: Setup MySQL 61 | uses: mirromutth/mysql-action@v1.1 62 | with: 63 | mysql version: "${{ matrix.mysql }}" 64 | mysql root password: "root" 65 | 66 | - 67 | name: Output PHP version for Symfony CLI 68 | run: php -v | head -n 1 | awk '{ print $2 }' > .php-version 69 | 70 | - 71 | name: Install certificates 72 | run: symfony server:ca:install 73 | 74 | - 75 | name: Run Chrome Headless 76 | 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 & 77 | 78 | - 79 | name: Run webserver 80 | run: (cd tests/Application && symfony server:start --port=8080 --dir=public --daemon) 81 | 82 | - 83 | name: Get Composer cache directory 84 | id: composer-cache 85 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 86 | 87 | - 88 | name: Cache Composer 89 | uses: actions/cache@v2 90 | with: 91 | path: ${{ steps.composer-cache.outputs.dir }} 92 | key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json **/composer.lock') }} 93 | restore-keys: | 94 | ${{ runner.os }}-php-${{ matrix.php }}-composer- 95 | 96 | - 97 | name: Configure global composer 98 | run: | 99 | composer global config --no-plugins allow-plugins.symfony/flex true 100 | composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^2.2.2" 101 | 102 | - 103 | name: Restrict Symfony version 104 | if: matrix.symfony != '' 105 | run: | 106 | composer config extra.symfony.require "${{ matrix.symfony }}" 107 | 108 | - 109 | name: Restrict Sylius version 110 | if: matrix.sylius != '' 111 | run: composer require "sylius/sylius:${{ matrix.sylius }}" --no-update --no-scripts --no-interaction 112 | 113 | - 114 | name: Install PHP dependencies 115 | run: composer install --no-interaction 116 | env: 117 | SYMFONY_REQUIRE: ${{ matrix.symfony }} 118 | 119 | - 120 | name: Get Yarn cache directory 121 | id: yarn-cache 122 | run: echo "::set-output name=dir::$(yarn cache dir)" 123 | 124 | - 125 | name: Cache Yarn 126 | uses: actions/cache@v2 127 | with: 128 | path: ${{ steps.yarn-cache.outputs.dir }} 129 | key: ${{ runner.os }}-node-${{ matrix.node }}-yarn-${{ hashFiles('**/package.json **/yarn.lock') }} 130 | restore-keys: | 131 | ${{ runner.os }}-node-${{ matrix.node }}-yarn- 132 | 133 | - 134 | name: Install JS dependencies 135 | run: (cd tests/Application && yarn install) 136 | 137 | - 138 | name: Prepare test application database 139 | run: | 140 | (cd tests/Application && bin/console doctrine:database:create -vvv) 141 | (cd tests/Application && bin/console doctrine:schema:create -vvv) 142 | 143 | - 144 | name: Prepare test application assets 145 | run: | 146 | (cd tests/Application && bin/console assets:install public -vvv) 147 | (cd tests/Application && yarn build:prod) 148 | 149 | - 150 | name: Prepare test application cache 151 | run: (cd tests/Application && bin/console cache:warmup -vvv) 152 | 153 | - 154 | name: Load fixtures in test application 155 | run: (cd tests/Application && bin/console sylius:fixtures:load -n) 156 | 157 | - 158 | name: Validate composer.json 159 | run: composer validate --ansi --strict 160 | 161 | - 162 | name: Validate database schema 163 | run: (cd tests/Application && bin/console doctrine:schema:validate) 164 | 165 | - 166 | name: Run PHPStan 167 | run: vendor/bin/phpstan analyse -c phpstan.neon -l max src/ 168 | 169 | - 170 | name: Run Psalm 171 | run: vendor/bin/psalm 172 | 173 | - 174 | name: Run PHPSpec 175 | run: vendor/bin/phpspec run --ansi -f progress --no-interaction 176 | 177 | - 178 | name: Run PHPUnit 179 | run: vendor/bin/phpunit --colors=always 180 | 181 | - 182 | name: Run Behat 183 | run: vendor/bin/behat --colors --strict -vvv --no-interaction || vendor/bin/behat --colors --strict -vvv --no-interaction --rerun 184 | 185 | - 186 | name: Upload Behat logs 187 | uses: actions/upload-artifact@v2 188 | if: failure() 189 | with: 190 | name: Behat logs 191 | path: etc/build/ 192 | if-no-files-found: ignore 193 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /CHANGELOG-1.0.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG FOR `1.0.X` 2 | 3 | ## v1.0.0-alpha 4 | 5 | #### Details 6 | 7 | ### Changed 8 | - [#57](https://github.com/Sylius/SyliusOrderCommentsPlugin/issues/57) [Maintenance] Fix branch alias ([@lchrusciel](https://github.com/lchrusciel)) 9 | - [#58](https://github.com/Sylius/SyliusOrderCommentsPlugin/issues/58) Sylius 1.3 support ([@JakobTolkemit](https://github.com/JakobTolkemit)) 10 | -------------------------------------------------------------------------------- /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 |

Plugin Skeleton

2 | 3 |

Adding comments to a Sylius order with customer notification.

4 | 5 | ![Workflow](https://github.com/Brille24/SyliusOrderCommentsPlugin/actions/workflows/build.yml/badge.svg) 6 | 7 | ![UI Example](https://user-images.githubusercontent.com/14860264/144292467-52745b86-dfa1-467f-98e7-f4311a8b86b3.png) 8 | 9 | 10 | ## Installation 11 | 1. Run `composer require brille24/sylius-order-comments-plugin` 12 | 2. Updating the database with migrations 13 | ```bash 14 | bin/console doctrine:mig:diff 15 | bin/console doctrine:mig:mig 16 | ``` 17 | 18 | ## Testing & Development 19 | For information on how to develop to test this plugin please refer to the official Sylius documentation under https://github.com/Sylius/PluginSkeleton/ . 20 | -------------------------------------------------------------------------------- /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 | extensions: 7 | DMore\ChromeExtension\Behat\ServiceContainer\ChromeExtension: ~ 8 | 9 | FriendsOfBehat\MinkDebugExtension: 10 | directory: etc/build 11 | clean_start: false 12 | screenshot: true 13 | 14 | Behat\MinkExtension: 15 | files_path: "%paths.base%/vendor/sylius/sylius/src/Sylius/Behat/Resources/fixtures/" 16 | base_url: "https://127.0.0.1:8080/" 17 | default_session: symfony 18 | javascript_session: chrome_headless 19 | sessions: 20 | symfony: 21 | symfony: ~ 22 | chrome_headless: 23 | chrome: 24 | api_url: http://127.0.0.1:9222 25 | validate_certificate: false 26 | chrome: 27 | selenium2: 28 | browser: chrome 29 | capabilities: 30 | browserName: chrome 31 | browser: chrome 32 | version: "" 33 | marionette: null # https://github.com/Behat/MinkExtension/pull/311 34 | chrome: 35 | switches: 36 | - "start-fullscreen" 37 | - "start-maximized" 38 | - "no-sandbox" 39 | extra_capabilities: 40 | unexpectedAlertBehaviour: accept 41 | firefox: 42 | selenium2: 43 | browser: firefox 44 | show_auto: false 45 | 46 | FriendsOfBehat\SymfonyExtension: 47 | bootstrap: tests/Application/config/bootstrap.php 48 | kernel: 49 | class: Tests\Brille24\SyliusOrderCommentsPlugin\Application\Kernel 50 | 51 | FriendsOfBehat\VariadicExtension: ~ 52 | 53 | FriendsOfBehat\SuiteSettingsExtension: 54 | paths: 55 | - "features" 56 | -------------------------------------------------------------------------------- /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": "brille24/sylius-order-comments-plugin", 3 | "type": "sylius-plugin", 4 | "description": "Order comments plugin for Sylius.", 5 | "keywords": [ 6 | "brille24", 7 | "sylius", 8 | "sylius-plugin" 9 | ], 10 | "license": "MIT", 11 | "require": { 12 | "php": "^8.0", 13 | "ramsey/uuid": "^3.9 || ^4.7", 14 | "ramsey/uuid-doctrine": "^1.4 || ^2.0.0", 15 | "sylius/mailer-bundle": "^1.8 || ^2.0@beta", 16 | "sylius/sylius": "^1.11", 17 | "symfony/webpack-encore-bundle": "^1.15" 18 | }, 19 | "require-dev": { 20 | "behat/behat": "^3.6.1", 21 | "behat/mink-selenium2-driver": "^1.4", 22 | "dmore/behat-chrome-extension": "^1.3", 23 | "dmore/chrome-mink-driver": "^2.7", 24 | "friends-of-behat/mink": "^1.8", 25 | "friends-of-behat/mink-browserkit-driver": "^1.4", 26 | "friends-of-behat/mink-debug-extension": "^2.0.0", 27 | "friends-of-behat/mink-extension": "^2.4", 28 | "friends-of-behat/page-object-extension": "^0.3", 29 | "friends-of-behat/suite-settings-extension": "^1.0", 30 | "friends-of-behat/symfony-extension": "^2.1", 31 | "friends-of-behat/variadic-extension": "^1.3", 32 | "phpspec/phpspec": "^7.2", 33 | "phpstan/extension-installer": "^1.0", 34 | "phpstan/phpstan": "^1.8.1", 35 | "phpstan/phpstan-doctrine": "1.3.37", 36 | "phpstan/phpstan-strict-rules": "^1.3.0", 37 | "phpstan/phpstan-webmozart-assert": "^1.2.0", 38 | "phpunit/phpunit": "^9.5", 39 | "polishsymfonycommunity/symfony-mocker-container": "^1.0", 40 | "sylius-labs/coding-standard": "^4.2", 41 | "symfony/browser-kit": "^5.4 || ^6.0", 42 | "symfony/debug-bundle": "^5.4 || ^6.0", 43 | "symfony/dotenv": "^5.4 || ^6.0", 44 | "symfony/flex": "^2.2.2", 45 | "symfony/intl": "^5.4 || ^6.0", 46 | "symfony/web-profiler-bundle": "^5.4 || ^6.0", 47 | "vimeo/psalm": "5.9.0" 48 | }, 49 | "config": { 50 | "sort-packages": true, 51 | "allow-plugins": { 52 | "dealerdirect/phpcodesniffer-composer-installer": false, 53 | "phpstan/extension-installer": true, 54 | "symfony/flex": true 55 | } 56 | }, 57 | "extra": { 58 | "branch-alias": { 59 | "dev-master": "1.12-dev" 60 | } 61 | }, 62 | "autoload": { 63 | "psr-4": { 64 | "Brille24\\OrderCommentsPlugin\\": "src/", 65 | "Tests\\Brille24\\OrderCommentsPlugin\\": "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 | "auto-scripts": { 84 | "cache:clear": "symfony-cmd", 85 | "assets:install %PUBLIC_DIR%": "symfony-cmd", 86 | "security-checker security:check": "script" 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /config/admin_routing.yaml: -------------------------------------------------------------------------------- 1 | sylius_order_comments_plugin_admin_partial: 2 | resource: "@Brille24SyliusOrderCommentsPlugin/config/routing/admin/order_comments.yaml" 3 | prefix: "/admin/orders" 4 | -------------------------------------------------------------------------------- /config/config.yaml: -------------------------------------------------------------------------------- 1 | doctrine: 2 | dbal: 3 | types: 4 | uuid: 'Ramsey\Uuid\Doctrine\UuidType' 5 | 6 | sylius_mailer: 7 | emails: 8 | unread_comment: 9 | subject: 'sylius.emails.unread_comment.subject' 10 | template: '@Brille24SyliusOrderCommentsPlugin/Email/unread_comment.html.twig' 11 | 12 | knp_gaufrette: 13 | adapters: 14 | sylius_comments_attachment: 15 | local: 16 | directory: '%sylius_core.public_dir%/media/comment_attachments' 17 | create: true 18 | filesystems: 19 | sylius_comments_attachment: 20 | adapter: 'sylius_comments_attachment' 21 | 22 | sylius_ui: 23 | events: 24 | sylius.admin.order.show.summary: 25 | blocks: 26 | order_comments: '@Brille24SyliusOrderCommentsPlugin/injected/admin_order_comments.html.twig' 27 | sylius.shop.account.order.show.subcontent: 28 | blocks: 29 | order_comments: '@Brille24SyliusOrderCommentsPlugin/injected/shop_order_comments.html.twig' 30 | -------------------------------------------------------------------------------- /config/doctrine/AttachedFile.orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /config/doctrine/Comment.orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /config/doctrine/Email.orm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /config/routing/admin/order_comments.yaml: -------------------------------------------------------------------------------- 1 | sylius_admin_order_comments_partial_comment_create: 2 | path: "/{orderId}/comments" 3 | methods: ["POST"] 4 | defaults: 5 | _controller: "brille24.order_comments_plugin.infrastructure.controller.ui.comment_form_action" 6 | 7 | sylius_admin_order_comments_partial_comment_index: 8 | path: "/{orderId}/comments" 9 | methods: ["GET"] 10 | defaults: 11 | _controller: "sylius.controller.order_comment::indexAction" 12 | _sylius: 13 | paginate: false 14 | limit: false 15 | repository: 16 | method: findBy 17 | arguments: 18 | - order: "expr:notFoundOnNull(service('sylius.repository.order').find($orderId))" 19 | - createdAt: asc 20 | template: "@Brille24SyliusOrderCommentsPlugin/index.html.twig" 21 | isAdmin: true 22 | -------------------------------------------------------------------------------- /config/routing/shop/order_comments.yaml: -------------------------------------------------------------------------------- 1 | sylius_shop_order_comments_partial_comment_create: 2 | path: "/{orderId}/comments" 3 | methods: ["POST"] 4 | defaults: 5 | _controller: "brille24.order_comments_plugin.infrastructure.controller.ui.comment_form_action" 6 | 7 | sylius_shop_order_comments_partial_comment_index: 8 | path: "/{number}/comments" 9 | methods: ["GET"] 10 | defaults: 11 | _controller: "sylius.controller.order_comment::indexAction" 12 | _sylius: 13 | paginate: false 14 | limit: false 15 | repository: 16 | method: findBy 17 | arguments: 18 | - order: "expr:notFoundOnNull(service('sylius.repository.order').findOneByNumber($number))" 19 | - createdAt: asc 20 | template: "@Brille24SyliusOrderCommentsPlugin/index.html.twig" 21 | isAdmin: false 22 | -------------------------------------------------------------------------------- /config/services.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | media/comment_attachments 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 42 | 43 | 44 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /config/shop_routing.yaml: -------------------------------------------------------------------------------- 1 | sylius_order_comments_plugin_shop_partial: 2 | resource: "@Brille24SyliusOrderCommentsPlugin/config/routing/shop/order_comments.yaml" 3 | prefix: "/shop/orders" 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/etc/build/.gitignore -------------------------------------------------------------------------------- /features/attaching_file_to_comment.feature: -------------------------------------------------------------------------------- 1 | @customer_order_comments 2 | Feature: Attaching file to comment 3 | In order to provide ability to attach file to comment 4 | As a Customer 5 | I want to be able to communicate with the store owner via order comments with more details 6 | 7 | Background: 8 | Given the store operates on a single channel in "United States" 9 | And this channel has "customer.service@test.com" as a contact email 10 | And the store has a product "PHP T-Shirt" 11 | And the store ships everywhere for free 12 | And the store allows paying with "Cash on Delivery" 13 | And there was account of "john.doe@gmail.com" with password "sylius" 14 | And there is a customer "john.doe@gmail.com" that placed an order "#00000022" 15 | And the customer bought a single "PHP T-Shirt" 16 | And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment 17 | And I am logged in as "john.doe@gmail.com" 18 | 19 | @domain @application @ui 20 | Scenario: Attaching file to comment 21 | When I comment the order "#00000022" with "Hello" and "file.pdf" file 22 | Then this order should have a comment with "Hello" and file "file.pdf" from this customer 23 | -------------------------------------------------------------------------------- /features/commenting_an_order_by_a_customer.feature: -------------------------------------------------------------------------------- 1 | @customer_order_comments 2 | Feature: Commenting an order by a customer 3 | In order to provide ability to comment an order 4 | As a Customer 5 | I want to be able to communicate with the store owner via order comments 6 | 7 | Background: 8 | Given the store operates on a single channel in "United States" 9 | And this channel has "customer.service@test.com" as a contact email 10 | And the store has a product "PHP T-Shirt" 11 | And the store ships everywhere for free 12 | And the store allows paying with "Cash on Delivery" 13 | And there was account of "john.doe@gmail.com" with password "sylius" 14 | And there is a customer "john.doe@gmail.com" that placed an order "#00000022" 15 | And the customer bought a single "PHP T-Shirt" 16 | And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment 17 | And I am logged in as "john.doe@gmail.com" 18 | 19 | @domain @application @ui 20 | Scenario: Customer commented an order 21 | When I comment the order "#00000022" with "Hello" 22 | Then this order should have a comment with "Hello" from this customer 23 | 24 | @application @ui 25 | Scenario: Customer commented an order 26 | Given a customer "john.doe@gmail.com" placed an order "#00000023" 27 | And the customer bought a single "PHP T-Shirt" 28 | And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment 29 | When I comment the order "#00000023" with "Hello" 30 | Then this order should have a comment with "Hello" from this customer 31 | But the order "#00000022" should not have any comments 32 | 33 | @domain @application @ui 34 | Scenario: Customer cannot comment an order with an empty message 35 | When I try to comment the order "#00000022" with an empty message 36 | Then I should be notified that comment is invalid 37 | And this order should not have any comments 38 | 39 | @domain @application 40 | Scenario: Customer with invalid email cannot comment an order 41 | When a customer with email "notEmail" try to comment an order "#00000022" 42 | Then I should be notified that comment is invalid 43 | And this order should not have any comments 44 | 45 | @application 46 | Scenario: Customer cannot comment an order which does not exist 47 | When I try to comment a not existing order with "Hello" 48 | Then I should be notified that comment is invalid 49 | And this order should not have any comments 50 | 51 | @application 52 | Scenario: Sending the email notification to the administrator about unread customer's comments 53 | Given I have commented the order "#00000022" with "Hello" 54 | Then the notification email should be sent to the administrator about "Hello" comment 55 | -------------------------------------------------------------------------------- /features/commenting_an_order_by_an_administrator.feature: -------------------------------------------------------------------------------- 1 | @administrator_order_comments 2 | Feature: Commenting an order by an administrator 3 | In order to communicate with the customer that made an order 4 | As an Administrator 5 | I want to be able to add a comment to the order 6 | 7 | Background: 8 | Given the store operates on a single channel in "United States" 9 | And the store has a product "PHP T-Shirt" 10 | And the store ships everywhere for free 11 | And the store allows paying with "Cash on Delivery" 12 | And there was account of "john.doe@test.com" with password "sylius" 13 | And there is a customer "john.doe@test.com" that placed an order "#00000022" 14 | And the customer bought a single "PHP T-Shirt" 15 | And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment 16 | And I am logged in as an administrator 17 | 18 | @domain @application @ui 19 | Scenario: Administrator commented an order 20 | When I comment the order "#00000022" with "How can I help you?" with the notify customer checkbox enabled 21 | Then this order should have a comment with "How can I help you?" from this administrator 22 | 23 | @application @ui 24 | Scenario: Administrator see only related comments 25 | Given a customer "john.doe@test.com" placed an order "#00000023" 26 | And the customer bought a single "PHP T-Shirt" 27 | And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment 28 | When I comment the order "#00000023" with "How can I help you?" with the notify customer checkbox enabled 29 | Then this order should have a comment with "How can I help you?" from this administrator 30 | But the order "#00000022" should not have any comments 31 | 32 | @domain @application @ui 33 | Scenario: Administrator cannot comment the order with an empty message 34 | When I try to comment the order "#00000022" with an empty message 35 | Then I should be notified that comment is invalid 36 | And this order should not have any comments 37 | 38 | @application 39 | Scenario: Sending an email notification to the customer about unread comments 40 | When I have commented the order "#00000022" with "How can I help you?" with the notify customer checkbox enabled 41 | Then the notification email should be sent to the customer about "How can I help you?" comment 42 | 43 | @application 44 | Scenario: Sending no email notification to the customer about unread comments 45 | When I have commented the order "#00000022" with "How can I not help you?" with the notify customer checkbox disabled 46 | Then the notification email should not be sent to the customer about "How can I not help you?" comment 47 | -------------------------------------------------------------------------------- /features/sorting_administrator_comments.feature: -------------------------------------------------------------------------------- 1 | @administrator_order_comments 2 | Feature: Sorting administrator comments 3 | In order to track the conversation properly 4 | As an Administrator 5 | I want to be see comments from the oldest to the newest 6 | 7 | Background: 8 | Given the store operates on a single channel in "United States" 9 | And the store has a product "PHP T-Shirt" 10 | And the store ships everywhere for free 11 | And the store allows paying with "Cash on Delivery" 12 | And there was account of "john.doe@gmail.com" with password "sylius" 13 | And there is a customer "john.doe@gmail.com" that placed an order "#00000022" 14 | And the customer bought a single "PHP T-Shirt" 15 | And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment 16 | And I am logged in as an administrator 17 | 18 | @ui 19 | Scenario: Administrator commented an order 20 | When I have commented the order "#00000022" with "Hello" with the notify customer checkbox enabled 21 | And I have commented the order "#00000022" with "How can I help you?" with the notify customer checkbox enabled 22 | Then the first comment from the top should have the "Hello" message 23 | -------------------------------------------------------------------------------- /features/sorting_customer_comments.feature: -------------------------------------------------------------------------------- 1 | @customer_order_comments 2 | Feature: Sorting customer comments 3 | In order to track the conversation properly 4 | As a Customer 5 | I want to be see comments from the oldest to the newest 6 | 7 | Background: 8 | Given the store operates on a single channel in "United States" 9 | And this channel has "customer.service@test.com" as a contact email 10 | And the store has a product "PHP T-Shirt" 11 | And the store ships everywhere for free 12 | And the store allows paying with "Cash on Delivery" 13 | And there was account of "john.doe@gmail.com" with password "sylius" 14 | And there is a customer "john.doe@gmail.com" that placed an order "#00000022" 15 | And the customer bought a single "PHP T-Shirt" 16 | And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment 17 | And I am logged in as "john.doe@gmail.com" 18 | 19 | @ui 20 | Scenario: Sorting customer comments 21 | Given I have commented the order "#00000022" with "Hello" 22 | And I wait 1 seconds 23 | And I have commented the order "#00000022" with "Is it me you are looking for?" 24 | Then the first comment from the top should have the "Hello" message 25 | -------------------------------------------------------------------------------- /node_modules: -------------------------------------------------------------------------------- 1 | tests/Application/node_modules -------------------------------------------------------------------------------- /phpspec.yml.dist: -------------------------------------------------------------------------------- 1 | suites: 2 | main: 3 | namespace: Brille24\SyliusOrderCommentsPlugin 4 | psr4_prefix: Brille24\SyliusOrderCommentsPlugin 5 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: max 3 | reportUnmatchedIgnoredErrors: false 4 | checkMissingIterableValueType: false 5 | paths: 6 | - src 7 | - tests/Behat 8 | 9 | excludes_analyse: 10 | # Makes PHPStan crash 11 | - 'src/DependencyInjection/Configuration.php' 12 | 13 | # Test dependencies 14 | - 'tests/Application/app/**.php' 15 | - 'tests/Application/src/**.php' 16 | 17 | ignoreErrors: 18 | - '/Parameter #1 \$configuration of method Symfony\\Component\\DependencyInjection\\Extension\\Extension::processConfiguration\(\) expects Symfony\\Component\\Config\\Definition\\ConfigurationInterface, Symfony\\Component\\Config\\Definition\\ConfigurationInterface\|null given\./' 19 | - '/Method Sylius\\Component\\Mailer\\Sender\\SenderInterface\:\:send\(\) invoked with 7 parameters\, 2\-5 required\./' 20 | -------------------------------------------------------------------------------- /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.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Application/Command/CommentOrder.php: -------------------------------------------------------------------------------- 1 | orderNumber; 28 | } 29 | 30 | public function authorEmail(): string 31 | { 32 | return $this->authorEmail; 33 | } 34 | 35 | public function message(): string 36 | { 37 | return $this->message; 38 | } 39 | 40 | public function file(): ?UploadedFile 41 | { 42 | return $this->file; 43 | } 44 | 45 | public function notifyCustomer(): bool 46 | { 47 | return $this->notifyCustomer; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Application/CommandHandler/CommentOrderHandler.php: -------------------------------------------------------------------------------- 1 | orderRepository->findOneBy(['number' => $command->orderNumber()]); 34 | 35 | if (null === $order) { 36 | throw new \DomainException(sprintf('Cannot comment an order "%s" because it does not exist', $command->orderNumber())); 37 | } 38 | 39 | $comment = new Comment($order, $command->authorEmail(), $command->message(), $command->notifyCustomer()); 40 | 41 | $file = $command->file(); 42 | if (null !== $file) { 43 | $extension = $file->guessExtension() ?? 'pdf'; 44 | $newFileName = Uuid::uuid4()->toString().'.'.$extension; 45 | $file->move($this->fileDir, $newFileName); 46 | 47 | $filePath = $comment->attachFile($this->fileDir.'/'.$newFileName); 48 | $this->eventDispatcher->dispatch(FileAttached::occur($filePath)); 49 | } 50 | 51 | $this->eventDispatcher->dispatch(OrderCommented::occur( 52 | $comment->getId(), 53 | $comment->order(), 54 | $comment->authorEmail(), 55 | $comment->message(), 56 | $comment->notifyCustomer(), 57 | $comment->createdAt(), 58 | $comment->attachedFile() 59 | )); 60 | 61 | $this->entityManager->persist($comment); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Application/Process/SendUnreadCommentEmailNotification.php: -------------------------------------------------------------------------------- 1 | 'handleOrderCommented', 25 | ]; 26 | } 27 | 28 | public function handleOrderCommented(OrderCommented $event): void 29 | { 30 | if (!$event->notifyCustomer()) { 31 | return; 32 | } 33 | 34 | $order = $event->order(); 35 | $customer = $order->getCustomer(); 36 | 37 | if (null === $customer) { 38 | return; 39 | } 40 | 41 | /** @var ChannelInterface $channel */ 42 | $channel = $order->getChannel(); 43 | 44 | $recipients = [$channel->getContactEmail(), $customer->getEmail()]; 45 | 46 | $this->sendUnreadCommentNotification( 47 | array_diff(array_filter($recipients), [$event->authorEmail()]), 48 | $order, 49 | $event->message(), 50 | (string) $event->authorEmail(), 51 | $event->attachedFile() 52 | ); 53 | } 54 | 55 | /** 56 | * @param array $recipients 57 | */ 58 | private function sendUnreadCommentNotification( 59 | array $recipients, 60 | OrderInterface $order, 61 | string $message, 62 | string $authorEmail, 63 | ?AttachedFile $attachedFile 64 | ): void { 65 | $attachments = ($attachedFile === null) ? [] : [$attachedFile->path() ?? '']; 66 | 67 | $orderChannel = $order->getChannel(); 68 | Assert::isInstanceOf($orderChannel, ChannelInterface::class); 69 | 70 | $orderChannelCode = $orderChannel->getCode(); 71 | Assert::notNull($orderChannelCode); 72 | 73 | $this->emailSender->sendWithChannelTemplate( 74 | 'unread_comment', 75 | $orderChannelCode, 76 | $recipients, 77 | [ 78 | 'order' => $order, 79 | 'message' => $message, 80 | 'authorEmail' => $authorEmail, 81 | ], 82 | $attachments 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Application/Process/SendUnreadCommentEmailNotificationInterface.php: -------------------------------------------------------------------------------- 1 | $this->channelRepository->findOneByCode($channelCode)]); 37 | 38 | try { 39 | /** 40 | * @psalm-suppress DeprecatedMethod 41 | * @psalm-suppress TooManyArguments 42 | */ 43 | $this->baseSender->send("{$code}_{$channelCode}", $recipients, $enrichedData, $attachments, $replyTo, $ccRecipients, $bccRecipients); 44 | } catch (InvalidArgumentException) { 45 | /** 46 | * @psalm-suppress DeprecatedMethod 47 | * @psalm-suppress TooManyArguments 48 | */ 49 | $this->baseSender->send($code, $recipients, $enrichedData, $attachments, $replyTo, $ccRecipients, $bccRecipients); 50 | } 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | public function send( 57 | string $code, 58 | array $recipients, 59 | array $data = [], 60 | array $attachments = [], 61 | array $replyTo = [] 62 | ): void { 63 | $channelCode = $this->channelContext->getChannel()->getCode(); 64 | Assert::notNull($channelCode); 65 | 66 | $this->sendWithChannelTemplate($code, $channelCode, $recipients, $data, $attachments, $replyTo); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Application/Process/Sender/ChanneledEmailSenderInterface.php: -------------------------------------------------------------------------------- 1 | processConfiguration($this->getConfiguration([], $container), $configs); 23 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../../config')); 24 | $loader->load('services.xml'); 25 | 26 | /** @var string $projectDir */ 27 | $projectDir = $container->getParameter('kernel.project_dir'); 28 | $container->setParameter( 29 | 'sylius_order_comment_plugin.comment_file_dir', 30 | $projectDir.'/public/media/comment_attachments' 31 | ); 32 | } 33 | 34 | public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface 35 | { 36 | return new Configuration(); 37 | } 38 | 39 | protected function getMigrationsNamespace(): string 40 | { 41 | return 'Brille24\SyliusOrderCommentsPlugin\Migrations'; 42 | } 43 | 44 | protected function getMigrationsDirectory(): string 45 | { 46 | return '@Brille24SyliusOrderCommentsPlugin/src/Infrastructure/Migrations'; 47 | } 48 | 49 | protected function getNamespacesOfMigrationsExecutedBefore(): array 50 | { 51 | return ['Sylius\Bundle\CoreBundle\Migrations']; 52 | } 53 | 54 | public function prepend(ContainerBuilder $container): void 55 | { 56 | $config = $this->getCurrentConfiguration($container); 57 | 58 | $this->registerResources('sylius', 'doctrine/orm', $config['resources'], $container); 59 | 60 | $this->prependDoctrineMigrations($container); 61 | $this->prependDoctrineMapping($container); 62 | } 63 | 64 | private function prependDoctrineMapping(ContainerBuilder $container): void 65 | { 66 | $config = array_merge(...$container->getExtensionConfig('doctrine')); 67 | 68 | // do not register mappings if dbal not configured. 69 | if (!isset($config['dbal']) || !isset($config['orm'])) { 70 | return; 71 | } 72 | 73 | $container->prependExtensionConfig('doctrine', [ 74 | 'orm' => [ 75 | 'mappings' => [ 76 | 'Brille24SyliusOrderCommentsPlugin' => [ 77 | 'type' => 'xml', 78 | 'dir' => $this->getPath($container, '/config/doctrine/'), 79 | 'is_bundle' => false, 80 | 'prefix' => 'Brille24\OrderCommentsPlugin\Domain\Model', 81 | 'alias' => 'Brille24SyliusOrderCommentsPlugin', 82 | ], 83 | ], 84 | ], 85 | ]); 86 | } 87 | 88 | private function getCurrentConfiguration(ContainerBuilder $container): array 89 | { 90 | /** @var ConfigurationInterface $configuration */ 91 | $configuration = $this->getConfiguration([], $container); 92 | 93 | $configs = $container->getExtensionConfig($this->getAlias()); 94 | 95 | return $this->processConfiguration($configuration, $configs); 96 | } 97 | 98 | private function getPath(ContainerBuilder $container, string $path): string 99 | { 100 | /** @var array> $metadata */ 101 | $metadata = $container->getParameter('kernel.bundles_metadata'); 102 | 103 | return $metadata['Brille24SyliusOrderCommentsPlugin']['path'] . $path; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | getRootNode(); 20 | 21 | $this->addResourcesSection($rootNode); 22 | 23 | return $treeBuilder; 24 | } 25 | 26 | private function addResourcesSection(ArrayNodeDefinition $node): void 27 | { 28 | $node 29 | ->children() 30 | ->arrayNode('resources') 31 | ->addDefaultsIfNotSet() 32 | ->children() 33 | ->arrayNode('order_comment') 34 | ->addDefaultsIfNotSet() 35 | ->children() 36 | ->variableNode('options')->end() 37 | ->arrayNode('classes') 38 | ->addDefaultsIfNotSet() 39 | ->children() 40 | ->scalarNode('model')->defaultValue(Comment::class)->cannotBeEmpty()->end() 41 | ->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end() 42 | ->scalarNode('repository')->defaultValue(EntityRepository::class)->cannotBeEmpty()->end() 43 | ->scalarNode('factory')->defaultValue(Factory::class)->end() 44 | ->scalarNode('form')->defaultValue(DefaultResourceType::class)->cannotBeEmpty()->end() 45 | ->end() 46 | ->end() 47 | ->end() 48 | ->end() 49 | ->end() 50 | ->end() 51 | ->end() 52 | ; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Domain/Event/FileAttached.php: -------------------------------------------------------------------------------- 1 | filePath; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Domain/Event/OrderCommented.php: -------------------------------------------------------------------------------- 1 | orderCommentId; 40 | } 41 | 42 | public function order(): OrderInterface 43 | { 44 | return $this->order; 45 | } 46 | 47 | public function authorEmail(): Email 48 | { 49 | return $this->authorEmail; 50 | } 51 | 52 | public function message(): string 53 | { 54 | return $this->message; 55 | } 56 | 57 | public function notifyCustomer(): bool 58 | { 59 | return $this->notifyCustomer; 60 | } 61 | 62 | public function createdAt(): \DateTimeInterface 63 | { 64 | return $this->createdAt; 65 | } 66 | 67 | public function attachedFile(): ?AttachedFile 68 | { 69 | return $this->attachedFile; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Domain/Model/AttachedFile.php: -------------------------------------------------------------------------------- 1 | path; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Domain/Model/Comment.php: -------------------------------------------------------------------------------- 1 | message) { 30 | throw new \DomainException('OrderComment cannot be created with empty message'); 31 | } 32 | 33 | $this->id = Uuid::uuid4(); 34 | $this->authorEmail = Email::fromString($authorEmail); 35 | $this->createdAt = new \DateTimeImmutable(); 36 | } 37 | 38 | public function attachFile(string $path): string 39 | { 40 | $this->attachedFile = AttachedFile::create($path); 41 | 42 | $path = $this->attachedFile->path(); 43 | Assert::string($path); 44 | 45 | return $path; 46 | } 47 | 48 | public function getId(): UuidInterface 49 | { 50 | return $this->id; 51 | } 52 | 53 | public function order(): OrderInterface 54 | { 55 | return $this->order; 56 | } 57 | 58 | public function authorEmail(): Email 59 | { 60 | return $this->authorEmail; 61 | } 62 | 63 | public function message(): string 64 | { 65 | return $this->message; 66 | } 67 | 68 | public function createdAt(): \DateTimeInterface 69 | { 70 | return $this->createdAt; 71 | } 72 | 73 | public function attachedFile(): ?AttachedFile 74 | { 75 | return $this->attachedFile; 76 | } 77 | 78 | public function notifyCustomer(): bool 79 | { 80 | return $this->notifyCustomer; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Domain/Model/Email.php: -------------------------------------------------------------------------------- 1 | email; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Infrastructure/Controller/Ui/OrderCommentAction.php: -------------------------------------------------------------------------------- 1 | formFactory->create(OrderCommentType::class); 34 | $form->handleRequest($request); 35 | $token = $this->securityTokenStorage->getToken(); 36 | 37 | /** @var string $referer */ 38 | $referer = $request->headers->get('referer'); 39 | if (null === $token || !$form->isValid()) { 40 | return new RedirectResponse($referer); 41 | } 42 | 43 | /** @var OrderComment $comment */ 44 | $comment = $form->getData(); 45 | 46 | /** @var UserInterface|string|null $user */ 47 | $user = $token->getUser(); 48 | /** @var OrderInterface $order */ 49 | $order = $this->orderRepository->find($request->attributes->get('orderId')); 50 | 51 | Assert::isInstanceOf($user, UserInterface::class); 52 | 53 | $orderNumber = $order->getNumber(); 54 | $email = $user->getEmail(); 55 | Assert::string($orderNumber); 56 | Assert::string($email); 57 | 58 | $this->commandBus->dispatch(CommentOrder::create( 59 | $orderNumber, 60 | $email, 61 | $comment->message, 62 | $comment->notifyCustomer, 63 | $comment->file 64 | )); 65 | 66 | return new RedirectResponse($referer); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Infrastructure/Controller/Ui/RenderOrderCommentAction.php: -------------------------------------------------------------------------------- 1 | formFactory->create(OrderCommentType::class); 21 | 22 | return new Response($this->twig->render( 23 | '@Brille24SyliusOrderCommentsPlugin/_form.html.twig', 24 | ['form' => $form->createView(), 'orderId' => $orderId, 'submitPath' => $submitPath, 'isAdmin' => $isAdmin] 25 | )); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Infrastructure/Form/DTO/OrderComment.php: -------------------------------------------------------------------------------- 1 | add( 22 | 'message', 23 | TextareaType::class, 24 | [ 25 | 'constraints' => [new NotBlank()], 26 | 'required' => true, 27 | 'empty_data' => '', 28 | ] 29 | ) 30 | ->add( 31 | 'notifyCustomer', 32 | CheckboxType::class, 33 | ['label' => 'sylius_order_comments.notify_customer'] 34 | ) 35 | ->add('file', FileType::class) 36 | ; 37 | } 38 | 39 | public function configureOptions(OptionsResolver $resolver): void 40 | { 41 | $resolver->setDefaults(['data_class' => OrderComment::class]); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Infrastructure/Migrations/Version20230317140309.php: -------------------------------------------------------------------------------- 1 | addSql('CREATE TABLE sylius_order_comment (id CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', order_id INT DEFAULT NULL, message TEXT NOT NULL, createdAt DATETIME NOT NULL, notifyCustomer TINYINT(1) NOT NULL, authorEmail_email VARCHAR(255) NOT NULL, attachedFile_path VARCHAR(255) DEFAULT NULL, INDEX IDX_8EA9CF098D9F6D38 (order_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); 24 | $this->addSql('ALTER TABLE sylius_order_comment ADD CONSTRAINT FK_8EA9CF098D9F6D38 FOREIGN KEY (order_id) REFERENCES sylius_order (id)'); 25 | } 26 | 27 | public function down(Schema $schema): void 28 | { 29 | // this down() migration is auto-generated, please modify it to your needs 30 | $this->addSql('ALTER TABLE sylius_order_comment DROP FOREIGN KEY FK_8EA9CF098D9F6D38'); 31 | $this->addSql('DROP TABLE sylius_order_comment'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /templates/Email/unread_comment.html.twig: -------------------------------------------------------------------------------- 1 | {% block subject %} 2 | You have unread comment from {{ authorEmail }} 3 | {% endblock %} 4 | 5 | {% block body %} 6 | {% autoescape %} 7 | Message from: {{ authorEmail }} 8 |
9 | Content: 10 |
11 | "{{ message }}" 12 | {% endautoescape %} 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /templates/_form.html.twig: -------------------------------------------------------------------------------- 1 |
2 | {{ form_start(form, {'action': path(submitPath, { 'orderId': orderId}), 'attr': {'class': 'ui reply form', 'novalidate': 'novalidate'}}) }} 3 |
4 | {{ form_row(form.message) }} 5 |
6 |
7 | {{ form_row(form.file) }} 8 |
9 | {% if isAdmin %} 10 |
11 | {{ form_label(form.notifyCustomer) }} 12 | {{ form_widget(form.notifyCustomer) }} 13 |
14 | {% endif %} 15 | 16 | {{ form_row(form._token) }} 17 | {{ form_end(form, {'render_rest': false}) }} 18 |
19 | -------------------------------------------------------------------------------- /templates/index.html.twig: -------------------------------------------------------------------------------- 1 |

{{ 'sylius.ui.order_comments'|trans }}

2 | {% for order_comment in order_comments %} 3 |
4 |
5 | {{ order_comment.authorEmail }} 6 | 13 |
14 | {{ order_comment.message }} 15 |
16 | 17 | {% if order_comment.attachedFile.path is not null %} 18 |
19 | 20 | 21 | 22 |
23 | {% endif %} 24 |
25 |
26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /templates/injected/admin_order_comments.html.twig: -------------------------------------------------------------------------------- 1 |
2 | {{ render(path('sylius_admin_order_comments_partial_comment_index', { 'orderId': resource.id })) }} 3 | {{ render(controller('brille24.order_comments_plugin.infrastructure.controller.ui.render_comment_form_action', { 4 | 'orderId': resource.id, 5 | 'submitPath': 'sylius_admin_order_comments_partial_comment_create', 6 | 'isAdmin': true 7 | })) }} 8 |
9 | -------------------------------------------------------------------------------- /templates/injected/shop_order_comments.html.twig: -------------------------------------------------------------------------------- 1 |
2 | {{ render(path('sylius_shop_order_comments_partial_comment_index', { 'number': order.number })) }} 3 | {{ render(controller('brille24.order_comments_plugin.infrastructure.controller.ui.render_comment_form_action', { 4 | 'orderId': order.id, 5 | 'submitPath': 'sylius_shop_order_comments_partial_comment_create', 6 | 'isAdmin': false 7 | })) }} 8 |
9 | -------------------------------------------------------------------------------- /tests/Application/.env: -------------------------------------------------------------------------------- 1 | # This file is a "template" of which env vars needs to be defined in your configuration or in an .env file 2 | # Set variables here that may be different on each deployment target of the app, e.g. development, staging, production. 3 | # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration 4 | 5 | ###> symfony/framework-bundle ### 6 | APP_ENV=dev 7 | APP_DEBUG=1 8 | APP_SECRET=EDITME 9 | ###< symfony/framework-bundle ### 10 | 11 | ###> doctrine/doctrine-bundle ### 12 | # Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url 13 | # For a sqlite database, use: "sqlite:///%kernel.project_dir%/var/data.db" 14 | # Set "serverVersion" to your server version to avoid edge-case exceptions and extra database calls 15 | DATABASE_URL=mysql://root@127.0.0.1/acme_sylius_example_plugin_%kernel.environment%?serverVersion=5.7 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=order_comments_plugin_development 22 | ###< lexik/jwt-authentication-bundle ### 23 | 24 | ###> symfony/mailer ### 25 | MAILER_DSN=null://null 26 | ###< symfony/mailer ### 27 | 28 | ###> symfony/messenger ### 29 | SYLIUS_MESSENGER_TRANSPORT_MAIN_DSN=doctrine://default 30 | SYLIUS_MESSENGER_TRANSPORT_MAIN_FAILED_DSN=doctrine://default?queue_name=main_failed 31 | SYLIUS_MESSENGER_TRANSPORT_CATALOG_PROMOTION_REMOVAL_DSN=doctrine://default?queue_name=catalog_promotion_removal 32 | SYLIUS_MESSENGER_TRANSPORT_CATALOG_PROMOTION_REMOVAL_FAILED_DSN=doctrine://default?queue_name=catalog_promotion_removal_failed 33 | ###< symfony/messenger ### 34 | -------------------------------------------------------------------------------- /tests/Application/.env.test: -------------------------------------------------------------------------------- 1 | APP_SECRET='ch4mb3r0f5ecr3ts' 2 | 3 | KERNEL_CLASS='Tests\Brille24\SyliusOrderCommentsPlugin\Application\Kernel' 4 | 5 | ###> symfony/messenger ### 6 | # Sync transport turned for testing env for the ease of testing 7 | SYLIUS_MESSENGER_TRANSPORT_MAIN_DSN=sync:// 8 | SYLIUS_MESSENGER_TRANSPORT_MAIN_FAILED_DSN=sync:// 9 | SYLIUS_MESSENGER_TRANSPORT_CATALOG_PROMOTION_REMOVAL_DSN=sync:// 10 | SYLIUS_MESSENGER_TRANSPORT_CATALOG_PROMOTION_REMOVAL_FAILED_DSN=sync:// 11 | ###< symfony/messenger ### 12 | -------------------------------------------------------------------------------- /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/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/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 | Brille24\OrderCommentsPlugin\Brille24SyliusOrderCommentsPlugin::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 | -------------------------------------------------------------------------------- /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 | - { resource: "@SyliusAdminBundle/Resources/config/app/config.yml" } 4 | - { resource: "@SyliusShopBundle/Resources/config/app/config.yml" } 5 | - { resource: "@SyliusApiBundle/Resources/config/app/config.yaml" } 6 | 7 | - { resource: "@Brille24SyliusOrderCommentsPlugin/config/config.yaml" } 8 | 9 | parameters: 10 | sylius_core.public_dir: '%kernel.project_dir%/public' 11 | 12 | sylius_api: 13 | enabled: true 14 | -------------------------------------------------------------------------------- /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 | patch_formats: 7 | json: ['application/merge-patch+json'] 8 | swagger: 9 | versions: [3] 10 | -------------------------------------------------------------------------------- /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 | url: '%env(resolve:DATABASE_URL)%' 11 | -------------------------------------------------------------------------------- /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/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.yaml: -------------------------------------------------------------------------------- 1 | brille24_sylius_order_comments_plugin_admin: 2 | resource: "@Brille24SyliusOrderCommentsPlugin/config/admin_routing.yaml" 3 | 4 | brille24_sylius_order_comments_plugin_shop: 5 | resource: "@Brille24SyliusOrderCommentsPlugin/config/shop_routing.yaml" 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/secrets/dev/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/tests/Application/config/secrets/dev/.gitignore -------------------------------------------------------------------------------- /tests/Application/config/secrets/prod/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/tests/Application/config/secrets/prod/.gitignore -------------------------------------------------------------------------------- /tests/Application/config/secrets/test/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/tests/Application/config/secrets/test/.gitignore -------------------------------------------------------------------------------- /tests/Application/config/secrets/test_cached/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/tests/Application/config/secrets/test_cached/.gitignore -------------------------------------------------------------------------------- /tests/Application/config/serialization/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/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.xml" } 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/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/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/templates/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/tests/Application/templates/.gitignore -------------------------------------------------------------------------------- /tests/Application/translations/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/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/Application/AdministratorOrderCommentsContext.php: -------------------------------------------------------------------------------- 1 | sharedStorage->get('administrator'); 38 | 39 | $this->commandBus->dispatch(CommentOrder::create($order->getNumber(), $user->getEmail(), $message, true)); 40 | } 41 | 42 | /** 43 | * @Given I have commented the order :order with :message with the notify customer checkbox disabled 44 | * @When I comment the order :order with :message with the notify customer checkbox disabled 45 | */ 46 | public function iCommentTheOrderWithMessageAndCheckboxDisabled(OrderInterface $order, string $message): void 47 | { 48 | /** @var AdminUserInterface $user */ 49 | $user = $this->sharedStorage->get('administrator'); 50 | 51 | $this->commandBus->dispatch(CommentOrder::create($order->getNumber(), $user->getEmail(), $message, false)); 52 | } 53 | 54 | /** 55 | * @Then /^(this order) should have a comment with "([^"]+)" from this administrator$/ 56 | */ 57 | public function thisOrderShouldHaveACommentWithFromThisAdministrator(OrderInterface $order, string $message): void 58 | { 59 | /** @var Comment $comment */ 60 | $comment = $this->orderCommentRepository->findOneBy(['order' => $order]); 61 | 62 | /** @var AdminUserInterface $user */ 63 | $user = $this->sharedStorage->get('administrator'); 64 | 65 | Assert::notNull($comment, 'This order does not have any comments.'); 66 | if ( 67 | $comment->message() !== $message || 68 | $comment->order() !== $order || 69 | $comment->authorEmail() != $user->getEmail() || 70 | !$comment->createdAt() instanceof \DateTimeInterface 71 | ) { 72 | throw new \RuntimeException( 73 | sprintf( 74 | 'There are no order comment with the "%s" message for the "%s" order from the "%s" administrator', 75 | $message, $order->getNumber(), $user->getEmail() 76 | )); 77 | } 78 | } 79 | 80 | /** 81 | * @When I try to comment the order :order with an empty message 82 | */ 83 | public function iTryToCommentTheOrderWithAnEmptyMessage(OrderInterface $order): void 84 | { 85 | try { 86 | $this->iCommentTheOrderWithMessageAndCheckboxEnabled($order, ''); 87 | } catch (HandlerFailedException $exception) { 88 | $innerException = $exception->getPrevious(); 89 | if (!($innerException instanceof \DomainException)) { 90 | throw $exception; 91 | } 92 | 93 | $this->sharedStorage->set('exception', $innerException); 94 | } 95 | } 96 | 97 | /** 98 | * @Then I should be notified that comment is invalid 99 | */ 100 | public function iShouldBeNotifiedThatCommentIsInvalid(): void 101 | { 102 | Assert::isInstanceOf($this->sharedStorage->get('exception'), \DomainException::class); 103 | } 104 | 105 | /** 106 | * @Then /^(this order) should not have any comments$/ 107 | * @Then the order :order should not have any comments 108 | */ 109 | public function thisOrderShouldNotHaveAnyComments(OrderInterface $order): void 110 | { 111 | $comments = $this->orderCommentRepository->findBy(['order' => $order]); 112 | 113 | Assert::isEmpty($comments, sprintf('This order should not have any comment, but %d found', count($comments))); 114 | } 115 | 116 | /** 117 | * @Then the notification email should be sent to the customer about :message comment 118 | */ 119 | public function theNotificationEmailShouldBeSentToTheCustomerAboutComment(string $message): void 120 | { 121 | /** @var ShopUserInterface $user */ 122 | $user = $this->sharedStorage->get('user'); 123 | Assert::true($this->emailChecker->hasMessageTo($message, $user->getEmail())); 124 | } 125 | 126 | /** 127 | * @Then the notification email should not be sent to the customer about :message comment 128 | */ 129 | public function theNotificationEmailShouldNotBeSentToTheCustomerAboutComment(string $message): void 130 | { 131 | /** @var ShopUserInterface $user */ 132 | $user = $this->sharedStorage->get('user'); 133 | Assert::false($this->emailChecker->hasMessageTo($message, $user->getEmail())); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /tests/Behat/Context/Application/CustomerOrderCommentsContext.php: -------------------------------------------------------------------------------- 1 | sharedStorage->get('user'); 39 | 40 | $this->commandBus->dispatch(CommentOrder::create($order->getNumber(), $user->getEmail(), $message, true)); 41 | } 42 | 43 | /** 44 | * @When I comment the order :order with :message and :fileName file 45 | */ 46 | public function iCommentTheOrderWithMessageAndFile(Orderinterface $order, string $message, string $fileName): void 47 | { 48 | /** @var ShopUserInterface $user */ 49 | $user = $this->sharedStorage->get('user'); 50 | $originalFilePath = __DIR__ . '/../../../Comments/Infrastructure/Form/Type/' . $fileName; 51 | 52 | // Copy the file, because the handler will move it. 53 | $filePath = $originalFilePath.'.bkp'; 54 | copy($originalFilePath, $filePath); 55 | 56 | $file = new UploadedFile($filePath, $filePath, null, null, true); 57 | 58 | $this->commandBus->dispatch(CommentOrder::create($order->getNumber(), $user->getEmail(), $message, true, $file)); 59 | } 60 | 61 | /** 62 | * @When I try to comment the order :order with an empty message 63 | */ 64 | public function aCustomerTryToCommentsTheOrderWithEmptyMessage(OrderInterface $order): void 65 | { 66 | /** @var ShopUserInterface $user */ 67 | $user = $this->sharedStorage->get('user'); 68 | try { 69 | $this->commandBus->dispatch(CommentOrder::create($order->getNumber(), $user->getEmail(), '', true)); 70 | } catch (HandlerFailedException $exception) { 71 | $innerException = $exception->getPrevious(); 72 | if (!($innerException instanceof \DomainException)) { 73 | throw $exception; 74 | } 75 | 76 | $this->sharedStorage->set('exception', $innerException); 77 | } 78 | } 79 | 80 | /** 81 | * @When a customer with email :email try to comment an order :order 82 | */ 83 | public function aCustomerWithEmailTryToCommentAnOrder(string $email, OrderInterface $order): void 84 | { 85 | try { 86 | $this->commandBus->dispatch(CommentOrder::create($order->getNumber(), $email, 'Hello', true)); 87 | } catch (HandlerFailedException $exception) { 88 | $innerException = $exception->getPrevious(); 89 | if (!($innerException instanceof \DomainException)) { 90 | throw $exception; 91 | } 92 | 93 | $this->sharedStorage->set('exception', $innerException); 94 | } 95 | } 96 | 97 | /** 98 | * @When I try to comment a not existing order with :message 99 | */ 100 | public function iTryToCommentAnNotExistingOrderWith(string $message): void 101 | { 102 | /** @var ShopUserInterface $user */ 103 | $user = $this->sharedStorage->get('user'); 104 | try { 105 | $this->commandBus->dispatch(CommentOrder::create('#0003', $user->getEmail(), $message, true)); 106 | } catch (HandlerFailedException $exception) { 107 | $innerException = $exception->getPrevious(); 108 | if (!($innerException instanceof \DomainException)) { 109 | throw $exception; 110 | } 111 | 112 | $this->sharedStorage->set('exception', $innerException); 113 | } 114 | } 115 | 116 | /** 117 | * @Then /^(this order) should have a comment with "([^"]+)" from this customer$/ 118 | */ 119 | public function thisOrderShouldHaveCommentWithFromThisCustomer(OrderInterface $order, string $message): void 120 | { 121 | /** @var Comment $comment */ 122 | $comment = $this->orderCommentRepository->findOneBy(['order' => $order]); 123 | 124 | /** @var ShopUserInterface $user */ 125 | $user = $this->sharedStorage->get('user'); 126 | 127 | Assert::notNull($comment, 'This order does not have any comments.'); 128 | if ( 129 | $comment->message() !== $message || 130 | $comment->order() !== $order || 131 | $comment->authorEmail() != $user->getEmail() || 132 | !$comment->createdAt() instanceof \DateTimeInterface 133 | ) { 134 | throw new \RuntimeException( 135 | sprintf( 136 | 'There are no order comment with this message "%s" for this order "%s" from this customer "%s"', 137 | $message, 138 | $order->getNumber(), 139 | $user->getEmail() 140 | ) 141 | ); 142 | } 143 | } 144 | 145 | /** 146 | * @Then I should be notified that comment is invalid 147 | */ 148 | public function thisOrderShouldNotHaveEmptyCommentFromThisCustomer(): void 149 | { 150 | Assert::isInstanceOf($this->sharedStorage->get('exception'), \DomainException::class); 151 | } 152 | 153 | /** 154 | * @Then /^(this order) should not have any comments$/ 155 | * @Then the order :order should not have any comments 156 | */ 157 | public function thisOrderShouldNotHaveAnyComments(OrderInterface $order): void 158 | { 159 | $comments = $this->orderCommentRepository->findBy(['order' => $order]); 160 | 161 | Assert::isEmpty($comments, sprintf('This order should not have any comment, but %d found', count($comments))); 162 | } 163 | 164 | /** 165 | * @Then the notification email should be sent to the administrator about :message comment 166 | */ 167 | public function theNotificationEmailShouldBeSentToTheAdministratorAboutComment(string $message): void 168 | { 169 | /** @var ChannelInterface $channel */ 170 | $channel = $this->sharedStorage->get('channel'); 171 | Assert::true($this->emailChecker->hasMessageTo($message, $channel->getContactEmail())); 172 | } 173 | 174 | /** 175 | * @Then /^(this order) should have a comment with "([^"]+)" and file "([^"]+)" from this customer$/ 176 | */ 177 | public function thisOrderShouldHaveACommentWithAndFileFromThisCustomer(Orderinterface $order, string $message, string $fileName): void 178 | { 179 | /** @var Comment $comment */ 180 | $comment = $this->orderCommentRepository->findOneBy(['order' => $order]); 181 | 182 | /** @var ShopUserInterface $user */ 183 | $user = $this->sharedStorage->get('user'); 184 | 185 | Assert::notNull($comment, 'This order does not have any comments.'); 186 | if ( 187 | $comment->message() !== $message || 188 | $comment->order() !== $order || 189 | $comment->authorEmail() != $user->getEmail() || 190 | !$comment->createdAt() instanceof \DateTimeInterface 191 | ) { 192 | throw new \RuntimeException( 193 | sprintf( 194 | 'There are no order comment with this message "%s" for this order "%s" from this customer "%s"', 195 | $message, 196 | $order->getNumber(), 197 | $user->getEmail() 198 | ) 199 | ); 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /tests/Behat/Context/Common/ChannelContext.php: -------------------------------------------------------------------------------- 1 | entityManager = $entityManager; 19 | } 20 | 21 | /** 22 | * @Given /^(this channel) has "([^"]+)" as a contact email$/ 23 | */ 24 | public function thisChannelHasAsAContactEmail(ChannelInterface $channel, string $contactEmail): void 25 | { 26 | $channel->setContactEmail($contactEmail); 27 | 28 | $this->entityManager->persist($channel); 29 | $this->entityManager->flush(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Behat/Context/Domain/AdministratorOrderCommentsContext.php: -------------------------------------------------------------------------------- 1 | commentOrder($order, $message, true); 31 | } 32 | 33 | /** 34 | * @When I comment the order :order with :message with the notify customer checkbox disabled 35 | */ 36 | public function iCommentTheOrderWithMessageAndCheckboxDisabled(OrderInterface $order, string $message): void 37 | { 38 | $this->commentOrder($order, $message, false); 39 | } 40 | 41 | /** 42 | * @When I try to comment the order :order with an empty message 43 | */ 44 | public function iTryToCommentTheOrderWith(OrderInterface $order): void 45 | { 46 | try { 47 | $this->iCommentTheOrderWithMessageAndCheckboxEnabled($order, ''); 48 | } catch (\DomainException $exception) { 49 | $this->sharedStorage->set('exception', $exception); 50 | } 51 | } 52 | 53 | /** 54 | * @Then /^(this order) should have a comment with "([^"]+)" from this administrator$/ 55 | */ 56 | public function thisOrderShouldHaveCommentWithFromThisAdministrator(OrderInterface $order, string $message): void 57 | { 58 | /** @var AdminUserInterface $user */ 59 | $user = $this->sharedStorage->get('administrator'); 60 | /** @var Comment $comment */ 61 | $comment = $this->sharedStorage->get('comment'); 62 | 63 | if ( 64 | $comment->message() !== $message || 65 | $comment->order() !== $order || 66 | $comment->authorEmail() != $user->getEmail() || 67 | !$comment->createdAt() instanceof \DateTimeInterface 68 | ) { 69 | throw new \InvalidArgumentException( 70 | sprintf( 71 | 'There are no order comment with the "%s" message for the "%s" order from the "%s" customer', 72 | $message, $order->getNumber(), $user->getEmail() 73 | )); 74 | } 75 | } 76 | 77 | /** 78 | * Creates a new comment and sets it into the shared storage. 79 | * @param OrderInterface $order 80 | * @param string $message 81 | * @param bool $notifyCustomer 82 | */ 83 | private function commentOrder(OrderInterface $order, string $message, bool $notifyCustomer): void 84 | { 85 | /** @var AdminUserInterface $user */ 86 | $user = $this->sharedStorage->get('administrator'); 87 | $comment = new Comment($order, $user->getEmail(), $message, $notifyCustomer); 88 | 89 | $this->eventDispatcher->dispatch(OrderCommented::occur( 90 | $comment->getId(), 91 | $comment->order(), 92 | $comment->authorEmail(), 93 | $comment->message(), 94 | $comment->notifyCustomer(), 95 | $comment->createdAt(), 96 | $comment->attachedFile() 97 | )); 98 | 99 | $this->sharedStorage->set('comment', $comment); 100 | } 101 | 102 | /** 103 | * @Then I should be notified that comment is invalid 104 | */ 105 | public function iShouldBeNotifiedThatCommentIsInvalid(): void 106 | { 107 | Assert::isInstanceOf($this->sharedStorage->get('exception'), \DomainException::class); 108 | } 109 | 110 | /** 111 | * @Then this order should not have any comments 112 | */ 113 | public function thisOrderShouldNotHaveAnyComments() 114 | { 115 | Assert::false($this->sharedStorage->has('comment'), 'At least one comment has been saved in shared storage, but none should'); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tests/Behat/Context/Domain/CustomerOrderCommentsContext.php: -------------------------------------------------------------------------------- 1 | commentOrder($order, $message, true); 32 | } 33 | 34 | /** 35 | * @When I comment the order :order with :message and :fileName file 36 | */ 37 | public function iCommentTheOrderWithMessageAndFile(Orderinterface $order, string $message, string $fileName): void 38 | { 39 | $this->commentOrder($order, $message, true, $fileName); 40 | } 41 | 42 | /** 43 | * @When I try to comment the order :order with an empty message 44 | */ 45 | public function aCustomerTryToCommentsTheOrderWithEmptyMessage(OrderInterface $order): void 46 | { 47 | try { 48 | $this->commentOrder($order, '', true); 49 | } catch (\DomainException $exception) { 50 | $this->sharedStorage->set('exception', $exception); 51 | } 52 | } 53 | 54 | /** 55 | * @When a customer with email :email try to comment an order :order 56 | */ 57 | public function aCustomerWithEmailTryToCommentAnOrder(string $email, OrderInterface $order): void 58 | { 59 | try { 60 | $this->commentOrder($order, 'Hello', true, null, $email); 61 | } catch (\DomainException $exception) { 62 | $this->sharedStorage->set('exception', $exception); 63 | } 64 | } 65 | 66 | /** 67 | * @Then /^(this order) should have a comment with "([^"]+)" from this customer$/ 68 | */ 69 | public function thisOrderShouldHaveCommentWithFromThisCustomer(OrderInterface $order, string $message): void 70 | { 71 | /** @var ShopUserInterface $user */ 72 | $user = $this->sharedStorage->get('user'); 73 | /** @var Comment $comment */ 74 | $comment = $this->sharedStorage->get('comment'); 75 | 76 | if ( 77 | $comment->message() !== $message || 78 | $comment->order() !== $order || 79 | $comment->authorEmail() != $user->getEmail() || 80 | !$comment->createdAt() instanceof \DateTimeInterface 81 | ) { 82 | throw new \RuntimeException( 83 | sprintf( 84 | 'There are no order comment with this message "%s" for this order "%s" from this customer "%s"', 85 | $message, 86 | $order->getNumber(), 87 | $user->getEmail() 88 | ) 89 | ); 90 | } 91 | } 92 | 93 | /** 94 | * Creates a new comment and sets it into the shared storage. 95 | * @param OrderInterface $order 96 | * @param string $message 97 | * @param bool $notifyCustomer 98 | * @param string|null $fileName 99 | * @param string|null $email 100 | */ 101 | private function commentOrder(OrderInterface $order, string $message, bool $notifyCustomer, string $fileName = null, string $email = null): void 102 | { 103 | if (null === $email) { 104 | /** @var ShopUserInterface $user */ 105 | $user = $this->sharedStorage->get('user'); 106 | $email = $user->getEmail(); 107 | } 108 | 109 | $comment = new Comment($order, $email, $message, $notifyCustomer); 110 | 111 | $this->eventDispatcher->dispatch(OrderCommented::occur( 112 | $comment->getId(), 113 | $comment->order(), 114 | $comment->authorEmail(), 115 | $comment->message(), 116 | $comment->notifyCustomer(), 117 | $comment->createdAt(), 118 | $comment->attachedFile() 119 | )); 120 | 121 | if (null !== $fileName) { 122 | $filePath = $comment->attachFile($fileName); 123 | $this->eventDispatcher->dispatch(FileAttached::occur($filePath)); 124 | } 125 | 126 | $this->sharedStorage->set('comment', $comment); 127 | } 128 | 129 | /** 130 | * @Then I should be notified that comment is invalid 131 | */ 132 | public function thisOrderShouldNotHaveEmptyCommentFromThisCustomer(): void 133 | { 134 | Assert::isInstanceOf($this->sharedStorage->get('exception'), \DomainException::class); 135 | } 136 | 137 | /** 138 | * @Then this order should not have any comments 139 | */ 140 | public function thisOrderShouldNotHaveAnyComments() 141 | { 142 | Assert::false($this->sharedStorage->has('comment'), 'At least one comment has been saved in shared storage, but none should'); 143 | } 144 | 145 | /** 146 | * @Then /^(this order) should have a comment with "([^"]+)" and file "([^"]+)" from this customer$/ 147 | */ 148 | public function thisOrderShouldHaveACommentWithAndFileFromThisCustomer(Orderinterface $order, string $message, string $fileName): void 149 | { 150 | /** @var ShopUserInterface $user */ 151 | $user = $this->sharedStorage->get('user'); 152 | /** @var Comment $comment */ 153 | $comment = $this->sharedStorage->get('comment'); 154 | 155 | if ( 156 | $comment->message() !== $message || 157 | $comment->order() !== $order || 158 | $comment->authorEmail() != $user->getEmail() || 159 | !$comment->createdAt() instanceof \DateTimeInterface || 160 | $comment->attachedFile()->path() != $fileName 161 | ) { 162 | throw new \RuntimeException( 163 | sprintf( 164 | 'There are no order comment with this message "%s" for this order "%s" from this customer "%s"', 165 | $message, 166 | $order->getNumber(), 167 | $user->getEmail() 168 | ) 169 | ); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /tests/Behat/Context/UI/AdministratorOrderCommentsContext.php: -------------------------------------------------------------------------------- 1 | sharedStorage = $sharedStorage; 37 | $this->orderPage = $orderPage; 38 | $this->orderCommentsElement = $orderCommentsElement; 39 | $this->orderCommentFormElement = $orderCommentFormElement; 40 | } 41 | 42 | /** 43 | * @When I comment the order :order with :message with the notify customer checkbox enabled 44 | * @Given I have commented the order :order with :message with the notify customer checkbox enabled 45 | */ 46 | public function iCommentTheOrderWithMessageAndCheckboxEnabled(OrderInterface $order, string $message): void 47 | { 48 | $this->orderPage->open(['id' => $order->getId()]); 49 | 50 | $this->orderCommentFormElement->enableCustomerNotified(); 51 | $this->orderCommentFormElement->specifyMessage($message); 52 | $this->orderCommentFormElement->comment(); 53 | 54 | sleep(1); 55 | } 56 | 57 | /** 58 | * @When I comment the order :order with :message with the notify customer checkbox disabled 59 | * @Given I have commented the order :order with :message with the notify customer checkbox disabled 60 | */ 61 | public function iCommentTheOrderWithMessageAndCheckboxDisabled(OrderInterface $order, string $message): void 62 | { 63 | $this->orderPage->open(['id' => $order->getId()]); 64 | 65 | $this->orderCommentFormElement->disableCustomerNotified(); 66 | $this->orderCommentFormElement->specifyMessage($message); 67 | $this->orderCommentFormElement->comment(); 68 | } 69 | 70 | /** 71 | * @When I try to comment the order :order with an empty message 72 | */ 73 | public function aCustomerTryToCommentsTheOrderWithEmptyMessage(OrderInterface $order): void 74 | { 75 | $this->orderPage->open(['id' => $order->getId()]); 76 | $this->orderCommentFormElement->enableCustomerNotified(); 77 | $this->orderCommentFormElement->specifyMessage(''); 78 | $this->orderCommentFormElement->comment(); 79 | } 80 | 81 | /** 82 | * @Then this order should have a comment with :message from this administrator 83 | * @Then the first comment from the top should have the :message message 84 | */ 85 | public function thisOrderShouldHaveACommentWithFromThisAdministrator(string $message): void 86 | { 87 | /** @var AdminUserInterface $user */ 88 | $user = $this->sharedStorage->get('administrator'); 89 | 90 | $comment = $this->orderCommentsElement->getFirstComment(); 91 | 92 | Assert::notNull($comment); 93 | Assert::same($comment->find('css', '.text')->getText(), $message); 94 | Assert::same($comment->find('css', '.author')->getText(), $user->getEmail()); 95 | } 96 | 97 | /** 98 | * @Then I should be notified that comment is invalid 99 | */ 100 | public function thisOrderShouldNotHaveEmptyCommentFromThisCustomer(): void 101 | { 102 | $order = $this->sharedStorage->get('order'); 103 | 104 | Assert::true($this->orderPage->isOpen(['id' => $order->getId()])); 105 | } 106 | 107 | /** 108 | * @Then the order :order should not have any comments 109 | * @Then /^(this order) should not have any comments$/ 110 | */ 111 | public function theOrderShouldNotHaveAnyComments(OrderInterface $order): void 112 | { 113 | $this->orderPage->open(['id' => $order->getId()]); 114 | 115 | Assert::same($this->orderCommentsElement->countComments(), 0, 'This order should not have any comment, but %s found.'); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tests/Behat/Context/UI/CustomerOrderCommentsContext.php: -------------------------------------------------------------------------------- 1 | sharedStorage = $sharedStorage; 37 | $this->orderPage = $orderPage; 38 | $this->orderCommentsElement = $orderCommentsElement; 39 | $this->orderCommentFormElement = $orderCommentFormElement; 40 | } 41 | 42 | /** 43 | * @When I comment the order :order with :message 44 | * @Given I have commented the order :order with :message 45 | */ 46 | public function iCommentTheOrderWith(OrderInterface $order, string $message): void 47 | { 48 | $this->orderPage->open(['number' => $order->getNumber()]); 49 | 50 | $this->orderCommentFormElement->specifyMessage($message); 51 | $this->orderCommentFormElement->comment(); 52 | 53 | $this->sharedStorage->set('order', $order); 54 | } 55 | 56 | 57 | /** 58 | * @Given I wait :seconds seconds 59 | */ 60 | public function andIWaitSeconds(int $seconds): void 61 | { 62 | sleep($seconds); 63 | } 64 | 65 | /** 66 | * @When I try to comment the order :order with an empty message 67 | */ 68 | public function aCustomerTryToCommentsTheOrderWithEmptyMessage(OrderInterface $order): void 69 | { 70 | $this->orderPage->open(['number' => $order->getNumber()]); 71 | $this->orderCommentFormElement->specifyMessage(''); 72 | $this->orderCommentFormElement->comment(); 73 | 74 | $this->sharedStorage->set('order', $order); 75 | } 76 | 77 | /** 78 | * @When I comment the order :order with :message and :fileName file 79 | */ 80 | public function iCommentTheOrderWithMessageAndFile(Orderinterface $order, string $message, string $fileName): void 81 | { 82 | $filePath = __DIR__ . '/../../../Comments/Infrastructure/Form/Type/' . $fileName; 83 | 84 | $this->orderPage->open(['number' => $order->getNumber()]); 85 | 86 | $this->orderCommentFormElement->specifyMessage($message); 87 | $this->orderCommentFormElement->attachFile($filePath); 88 | $this->orderCommentFormElement->comment(); 89 | 90 | $this->sharedStorage->set('order', $order); 91 | } 92 | 93 | /** 94 | * @Then this order should have a comment with :message from this customer 95 | * @Then the first comment from the top should have the :message message 96 | */ 97 | public function thisOrderShouldHaveACommentWithFromThisAdministrator(string $message): void 98 | { 99 | $order = $this->sharedStorage->get('order'); 100 | $this->orderPage->open(['number' => $order->getNumber()]); 101 | 102 | /** @var AdminUserInterface $user */ 103 | $user = $this->sharedStorage->get('user'); 104 | 105 | $comment = $this->orderCommentsElement->getFirstComment(); 106 | 107 | Assert::notNull($comment); 108 | Assert::same($comment->find('css', '.text')->getText(), $message); 109 | Assert::same($comment->find('css', '.author')->getText(), $user->getEmail()); 110 | } 111 | 112 | /** 113 | * @Then the order :order should not have any comments 114 | * @Then /^(this order) should not have any comments$/ 115 | */ 116 | public function theOrderShouldNotHaveAnyComments(OrderInterface $order): void 117 | { 118 | $this->orderPage->open(['number' => $order->getNumber()]); 119 | 120 | Assert::same($this->orderCommentsElement->countComments(), 0, 'This order should not have any comment, but %s found.'); 121 | 122 | $this->sharedStorage->set('order', $order); 123 | } 124 | 125 | /** 126 | * @Then I should be notified that comment is invalid 127 | */ 128 | public function thisOrderShouldNotHaveEmptyCommentFromThisCustomer(): void 129 | { 130 | } 131 | 132 | /** 133 | * @Then this order should have a comment with :message and file :fileName from this customer 134 | */ 135 | public function thisOrderShouldHaveACommentWithAndFileFromThisCustomer(string $message, string $fileName): void 136 | { 137 | $order = $this->sharedStorage->get('order'); 138 | $this->orderPage->open(['number' => $order->getNumber()]); 139 | 140 | /** @var AdminUserInterface $user */ 141 | $user = $this->sharedStorage->get('user'); 142 | 143 | $comment = $this->orderCommentsElement->getFirstComment(); 144 | 145 | Assert::notNull($comment); 146 | Assert::same($comment->find('css', '.text')->getText(), $message); 147 | Assert::same($comment->find('css', '.author')->getText(), $user->getEmail()); 148 | Assert::true($comment->find('css', '.file')->isValid()); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /tests/Behat/Element/Element.php: -------------------------------------------------------------------------------- 1 | session = $session; 35 | $this->parameters = $parameters; 36 | } 37 | 38 | protected function getParameter(string $name): NodeElement 39 | { 40 | return $this->parameters[$name] ?? null; 41 | } 42 | 43 | /** 44 | * Defines elements by returning an array with items being: 45 | * - :elementName => :cssLocator 46 | * - :elementName => [:selectorType => :locator] 47 | */ 48 | protected function getDefinedElements(): array 49 | { 50 | return []; 51 | } 52 | 53 | /** 54 | * @param string $name 55 | * @param array $parameters 56 | * 57 | * @return NodeElement 58 | * 59 | * @throws ElementNotFoundException 60 | */ 61 | protected function getElement(string $name, array $parameters = []): NodeElement 62 | { 63 | $element = $this->createElement($name, $parameters); 64 | 65 | if (!$this->getDocument()->has('xpath', $element->getXpath())) { 66 | throw new ElementNotFoundException( 67 | $this->getSession(), 68 | sprintf('Element named "%s" with parameters %s', $name, implode(', ', $parameters)), 69 | 'xpath', 70 | $element->getXpath() 71 | ); 72 | } 73 | 74 | return $element; 75 | } 76 | 77 | protected function hasElement(string $name, array $parameters = []): bool 78 | { 79 | return $this->getDocument()->has('xpath', $this->createElement($name, $parameters)->getXpath()); 80 | } 81 | 82 | protected function getSession(): Session 83 | { 84 | return $this->session; 85 | } 86 | 87 | protected function getDriver(): DriverInterface 88 | { 89 | return $this->session->getDriver(); 90 | } 91 | 92 | protected function getDocument(): DocumentElement 93 | { 94 | if (null === $this->document) { 95 | $this->document = new DocumentElement($this->session); 96 | } 97 | 98 | return $this->document; 99 | } 100 | 101 | private function createElement(string $name, array $parameters = []): NodeElement 102 | { 103 | $definedElements = $this->getDefinedElements(); 104 | 105 | if (!isset($definedElements[$name])) { 106 | throw new \InvalidArgumentException(sprintf( 107 | 'Could not find a defined element with name "%s". The defined ones are: %s.', 108 | $name, 109 | implode(', ', array_keys($definedElements)) 110 | )); 111 | } 112 | 113 | $elementSelector = $this->resolveParameters($name, $parameters, $definedElements); 114 | 115 | return new NodeElement( 116 | $this->getSelectorAsXpath($elementSelector, $this->session->getSelectorsHandler()), 117 | $this->session 118 | ); 119 | } 120 | 121 | /** 122 | * @param string|array $selector 123 | * @param SelectorsHandler $selectorsHandler 124 | * 125 | * @return string 126 | */ 127 | private function getSelectorAsXpath($selector, SelectorsHandler $selectorsHandler): string 128 | { 129 | $selectorType = is_array($selector) ? key($selector) : 'css'; 130 | $locator = is_array($selector) ? $selector[$selectorType] : $selector; 131 | 132 | return $selectorsHandler->selectorToXpath($selectorType, $locator); 133 | } 134 | 135 | private function resolveParameters(string $name, array $parameters, array $definedElements): string 136 | { 137 | if (!is_array($definedElements[$name])) { 138 | return strtr($definedElements[$name], $parameters); 139 | } 140 | 141 | array_map( 142 | function ($definedElement) use ($parameters) { 143 | return strtr($definedElement, $parameters); 144 | }, $definedElements[$name] 145 | ); 146 | 147 | return $definedElements[$name]; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /tests/Behat/Element/OrderCommentFormElement.php: -------------------------------------------------------------------------------- 1 | getDocument()->fillField('Message', $message); 12 | } 13 | 14 | public function attachFile($path): void 15 | { 16 | $this->getDocument()->find('css', 'input[type="file"]')->attachFile($path); 17 | } 18 | 19 | public function enableCustomerNotified(): void 20 | { 21 | $this->getDocument()->find('css', '#order_comment_notifyCustomer')->check(); 22 | } 23 | 24 | public function disableCustomerNotified(): void 25 | { 26 | $this->getDocument()->find('css', '#order_comment_notifyCustomer')->uncheck(); 27 | } 28 | 29 | public function comment(): void 30 | { 31 | $this->getDocument()->pressButton('Comment'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/Behat/Element/OrderCommentFormElementInterface.php: -------------------------------------------------------------------------------- 1 | getDocument()->find('css', '#comments .comment'); 14 | } 15 | 16 | public function countComments(): int 17 | { 18 | return count($this->getDocument()->findAll('css', '#comments .comment')); 19 | } 20 | 21 | protected function getDefinedElements(): array 22 | { 23 | return array_merge(parent::getDefinedElements(), [ 24 | 'comments' => '#comments', 25 | ]); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/Behat/Element/OrderCommentsElementInterface.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /tests/Behat/Resources/suites.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - suites/domain/customer_order_comments.yml 3 | - suites/application/customer_order_comments.yml 4 | - suites/ui/customer_order_comments.yml 5 | 6 | - suites/domain/administrator_order_comments.yml 7 | - suites/application/administrator_order_comments.yml 8 | - suites/ui/administrator_order_comments.yml 9 | -------------------------------------------------------------------------------- /tests/Behat/Resources/suites/application/administrator_order_comments.yml: -------------------------------------------------------------------------------- 1 | # Put your Behat suites definitions here 2 | 3 | default: 4 | suites: 5 | application_admistrator_order_comments: 6 | contexts: 7 | - sylius.behat.context.hook.doctrine_orm 8 | - sylius.behat.context.hook.mailer 9 | 10 | - sylius.behat.context.setup.channel 11 | - sylius.behat.context.setup.order 12 | - sylius.behat.context.setup.payment 13 | - sylius.behat.context.setup.product 14 | - sylius.behat.context.setup.shipping 15 | - sylius.behat.context.setup.user 16 | - sylius.behat.context.setup.admin_security 17 | 18 | - sylius.behat.context.transform.address 19 | - sylius.behat.context.transform.customer 20 | - sylius.behat.context.transform.order 21 | - sylius.behat.context.transform.payment 22 | - sylius.behat.context.transform.product 23 | - sylius.behat.context.transform.shared_storage 24 | - sylius.behat.context.transform.shipping_method 25 | 26 | - brille24.order_comments_plugin.behat.application.administrator_order_comments 27 | filters: 28 | tags: "@administrator_order_comments && @application" 29 | -------------------------------------------------------------------------------- /tests/Behat/Resources/suites/application/customer_order_comments.yml: -------------------------------------------------------------------------------- 1 | # Put your Behat suites definitions here 2 | 3 | default: 4 | suites: 5 | application_customer_order_comments: 6 | contexts: 7 | - sylius.behat.context.hook.doctrine_orm 8 | - sylius.behat.context.hook.mailer 9 | 10 | - sylius.behat.context.setup.channel 11 | - sylius.behat.context.setup.order 12 | - sylius.behat.context.setup.payment 13 | - sylius.behat.context.setup.product 14 | - sylius.behat.context.setup.shop_security 15 | - sylius.behat.context.setup.shipping 16 | - sylius.behat.context.setup.user 17 | 18 | - sylius.behat.context.transform.address 19 | - sylius.behat.context.transform.customer 20 | - sylius.behat.context.transform.order 21 | - sylius.behat.context.transform.payment 22 | - sylius.behat.context.transform.product 23 | - sylius.behat.context.transform.shared_storage 24 | - sylius.behat.context.transform.shipping_method 25 | 26 | - brille24.order_comments_plugin.behat.common.channel 27 | 28 | - brille24.order_comments_plugin.behat.application.customer_order_comments 29 | filters: 30 | tags: "@customer_order_comments && @application" 31 | -------------------------------------------------------------------------------- /tests/Behat/Resources/suites/domain/administrator_order_comments.yml: -------------------------------------------------------------------------------- 1 | # Put your Behat suites definitions here 2 | 3 | default: 4 | suites: 5 | domain_administrator_order_comments: 6 | contexts: 7 | - sylius.behat.context.hook.doctrine_orm 8 | - sylius.behat.context.hook.mailer 9 | 10 | - sylius.behat.context.setup.channel 11 | - sylius.behat.context.setup.order 12 | - sylius.behat.context.setup.payment 13 | - sylius.behat.context.setup.product 14 | - sylius.behat.context.setup.shipping 15 | - sylius.behat.context.setup.user 16 | - sylius.behat.context.setup.admin_security 17 | 18 | - sylius.behat.context.transform.address 19 | - sylius.behat.context.transform.customer 20 | - sylius.behat.context.transform.order 21 | - sylius.behat.context.transform.payment 22 | - sylius.behat.context.transform.product 23 | - sylius.behat.context.transform.shared_storage 24 | - sylius.behat.context.transform.shipping_method 25 | 26 | - brille24.order_comments_plugin.behat.domain.administrator_order_comments 27 | filters: 28 | tags: "@administrator_order_comments && @domain" 29 | -------------------------------------------------------------------------------- /tests/Behat/Resources/suites/domain/customer_order_comments.yml: -------------------------------------------------------------------------------- 1 | # Put your Behat suites definitions here 2 | 3 | default: 4 | suites: 5 | domain_customer_order_comments: 6 | contexts: 7 | - sylius.behat.context.hook.doctrine_orm 8 | - sylius.behat.context.hook.mailer 9 | 10 | - sylius.behat.context.setup.channel 11 | - sylius.behat.context.setup.order 12 | - sylius.behat.context.setup.payment 13 | - sylius.behat.context.setup.product 14 | - sylius.behat.context.setup.shop_security 15 | - sylius.behat.context.setup.shipping 16 | - sylius.behat.context.setup.user 17 | 18 | - sylius.behat.context.transform.address 19 | - sylius.behat.context.transform.customer 20 | - sylius.behat.context.transform.order 21 | - sylius.behat.context.transform.payment 22 | - sylius.behat.context.transform.product 23 | - sylius.behat.context.transform.shared_storage 24 | - sylius.behat.context.transform.shipping_method 25 | 26 | - brille24.order_comments_plugin.behat.common.channel 27 | 28 | - brille24.order_comments_plugin.behat.domain.customer_order_comments 29 | filters: 30 | tags: "@customer_order_comments && @domain" 31 | -------------------------------------------------------------------------------- /tests/Behat/Resources/suites/ui/administrator_order_comments.yml: -------------------------------------------------------------------------------- 1 | default: 2 | suites: 3 | ui_admistrator_order_comments: 4 | contexts: 5 | - sylius.behat.context.hook.doctrine_orm 6 | - sylius.behat.context.hook.mailer 7 | 8 | - sylius.behat.context.setup.channel 9 | - sylius.behat.context.setup.order 10 | - sylius.behat.context.setup.payment 11 | - sylius.behat.context.setup.product 12 | - sylius.behat.context.setup.shipping 13 | - sylius.behat.context.setup.user 14 | - sylius.behat.context.setup.admin_security 15 | 16 | - sylius.behat.context.transform.address 17 | - sylius.behat.context.transform.customer 18 | - sylius.behat.context.transform.order 19 | - sylius.behat.context.transform.payment 20 | - sylius.behat.context.transform.product 21 | - sylius.behat.context.transform.shared_storage 22 | - sylius.behat.context.transform.shipping_method 23 | 24 | - brille24.order_comments_plugin.behat.ui.administrator_order_comments 25 | filters: 26 | tags: "@administrator_order_comments && @ui" 27 | -------------------------------------------------------------------------------- /tests/Behat/Resources/suites/ui/customer_order_comments.yml: -------------------------------------------------------------------------------- 1 | # Put your Behat suites definitions here 2 | 3 | default: 4 | suites: 5 | ui_customer_order_comments: 6 | contexts: 7 | - sylius.behat.context.hook.doctrine_orm 8 | - sylius.behat.context.hook.mailer 9 | 10 | - sylius.behat.context.setup.channel 11 | - sylius.behat.context.setup.order 12 | - sylius.behat.context.setup.payment 13 | - sylius.behat.context.setup.product 14 | - sylius.behat.context.setup.shop_security 15 | - sylius.behat.context.setup.shipping 16 | - sylius.behat.context.setup.user 17 | 18 | - sylius.behat.context.transform.address 19 | - sylius.behat.context.transform.customer 20 | - sylius.behat.context.transform.order 21 | - sylius.behat.context.transform.payment 22 | - sylius.behat.context.transform.product 23 | - sylius.behat.context.transform.shared_storage 24 | - sylius.behat.context.transform.shipping_method 25 | 26 | - brille24.order_comments_plugin.behat.common.channel 27 | 28 | - brille24.order_comments_plugin.behat.ui.customer_order_comments 29 | filters: 30 | tags: "@customer_order_comments && @ui" 31 | -------------------------------------------------------------------------------- /tests/Comments/Application/Command/CommentOrderTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('#00002', $command->orderNumber()); 21 | $this->assertEquals('test@test.com', $command->authorEmail()); 22 | $this->assertEquals('Hello', $command->message()); 23 | $this->assertEquals(true, $command->notifyCustomer()); 24 | } 25 | 26 | /** 27 | * @test 28 | */ 29 | public function it_has_option_file_path_and_file_type(): void 30 | { 31 | $filePath = __DIR__.'/../../Infrastructure/Form/Type/text.txt'; 32 | 33 | $file = new UploadedFile($filePath, $filePath, null, null, true); 34 | $command = CommentOrder::create('#00002', 'test@test.com', 'Hello', true, $file); 35 | 36 | $this->assertEquals($file, $command->file()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/Comments/Application/Process/ChanneledEmailSenderTest.php: -------------------------------------------------------------------------------- 1 | sender = $this->createMock(SenderInterface::class); 33 | 34 | $this->channel = $this->createMock(ChannelInterface::class); 35 | $this->channelContext = $this->createMock(ChannelContextInterface::class); 36 | 37 | /** @var ChannelRepositoryInterface|MockObject $channelRepository */ 38 | $channelRepository = $this->createMock(ChannelRepositoryInterface::class); 39 | $channelRepository 40 | ->method('findOneByCode') 41 | ->with('glasses24') 42 | ->willReturn($this->channel) 43 | ; 44 | 45 | $this->channeledEmailSender = 46 | new ChanneledEmailSender($this->sender, $channelRepository, $this->channelContext); 47 | } 48 | 49 | public function testSendsTheEmailWithChanneledTemplate(): void 50 | { 51 | $this->sender->expects($this->once())->method('send')->with($this->equalTo('welcome_glasses24')); 52 | 53 | $this->channeledEmailSender 54 | ->sendWithChannelTemplate('welcome', 'glasses24', ['test@localhost.com'], ['message' => 'Hello']); 55 | } 56 | 57 | public function testGetsChannelFromChannelContext(): void 58 | { 59 | $this->channelContext->method('getChannel')->willReturn($this->channel); 60 | $this->channel->method('getCode')->willReturn('glasses24'); 61 | $this->sender->expects($this->once())->method('send')->with($this->equalTo('welcome_glasses24')); 62 | 63 | $this->channeledEmailSender 64 | ->send('welcome', ['test@localhost.com'], ['message' => 'Hello']); 65 | } 66 | 67 | public function testSendsAnUnchanneledEmailIfTheChannelHasNoConfig(): void 68 | { 69 | $this->channelContext->method('getChannel')->willReturn($this->channel); 70 | $this->channel->method('getCode')->willReturn('glasses24'); 71 | $this->sender 72 | ->expects($this->atLeastOnce()) 73 | ->method('send') 74 | ->withConsecutive( 75 | [ 76 | 'welcome_glasses24', 77 | ['test@localhost.com'], 78 | ['message' => 'Hello', 'channel' => $this->channel], 79 | [], 80 | [], 81 | ], 82 | ['welcome'], 83 | ) 84 | ->will( 85 | new ConsecutiveCalls([ 86 | $this->throwException(new InvalidArgumentException()), 87 | $this->returnValue(null), 88 | ]) 89 | ) 90 | ; 91 | $this->channeledEmailSender 92 | ->send('welcome', ['test@localhost.com'], ['message' => 'Hello']); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/Comments/Domain/Event/FileAttachedTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('test/test/file.pdf', $event->filePath()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/Comments/Domain/Event/OrderCommentedTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($commentId, $event->orderCommentId()); 32 | $this->assertEquals($order, $event->order()); 33 | $this->assertEquals('test@test.com', $event->authorEmail()); 34 | $this->assertEquals('Hello', $event->message()); 35 | $this->assertEquals(true, $event->notifyCustomer()); 36 | $this->assertInstanceOf(\DateTimeImmutable::class, $event->createdAt()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/Comments/Domain/Model/AttachedFileTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('test/test/file.pdf', $uploadedFile->path()); 20 | } 21 | 22 | /** 23 | * @test 24 | */ 25 | public function it_cannot_be_created_with_empty_path(): void 26 | { 27 | $this->expectException(\DomainException::class); 28 | 29 | AttachedFile::create(''); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Comments/Domain/Model/CommentTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($order, $comment->order()); 23 | $this->assertEquals('test@test.com', $comment->authorEmail()); 24 | $this->assertEquals('Hello', $comment->message()); 25 | $this->assertEquals(true, $comment->notifyCustomer()); 26 | $this->assertInstanceOf(\DateTimeImmutable::class, $comment->createdAt()); 27 | } 28 | 29 | /** 30 | * @test 31 | */ 32 | public function order_cannot_be_commented_with_empty_message(): void 33 | { 34 | $this->expectException(\DomainException::class); 35 | 36 | $order = new Order(); 37 | 38 | new Comment($order, 'test@test.com', '', true); 39 | } 40 | 41 | /** 42 | * @test 43 | */ 44 | public function order_cannot_be_commented_with_invalid_email(): void 45 | { 46 | $this->expectException(\DomainException::class); 47 | 48 | $order = new Order(); 49 | 50 | new Comment($order, 'abcd.com', 'Hello', true); 51 | } 52 | 53 | /** 54 | * @test 55 | */ 56 | public function it_can_have_file_attached(): void 57 | { 58 | $order = new Order(); 59 | 60 | $comment = new Comment($order, 'test@test.com', 'Hello', true); 61 | $comment->attachFile('test/test.pdf'); 62 | 63 | $this->assertNotNull($comment->attachedFile()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/Comments/Domain/Model/EmailTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('test@test.com', $email->__toString()); 20 | } 21 | 22 | /** 23 | * @test 24 | */ 25 | public function it_cannot_be_created_from_invalid_string(): void 26 | { 27 | $this->expectException(\DomainException::class); 28 | 29 | Email::fromString('abcd.com'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Comments/Infrastructure/Form/Type/file.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/tests/Comments/Infrastructure/Form/Type/file.pdf -------------------------------------------------------------------------------- /tests/Comments/Infrastructure/Form/Type/text.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Brille24/SyliusOrderCommentsPlugin/1c59f1a13aead1387a3f5a44d2a945c9cd996aad/tests/Comments/Infrastructure/Form/Type/text.txt -------------------------------------------------------------------------------- /translations/messages.de.yml: -------------------------------------------------------------------------------- 1 | sylius_order_comments: 2 | notify_customer: "Kunden über den Kommentar benachrichtigen" 3 | customer_notified: "Kunde benachrichtig!" 4 | customer_not_notified: "Kunde wurde nicht benachrichtigt!" 5 | -------------------------------------------------------------------------------- /translations/messages.en.yml: -------------------------------------------------------------------------------- 1 | sylius_order_comments: 2 | notify_customer: "Notify customer about this comment!" 3 | customer_notified: "Customer notified!" 4 | customer_not_notified: "Customer not notified!" 5 | --------------------------------------------------------------------------------