From b070343603476305afa11412240958b9a815e2b6 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 18 Jun 2024 19:39:44 +0200 Subject: [PATCH 01/10] Remove recipes from plugin --- .../monsieurbiz_sylius_rich_editor_plugin.yaml | 2 -- .../monsieurbiz_sylius_rich_editor_plugin.yaml | 2 -- recipes/1.0/manifest.json | 10 ---------- .../monsieurbiz_sylius_rich_editor_plugin.yaml | 2 -- .../monsieurbiz_sylius_rich_editor_plugin.yaml | 3 --- recipes/2.0/manifest.json | 14 -------------- 6 files changed, 33 deletions(-) delete mode 100644 recipes/1.0/config/packages/monsieurbiz_sylius_rich_editor_plugin.yaml delete mode 100644 recipes/1.0/config/routes/monsieurbiz_sylius_rich_editor_plugin.yaml delete mode 100644 recipes/1.0/manifest.json delete mode 100644 recipes/2.0/config/packages/monsieurbiz_sylius_rich_editor_plugin.yaml delete mode 100644 recipes/2.0/config/routes/monsieurbiz_sylius_rich_editor_plugin.yaml delete mode 100644 recipes/2.0/manifest.json diff --git a/recipes/1.0/config/packages/monsieurbiz_sylius_rich_editor_plugin.yaml b/recipes/1.0/config/packages/monsieurbiz_sylius_rich_editor_plugin.yaml deleted file mode 100644 index 71e3ce6e..00000000 --- a/recipes/1.0/config/packages/monsieurbiz_sylius_rich_editor_plugin.yaml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: "@MonsieurBizSyliusRichEditorPlugin/Resources/config/config.yaml" } diff --git a/recipes/1.0/config/routes/monsieurbiz_sylius_rich_editor_plugin.yaml b/recipes/1.0/config/routes/monsieurbiz_sylius_rich_editor_plugin.yaml deleted file mode 100644 index d6979d2e..00000000 --- a/recipes/1.0/config/routes/monsieurbiz_sylius_rich_editor_plugin.yaml +++ /dev/null @@ -1,2 +0,0 @@ -monsieur_biz_rich_editor_plugin: - resource: "@MonsieurBizSyliusRichEditorPlugin/Resources/config/routing.yaml" diff --git a/recipes/1.0/manifest.json b/recipes/1.0/manifest.json deleted file mode 100644 index a33a848a..00000000 --- a/recipes/1.0/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bundles": { - "MonsieurBiz\\SyliusRichEditorPlugin\\MonsieurBizSyliusRichEditorPlugin": [ - "all" - ] - }, - "copy-from-recipe": { - "config/": "%CONFIG_DIR%/" - } -} diff --git a/recipes/2.0/config/packages/monsieurbiz_sylius_rich_editor_plugin.yaml b/recipes/2.0/config/packages/monsieurbiz_sylius_rich_editor_plugin.yaml deleted file mode 100644 index 71e3ce6e..00000000 --- a/recipes/2.0/config/packages/monsieurbiz_sylius_rich_editor_plugin.yaml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: "@MonsieurBizSyliusRichEditorPlugin/Resources/config/config.yaml" } diff --git a/recipes/2.0/config/routes/monsieurbiz_sylius_rich_editor_plugin.yaml b/recipes/2.0/config/routes/monsieurbiz_sylius_rich_editor_plugin.yaml deleted file mode 100644 index c770b017..00000000 --- a/recipes/2.0/config/routes/monsieurbiz_sylius_rich_editor_plugin.yaml +++ /dev/null @@ -1,3 +0,0 @@ -monsieurbiz_richeditor_admin: - resource: "@MonsieurBizSyliusRichEditorPlugin/Resources/config/routing/admin.yaml" - prefix: /%sylius_admin.path_name% diff --git a/recipes/2.0/manifest.json b/recipes/2.0/manifest.json deleted file mode 100644 index b13c2b36..00000000 --- a/recipes/2.0/manifest.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "bundles": { - "MonsieurBiz\\SyliusRichEditorPlugin\\MonsieurBizSyliusRichEditorPlugin": [ - "all" - ] - }, - "copy-from-recipe": { - "config/": "%CONFIG_DIR%/" - }, - "env": { - "MONSIEURBIZ_SYLIUS_RICH_EDITOR_UPLOAD_DIR": "/media/rich-editor", - "MONSIEURBIZ_SYLIUS_RICH_EDITOR_IMAGE_UPLOAD_DIR": "/media/image" - } -} From 4b79d707c6746dd80673d2b0fc3ce98c2e066db8 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 18 Jun 2024 19:40:07 +0200 Subject: [PATCH 02/10] Update dependencies and workflows to use Sylius 1.13 --- .github/workflows/recipe.yaml | 43 ++++++++++++------------ .github/workflows/security.yaml | 21 +++++++----- .github/workflows/tests.yaml | 30 +++++++++-------- .php-cs-fixer.dist.php | 29 +++++++++------- .php-version.dist | 2 +- Makefile | 36 +++++++------------- README.md | 22 ++++++++++-- composer.json | 59 ++++++++------------------------- phpstan.neon | 19 +++-------- 9 files changed, 115 insertions(+), 146 deletions(-) diff --git a/.github/workflows/recipe.yaml b/.github/workflows/recipe.yaml index 49bc729d..0e164e11 100644 --- a/.github/workflows/recipe.yaml +++ b/.github/workflows/recipe.yaml @@ -9,22 +9,20 @@ jobs: recipe: - name: Flex recipe (PHP ${{ matrix.php }}, Sylius ${{ matrix.sylius }}) - runs-on: ubuntu-latest strategy: fail-fast: false matrix: php: ['8.0', '8.1', '8.2'] - sylius: ['~1.11.0', '~1.12.0'] - include: - - php: '8.1' - sylius: '~1.12.0' - sylius_paypal: '~1.5.0' + sylius: ["~1.11.0", "~1.12.0", "~1.13.0"] + exclude: - php: '8.2' + sylius: '~1.11.0' + - php: '8.0' sylius: '~1.12.0' - sylius_paypal: '~1.5.0' + - php: '8.0' + sylius: '~1.13.0' steps: - name: Setup PHP @@ -32,24 +30,33 @@ jobs: with: php-version: ${{ matrix.php }} extensions: gd, intl, json + ini-values: date.timezone=UTC + tools: symfony-cli - name: Set project php-version run: | - echo "${{ matrix.php }}" > .php-version + echo ${{ matrix.php }} > .php-version - uses: actions/checkout@v3 with: path: plugin - - run: mkdir -p /home/runner/{.composer/cache,.config/composer} + - name: Determine composer cache directory + id: composer-cache-directory + working-directory: plugin + run: echo "directory=$(composer config cache-dir)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - name: Cache dependencies installed with composer + uses: actions/cache@v3 id: cache-composer with: - path: /home/runner/.composer/cache - key: composer2-php:${{ matrix.php }}-sylius:${{ matrix.sylius }}-${{ github.sha }} + path: ${{ steps.composer-cache-directory.outputs.directory }} + key: composer2-php:${{ matrix.php }}-sylius:${{ matrix.sylius }}-${{ hashFiles('**/composer.json') }} restore-keys: composer2-php:${{ matrix.php }}-sylius:${{ matrix.sylius }}- + - name: Ensure that composer cache directory exists + run: mkdir -p ${{ steps.composer-cache-directory.outputs.directory }} + - name: Composer Github Auth run: composer config -g github-oauth.github.com ${{ github.token }} @@ -63,14 +70,6 @@ jobs: run: | composer require --no-install --no-scripts --no-progress sylius/sylius="${{ matrix.sylius }}" - # Fix Paypal 1.5 on Sylius 1.12 and PHP 8.1 - - name: Make sure to install the required version of Sylius Paypal Plugin - if: ${{ matrix.sylius_paypal }} - working-directory: ./sylius - run: | - composer require --no-install --no-scripts --no-progress sylius/paypal-plugin="${{ matrix.sylius_paypal }}" # @see https://github.com/Sylius/PayPalPlugin/issues/295 - - - name: Setup some requirements working-directory: ./sylius run: | @@ -82,7 +81,7 @@ jobs: composer config --no-plugins --json extra.symfony.endpoint '["https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master","flex://defaults"]' composer config repositories.plugin '{"type": "path", "url": "../plugin/"}' - - name: Require plugin & install all + - name: Require plugin & install all dependencies working-directory: ./sylius run: | composer require monsieurbiz/sylius-rich-editor-plugin="*@dev" diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml index 67a89bbc..c100cfa1 100644 --- a/.github/workflows/security.yaml +++ b/.github/workflows/security.yaml @@ -8,14 +8,12 @@ jobs: security: - name: Security check (PHP ${{ matrix.php }}) - runs-on: ubuntu-latest strategy: fail-fast: false matrix: - php: ['8.0', '8.1', '8.2'] + php: ['8.1', '8.2'] steps: - uses: actions/checkout@v3 @@ -30,21 +28,26 @@ jobs: run: | echo "${{ matrix.php }}" > .php-version - - uses: actions/cache@v3 + - name: Determine composer cache directory + id: composer-cache-directory + run: echo "directory=$(composer config cache-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies installed with composer + uses: actions/cache@v3 id: cache-composer with: - path: /home/runner/.composer/cache + path: ${{ steps.composer-cache-directory.outputs.directory }} key: composer2-php:${{ matrix.php }}-${{ github.sha }} restore-keys: composer2-php:${{ matrix.php }}- - - run: mkdir -p /home/runner/{.composer/cache,.config/composer} + - name: Ensure that composer cache directory exists + run: mkdir -p ${{ steps.composer-cache-directory.outputs.directory }} - name: Composer Github Auth run: composer config -g github-oauth.github.com ${{ github.token }} - - uses: actions/checkout@v3 - - name: Install PHP dependencies run: composer update --prefer-dist - - uses: symfonycorp/security-checker-action@v3 + - uses: symfonycorp/security-checker-action@v4 + diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 62f80d9d..877ce6a6 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -9,14 +9,12 @@ jobs: php: - name: Quality tests (PHP ${{ matrix.php }}) - runs-on: ubuntu-latest strategy: fail-fast: false matrix: - php: ['8.0', '8.1', '8.2'] + php: ['8.1', '8.2'] env: SYMFONY_ARGS: --no-tls @@ -24,34 +22,36 @@ jobs: DOCKER_INTERACTIVE_ARGS: -t steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 with: - node-version: '16' - + node-version: '14' - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: gd, intl, json + ini-values: date.timezone=UTC + tools: symfony-cli - name: Set project php-version run: | echo "${{ matrix.php }}" > .php-version - - name: Install symfony CLI - run: | - curl -1sLf 'https://dl.cloudsmith.io/public/symfony/stable/setup.deb.sh' | sudo -E bash - sudo apt install symfony-cli + - name: Determine composer cache directory + id: composer-cache-directory + run: echo "directory=$(composer config cache-dir)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - name: Cache dependencies installed with composer + uses: actions/cache@v3 id: cache-composer with: - path: /home/runner/.composer/cache + path: ${{ steps.composer-cache-directory.outputs.directory }} key: composer2-php:${{ matrix.php }}-${{ github.sha }} restore-keys: composer2-php:${{ matrix.php }}- - - run: mkdir -p /home/runner/{.composer/cache,.config/composer} + - name: Ensure that composer cache directory exists + run: mkdir -p ${{ steps.composer-cache-directory.outputs.directory }} - name: Composer Github Auth run: composer config -g github-oauth.github.com ${{ github.token }} @@ -66,6 +66,8 @@ jobs: - run: make test.phpstan + - run: make test.phpmd + - run: make test.phpspec - run: make test.yaml diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 81db8c5c..75adfa74 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -49,10 +49,8 @@ 'binary_operator_spaces' => true, 'blank_line_after_opening_tag' => true, 'blank_line_after_namespace' => true, + 'blank_lines_before_namespace' => true, 'blank_line_before_statement' => true, - 'braces' => [ - 'allow_single_line_closure' => true, - ], 'cast_spaces' => true, 'class_attributes_separation' => true, 'class_definition' => [ @@ -62,7 +60,7 @@ 'combine_consecutive_issets' => true, 'combine_consecutive_unsets' => true, 'comment_to_phpdoc' => true, - 'compact_nullable_typehint' => true, + 'compact_nullable_type_declaration' => true, 'concat_space' => [ 'spacing' => 'one', ], @@ -88,8 +86,12 @@ 'fully_qualified_strict_types' => true, 'function_declaration' => true, 'function_to_constant' => true, - 'function_typehint_space' => true, 'general_phpdoc_tag_rename' => true, + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => false, + 'import_functions' => false, + ], 'header_comment' => [ 'header' => $header, 'location' => 'after_open', @@ -110,6 +112,7 @@ 'lowercase_static_reference' => true, 'magic_constant_casing' => true, 'method_argument_space' => true, + 'modernize_strpos' => false, 'modernize_types_casting' => true, 'multiline_comment_opening_closing' => true, 'multiline_whitespace_before_semicolons' => [ @@ -117,7 +120,7 @@ ], 'native_constant_invocation' => true, 'native_function_casing' => true, - 'new_with_braces' => true, + 'new_with_parentheses' => true, 'no_alias_functions' => true, 'no_alternative_syntax' => true, 'no_blank_lines_after_class_opening' => true, @@ -156,27 +159,27 @@ 'no_short_bool_cast' => true, 'no_spaces_after_function_name' => true, 'no_spaces_around_offset' => true, - 'no_spaces_inside_parenthesis' => true, + 'spaces_inside_parentheses' => true, 'no_superfluous_elseif' => true, 'no_superfluous_phpdoc_tags' => [ 'allow_mixed' => true, ], 'no_unset_cast' => true, 'no_unneeded_control_parentheses' => true, - 'no_unneeded_curly_braces' => true, + 'no_unneeded_braces' => true, 'no_unneeded_final_method' => true, 'no_unset_on_property' => true, 'no_unused_imports' => true, 'no_useless_else' => true, 'no_useless_return' => true, - 'no_trailing_comma_in_list_call' => true, - 'no_trailing_comma_in_singleline_array' => true, + 'no_trailing_comma_in_singleline' => true, 'no_trailing_whitespace' => true, 'no_trailing_whitespace_in_comment' => true, 'no_whitespace_before_comma_in_array' => true, 'no_whitespace_in_blank_line' => true, 'non_printable_character' => true, 'normalize_index_brace' => true, + 'nullable_type_declaration_for_default_null_value' => false, 'object_operator_without_whitespace' => true, 'ordered_imports' => [ 'imports_order' => [ @@ -211,7 +214,9 @@ 'phpdoc_order' => true, 'phpdoc_return_self_reference' => true, 'phpdoc_scalar' => true, - 'phpdoc_separation' => true, + 'phpdoc_separation' => ['groups' => [ + ['ORM\\*'], ['Assert\\*'], + ]], 'phpdoc_single_line_var_spacing' => true, 'phpdoc_tag_type' => true, 'phpdoc_to_comment' => false, @@ -231,7 +236,6 @@ 'self_accessor' => true, 'short_scalar_cast' => true, 'single_blank_line_at_eof' => true, - 'single_blank_line_before_namespace' => true, 'single_class_element_per_statement' => true, 'single_import_per_statement' => true, 'single_line_after_imports' => true, @@ -248,6 +252,7 @@ 'elements' => ['arrays'], ], 'trim_array_spaces' => true, + 'type_declaration_spaces' => true, 'unary_operator_spaces' => true, 'visibility_required' => [ 'elements' => [ diff --git a/.php-version.dist b/.php-version.dist index b8eb0263..2983cad0 100644 --- a/.php-version.dist +++ b/.php-version.dist @@ -1 +1 @@ -8.1 +8.2 diff --git a/Makefile b/Makefile index a1410d39..e49fc24b 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,7 @@ .DEFAULT_GOAL := help SHELL=/bin/bash APP_DIR=tests/Application -SYLIUS_VERSION=1.12.0 -SYLIUS_PAYPAL_VERSION=1.5.0 +SYLIUS_VERSION=1.13.0 SYMFONY=cd ${APP_DIR} && symfony COMPOSER=symfony composer CONSOLE=${SYMFONY} console @@ -26,7 +25,7 @@ reset: ## Stop docker and remove dependencies ${MAKE} docker.down || true rm -rf ${APP_DIR}/node_modules ${APP_DIR}/yarn.lock rm -rf ${APP_DIR} - rm -rf vendor composer.lock node_modules yarn.lock + rm -rf vendor composer.lock .PHONY: reset dependencies: composer.lock node_modules ## Setup the dependencies @@ -48,8 +47,9 @@ yarn.install: ${APP_DIR}/yarn.lock ${APP_DIR}/yarn.lock: ln -sf ${APP_DIR}/node_modules node_modules cd ${APP_DIR} && ${YARN} install && ${YARN} build - ${YARN} install - ${YARN} encore prod +# No CSS and JS on this plugin yet +# ${YARN} install +# ${YARN} encore prod node_modules: ${APP_DIR}/node_modules ## Install the Node dependencies using yarn @@ -59,7 +59,7 @@ ${APP_DIR}/node_modules: yarn.install ### TEST APPLICATION ### ¯¯¯¯¯ -application: .php-version php.ini ${APP_DIR} setup_application ${APP_DIR}/docker-compose.yaml ## Setup the entire Test Application +application: .php-version php.ini ${APP_DIR} setup_application ${APP_DIR}/docker-compose.yaml ${APP_DIR}: (${COMPOSER} create-project --no-interaction --prefer-dist --no-scripts --no-progress --no-install sylius/sylius-standard="~${SYLIUS_VERSION}" ${APP_DIR}) @@ -70,21 +70,21 @@ setup_application: (cd ${APP_DIR} && ${COMPOSER} config extra.symfony.allow-contrib true) (cd ${APP_DIR} && ${COMPOSER} config minimum-stability dev) (cd ${APP_DIR} && ${COMPOSER} config --no-plugins allow-plugins true) + (cd ${APP_DIR} && ${COMPOSER} config --no-plugins --json extra.symfony.endpoint '["https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master","flex://defaults"]') (cd ${APP_DIR} && ${COMPOSER} require --no-install --no-scripts --no-progress sylius/sylius="~${SYLIUS_VERSION}") # Make sure to install the required version of sylius because the sylius-standard has a soft constraint - (cd ${APP_DIR} && ${COMPOSER} require --no-install --no-scripts --no-progress sylius/paypal-plugin="~${SYLIUS_PAYPAL_VERSION}") # @see https://github.com/Sylius/PayPalPlugin/issues/295 $(MAKE) ${APP_DIR}/.php-version $(MAKE) ${APP_DIR}/php.ini (cd ${APP_DIR} && ${COMPOSER} install --no-interaction) $(MAKE) apply_dist - (cd ${APP_DIR} && ${COMPOSER} require --no-interaction --no-progress monsieurbiz/${PLUGIN_NAME}="*@dev") + (cd ${APP_DIR} && ${COMPOSER} require --no-progress monsieurbiz/${PLUGIN_NAME}="*@dev") rm -rf ${APP_DIR}/var/cache ${APP_DIR}/docker-compose.yaml: rm -f ${APP_DIR}/docker-compose.yml rm -f ${APP_DIR}/docker-compose.yaml - rm -f ${APP_DIR}/compose.yml - rm -f ${APP_DIR}/compose.override.dist.yml + rm -f ${APP_DIR}/compose.yml # Remove Sylius file about Docker + rm -f ${APP_DIR}/compose.override.dist.yml # Remove Sylius file about Docker ln -s ../../docker-compose.yaml.dist ${APP_DIR}/docker-compose.yaml .PHONY: ${APP_DIR}/docker-compose.yaml @@ -118,7 +118,7 @@ test.phpstan: ## Run PHPStan ${COMPOSER} phpstan test.phpmd: ## Run PHPMD - ${COMPOSER} phpmd || true + ${COMPOSER} phpmd test.phpunit: ## Run PHPUnit ${COMPOSER} phpunit @@ -136,7 +136,7 @@ test.container: ## Lint the symfony container ${CONSOLE} lint:container test.yaml: ## Lint the symfony Yaml files - ${CONSOLE} lint:yaml --parse-tags ../../recipes ../../src/Resources/config + ${CONSOLE} lint:yaml ../../src/Resources/config --parse-tags test.schema: ## Validate MySQL Schema ${CONSOLE} doctrine:schema:validate @@ -204,18 +204,6 @@ server.start: ## Run the local webserver using Symfony server.stop: ## Stop the local webserver ${SYMFONY} local:server:stop -### -### THEMING -### ¯¯¯¯¯¯¯ - -.PHONY: sylius.theming.build -sylius.theming.build: yarn.install - ${YARN} build - -.PHONY: sylius.theming.watch -sylius.theming.watch: yarn.install - ${YARN} watch - ### ### HELP ### ¯¯¯¯ diff --git a/README.md b/README.md index 2fdc5aed..a6840956 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,31 @@ [![Banner of Sylius Rich Editor plugin](docs/images/banner.jpg)](https://monsieurbiz.com/agence-web-experte-sylius) -

