From 44fbcae08061e25b08b3f48fd6cb58956beb2475 Mon Sep 17 00:00:00 2001 From: David ALLIX Date: Wed, 3 Jan 2024 12:27:04 +0100 Subject: [PATCH] SF7 compat & Some cleanings (#387) --- .github/workflows/ci.yml | 112 ++++++++---------- .php-cs-fixer.dist.php | 50 ++++---- .phpqa.yml | 15 --- composer.json | 43 +++---- phpunit.xml.dist | 2 +- rector.php | 37 ++++++ .../A2lixTranslationFormExtension.php | 4 +- .../Compiler/LocaleProviderPass.php | 2 +- src/DependencyInjection/Configuration.php | 8 +- .../TranslationsFormsListener.php | 5 +- .../EventListener/TranslationsListener.php | 11 +- src/Form/Type/TranslatedEntityType.php | 19 +-- src/Form/Type/TranslationsFormsType.php | 20 +--- .../Type/TranslationsLocalesSelectorType.php | 10 +- src/Form/Type/TranslationsType.php | 18 +-- src/Locale/SimpleProvider.php | 14 +-- tests/Fixtures/Entity/MediaLocalize.php | 46 +++---- tests/Fixtures/Entity/Product.php | 54 ++++----- tests/Fixtures/Entity/ProductTranslation.php | 77 +++++------- .../TranslationsFormsTypeAdvancedTest.php | 14 +-- .../Type/TranslationsFormsTypeSimpleTest.php | 24 ++-- .../Type/TranslationsTypeAdvancedTest.php | 26 ++-- .../Form/Type/TranslationsTypeSimpleTest.php | 26 ++-- tests/Form/TypeTestCase.php | 14 +-- tests/Locale/SimpleProviderTest.php | 6 +- 25 files changed, 295 insertions(+), 362 deletions(-) delete mode 100644 .phpqa.yml create mode 100644 rector.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 116d4ec..4a2bfff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,8 +4,6 @@ on: ["push", "pull_request"] env: COMPOSER_ALLOW_SUPERUSER: '1' - SYMFONY_PHPUNIT_VERSION: 9.5 - SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT: 1 SYMFONY_DEPRECATIONS_HELPER: max[self]=0 jobs: @@ -13,35 +11,33 @@ jobs: name: Analyze runs-on: ubuntu-latest container: - image: php:7.4-alpine + image: php:8.3-alpine options: >- --tmpfs /tmp:exec --tmpfs /var/tmp:exec steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Composer run: wget -qO - https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer --quiet - - name: Cache Composer dependencies - uses: actions/cache@v1 + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + - uses: actions/cache@v3 with: - path: ~/.composer/cache - key: composer-php${{ matrix.php }}-highest- + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-8.3-highest-${{ hashFiles('**/composer.json') }} restore-keys: | - composer-php${{ matrix.php }}-highest- - composer- + ${{ runner.os }}-composer-8.3-highest - name: Validate Composer run: composer validate - - name: Install xsl PHP extension - run: | - apk add $PHPIZE_DEPS libxslt-dev - docker-php-ext-install xsl - name: Install highest dependencies with Composer - run: composer update --no-progress --ansi + run: composer update --no-progress --no-suggest --ansi - name: Disable PHP memory limit run: echo 'memory_limit=-1' >> /usr/local/etc/php/php.ini - - name: Analyze - run: vendor/bin/phpqa --execution no-parallel --progress-delay=-1 --ansi + - name: Run CS-Fixer + run: vendor/bin/php-cs-fixer fix --dry-run --diff --format=checkstyle phpunit: name: PHPUnit (PHP ${{ matrix.php }} Deps ${{ matrix.dependencies }}) @@ -54,69 +50,57 @@ jobs: strategy: matrix: php: - - '7.2' - - '7.3' - - '7.4' - - '8.0' - '8.1' + - '8.2' + - '8.3' dependencies: - - lowest - - highest + - 'lowest' + - 'highest' include: - - php: '7.2' - phpunit-version: 8.5 - - php: '7.3' - phpunit-version: 9.5 - - php: '7.4' - phpunit-version: 9.5 - - php: '8.0' - phpunit-version: 9.5 - php: '8.1' - phpunit-version: 9.5 + phpunit-version: 10 + - php: '8.2' + phpunit-version: 10 + - php: '8.3' + phpunit-version: 10 fail-fast: false steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Composer run: wget -qO - https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer --quiet - - name: Cache Composer dependencies - uses: actions/cache@v1 + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + - uses: actions/cache@v3 with: - path: ~/.composer/cache - key: composer-php${{ matrix.php }}-${{ matrix.dependencies }}- + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ matrix.dependencies }}-${{ hashFiles('**/composer.json') }} restore-keys: | - composer-php${{ matrix.php }}-${{ matrix.dependencies }}- - composer- - - name: Install xsl PHP extension - run: | - apk add $PHPIZE_DEPS libxslt-dev - docker-php-ext-install xsl + ${{ runner.os }}-composer-${{ matrix.php }}-${{ matrix.dependencies }} - name: Install lowest dependencies with Composer if: matrix.dependencies == 'lowest' - run: composer update --no-progress --prefer-stable --prefer-lowest --ansi + run: composer update --no-progress --no-suggest --prefer-stable --prefer-lowest --ansi - name: Install highest dependencies with Composer if: matrix.dependencies == 'highest' - run: composer update --no-progress --ansi + run: composer update --no-progress --no-suggest --ansi - name: Run tests with PHPUnit env: - SYMFONY_PHPUNIT_VERSION: ${{ matrix.phpunit-version }} + SYMFONY_MAX_PHPUNIT_VERSION: ${{ matrix.phpunit-version }} run: vendor/bin/simple-phpunit --colors=always coverage: - name: Coverage (PHP ${{ matrix.php }}) + name: Coverage (PHP 8.3) runs-on: ubuntu-latest container: - image: php:${{ matrix.php }}-alpine + image: php:8.3-alpine options: >- --tmpfs /tmp:exec --tmpfs /var/tmp:exec - strategy: - matrix: - php: - - '7.4' steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install pcov PHP extension run: | apk add $PHPIZE_DEPS @@ -124,23 +108,21 @@ jobs: docker-php-ext-enable pcov - name: Install Composer run: wget -qO - https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer --quiet - - name: Cache Composer dependencies - uses: actions/cache@v1 + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + - uses: actions/cache@v3 with: - path: ~/.composer/cache - key: composer-php${{ matrix.php }}-highest- + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-8.3-highest-${{ hashFiles('**/composer.json') }} restore-keys: | - composer-php${{ matrix.php }}-highest- - composer- - - name: Install xsl PHP extension - run: | - apk add $PHPIZE_DEPS libxslt-dev - docker-php-ext-install xsl + ${{ runner.os }}-composer-8.3-highest - name: Install highest dependencies with Composer - run: composer update --no-progress --ansi + run: composer update --no-progress --no-suggest --ansi - name: Run coverage with PHPUnit run: vendor/bin/simple-phpunit --coverage-clover ./coverage.xml --colors=always - name: Send code coverage report to Codecov.io - uses: codecov/codecov-action@v1.0.3 # 1.0.4+ uncompatible alpine :/ + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 7d669b5..89afc15 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -9,33 +9,43 @@ file that was distributed with this source code. HEADER; + +$finder = (new PhpCsFixer\Finder()) + ->in(['src', 'tests']) +; + return (new PhpCsFixer\Config()) ->setRiskyAllowed(true) + ->registerCustomFixers(new PhpCsFixerCustomFixers\Fixers()) ->setRules([ - '@DoctrineAnnotation' => true, - '@PHP70Migration' => true, - '@PHP70Migration:risky' => true, - '@PHP71Migration' => true, - '@PHP71Migration:risky' => true, - '@PHP73Migration' => true, - '@PHPUnit75Migration:risky' => true, + '@PHP82Migration' => true, '@PhpCsFixer' => true, '@PhpCsFixer:risky' => true, - '@Symfony' => true, - '@Symfony:risky' => true, - 'array_syntax' => ['syntax' => 'short'], - 'date_time_immutable' => true, - 'header_comment' => ['header' => $header], - 'general_phpdoc_annotation_remove' => true, + + // From https://github.com/symfony/demo/blob/main/.php-cs-fixer.dist.php 'linebreak_after_opening_tag' => true, - 'list_syntax' => ['syntax' => 'short'], - 'no_superfluous_phpdoc_tags' => true, + // 'mb_str_functions' => true, + 'no_php4_constructor' => true, + 'no_unreachable_default_argument_value' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, 'php_unit_strict' => false, + 'php_unit_internal_class' => false, 'php_unit_test_class_requires_covers' => false, + 'phpdoc_order' => true, + 'strict_comparison' => true, + 'strict_param' => true, + 'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arrays', 'parameters']], + 'statement_indentation' => true, + 'method_chaining_indentation' => true, + 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline', 'attribute_placement' => 'ignore'], + + PhpCsFixerCustomFixers\Fixer\ConstructorEmptyBracesFixer::name() => true, + PhpCsFixerCustomFixers\Fixer\MultilineCommentOpeningClosingAloneFixer::name() => true, + PhpCsFixerCustomFixers\Fixer\MultilinePromotedPropertiesFixer::name() => true, + PhpCsFixerCustomFixers\Fixer\NoDuplicatedImportsFixer::name() => true, + PhpCsFixerCustomFixers\Fixer\NoImportFromGlobalNamespaceFixer::name() => true, + PhpCsFixerCustomFixers\Fixer\PhpdocSingleLineVarFixer::name() => true, ]) - ->setFinder( - (new PhpCsFixer\Finder()) - ->exclude(['vendor']) - ->in(['src', 'tests']) - ) + ->setFinder($finder) ; diff --git a/.phpqa.yml b/.phpqa.yml deleted file mode 100644 index 77c34e6..0000000 --- a/.phpqa.yml +++ /dev/null @@ -1,15 +0,0 @@ -phpqa: - tools: - - php-cs-fixer:0 - - phpunit:0 - - psalm - output: cli - -phpunit: - binary: ./vendor/bin/simple-phpunit - -php-cs-fixer: - config: .php-cs-fixer.dist.php - -psalm: - config: psalm.xml diff --git a/composer.json b/composer.json index 13050e3..46e098b 100644 --- a/composer.json +++ b/composer.json @@ -26,28 +26,29 @@ } ], "require": { - "php": ">=7.2", - "a2lix/auto-form-bundle": "^0.2|^0.3|^0.4", - "symfony/config": "^3.4.30|^4.3|^5.0|^6.0", - "symfony/dependency-injection": "^3.4.30|^4.3|^5.0|^6.0", - "symfony/doctrine-bridge": "^3.4.30|^4.3|^5.0|^6.0", - "symfony/event-dispatcher": "^3.4.30|^4.3|^5.0|^6.0", - "symfony/form": "^3.4.30|^4.3|^5.0|^6.0", - "symfony/http-foundation": "^3.4.30|^4.3|^5.0|^6.0", - "symfony/http-kernel": "^3.4.30|^4.3|^5.0|^6.0", - "symfony/options-resolver": "^3.4.30|^4.3|^5.0|^6.0" + "php": "^8.1", + "a2lix/auto-form-bundle": "^0.4", + "symfony/config": "^5.4.30|^6.3.10|^7.0", + "symfony/dependency-injection": "^5.4.30|^6.3.10|^7.0", + "symfony/doctrine-bridge": "^5.4.30|^6.3.10|^7.0", + "symfony/event-dispatcher": "^5.4.30|^6.3.10|^7.0", + "symfony/form": "^5.4.30|^6.3.10|^7.0", + "symfony/http-foundation": "^5.4.30|^6.3.10|^7.0", + "symfony/http-kernel": "^5.4.30|^6.3.10|^7.0", + "symfony/options-resolver": "^5.4.30|^6.3.10|^7.0" }, "require-dev": { - "doctrine/orm": "^2.7", - "edgedesign/phpqa": "^1.25", - "friendsofphp/php-cs-fixer": "^3.4.0", - "knplabs/doctrine-behaviors": "^2.0", - "matthiasnoback/symfony-dependency-injection-test": "^4.3", - "phpstan/phpstan": "^1.2.0", - "symfony/cache": "^5.4", - "symfony/phpunit-bridge": "^6.0", - "symfony/validator": "^3.4.30|^4.3|^5.0|^6.0", - "vimeo/psalm": "^4.15" + "doctrine/orm": "^2.15", + "friendsofphp/php-cs-fixer": "^3.45", + "knplabs/doctrine-behaviors": "^2.3", + "kubawerlos/php-cs-fixer-custom-fixers": "^3.18", + "matthiasnoback/symfony-dependency-injection-test": "^5.0", + "phpstan/phpstan": "^1.10", + "rector/rector": "^0.18", + "symfony/cache": "^5.4.30|^6.3.10|^7.0", + "symfony/phpunit-bridge": "^5.4.30|^6.3.10|^7.0", + "symfony/validator": "^5.4.30|^6.3.10|^7.0", + "vimeo/psalm": "^5.18" }, "suggest": { "knplabs/doctrine-behaviors": "For Knp strategy", @@ -61,7 +62,7 @@ "psalm" ], "phpunit": [ - "SYMFONY_DEPRECATIONS_HELPER=max[self]=0 SYMFONY_PHPUNIT_VERSION=9.5 SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 simple-phpunit" + "SYMFONY_DEPRECATIONS_HELPER=max[self]=0 simple-phpunit" ] }, "config": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 27b2ce8..b1de987 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -2,7 +2,7 @@ parallel(); + $rectorConfig->paths([ + __DIR__.'/src', + __DIR__.'/tests', + ]); + $rectorConfig->importNames(); + $rectorConfig->importShortClasses(false); + + $rectorConfig->phpVersion(PhpVersion::PHP_82); + $rectorConfig->sets([ + LevelSetList::UP_TO_PHP_82, + + DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES, + // DoctrineSetList::DOCTRINE_CODE_QUALITY, + DoctrineSetList::DOCTRINE_ORM_214, + DoctrineSetList::DOCTRINE_DBAL_30, + + PHPUnitLevelSetList::UP_TO_PHPUNIT_91, + // PHPUnitSetList::PHPUNIT_CODE_QUALITY, + // PHPUnitSetList::PHPUNIT_YIELD_DATA_PROVIDER, + ]); +}; diff --git a/src/DependencyInjection/A2lixTranslationFormExtension.php b/src/DependencyInjection/A2lixTranslationFormExtension.php index 3dbf8c1..affd5ac 100644 --- a/src/DependencyInjection/A2lixTranslationFormExtension.php +++ b/src/DependencyInjection/A2lixTranslationFormExtension.php @@ -16,7 +16,7 @@ use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\HttpKernel\DependencyInjection\Extension; class A2lixTranslationFormExtension extends Extension @@ -26,7 +26,7 @@ public function load(array $configs, ContainerBuilder $container): void $processor = new Processor(); $config = $processor->processConfiguration(new Configuration(), $configs); - $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('a2lix_form.xml'); $container->setParameter('a2lix_translation_form.locale_provider', $config['locale_provider']); diff --git a/src/DependencyInjection/Compiler/LocaleProviderPass.php b/src/DependencyInjection/Compiler/LocaleProviderPass.php index d100846..7c6ce8b 100644 --- a/src/DependencyInjection/Compiler/LocaleProviderPass.php +++ b/src/DependencyInjection/Compiler/LocaleProviderPass.php @@ -18,7 +18,7 @@ class LocaleProviderPass implements CompilerPassInterface { - public const DEFAULT_LOCALE_PROVIDER_KEY = 'default'; + final public const DEFAULT_LOCALE_PROVIDER_KEY = 'default'; public function process(ContainerBuilder $container): void { diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 53c380c..42696e0 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -37,9 +37,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->arrayNode('locales') ->beforeNormalization() ->ifString() - ->then(function ($v) { - return preg_split('/\s*,\s*/', $v); - }) + ->then(static fn ($v) => preg_split('/\s*,\s*/', (string) $v)) ->end() ->requiresAtLeastOneElement() ->prototype('scalar')->end() @@ -48,9 +46,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->arrayNode('required_locales') ->beforeNormalization() ->ifString() - ->then(function ($v) { - return preg_split('/\s*,\s*/', $v); - }) + ->then(static fn ($v) => preg_split('/\s*,\s*/', (string) $v)) ->end() ->prototype('scalar')->end() ->info('Set the list of required locales to manage. eg: [en]') diff --git a/src/Form/EventListener/TranslationsFormsListener.php b/src/Form/EventListener/TranslationsFormsListener.php index e2b9a77..3a68b3b 100644 --- a/src/Form/EventListener/TranslationsFormsListener.php +++ b/src/Form/EventListener/TranslationsFormsListener.php @@ -33,7 +33,9 @@ public function preSetData(FormEvent $event): void $formOptions = $form->getConfig()->getOptions(); foreach ($formOptions['locales'] as $locale) { - $form->add($locale, $formOptions['form_type'], + $form->add( + $locale, + $formOptions['form_type'], $formOptions['form_options'] + [ 'required' => \in_array($locale, $formOptions['required_locales'], true), ] @@ -54,6 +56,7 @@ public function submit(FormEvent $event): void || empty($translation) // Default ) { $data->removeElement($translation); + continue; } diff --git a/src/Form/EventListener/TranslationsListener.php b/src/Form/EventListener/TranslationsListener.php index 5098646..d200f6e 100644 --- a/src/Form/EventListener/TranslationsListener.php +++ b/src/Form/EventListener/TranslationsListener.php @@ -22,13 +22,9 @@ class TranslationsListener implements EventSubscriberInterface { - /** @var FormManipulatorInterface */ - private $formManipulator; - - public function __construct(FormManipulatorInterface $formManipulator) - { - $this->formManipulator = $formManipulator; - } + public function __construct( + private readonly FormManipulatorInterface $formManipulator, + ) {} public static function getSubscribedEvents(): array { @@ -79,6 +75,7 @@ public function submit(FormEvent $event): void || empty($translation) // Default ) { $data->removeElement($translation); + continue; } diff --git a/src/Form/Type/TranslatedEntityType.php b/src/Form/Type/TranslatedEntityType.php index 0334175..95daded 100644 --- a/src/Form/Type/TranslatedEntityType.php +++ b/src/Form/Type/TranslatedEntityType.php @@ -22,24 +22,17 @@ class TranslatedEntityType extends AbstractType { - /** @var RequestStack */ - private $requestStack; - - public function __construct(RequestStack $requestStack) - { - $this->requestStack = $requestStack; - } + public function __construct( + private readonly RequestStack $requestStack, + ) {} public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'translation_path' => 'translations', - 'query_builder' => function (EntityRepository $er) { - return $er->createQueryBuilder('e') - ->select('e, t') - ->join('e.translations', 't') - ; - }, + 'query_builder' => static fn (EntityRepository $er) => $er->createQueryBuilder('e') + ->select('e, t') + ->join('e.translations', 't'), 'choice_label' => function (Options $options) { if (null === ($request = $this->requestStack->getCurrentRequest())) { throw new \RuntimeException('Error while getting request'); diff --git a/src/Form/Type/TranslationsFormsType.php b/src/Form/Type/TranslationsFormsType.php index 6b54e04..6e94959 100644 --- a/src/Form/Type/TranslationsFormsType.php +++ b/src/Form/Type/TranslationsFormsType.php @@ -26,16 +26,10 @@ class TranslationsFormsType extends AbstractType { - /** @var TranslationsFormsListener */ - private $translationsFormsListener; - /** @var LocaleProviderInterface */ - private $localeProvider; - - public function __construct(TranslationsFormsListener $translationsFormsListener, LocaleProviderInterface $localeProvider) - { - $this->translationsFormsListener = $translationsFormsListener; - $this->localeProvider = $localeProvider; - } + public function __construct( + private readonly TranslationsFormsListener $translationsFormsListener, + private readonly LocaleProviderInterface $localeProvider, + ) {} public function buildForm(FormBuilderInterface $builder, array $options): void { @@ -52,9 +46,7 @@ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'by_reference' => false, - 'empty_data' => function (FormInterface $form) { - return new ArrayCollection(); - }, + 'empty_data' => static fn (FormInterface $form) => new ArrayCollection(), 'locales' => $this->localeProvider->getLocales(), 'default_locale' => $this->localeProvider->getDefaultLocale(), 'required_locales' => $this->localeProvider->getRequiredLocales(), @@ -63,7 +55,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setRequired('form_type'); - $resolver->setNormalizer('form_options', function (Options $options, $value): array { + $resolver->setNormalizer('form_options', static function (Options $options, $value): array { // Check mandatory data_class option when AutoFormType use if (($options['form_type'] instanceof AutoFormType) && !isset($value['data_class'])) { throw new \RuntimeException('Missing "data_class" option under "form_options" of TranslationsFormsType. Required when "form_type" use "AutoFormType".'); diff --git a/src/Form/Type/TranslationsLocalesSelectorType.php b/src/Form/Type/TranslationsLocalesSelectorType.php index 88d1363..b8bea9f 100644 --- a/src/Form/Type/TranslationsLocalesSelectorType.php +++ b/src/Form/Type/TranslationsLocalesSelectorType.php @@ -22,13 +22,9 @@ class TranslationsLocalesSelectorType extends AbstractType { - /** @var LocaleProviderInterface */ - private $localeProvider; - - public function __construct(LocaleProviderInterface $localeProvider) - { - $this->localeProvider = $localeProvider; - } + public function __construct( + private readonly LocaleProviderInterface $localeProvider, + ) {} public function buildView(FormView $view, FormInterface $form, array $options): void { diff --git a/src/Form/Type/TranslationsType.php b/src/Form/Type/TranslationsType.php index 88f30e2..4794acf 100644 --- a/src/Form/Type/TranslationsType.php +++ b/src/Form/Type/TranslationsType.php @@ -24,16 +24,10 @@ class TranslationsType extends AbstractType { - /** @var TranslationsListener */ - private $translationsListener; - /** @var LocaleProviderInterface */ - private $localeProvider; - - public function __construct(TranslationsListener $translationsListener, LocaleProviderInterface $localeProvider) - { - $this->translationsListener = $translationsListener; - $this->localeProvider = $localeProvider; - } + public function __construct( + private readonly TranslationsListener $translationsListener, + private readonly LocaleProviderInterface $localeProvider, + ) {} public function buildForm(FormBuilderInterface $builder, array $options): void { @@ -50,9 +44,7 @@ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'by_reference' => false, - 'empty_data' => function (FormInterface $form) { - return new ArrayCollection(); - }, + 'empty_data' => static fn (FormInterface $form) => new ArrayCollection(), 'locale_labels' => null, 'locales' => $this->localeProvider->getLocales(), 'default_locale' => $this->localeProvider->getDefaultLocale(), diff --git a/src/Locale/SimpleProvider.php b/src/Locale/SimpleProvider.php index b4e97df..d25f881 100644 --- a/src/Locale/SimpleProvider.php +++ b/src/Locale/SimpleProvider.php @@ -15,15 +15,11 @@ class SimpleProvider implements LocaleProviderInterface { - /** @var array */ - protected $locales; - /** @var string */ - protected $defaultLocale; - /** @var array */ - protected $requiredLocales; - - public function __construct(array $locales, string $defaultLocale, array $requiredLocales = []) - { + public function __construct( + private array $locales, + private string $defaultLocale, + private array $requiredLocales = [], + ) { if (!\in_array($defaultLocale, $locales, true)) { if (\count($locales)) { throw new \InvalidArgumentException(sprintf('Default locale `%s` not found within the configured locales `[%s]`. Perhaps you need to add it to your `a2lix_translation_form.locales` bundle configuration?', $defaultLocale, implode(',', $locales))); diff --git a/tests/Fixtures/Entity/MediaLocalize.php b/tests/Fixtures/Entity/MediaLocalize.php index 5c45690..abe18b6 100644 --- a/tests/Fixtures/Entity/MediaLocalize.php +++ b/tests/Fixtures/Entity/MediaLocalize.php @@ -15,37 +15,25 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] class MediaLocalize { - /** - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - protected $id; - - /** - * @ORM\Column(length=10) - */ - protected $locale; - - /** - * @ORM\ManyToOne(targetEntity="Product", inversedBy="medias") - */ - protected $product; - - /** - * @ORM\Column(nullable=true) - */ - protected $url; - - /** - * @ORM\Column(nullable=true) - */ - protected $description; + #[ORM\Id] + #[ORM\Column(type: 'integer')] + #[ORM\GeneratedValue(strategy: 'AUTO')] + private ?int $id = null; + + #[ORM\Column(length: 10)] + private ?string $locale = null; + + #[ORM\ManyToOne(targetEntity: Product::class, inversedBy: 'medias')] + private Product $product; + + #[ORM\Column(nullable: true)] + private ?string $url = null; + + #[ORM\Column(nullable: true)] + private ?string $description = null; public function getId(): ?int { diff --git a/tests/Fixtures/Entity/Product.php b/tests/Fixtures/Entity/Product.php index 63457c4..c78c7f0 100644 --- a/tests/Fixtures/Entity/Product.php +++ b/tests/Fixtures/Entity/Product.php @@ -17,42 +17,28 @@ use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - */ +#[ORM\Entity] class Product { - /** - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - protected $id; - - /** - * @ORM\Column(nullable=true) - */ - protected $title; - - /** - * @ORM\Column(type="text", nullable=true) - */ - protected $description; - - /** - * @ORM\Column(nullable=true) - */ - protected $url; - - /** - * @ORM\OneToMany(targetEntity="MediaLocalize", mappedBy="product", indexBy="locale", cascade={"all"}, orphanRemoval=true) - */ - protected $medias; - - /** - * @ORM\OneToMany(targetEntity="ProductTranslation", mappedBy="object", indexBy="locale", cascade={"all"}, orphanRemoval=true) - */ - protected $translations; + #[ORM\Id] + #[ORM\Column(type: 'integer')] + #[ORM\GeneratedValue(strategy: 'AUTO')] + private ?int $id = null; + + #[ORM\Column(nullable: true)] + private ?string $title = null; + + #[ORM\Column(type: 'text', nullable: true)] + private ?string $description = null; + + #[ORM\Column(nullable: true)] + private ?string $url = null; + + #[ORM\OneToMany(targetEntity: MediaLocalize::class, mappedBy: 'product', indexBy: 'locale', cascade: ['all'], orphanRemoval: true)] + private ArrayCollection $medias; + + #[ORM\OneToMany(targetEntity: ProductTranslation::class, mappedBy: 'object', indexBy: 'locale', cascade: ['all'], orphanRemoval: true)] + private ArrayCollection $translations; public function __construct() { diff --git a/tests/Fixtures/Entity/ProductTranslation.php b/tests/Fixtures/Entity/ProductTranslation.php index 07f6f6e..aecdd58 100644 --- a/tests/Fixtures/Entity/ProductTranslation.php +++ b/tests/Fixtures/Entity/ProductTranslation.php @@ -15,41 +15,28 @@ use Doctrine\ORM\Mapping as ORM; -/** - * @ORM\Entity - * @ORM\Table(name="product_translations", uniqueConstraints={ - * @ORM\UniqueConstraint(name="lookup_unique_idx", columns={"locale", "object_id"}) - * }) - */ +#[ORM\Table(name: 'product_translations')] +#[ORM\UniqueConstraint(name: 'lookup_unique_idx', columns: ['locale', 'object_id'])] +#[ORM\Entity] class ProductTranslation { - /** - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - protected $id; - - /** - * @ORM\Column(length=10) - */ - protected $locale; - - /** - * @ORM\ManyToOne(targetEntity="Product", inversedBy="translations") - * @ORM\JoinColumn(name="translatable_id", referencedColumnName="id", onDelete="CASCADE", nullable=false) - */ - protected $translatable; - - /** - * @ORM\Column(nullable=true) - */ - protected $title; - - /** - * @ORM\Column(type="text", nullable=true) - */ - protected $description; + #[ORM\Id] + #[ORM\Column(type: 'integer')] + #[ORM\GeneratedValue(strategy: 'AUTO')] + private ?int $id = null; + + #[ORM\Column(length: 10)] + private ?string $locale = null; + + #[ORM\Column(nullable: true)] + private ?string $title = null; + + #[ORM\Column(type: 'text', nullable: true)] + private ?string $description = null; + + #[ORM\ManyToOne(targetEntity: Product::class, inversedBy: 'translations')] + #[ORM\JoinColumn(name: 'translatable_id', referencedColumnName: 'id', onDelete: 'CASCADE', nullable: false)] + private Product $translatable; public function getId(): ?int { @@ -68,18 +55,6 @@ public function setLocale(string $locale): self return $this; } - public function getTranslatable(): Product - { - return $this->translatable; - } - - public function setTranslatable(Product $translatable): self - { - $this->translatable = $translatable; - - return $this; - } - public function getTitle(): ?string { return $this->title; @@ -103,4 +78,16 @@ public function setDescription(?string $description): self return $this; } + + public function getTranslatable(): Product + { + return $this->translatable; + } + + public function setTranslatable(Product $translatable): self + { + $this->translatable = $translatable; + + return $this; + } } diff --git a/tests/Form/Type/TranslationsFormsTypeAdvancedTest.php b/tests/Form/Type/TranslationsFormsTypeAdvancedTest.php index 2760c19..f5dfb10 100644 --- a/tests/Form/Type/TranslationsFormsTypeAdvancedTest.php +++ b/tests/Form/Type/TranslationsFormsTypeAdvancedTest.php @@ -48,16 +48,14 @@ public function testEmptyFormOverrideLocales(): void $mediasForm = $form->get('medias')->all(); $mediasLocales = array_keys($mediasForm); - $mediasRequiredLocales = array_keys(array_filter($mediasForm, function ($form) { - return $form->isRequired(); - })); + $mediasRequiredLocales = array_keys(array_filter($mediasForm, static fn ($form) => $form->isRequired())); - static::assertEquals($overrideLocales, $mediasLocales, 'Locales should be same as config'); - static::assertEquals($overrideRequiredLocales, $mediasRequiredLocales, 'Required locales should be same as config'); + self::assertEquals($overrideLocales, $mediasLocales, 'Locales should be same as config'); + self::assertEquals($overrideRequiredLocales, $mediasRequiredLocales, 'Required locales should be same as config'); - static::assertEquals(['url', 'description'], array_keys($mediasForm['en']->all()), 'Fields should matches MediaLocalizeType fields'); - static::assertEquals(['url', 'description'], array_keys($mediasForm['fr']->all()), 'Fields should matches MediaLocalizeType fields'); - static::assertEquals(['url', 'description'], array_keys($mediasForm['es']->all()), 'Fields should matches MediaLocalizeType fields'); + self::assertEquals(['url', 'description'], array_keys($mediasForm['en']->all()), 'Fields should matches MediaLocalizeType fields'); + self::assertEquals(['url', 'description'], array_keys($mediasForm['fr']->all()), 'Fields should matches MediaLocalizeType fields'); + self::assertEquals(['url', 'description'], array_keys($mediasForm['es']->all()), 'Fields should matches MediaLocalizeType fields'); } protected function getExtensions(): array diff --git a/tests/Form/Type/TranslationsFormsTypeSimpleTest.php b/tests/Form/Type/TranslationsFormsTypeSimpleTest.php index 986d52e..59ee510 100644 --- a/tests/Form/Type/TranslationsFormsTypeSimpleTest.php +++ b/tests/Form/Type/TranslationsFormsTypeSimpleTest.php @@ -44,16 +44,14 @@ public function testEmptyForm(): void $mediasForm = $form->get('medias')->all(); $mediasLocales = array_keys($mediasForm); - $mediasRequiredLocales = array_keys(array_filter($mediasForm, function ($form) { - return $form->isRequired(); - })); + $mediasRequiredLocales = array_keys(array_filter($mediasForm, static fn ($form) => $form->isRequired())); - static::assertEquals($this->locales, $mediasLocales, 'Locales should be same as config'); - static::assertEquals($this->requiredLocales, $mediasRequiredLocales, 'Required locales should be same as config'); + self::assertEquals($this->locales, $mediasLocales, 'Locales should be same as config'); + self::assertEquals($this->requiredLocales, $mediasRequiredLocales, 'Required locales should be same as config'); - static::assertEquals(['url', 'description'], array_keys($mediasForm['en']->all()), 'Fields should matches MediaLocalizeType fields'); - static::assertEquals(['url', 'description'], array_keys($mediasForm['fr']->all()), 'Fields should matches MediaLocalizeType fields'); - static::assertEquals(['url', 'description'], array_keys($mediasForm['de']->all()), 'Fields should matches MediaLocalizeType fields'); + self::assertEquals(['url', 'description'], array_keys($mediasForm['en']->all()), 'Fields should matches MediaLocalizeType fields'); + self::assertEquals(['url', 'description'], array_keys($mediasForm['fr']->all()), 'Fields should matches MediaLocalizeType fields'); + self::assertEquals(['url', 'description'], array_keys($mediasForm['de']->all()), 'Fields should matches MediaLocalizeType fields'); } public function testCreationForm(): Product @@ -109,8 +107,8 @@ public function testCreationForm(): Product ]; $form->submit($formData); - static::assertTrue($form->isSynchronized()); - static::assertEquals($product, $form->getData()); + self::assertTrue($form->isSynchronized()); + self::assertEquals($product, $form->getData()); return $product; } @@ -151,14 +149,14 @@ public function testEditionForm(Product $product): void ; $form->submit($formData); - static::assertTrue($form->isSynchronized()); - static::assertEquals($product, $form->getData()); + self::assertTrue($form->isSynchronized()); + self::assertEquals($product, $form->getData()); $view = $form->createView(); $children = $view->children; foreach (array_keys($formData) as $key) { - static::assertArrayHasKey($key, $children); + self::assertArrayHasKey($key, $children); } } diff --git a/tests/Form/Type/TranslationsTypeAdvancedTest.php b/tests/Form/Type/TranslationsTypeAdvancedTest.php index 3bb2c9b..d21746c 100644 --- a/tests/Form/Type/TranslationsTypeAdvancedTest.php +++ b/tests/Form/Type/TranslationsTypeAdvancedTest.php @@ -46,16 +46,14 @@ public function testEmptyFormOverrideLocales(): void $translationsForm = $form->get('translations')->all(); $translationsLocales = array_keys($translationsForm); - $translationsRequiredLocales = array_keys(array_filter($translationsForm, function ($form) { - return $form->isRequired(); - })); + $translationsRequiredLocales = array_keys(array_filter($translationsForm, static fn ($form) => $form->isRequired())); - static::assertEquals($overrideLocales, $translationsLocales, 'Locales should be same as config'); - static::assertEquals($overrideRequiredLocales, $translationsRequiredLocales, 'Required locales should be same as config'); + self::assertEquals($overrideLocales, $translationsLocales, 'Locales should be same as config'); + self::assertEquals($overrideRequiredLocales, $translationsRequiredLocales, 'Required locales should be same as config'); - static::assertEquals(['title', 'description'], array_keys($translationsForm['en']->all()), 'Fields should matches ProductTranslation fields'); - static::assertEquals(['title', 'description'], array_keys($translationsForm['fr']->all()), 'Fields should matches ProductTranslation fields'); - static::assertEquals(['title', 'description'], array_keys($translationsForm['es']->all()), 'Fields should matches ProductTranslation fields'); + self::assertEquals(['title', 'description'], array_keys($translationsForm['en']->all()), 'Fields should matches ProductTranslation fields'); + self::assertEquals(['title', 'description'], array_keys($translationsForm['fr']->all()), 'Fields should matches ProductTranslation fields'); + self::assertEquals(['title', 'description'], array_keys($translationsForm['es']->all()), 'Fields should matches ProductTranslation fields'); } public function testEmptyFormOverrideFields(): void @@ -70,9 +68,9 @@ public function testEmptyFormOverrideFields(): void ; $translationsForm = $form->get('translations')->all(); - static::assertEquals(['title'], array_keys($translationsForm['en']->all()), 'Fields should not contains description'); - static::assertEquals(['title'], array_keys($translationsForm['fr']->all()), 'Fields should not contains description'); - static::assertEquals(['title'], array_keys($translationsForm['de']->all()), 'Fields should not contains description'); + self::assertEquals(['title'], array_keys($translationsForm['en']->all()), 'Fields should not contains description'); + self::assertEquals(['title'], array_keys($translationsForm['fr']->all()), 'Fields should not contains description'); + self::assertEquals(['title'], array_keys($translationsForm['de']->all()), 'Fields should not contains description'); } public function testLabels(): void @@ -90,9 +88,9 @@ public function testLabels(): void ; $translationsForm = $form->get('translations')->all(); - static::assertEquals('English', $translationsForm['en']->getConfig()->getOptions()['label'], 'Label should be explicitely set'); - static::assertEquals('Français', $translationsForm['fr']->getConfig()->getOptions()['label'], 'Label should be explicitely set'); - static::assertNull($translationsForm['de']->getConfig()->getOptions()['label'], 'Label should default to null'); + self::assertEquals('English', $translationsForm['en']->getConfig()->getOptions()['label'], 'Label should be explicitely set'); + self::assertEquals('Français', $translationsForm['fr']->getConfig()->getOptions()['label'], 'Label should be explicitely set'); + self::assertNull($translationsForm['de']->getConfig()->getOptions()['label'], 'Label should default to null'); } protected function getExtensions(): array diff --git a/tests/Form/Type/TranslationsTypeSimpleTest.php b/tests/Form/Type/TranslationsTypeSimpleTest.php index b271773..63b480a 100644 --- a/tests/Form/Type/TranslationsTypeSimpleTest.php +++ b/tests/Form/Type/TranslationsTypeSimpleTest.php @@ -41,16 +41,14 @@ public function testEmptyForm(): void $translationsForm = $form->get('translations')->all(); $translationsLocales = array_keys($translationsForm); - $translationsRequiredLocales = array_keys(array_filter($translationsForm, function ($form) { - return $form->isRequired(); - })); + $translationsRequiredLocales = array_keys(array_filter($translationsForm, static fn ($form) => $form->isRequired())); - static::assertEquals($this->locales, $translationsLocales, 'Locales should be same as config'); - static::assertEquals($this->requiredLocales, $translationsRequiredLocales, 'Required locales should be same as config'); + self::assertEquals($this->locales, $translationsLocales, 'Locales should be same as config'); + self::assertEquals($this->requiredLocales, $translationsRequiredLocales, 'Required locales should be same as config'); - static::assertEquals(['title', 'description'], array_keys($translationsForm['en']->all()), 'Fields should matches ProductTranslation fields'); - static::assertEquals(['title', 'description'], array_keys($translationsForm['fr']->all()), 'Fields should matches ProductTranslation fields'); - static::assertEquals(['title', 'description'], array_keys($translationsForm['de']->all()), 'Fields should matches ProductTranslation fields'); + self::assertEquals(['title', 'description'], array_keys($translationsForm['en']->all()), 'Fields should matches ProductTranslation fields'); + self::assertEquals(['title', 'description'], array_keys($translationsForm['fr']->all()), 'Fields should matches ProductTranslation fields'); + self::assertEquals(['title', 'description'], array_keys($translationsForm['de']->all()), 'Fields should matches ProductTranslation fields'); } public function testCreationForm(): Product @@ -104,8 +102,8 @@ public function testCreationForm(): Product ]; $form->submit($formData); - static::assertTrue($form->isSynchronized()); - static::assertEquals($product, $form->getData()); + self::assertTrue($form->isSynchronized()); + self::assertEquals($product, $form->getData()); return $product; } @@ -113,7 +111,7 @@ public function testCreationForm(): Product /** * @depends testCreationForm */ - public function testEditionForm($product): void + public function testEditionForm(Product $product): void { $product->getTranslations()['en']->setDescription('desc ennnnnnn'); $product->getTranslations()['fr']->setTitle('title frrrrrr'); @@ -144,14 +142,14 @@ public function testEditionForm($product): void ; $form->submit($formData); - static::assertTrue($form->isSynchronized()); - static::assertEquals($product, $form->getData()); + self::assertTrue($form->isSynchronized()); + self::assertEquals($product, $form->getData()); $view = $form->createView(); $children = $view->children; foreach (array_keys($formData) as $key) { - static::assertArrayHasKey($key, $children); + self::assertArrayHasKey($key, $children); } } diff --git a/tests/Form/TypeTestCase.php b/tests/Form/TypeTestCase.php index f1f09dd..040c11f 100644 --- a/tests/Form/TypeTestCase.php +++ b/tests/Form/TypeTestCase.php @@ -22,8 +22,9 @@ use A2lix\TranslationFormBundle\Form\Type\TranslationsFormsType; use A2lix\TranslationFormBundle\Form\Type\TranslationsType; use A2lix\TranslationFormBundle\Locale\SimpleProvider; +use Doctrine\DBAL\DriverManager; use Doctrine\ORM\EntityManager; -use Doctrine\ORM\Tools\Setup; +use Doctrine\ORM\ORMSetup; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Extension\Validator\Type\FormTypeValidatorExtension; use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser; @@ -35,7 +36,7 @@ abstract class TypeTestCase extends BaseTypeTestCase { - protected $doctrineORMManipulator; + protected ?DoctrineORMManipulator $doctrineORMManipulator = null; protected function setUp(): void { @@ -53,9 +54,7 @@ protected function setUp(): void new FormTypeValidatorExtension($validator) ) ->addTypeGuesser( - $this->getMockBuilder(ValidatorTypeGuesser::class) - ->disableOriginalConstructor() - ->getMock() + $this->createMock(ValidatorTypeGuesser::class) ) ->getFormFactory() ; @@ -73,8 +72,9 @@ protected function getDoctrineORMFormManipulator(): DoctrineORMManipulator return $this->doctrineORMManipulator; } - $config = Setup::createAnnotationMetadataConfiguration([__DIR__.'/../Fixtures/Entity'], true, null, null, false); - $entityManager = EntityManager::create(['driver' => 'pdo_sqlite'], $config); + $config = ORMSetup::createAttributeMetadataConfiguration([__DIR__.'/../Fixtures/Entity'], true); + $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'memory' => true], $config); + $entityManager = new EntityManager($connection, $config); $doctrineORMInfo = new DoctrineORMInfo($entityManager->getMetadataFactory()); return $this->doctrineORMManipulator = new DoctrineORMManipulator($doctrineORMInfo, ['id', 'locale', 'translatable']); diff --git a/tests/Locale/SimpleProviderTest.php b/tests/Locale/SimpleProviderTest.php index 6547acc..2016b6b 100644 --- a/tests/Locale/SimpleProviderTest.php +++ b/tests/Locale/SimpleProviderTest.php @@ -77,14 +77,14 @@ public function testGetLocales(): void $expected = $this->provider->getLocales(); $locales = $this->locales; - static::assertSame(array_diff($expected, $locales), array_diff($locales, $expected)); + self::assertSame(array_diff($expected, $locales), array_diff($locales, $expected)); } public function testGetDefaultLocale(): void { $expected = $this->provider->getDefaultLocale(); - static::assertSame($this->defaultLocale, $expected); + self::assertSame($this->defaultLocale, $expected); } public function getRequiredLocales(): void @@ -92,6 +92,6 @@ public function getRequiredLocales(): void $expected = $this->provider->getDefaultLocale(); $requiredLocales = $this->requiredLocales; - static::assertSame(array_diff($expected, $requiredLocales), array_diff($requiredLocales, $expected)); + self::assertSame(array_diff($expected, $requiredLocales), array_diff($requiredLocales, $expected)); } }