Rich Editor

- -[![Rich Editor Plugin license](https://img.shields.io/github/license/monsieurbiz/SyliusRichEditorPlugin?public)](https://github.com/monsieurbiz/SyliusRichEditorPlugin/blob/master/LICENSE.txt) [![Tests](https://github.com/monsieurbiz/SyliusRichEditorPlugin/actions/workflows/tests.yaml/badge.svg)](https://github.com/monsieurbiz/SyliusRichEditorPlugin/actions/workflows/tests.yaml) [![Security](https://github.com/monsieurbiz/SyliusRichEditorPlugin/actions/workflows/security.yaml/badge.svg)](https://github.com/monsieurbiz/SyliusRichEditorPlugin/actions/workflows/security.yaml) [![Flex Recipe](https://github.com/monsieurbiz/SyliusRichEditorPlugin/actions/workflows/recipe.yaml/badge.svg)](https://github.com/monsieurbiz/SyliusRichEditorPlugin/actions/workflows/recipe.yaml) +

Sylius Rich Editor

+[![Rich Editor Plugin license](https://img.shields.io/github/license/monsieurbiz/SyliusRichEditorPlugin?public)](https://github.com/monsieurbiz/SyliusRichEditorPlugin/blob/master/LICENSE.txt) +[![Tests Status](https://img.shields.io/github/actions/workflow/status/monsieurbiz/SyliusRichEditorPlugin/tests.yaml?branch=master&logo=github)](https://github.com/monsieurbiz/SyliusRichEditorPlugin/actions?query=workflow%3ATests) +[![Recipe Status](https://img.shields.io/github/actions/workflow/status/monsieurbiz/SyliusRichEditorPlugin/recipe.yaml?branch=master&label=recipes&logo=github)](https://github.com/monsieurbiz/SyliusRichEditorPlugin/actions?query=workflow%3ASecurity) +[![Security Status](https://img.shields.io/github/actions/workflow/status/monsieurbiz/SyliusRichEditorPlugin/security.yaml?branch=master&label=security&logo=github)](https://github.com/monsieurbiz/SyliusRichEditorPlugin/actions?query=workflow%3ASecurity) This plugin adds a rich editor on the fields you want. Now you can manage your content very easily! ![Example of rich editor field](docs/images/screenshots/demo.gif) +## Compatibility + +| Sylius Version | PHP Version | +|---|---| +| 1.11 | 8.0 - 8.1 | +| 1.12 | 8.1 - 8.2 | +| 1.13 | 8.1 - 8.2 | + ## Installation +If you want to use our recipes, you can configure your composer.json by running: + +```json +composer config --no-plugins --json extra.symfony.endpoint '["https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master","flex://defaults"]' +``` + ```bash composer require monsieurbiz/sylius-rich-editor-plugin ``` diff --git a/composer.json b/composer.json index 78d0270b..8f7adf09 100644 --- a/composer.json +++ b/composer.json @@ -6,45 +6,16 @@ "license": "MIT", "require": { "php": "^8.0", - "ext-json": "*", - "ext-intl": "*", - "sylius/sylius": ">=1.10 <1.13" + "sylius/sylius": ">=1.11 <1.14" }, "require-dev": { - "behat/behat": "^3.6.1", - "behat/mink-selenium2-driver": "^1.4", - "dmore/behat-chrome-extension": "^1.3", - "dmore/chrome-mink-driver": "^2.7", - "doctrine/data-fixtures": "^1.4", - "ergebnis/composer-normalize": "^2.5", - "friends-of-behat/mink": "^1.8", - "friends-of-behat/mink-browserkit-driver": "^1.4", - "friends-of-behat/mink-extension": "^2.4", - "friends-of-behat/page-object-extension": "^0.3", - "friends-of-behat/symfony-extension": "^2.1", - "friends-of-behat/variadic-extension": "^1.3", - "hwi/oauth-bundle": "^1.1", - "lchrusciel/api-test-case": "^5.0", - "matthiasnoback/symfony-config-test": "^4.2", - "matthiasnoback/symfony-dependency-injection-test": "^4.1", - "mikey179/vfsstream": "^1.6", - "mockery/mockery": "^1.4", - "pamil/prophecy-common": "^0.1", - "phpspec/phpspec": "^6.1|^7.2", - "phpstan/phpstan": "^0.12.57", - "phpstan/phpstan-doctrine": "^0.12.19", - "phpstan/phpstan-webmozart-assert": "^0.12.7", - "phpunit/phpunit": "^8.5", - "psalm/plugin-mockery": "^0.3", - "psr/event-dispatcher": "^1.0", - "sylius-labs/coding-standard": "^3.1", - "symfony/browser-kit": "^4.4", - "symfony/debug-bundle": "^4.4", - "symfony/dotenv": "^4.4", - "symfony/flex": "^1.7", - "symfony/web-profiler-bundle": "^4.4", - "phpmd/phpmd": "@stable", - "symfony/maker-bundle": "^1.39" + "friendsofphp/php-cs-fixer": "^3.16", + "phpspec/phpspec": "^7.0", + "phpstan/phpstan": "^1.8.4", + "phpstan/phpstan-doctrine": "^1.3.2", + "phpstan/phpstan-webmozart-assert": "^1.1", + "phpunit/phpunit": "^10.5", + "phpmd/phpmd": "^2.15" }, "prefer-stable": true, "autoload": { @@ -57,7 +28,7 @@ "cache:clear": "symfony-cmd", "assets:install %PUBLIC_DIR%": "symfony-cmd" }, - "phpcs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix --using-cache=false", + "phpcs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix --using-cache=no", "phpstan": "phpstan analyse -c phpstan.neon src/", "phpmd": "phpmd --exclude Migrations/* src/ ansi phpmd.xml", "phpunit": "phpunit", @@ -65,23 +36,19 @@ }, "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.8-dev" }, "symfony": { "docker": false, - "endpoint": [ - "https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master", - "flex://defaults" - ] + "endpoint": ["https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master", "flex://defaults"] } }, "config": { "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true, "symfony/thanks": true, - "phpstan/extension-installer": true, - "ergebnis/composer-normalize": true, "symfony/flex": true, + "dealerdirect/phpcodesniffer-composer-installer": true, + "ergebnis/composer-normalize": true, "php-http/discovery": true } } diff --git a/phpstan.neon b/phpstan.neon index dc6ef67f..39b3f307 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,26 +1,15 @@ -includes: - - vendor/phpstan/phpstan-doctrine/extension.neon - - vendor/phpstan/phpstan-webmozart-assert/extension.neon - parameters: level: max paths: - %rootDir%/src/ - reportUnmatchedIgnoredErrors: false - checkMissingIterableValueType: false - - excludes_analyse: + excludePaths: # Makes PHPStan crash - - 'src/DependencyInjection/Configuration.php' - 'src/DependencyInjection/MonsieurBizSyliusRichEditorExtension.php' # Test dependencies - - 'tests/Application/app/**.php' - - 'tests/Application/src/**.php' - - # Skeleton files - - 'src/Resources/skeleton/*.php' + - 'tests/Application/**/*' ignoreErrors: - - '/Parameter #1 \$configuration of method Symfony\\Component\\DependencyInjection\\Extension\\Extension::processConfiguration\(\) expects Symfony\\Component\\Config\\Definition\\ConfigurationInterface, Symfony\\Component\\Config\\Definition\\ConfigurationInterface\|null given\./' + - identifier: missingType.generics + - identifier: missingType.iterableValue From cbe52537a3cb80ce331cd93da258d99c6467914f Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 18 Jun 2024 20:05:35 +0200 Subject: [PATCH 03/10] Fix PHP CS --- .../UiElementRegistryPass.php | 3 ++- src/Form/Type/WysiwygType.php | 4 ++-- src/UiElement/Metadata.php | 12 +++++++----- src/UiElement/Metadata/Registry.php | 3 ++- src/UiElement/MetadataInterface.php | 6 ------ src/UiElement/Registry.php | 3 ++- src/UiElement/RegistryInterface.php | 3 ++- src/UiElement/UiElementInterface.php | 6 ++---- src/UiElement/UiElementTrait.php | 3 ++- tests/spec/UiElement/MetadataSpec.php | 18 +++++++++--------- 10 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/DependencyInjection/UiElementRegistryPass.php b/src/DependencyInjection/UiElementRegistryPass.php index 86614107..705abe04 100644 --- a/src/DependencyInjection/UiElementRegistryPass.php +++ b/src/DependencyInjection/UiElementRegistryPass.php @@ -17,6 +17,7 @@ use MonsieurBiz\SyliusRichEditorPlugin\UiElement\Metadata; use MonsieurBiz\SyliusRichEditorPlugin\UiElement\UiElement; use MonsieurBiz\SyliusRichEditorPlugin\UiElement\UiElementInterface; +use ReflectionAttribute; use ReflectionClass; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -72,7 +73,7 @@ private function processAttribute(ContainerBuilder $container, Definition $regis */ private function processClass(Definition $definition, ReflectionClass $reflectionClass, ContainerBuilder $container, Definition $registry, Definition $metadataRegistry): void { - foreach ($reflectionClass->getAttributes(AsUiElement::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) { + foreach ($reflectionClass->getAttributes(AsUiElement::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) { $attribute = $attribute->newInstance(); /** @var AsUiElement $attribute */ $code = $attribute->getCode(); diff --git a/src/Form/Type/WysiwygType.php b/src/Form/Type/WysiwygType.php index e1124b60..9ae372f3 100644 --- a/src/Form/Type/WysiwygType.php +++ b/src/Form/Type/WysiwygType.php @@ -85,7 +85,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('editor_toolbar_buttons', ['null', 'array']); $resolver->setAllowedTypes('editor_custom_config', ['null', 'array']); - $resolver->setNormalizer('editor_toolbar_buttons', function (Options $options, array|null $value): string { + $resolver->setNormalizer('editor_toolbar_buttons', function (Options $options, ?array $value): string { $editor = $this->editorCollection->getEditor($options['editor_type']); return match ($options['editor_toolbar_type']) { @@ -96,7 +96,7 @@ public function configureOptions(OptionsResolver $resolver): void }; }); - $resolver->setNormalizer('editor_custom_config', function (Options $options, array|null $value): string { + $resolver->setNormalizer('editor_custom_config', function (Options $options, ?array $value): string { return $this->encoder->encode($value ?? [], 'json'); }); } diff --git a/src/UiElement/Metadata.php b/src/UiElement/Metadata.php index 9c0a24e4..79d0a7ed 100644 --- a/src/UiElement/Metadata.php +++ b/src/UiElement/Metadata.php @@ -13,6 +13,8 @@ namespace MonsieurBiz\SyliusRichEditorPlugin\UiElement; +use InvalidArgumentException; + final class Metadata implements MetadataInterface { private string $code; @@ -25,10 +27,10 @@ final class Metadata implements MetadataInterface private function __construct(string $code, array $parameters) { if (!isset($parameters['classes'], $parameters['templates'])) { - throw new \InvalidArgumentException('Classes and Templates must be specified in parameters.'); + throw new InvalidArgumentException('Classes and Templates must be specified in parameters.'); } if (1 !== substr_count($code, '.')) { - throw new \InvalidArgumentException('The Code should contain one dot (.).'); + throw new InvalidArgumentException('The Code should contain one dot (.).'); } $this->code = $code; $this->parameters = $parameters; @@ -82,7 +84,7 @@ public function isEnabled(): bool public function getParameter(string $name) { if (!$this->hasParameter($name)) { - throw new \InvalidArgumentException(sprintf('Parameter "%s" is not configured for resource "%s".', $name, $this->getCode())); + throw new InvalidArgumentException(sprintf('Parameter "%s" is not configured for resource "%s".', $name, $this->getCode())); } return $this->parameters[$name]; @@ -110,7 +112,7 @@ public function getParameters(): array public function getClass(string $name): string { if (!$this->hasClass($name)) { - throw new \InvalidArgumentException(sprintf('Class "%s" is not configured for resource "%s".', $name, $this->getCode())); + throw new InvalidArgumentException(sprintf('Class "%s" is not configured for resource "%s".', $name, $this->getCode())); } return $this->parameters['classes'][$name]; @@ -130,7 +132,7 @@ public function hasClass(string $name): bool public function getTemplate(string $name): string { if (!$this->hasTemplate($name)) { - throw new \InvalidArgumentException(sprintf('Template "%s" is not configured for resource "%s".', $name, $this->getCode())); + throw new InvalidArgumentException(sprintf('Template "%s" is not configured for resource "%s".', $name, $this->getCode())); } return $this->parameters['templates'][$name]; diff --git a/src/UiElement/Metadata/Registry.php b/src/UiElement/Metadata/Registry.php index 25add863..b4eaca57 100644 --- a/src/UiElement/Metadata/Registry.php +++ b/src/UiElement/Metadata/Registry.php @@ -13,6 +13,7 @@ namespace MonsieurBiz\SyliusRichEditorPlugin\UiElement\Metadata; +use InvalidArgumentException; use MonsieurBiz\SyliusRichEditorPlugin\UiElement\Metadata; use MonsieurBiz\SyliusRichEditorPlugin\UiElement\MetadataInterface; @@ -29,7 +30,7 @@ final class Registry implements RegistryInterface public function get(string $code): MetadataInterface { if (!\array_key_exists($code, $this->metadata)) { - throw new \InvalidArgumentException(sprintf('Resource "%s" does not exist.', $code)); + throw new InvalidArgumentException(sprintf('Resource "%s" does not exist.', $code)); } return $this->metadata[$code]; diff --git a/src/UiElement/MetadataInterface.php b/src/UiElement/MetadataInterface.php index 1fac01e6..b7bae108 100644 --- a/src/UiElement/MetadataInterface.php +++ b/src/UiElement/MetadataInterface.php @@ -15,16 +15,10 @@ interface MetadataInterface { - /** - * @return MetadataInterface - */ public static function fromCodeAndConfiguration(string $code, array $parameters): self; public function getCode(): string; - /** - * @return string - */ public function getAlias(): ?string; public function getCamelCasedCode(): string; diff --git a/src/UiElement/Registry.php b/src/UiElement/Registry.php index a015bd4e..567d53db 100644 --- a/src/UiElement/Registry.php +++ b/src/UiElement/Registry.php @@ -14,6 +14,7 @@ namespace MonsieurBiz\SyliusRichEditorPlugin\UiElement; use MonsieurBiz\SyliusRichEditorPlugin\Exception\UiElementNotFoundException; +use ReturnTypeWillChange; use Webmozart\Assert\Assert; final class Registry implements RegistryInterface @@ -68,7 +69,7 @@ public function getUiElements(): array /** * @inheritdoc */ - #[\ReturnTypeWillChange] + #[ReturnTypeWillChange] public function jsonSerialize(): mixed { return $this->uiElements; diff --git a/src/UiElement/RegistryInterface.php b/src/UiElement/RegistryInterface.php index 5742002d..49cd629e 100644 --- a/src/UiElement/RegistryInterface.php +++ b/src/UiElement/RegistryInterface.php @@ -13,9 +13,10 @@ namespace MonsieurBiz\SyliusRichEditorPlugin\UiElement; +use JsonSerializable; use MonsieurBiz\SyliusRichEditorPlugin\Exception\UiElementNotFoundException; -interface RegistryInterface extends \JsonSerializable +interface RegistryInterface extends JsonSerializable { public function addUiElement(UiElementInterface $uiElement): void; diff --git a/src/UiElement/UiElementInterface.php b/src/UiElement/UiElementInterface.php index 9b9fae4c..ce2e2d27 100644 --- a/src/UiElement/UiElementInterface.php +++ b/src/UiElement/UiElementInterface.php @@ -14,10 +14,11 @@ namespace MonsieurBiz\SyliusRichEditorPlugin\UiElement; use InvalidArgumentException; +use JsonSerializable; use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Environment; -interface UiElementInterface extends \JsonSerializable +interface UiElementInterface extends JsonSerializable { public function setMetadata(MetadataInterface $metadata): void; @@ -27,9 +28,6 @@ public function setTwigEnvironment(Environment $twig): void; public function getCode(): string; - /** - * @return string - */ public function getAlias(): ?string; public function getTitle(): string; diff --git a/src/UiElement/UiElementTrait.php b/src/UiElement/UiElementTrait.php index 7306ac6c..b40ae46b 100644 --- a/src/UiElement/UiElementTrait.php +++ b/src/UiElement/UiElementTrait.php @@ -14,6 +14,7 @@ namespace MonsieurBiz\SyliusRichEditorPlugin\UiElement; use Exception; +use ReturnTypeWillChange; use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Environment; @@ -165,7 +166,7 @@ public function ignore(): void /** * @inheritdoc */ - #[\ReturnTypeWillChange] + #[ReturnTypeWillChange] public function jsonSerialize(): mixed { return [ diff --git a/tests/spec/UiElement/MetadataSpec.php b/tests/spec/UiElement/MetadataSpec.php index 9d2d9008..9e9c5496 100644 --- a/tests/spec/UiElement/MetadataSpec.php +++ b/tests/spec/UiElement/MetadataSpec.php @@ -57,19 +57,19 @@ public function it_gives_you_a_singleton(): void ; $this->shouldThrow(InvalidArgumentException::class)->during( - 'fromCodeAndConfiguration', - ['app.yep', []] - ); + 'fromCodeAndConfiguration', + ['app.yep', []] + ); $this->shouldThrow(InvalidArgumentException::class)->during( - 'fromCodeAndConfiguration', - ['app.yep.bam', self::PARAMETERS] - ); + 'fromCodeAndConfiguration', + ['app.yep.bam', self::PARAMETERS] + ); $this->shouldThrow(InvalidArgumentException::class)->during( - 'fromCodeAndConfiguration', - ['app', self::PARAMETERS] - ); + 'fromCodeAndConfiguration', + ['app', self::PARAMETERS] + ); } public function it_gives_back_the_code(): void From 654e519a41df9496675f96ff8dc3a2c8bb2bf8e3 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 18 Jun 2024 21:31:41 +0200 Subject: [PATCH 04/10] Fix PHP Stan --- phpstan.neon | 7 ++++++- src/Controller/FormController.php | 19 ++++++++++++----- src/DependencyInjection/Configuration.php | 10 +++------ .../MonsieurBizSyliusRichEditorExtension.php | 2 +- .../UiElementRegistryPass.php | 2 +- src/Form/Type/AlignmentType.php | 2 +- src/Form/Type/RichEditorType.php | 2 +- src/Form/Type/UiElement/ImageType.php | 2 +- src/Form/Type/UiElement/SeparatorType.php | 1 + src/Form/Type/UiElement/VideoType.php | 4 ++-- src/Form/Type/WysiwygType.php | 13 ++++++++---- src/UiElement/UiElementFormOptionsTrait.php | 1 + src/UiElement/UiElementTrait.php | 21 +++++++++++++++---- .../Constraints/YoutubeUrlValidator.php | 9 +++++--- 14 files changed, 64 insertions(+), 31 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 39b3f307..3db8ce03 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -10,6 +10,11 @@ parameters: # Test dependencies - 'tests/Application/**/*' + # Skeleton files + - 'src/Resources/skeleton/*.php' + + # Maker files + - 'src/Maker/*.php' + ignoreErrors: - - identifier: missingType.generics - identifier: missingType.iterableValue diff --git a/src/Controller/FormController.php b/src/Controller/FormController.php index e9db1404..21fe9785 100644 --- a/src/Controller/FormController.php +++ b/src/Controller/FormController.php @@ -58,6 +58,9 @@ public function viewAction(Request $request, string $code): Response $data = []; $isEdition = $request->isMethod('post'); if ($isEdition && ($data = $request->get('data'))) { + if (!\is_string($data)) { + throw $this->createNotFoundException(); + } $data = json_decode($data, true); if (!\is_array($data)) { throw $this->createNotFoundException(); @@ -84,6 +87,9 @@ public function viewAction(Request $request, string $code): Response public function renderElementsAction(Request $request, SwitchAdminLocaleInterface $switchAdminLocale): Response { if ($uiElements = $request->get('ui_elements')) { + if (!\is_string($uiElements)) { + throw $this->createNotFoundException(); + } $uiElements = json_decode($uiElements, true); if (!\is_array($uiElements)) { throw $this->createNotFoundException(); @@ -92,7 +98,7 @@ public function renderElementsAction(Request $request, SwitchAdminLocaleInterfac // if we have a locale value in the post data, we change the current // admin locale to make the ui elements in the correct version. - if ($locale = $request->get('locale')) { + if (($locale = $request->get('locale')) && \is_string($locale)) { $switchAdminLocale->switchLocale($locale); } @@ -104,8 +110,8 @@ public function renderElementsAction(Request $request, SwitchAdminLocaleInterfac if (!isset($uiElementData['code'])) { if (isset($uiElementData['type'], $uiElementData['fields'])) { $uiElementData['code'] = $uiElementData['type']; - $uiElementData['data'] = $uiElementData['fields']; // @phpstan-ignore-line - unset($uiElementData['type'], $uiElementData['fields']); // @phpstan-ignore-line + $uiElementData['data'] = $uiElementData['fields']; + unset($uiElementData['type'], $uiElementData['fields']); } else { continue; } @@ -188,7 +194,7 @@ public function submitAction(Request $request, FileUploaderInterface $fileUpload /** * Build a new form data array with the uploaded file path instead of files, or current filenames on edition. * - * @param mixed $requestData + * @param array|string $requestData * * @return array|mixed|string */ @@ -217,7 +223,10 @@ private function processFormDataWithoutChild(FormInterface $form, FileUploaderIn { if ($form->isValid() && $form->getData() instanceof UploadedFile) { // Upload image selected by user - return $fileUploader->upload($form->getData(), $form->getConfig()->getOption('file-type')); + /** @var ?string $fileType */ + $fileType = $form->getConfig()->getOption('file-type'); + + return $fileUploader->upload($form->getData(), $fileType); } if ($form->getConfig()->getType()->getInnerType() instanceof NativeFileType && !empty($requestData)) { // Check if we have a string value for this fields which is the file path (During edition for example) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 5e84b1b0..3f227f88 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -26,12 +26,8 @@ final class Configuration implements ConfigurationInterface public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('monsieurbiz_sylius_richeditor'); - if (method_exists($treeBuilder, 'getRootNode')) { - $rootNode = $treeBuilder->getRootNode(); - } else { - // BC layer for symfony/config 4.1 and older - $rootNode = /** @scrutinizer ignore-deprecated */ $treeBuilder->root('monsieurbiz_sylius_richeditor'); - } + /** @var ArrayNodeDefinition $rootNode */ + $rootNode = $treeBuilder->getRootNode(); $this->addUiElements($rootNode); @@ -40,7 +36,7 @@ public function getConfigTreeBuilder(): TreeBuilder private function addUiElements(ArrayNodeDefinition $rootNode): void { - /** @scrutinizer ignore-call */ + /** @phpstan-ignore-next-line */ $rootNode ->children() ->scalarNode('upload_directory')->end() diff --git a/src/DependencyInjection/MonsieurBizSyliusRichEditorExtension.php b/src/DependencyInjection/MonsieurBizSyliusRichEditorExtension.php index 0372232d..ab287910 100644 --- a/src/DependencyInjection/MonsieurBizSyliusRichEditorExtension.php +++ b/src/DependencyInjection/MonsieurBizSyliusRichEditorExtension.php @@ -26,7 +26,7 @@ final class MonsieurBizSyliusRichEditorExtension extends Extension public function load(array $config, ContainerBuilder $container): void { $configuration = $this->getConfiguration([], $container); - $config = $this->processConfiguration(/** @scrutinizer ignore-type */ $configuration, $config); + $config = $this->processConfiguration($configuration, $config); $container->setParameter('monsieurbiz.richeditor.config.ui_elements', $config['ui_elements']); $container->setParameter('monsieurbiz.richeditor.config.upload_directory', $config['upload_directory']); $container->setParameter('monsieurbiz.richeditor.config.image_upload_directory', $config['image_upload_directory']); diff --git a/src/DependencyInjection/UiElementRegistryPass.php b/src/DependencyInjection/UiElementRegistryPass.php index 705abe04..90b628bf 100644 --- a/src/DependencyInjection/UiElementRegistryPass.php +++ b/src/DependencyInjection/UiElementRegistryPass.php @@ -121,7 +121,7 @@ private function registerUiElement(string $code, array $configuration, Container */ private function validateUiElementResource(string $class): void { - $interfaces = (array) (class_implements($class) ?? []); + $interfaces = (array) class_implements($class); if (!\in_array(UiElementInterface::class, $interfaces, true)) { throw new InvalidArgumentException(sprintf('Class "%s" must implement "%s" to be registered as a UiElement resource.', $class, UiElementInterface::class)); diff --git a/src/Form/Type/AlignmentType.php b/src/Form/Type/AlignmentType.php index f306a0df..4dfb2aac 100644 --- a/src/Form/Type/AlignmentType.php +++ b/src/Form/Type/AlignmentType.php @@ -38,7 +38,7 @@ public function configureOptions(OptionsResolver $resolver): void public function buildForm(FormBuilderInterface $builder, array $options): void { // Add justify choices depending on options - if ($options['show_justify']) { + if ($options['show_justify'] && \is_array($options['choices'])) { $options['choices']['monsieurbiz_richeditor_plugin.form.align.justify'] = 'justify'; } parent::buildForm($builder, $options); diff --git a/src/Form/Type/RichEditorType.php b/src/Form/Type/RichEditorType.php index f8484a95..f2afc3ac 100644 --- a/src/Form/Type/RichEditorType.php +++ b/src/Form/Type/RichEditorType.php @@ -26,7 +26,7 @@ class RichEditorType extends TextType public function buildView(FormView $view, FormInterface $form, array $options): void { $view->vars['attr']['data-component'] = 'rich-editor'; - $view->vars['attr']['data-tags'] = implode(',', $options['tags'] ?? []); + $view->vars['attr']['data-tags'] = implode(',', \is_array($options['tags']) ? $options['tags'] : []); if (null !== $options['locale']) { $view->vars['attr']['data-locale'] = $options['locale']; } diff --git a/src/Form/Type/UiElement/ImageType.php b/src/Form/Type/UiElement/ImageType.php index cf2328d1..195786e9 100644 --- a/src/Form/Type/UiElement/ImageType.php +++ b/src/Form/Type/UiElement/ImageType.php @@ -82,7 +82,7 @@ public function addEvents(FormBuilderInterface $builder, array $options): void $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event): void { // Change image field constraints depending on submitted value $options = $event->getForm()->get('image')->getConfig()->getOptions(); - $options['constraints'] = RichEditorConstraints::getImageConstraints($event->getData(), 'image'); + $options['constraints'] = RichEditorConstraints::getImageConstraints(\is_array($event->getData()) ? $event->getData() : [], 'image'); $event->getForm()->add('image', $this->getImageType(), $options); }); } diff --git a/src/Form/Type/UiElement/SeparatorType.php b/src/Form/Type/UiElement/SeparatorType.php index 25b7beaf..e3c6632b 100644 --- a/src/Form/Type/UiElement/SeparatorType.php +++ b/src/Form/Type/UiElement/SeparatorType.php @@ -32,6 +32,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'required' => false, ]) ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { + /** @var array $data */ $data = $event->getData(); $data['hidden'] = (bool) ($data['hidden'] ?? false); $event->setData($data); diff --git a/src/Form/Type/UiElement/VideoType.php b/src/Form/Type/UiElement/VideoType.php index 2084b1eb..aa790777 100644 --- a/src/Form/Type/UiElement/VideoType.php +++ b/src/Form/Type/UiElement/VideoType.php @@ -71,12 +71,12 @@ public function addEvents(FormBuilderInterface $builder, array $options): void $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event): void { // Change video field constraints depending on submitted value $options = $event->getForm()->get('video')->getConfig()->getOptions(); - $options['constraints'] = RichEditorConstraints::getVideoConstraints($event->getData(), 'video'); + $options['constraints'] = RichEditorConstraints::getVideoConstraints(\is_array($event->getData()) ? $event->getData() : [], 'video'); $event->getForm()->add('video', $this->getVideoType(), $options); // Change image field constraints depending on submitted value $options = $event->getForm()->get('image')->getConfig()->getOptions(); - $options['constraints'] = RichEditorConstraints::getImageConstraints($event->getData(), 'image', false); + $options['constraints'] = RichEditorConstraints::getImageConstraints(\is_array($event->getData()) ? $event->getData() : [], 'image', false); $event->getForm()->add('image', $this->getImageType(), $options); }); } diff --git a/src/Form/Type/WysiwygType.php b/src/Form/Type/WysiwygType.php index 9ae372f3..b67cf6ce 100644 --- a/src/Form/Type/WysiwygType.php +++ b/src/Form/Type/WysiwygType.php @@ -86,12 +86,14 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('editor_custom_config', ['null', 'array']); $resolver->setNormalizer('editor_toolbar_buttons', function (Options $options, ?array $value): string { - $editor = $this->editorCollection->getEditor($options['editor_type']); + /** @var string $editorType */ + $editorType = $options['editor_type']; + $editor = $this->editorCollection->getEditor($editorType); return match ($options['editor_toolbar_type']) { EditorInterface::TOOLBAR_TYPE_MINIMAL => $this->encoder->encode($editor->getMinimalButtons(), 'json'), - EditorInterface::TOOLBAR_TYPE_BASIC => $this->encoder->encode($editor->getBasicButtons() ?? [], 'json'), - EditorInterface::TOOLBAR_TYPE_FULL => $this->encoder->encode($editor->getFullButtons() ?? [], 'json'), + EditorInterface::TOOLBAR_TYPE_BASIC => $this->encoder->encode($editor->getBasicButtons(), 'json'), + EditorInterface::TOOLBAR_TYPE_FULL => $this->encoder->encode($editor->getFullButtons(), 'json'), default => $this->encoder->encode($value ?? [], 'json'), }; }); @@ -103,9 +105,12 @@ public function configureOptions(OptionsResolver $resolver): void private function getDataValues(array $options): array { + /** @var string $editorType */ + $editorType = $options['editor_type']; + return [ 'data-component' => 'wysiwyg-editor', - 'data-editor-type' => $options['editor_type'], + 'data-editor-type' => $editorType, 'data-editor-height' => $options['editor_height'], 'data-editor-locale' => $options['editor_locale'], 'data-editor-buttons' => $options['editor_toolbar_buttons'], diff --git a/src/UiElement/UiElementFormOptionsTrait.php b/src/UiElement/UiElementFormOptionsTrait.php index 8c92be43..9a8fd7af 100644 --- a/src/UiElement/UiElementFormOptionsTrait.php +++ b/src/UiElement/UiElementFormOptionsTrait.php @@ -25,6 +25,7 @@ trait UiElementFormOptionsTrait public function getFormOptions(): array { try { + /** @phpstan-ignore-next-line */ return $this->metadata->getParameter('form_options'); } catch (InvalidArgumentException) { return []; diff --git a/src/UiElement/UiElementTrait.php b/src/UiElement/UiElementTrait.php index b40ae46b..a35c374b 100644 --- a/src/UiElement/UiElementTrait.php +++ b/src/UiElement/UiElementTrait.php @@ -14,6 +14,7 @@ namespace MonsieurBiz\SyliusRichEditorPlugin\UiElement; use Exception; +use PHPUnit\Framework\Assert; use ReturnTypeWillChange; use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Environment; @@ -81,7 +82,10 @@ public function isEnabled(): bool */ public function getTitle(): string { - return $this->metadata->getParameter('title'); + $value = $this->metadata->getParameter('title'); + Assert::assertIsString($value); + + return $value; } /** @@ -89,7 +93,10 @@ public function getTitle(): string */ public function getDescription(): string { - return $this->metadata->getParameter('description'); + $value = $this->metadata->getParameter('description'); + Assert::assertIsString($value); + + return $value; } /** @@ -97,7 +104,10 @@ public function getDescription(): string */ public function getIcon(): string { - return $this->metadata->getParameter('icon'); + $value = $this->metadata->getParameter('icon'); + Assert::assertIsString($value); + + return $value; } /** @@ -105,7 +115,10 @@ public function getIcon(): string */ public function getWireframe(): string { - return $this->metadata->getParameter('wireframe'); + $value = $this->metadata->getParameter('wireframe'); + Assert::assertIsString($value); + + return $value; } /** diff --git a/src/Validator/Constraints/YoutubeUrlValidator.php b/src/Validator/Constraints/YoutubeUrlValidator.php index 3a2c5fa2..428946e0 100644 --- a/src/Validator/Constraints/YoutubeUrlValidator.php +++ b/src/Validator/Constraints/YoutubeUrlValidator.php @@ -21,15 +21,18 @@ class YoutubeUrlValidator extends ConstraintValidator { public const YOUTUBE_REGEX_VALIDATOR = '`^(?:https?://)?(?:www\.)?(?:youtu.be/|youtube\.com/(?:watch(?:/|/?\?(?:\S*&)?v=)|embed/))([\w\d-]+)$`'; - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof YoutubeUrl) { throw new UnexpectedTypeException($constraint, YoutubeUrl::class); } - if (!preg_match(self::YOUTUBE_REGEX_VALIDATOR, (string) $value)) { + /** @phpstan-ignore-next-line */ + $value = (string) $value; + + if (!preg_match(self::YOUTUBE_REGEX_VALIDATOR, $value)) { $this->context->buildViolation($constraint->message) - ->setParameter('{{ string }}', (string) $value) + ->setParameter('{{ string }}', $value) ->addViolation() ; } From e4b9fc0154965671ae5703c51360bbed051264e2 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 18 Jun 2024 21:38:24 +0200 Subject: [PATCH 05/10] Ignore some PHP MD errors --- src/Controller/FormController.php | 9 +++++++++ src/Form/Constraints/RichEditorConstraints.php | 4 ++++ src/Form/Type/UiElement/ButtonLinkType.php | 2 +- src/Form/Type/UiElement/ImageType.php | 3 +++ src/Form/Type/UiElement/VideoType.php | 3 +++ src/Form/Type/WysiwygType.php | 2 ++ src/Twig/RichEditorExtension.php | 5 +++++ 7 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Controller/FormController.php b/src/Controller/FormController.php index 21fe9785..4b7e8e48 100644 --- a/src/Controller/FormController.php +++ b/src/Controller/FormController.php @@ -44,6 +44,8 @@ public function __construct(RegistryInterface $uiElementRegistry) /** * Generate the form for an element. + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function viewAction(Request $request, string $code): Response { @@ -83,6 +85,9 @@ public function viewAction(Request $request, string $code): Response /** * Render all UI elements in HTML. + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ElseExpression) */ public function renderElementsAction(Request $request, SwitchAdminLocaleInterface $switchAdminLocale): Response { @@ -218,6 +223,8 @@ private function processFormData(FormInterface $form, FileUploaderInterface $fil * @param array|string $requestData * * @return array|mixed|string + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ private function processFormDataWithoutChild(FormInterface $form, FileUploaderInterface $fileUploader, $requestData) { @@ -240,6 +247,8 @@ private function processFormDataWithoutChild(FormInterface $form, FileUploaderIn * Recursively convert multidimensional array to one dimension * The key is the full input name (ex : `image_collection[images][0][image]`) * It is used in form with file inputs when the form is not valid to avoid to loose uploaded files. + * + * @SuppressWarnings(PHPMD.ElseExpression) */ private function convertFormDataForRequest(array $formData, string $prefix = ''): array { diff --git a/src/Form/Constraints/RichEditorConstraints.php b/src/Form/Constraints/RichEditorConstraints.php index 7b2e2ec9..f1db5254 100644 --- a/src/Form/Constraints/RichEditorConstraints.php +++ b/src/Form/Constraints/RichEditorConstraints.php @@ -22,6 +22,8 @@ final class RichEditorConstraints * Return constraint depending on data * If user created the element, the field is required * If it's an edition and it contains a filename, we don't flag it as required. + * + * @SuppressWarnings(PHPMD.BooleanArgumentFlag) */ public static function getImageConstraints(array $data, string $fieldName, bool $required = true, array $defaultConstraints = []): array { @@ -42,6 +44,8 @@ public static function getImageConstraints(array $data, string $fieldName, bool * Return constraint depending on data * If user created the element, the field is required * If it's an edition and it contains a filename, we don't flag it as required. + * + * @SuppressWarnings(PHPMD.BooleanArgumentFlag) */ public static function getVideoConstraints(array $data, string $fieldName, bool $required = true, array $defaultConstraints = []): array { diff --git a/src/Form/Type/UiElement/ButtonLinkType.php b/src/Form/Type/UiElement/ButtonLinkType.php index f8008387..e9bac5fe 100644 --- a/src/Form/Type/UiElement/ButtonLinkType.php +++ b/src/Form/Type/UiElement/ButtonLinkType.php @@ -22,7 +22,7 @@ class ButtonLinkType extends AbstractType { /** - * @inheritdoc + * @SuppressWarnings(PHPMD.ElseExpression) */ public function buildForm(FormBuilderInterface $builder, array $options): void { diff --git a/src/Form/Type/UiElement/ImageType.php b/src/Form/Type/UiElement/ImageType.php index 195786e9..c4465d36 100644 --- a/src/Form/Type/UiElement/ImageType.php +++ b/src/Form/Type/UiElement/ImageType.php @@ -36,6 +36,9 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $this->addEvents($builder, $options); } + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ public function addFields(FormBuilderInterface $builder, array $options): void { $builder diff --git a/src/Form/Type/UiElement/VideoType.php b/src/Form/Type/UiElement/VideoType.php index aa790777..3b781e7f 100644 --- a/src/Form/Type/UiElement/VideoType.php +++ b/src/Form/Type/UiElement/VideoType.php @@ -35,6 +35,9 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $this->addEvents($builder, $options); } + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ public function addFields(FormBuilderInterface $builder, array $options): void { $builder diff --git a/src/Form/Type/WysiwygType.php b/src/Form/Type/WysiwygType.php index b67cf6ce..f8cd71c5 100644 --- a/src/Form/Type/WysiwygType.php +++ b/src/Form/Type/WysiwygType.php @@ -43,6 +43,8 @@ public function __construct( /** * @inheritdoc + * + * @SuppressWarnings(PHPMD.ElseExpression) */ public function buildView(FormView $view, FormInterface $form, array $options): void { diff --git a/src/Twig/RichEditorExtension.php b/src/Twig/RichEditorExtension.php index 1860d459..8b0dadb1 100644 --- a/src/Twig/RichEditorExtension.php +++ b/src/Twig/RichEditorExtension.php @@ -158,6 +158,8 @@ public function renderElements(array $context, array $elements): string * @throws LoaderError [twig.render] When the template cannot be found * @throws SyntaxError [twig.render] When an error occurred during compilation * @throws RuntimeError [twig.render] When an error occurred during rendering + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function renderElement(array $context, array $element): string { @@ -231,6 +233,9 @@ public function getDefaultElementDataField(): string return $this->defaultElementDataField; } + /** + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ public function getCurrentFilePath(array $context, string $varName = 'full_name'): ?string { $form = $context['form']; From 5a4af4dc4026653d3645de088c054ca764e5eff4 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 18 Jun 2024 21:45:34 +0200 Subject: [PATCH 06/10] Add shorts compatibility in Youtube links --- src/Validator/Constraints/YoutubeUrlValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Validator/Constraints/YoutubeUrlValidator.php b/src/Validator/Constraints/YoutubeUrlValidator.php index 428946e0..b14f4243 100644 --- a/src/Validator/Constraints/YoutubeUrlValidator.php +++ b/src/Validator/Constraints/YoutubeUrlValidator.php @@ -19,7 +19,7 @@ class YoutubeUrlValidator extends ConstraintValidator { - public const YOUTUBE_REGEX_VALIDATOR = '`^(?:https?://)?(?:www\.)?(?:youtu.be/|youtube\.com/(?:watch(?:/|/?\?(?:\S*&)?v=)|embed/))([\w\d-]+)$`'; + public const YOUTUBE_REGEX_VALIDATOR = '`^(?:https?://)?(?:www\.)?(?:youtu.be/|youtube\.com/(?:watch(?:/|/?\?(?:\S*&)?v=)|embed|shorts/))([\w\d-]+)$`'; public function validate(mixed $value, Constraint $constraint): void { From 3ae8e9fd746872330b05a809696bd6b5cd0cc298 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 18 Jun 2024 22:10:37 +0200 Subject: [PATCH 07/10] Allow unresolvable data_root in liip imagine if folder does not exists --- src/Resources/config/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Resources/config/config.yaml b/src/Resources/config/config.yaml index b5cbf51f..d130fa8c 100644 --- a/src/Resources/config/config.yaml +++ b/src/Resources/config/config.yaml @@ -22,5 +22,6 @@ liip_imagine: loaders: default: filesystem: + allow_unresolvable_data_roots: true data_root: - "%sylius_core.public_dir%%env(MONSIEURBIZ_SYLIUS_RICH_EDITOR_UPLOAD_DIR)%" From 716e8a20af99b839c12255ecbe2212f4c3f8dff3 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Mon, 24 Jun 2024 18:47:37 +0200 Subject: [PATCH 08/10] Add host name from symfony route host in dev env local --- dist/.env.local | 1 + 1 file changed, 1 insertion(+) create mode 100644 dist/.env.local diff --git a/dist/.env.local b/dist/.env.local new file mode 100644 index 00000000..6c1a99ee --- /dev/null +++ b/dist/.env.local @@ -0,0 +1 @@ +SYLIUS_FIXTURES_HOSTNAME=${SYMFONY_DEFAULT_ROUTE_HOST:-localhost} From 0f2a88728cd59a7f2bad8353eb34e09166b77800 Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 2 Jul 2024 11:30:46 +0200 Subject: [PATCH 09/10] Correct README composer command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6840956..aeb1b019 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ This plugin adds a rich editor on the fields you want. Now you can manage your c If you want to use our recipes, you can configure your composer.json by running: -```json +```bash composer config --no-plugins --json extra.symfony.endpoint '["https://api.github.com/repos/monsieurbiz/symfony-recipes/contents/index.json?ref=flex/master","flex://defaults"]' ``` From 3347006e1c12781a9a3cc8845eb99bb646bebbcf Mon Sep 17 00:00:00 2001 From: Maxime Huran Date: Tue, 2 Jul 2024 11:30:56 +0200 Subject: [PATCH 10/10] Correct tests --- src/UiElement/UiElementFormOptionsTrait.php | 2 +- src/UiElement/UiElementTrait.php | 25 +++++++-------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/UiElement/UiElementFormOptionsTrait.php b/src/UiElement/UiElementFormOptionsTrait.php index 9a8fd7af..9525aebb 100644 --- a/src/UiElement/UiElementFormOptionsTrait.php +++ b/src/UiElement/UiElementFormOptionsTrait.php @@ -25,7 +25,7 @@ trait UiElementFormOptionsTrait public function getFormOptions(): array { try { - /** @phpstan-ignore-next-line */ + /** @var array */ return $this->metadata->getParameter('form_options'); } catch (InvalidArgumentException) { return []; diff --git a/src/UiElement/UiElementTrait.php b/src/UiElement/UiElementTrait.php index a35c374b..3498c52a 100644 --- a/src/UiElement/UiElementTrait.php +++ b/src/UiElement/UiElementTrait.php @@ -14,7 +14,6 @@ namespace MonsieurBiz\SyliusRichEditorPlugin\UiElement; use Exception; -use PHPUnit\Framework\Assert; use ReturnTypeWillChange; use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Environment; @@ -82,10 +81,8 @@ public function isEnabled(): bool */ public function getTitle(): string { - $value = $this->metadata->getParameter('title'); - Assert::assertIsString($value); - - return $value; + /** @var string */ + return $this->metadata->getParameter('title'); } /** @@ -93,10 +90,8 @@ public function getTitle(): string */ public function getDescription(): string { - $value = $this->metadata->getParameter('description'); - Assert::assertIsString($value); - - return $value; + /** @var string */ + return $this->metadata->getParameter('description'); } /** @@ -104,10 +99,8 @@ public function getDescription(): string */ public function getIcon(): string { - $value = $this->metadata->getParameter('icon'); - Assert::assertIsString($value); - - return $value; + /** @var string */ + return $this->metadata->getParameter('icon'); } /** @@ -115,10 +108,8 @@ public function getIcon(): string */ public function getWireframe(): string { - $value = $this->metadata->getParameter('wireframe'); - Assert::assertIsString($value); - - return $value; + /** @var string */ + return $this->metadata->getParameter('wireframe'); } /**