From b4eb5aeb890afc82ed5c7ecf23d4ddd3bfb582e4 Mon Sep 17 00:00:00 2001 From: Thomas Jarrand Date: Fri, 23 Feb 2024 08:11:11 +0100 Subject: [PATCH] Symfony 7 Support --- .github/workflows/ci.yaml | 24 ++++-- .php-cs-fixer.php | 3 - Builders/FormTreeBuilder.php | 4 +- DependencyInjection/Configuration.php | 12 +-- .../ElaoFormTranslationExtension.php | 9 +-- Form/Extension/ButtonTypeExtension.php | 14 ---- Form/Extension/ChoiceTypeExtension.php | 14 ---- Form/Extension/CollectionTypeExtension.php | 17 ---- Form/Extension/FormTypeExtension.php | 14 ---- Form/Extension/TreeAwareExtension.php | 21 +++-- Makefile | 77 +++++++++++++------ Model/FormTree.php | 19 +++-- Tests/Builders/FormTreeBuilderTest.php | 7 +- Tests/FormTranslationTestCase.php | 18 ++--- composer.json | 13 +++- phpstan.neon.dist | 2 +- 16 files changed, 126 insertions(+), 142 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fa3624f..226f6a0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,13 +21,15 @@ jobs: - name: 'Setup PHP' uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: '8.3' - name: 'Install dependencies' - run: make php-cs-fixer.phar + run: | + make install + vendor/bin/simple-phpunit --version - name: 'Check style' - run: ./php-cs-fixer.phar fix --dry-run --no-interaction --diff + run: make lint test: name: ${{ matrix.name }} @@ -40,10 +42,10 @@ jobs: matrix: include: # Lowest deps - - name: 'Test lowest deps [Linux, PHP 7.4]' + - name: 'Test lowest deps Symfony 5.4 [Linux, PHP 7.4]' os: 'ubuntu-latest' php: '7.4' - symfony: '4.4.*@dev' + symfony: '5.4.*@dev' composer-flags: '--prefer-lowest' allow-unstable: true @@ -60,11 +62,17 @@ jobs: symfony: '6.0.*@dev' allow-unstable: true + - name: 'Test next Symfony 6.4 [Linux, PHP 8.2]' + os: 'ubuntu-latest' + php: '8.2' + symfony: '6.4.*@dev' + allow-unstable: true + # Bleeding edge (unreleased dev versions where failures are allowed) - - name: 'Test next Symfony [Linux, PHP 8.1] (allowed failure)' + - name: 'Test next Symfony [Linux, PHP 8.3] (allowed failure)' os: 'ubuntu-latest' - php: '8.1' - symfony: '6.1.*@dev' + php: '8.3' + symfony: '7.0.*@dev' composer-flags: '--ignore-platform-req php' allow-unstable: true allow-failure: true diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index d5ef888..2b834e8 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -34,8 +34,5 @@ 'simplified_null_return' => false, 'void_return' => true, 'yoda_style' => [], - - // @see https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues/5495 - 'binary_operator_spaces' => ['operators' => ['|' => null]] ]) ; diff --git a/Builders/FormTreeBuilder.php b/Builders/FormTreeBuilder.php index 722c60c..fc01131 100644 --- a/Builders/FormTreeBuilder.php +++ b/Builders/FormTreeBuilder.php @@ -23,6 +23,8 @@ class FormTreeBuilder { /** * Form type with no children labels + * + * @var array */ private array $noChildren = ['date', 'time', 'datetime', 'choice']; @@ -47,7 +49,7 @@ public function getTree(FormView $view): FormTree /** * Set form type that should not be treated as having children * - * @param array $types An array of types + * @param array $types An array of types */ public function setNoChildren(array $types): void { diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index df365d5..3ad4b55 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -22,9 +22,6 @@ */ class Configuration implements ConfigurationInterface { - /** - * {@inheritdoc} - */ public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('elao_form_translation'); @@ -78,18 +75,22 @@ public function getConfigTreeBuilder(): TreeBuilder ->children() ->scalarNode('children') ->defaultValue('children') + ->treatNullLike(false) ->info('Prefix for children nodes (string|false)') ->end() ->scalarNode('prototype') ->defaultValue('prototype') + ->treatNullLike(false) ->info('Prefix for prototype nodes (string|false)') ->end() ->scalarNode('root') ->defaultValue('form') + ->treatNullLike(false) ->info('Prefix at the root of the key (string|false)') ->end() ->scalarNode('separator') ->defaultValue('.') + ->treatNullLike(false) ->info('Separator te be used between nodes (string|false)') ->end() ->end() @@ -106,12 +107,11 @@ public function getConfigTreeBuilder(): TreeBuilder /** * Add Keys Config * - * @param string $key - * @param array $default + * @param array $default * * @return ArrayNodeDefinition|NodeDefinition */ - public function addKeysConfig($key, $default = []) + public function addKeysConfig(string $key, array $default = []) { $treeBuilder = new TreeBuilder($key); $node = $treeBuilder->getRootNode(); diff --git a/DependencyInjection/ElaoFormTranslationExtension.php b/DependencyInjection/ElaoFormTranslationExtension.php index c2af423..6476a71 100644 --- a/DependencyInjection/ElaoFormTranslationExtension.php +++ b/DependencyInjection/ElaoFormTranslationExtension.php @@ -24,9 +24,6 @@ */ class ElaoFormTranslationExtension extends Extension { - /** - * {@inheritdoc} - */ public function load(array $configs, ContainerBuilder $container): void { $configuration = new Configuration(); @@ -45,9 +42,9 @@ public function load(array $configs, ContainerBuilder $container): void /** * Load Tree configuration * - * @param ContainerBuilder $container The container builder - * @param LoaderInterface $loader The loader - * @param array $config An array of config keys + * @param ContainerBuilder $container The container builder + * @param LoaderInterface $loader The loader + * @param array $config An array of config keys */ private function loadTreeConfig(ContainerBuilder $container, LoaderInterface $loader, array $config): void { diff --git a/Form/Extension/ButtonTypeExtension.php b/Form/Extension/ButtonTypeExtension.php index 6780038..8dfad4e 100644 --- a/Form/Extension/ButtonTypeExtension.php +++ b/Form/Extension/ButtonTypeExtension.php @@ -18,25 +18,11 @@ */ class ButtonTypeExtension extends TreeAwareExtension { - /** - * {@inheritdoc} - */ public static function getExtendedTypes(): iterable { return [ButtonType::class]; } - /** - * {@inheritdoc} - */ - public function getExtendedType() - { - return self::getExtendedTypes()[0]; - } - - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { if ($this->autoGenerate) { diff --git a/Form/Extension/ChoiceTypeExtension.php b/Form/Extension/ChoiceTypeExtension.php index 5d4dd38..af46aee 100644 --- a/Form/Extension/ChoiceTypeExtension.php +++ b/Form/Extension/ChoiceTypeExtension.php @@ -18,25 +18,11 @@ */ class ChoiceTypeExtension extends TreeAwareExtension { - /** - * {@inheritdoc} - */ public static function getExtendedTypes(): iterable { return [ChoiceType::class]; } - /** - * {@inheritdoc} - */ - public function getExtendedType() - { - return self::getExtendedTypes()[0]; - } - - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { if ($this->defaultTranslationDomain !== null) { diff --git a/Form/Extension/CollectionTypeExtension.php b/Form/Extension/CollectionTypeExtension.php index b2ae0b9..1850c72 100644 --- a/Form/Extension/CollectionTypeExtension.php +++ b/Form/Extension/CollectionTypeExtension.php @@ -20,25 +20,11 @@ */ class CollectionTypeExtension extends TreeAwareExtension { - /** - * {@inheritdoc} - */ public static function getExtendedTypes(): iterable { return [CollectionType::class]; } - /** - * {@inheritdoc} - */ - public function getExtendedType() - { - return self::getExtendedTypes()[0]; - } - - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { if ($this->autoGenerate) { @@ -47,9 +33,6 @@ public function configureOptions(OptionsResolver $resolver): void } } - /** - * {@inheritdoc} - */ public function finishView(FormView $view, FormInterface $form, array $options): void { if (isset($this->treeBuilder) && isset($this->keyBuilder) && $options['allow_add'] && $options['prototype']) { diff --git a/Form/Extension/FormTypeExtension.php b/Form/Extension/FormTypeExtension.php index eb79acb..cac22d7 100644 --- a/Form/Extension/FormTypeExtension.php +++ b/Form/Extension/FormTypeExtension.php @@ -18,25 +18,11 @@ */ class FormTypeExtension extends TreeAwareExtension { - /** - * {@inheritdoc} - */ public static function getExtendedTypes(): iterable { return [FormType::class]; } - /** - * {@inheritdoc} - */ - public function getExtendedType() - { - return self::getExtendedTypes()[0]; - } - - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { if ($this->autoGenerate) { diff --git a/Form/Extension/TreeAwareExtension.php b/Form/Extension/TreeAwareExtension.php index d85edae..bf536bf 100644 --- a/Form/Extension/TreeAwareExtension.php +++ b/Form/Extension/TreeAwareExtension.php @@ -35,6 +35,8 @@ abstract class TreeAwareExtension extends AbstractTypeExtension /** * Buildable keys list + * + * @var array */ protected array $keys; @@ -67,7 +69,7 @@ public function setAutoGenerate(bool $enabled): void * * @param FormTreeBuilder $treeBuilder The FormKeyBuilder */ - public function setTreeBuilder(FormTreeBuilder $treeBuilder = null): void + public function setTreeBuilder(FormTreeBuilder $treeBuilder): void { $this->treeBuilder = $treeBuilder; } @@ -77,7 +79,7 @@ public function setTreeBuilder(FormTreeBuilder $treeBuilder = null): void * * @param FormKeyBuilder $keyBuilder The FormKeyBuilder */ - public function setKeyBuilder(FormKeyBuilder $keyBuilder = null): void + public function setKeyBuilder(FormKeyBuilder $keyBuilder): void { $this->keyBuilder = $keyBuilder; } @@ -85,7 +87,7 @@ public function setKeyBuilder(FormKeyBuilder $keyBuilder = null): void /** * Set buildable keys * - * @param array $keys Array of keys + * @param array $keys Array of keys */ public function setKeys(array $keys): void { @@ -102,9 +104,6 @@ public function setDefaultTranslationDomain($defaultTranslationDomain): void $this->defaultTranslationDomain = $defaultTranslationDomain; } - /** - * {@inheritdoc} - */ public function finishView(FormView $view, FormInterface $form, array $options): void { if (isset($this->treeBuilder) && isset($this->keyBuilder)) { @@ -132,7 +131,10 @@ protected function generateKey(FormView &$view, $key, $value): void $this->setVar($view->vars, $key, $this->keyBuilder->buildKeyFromTree($view->vars['tree'], $value)); } - protected function setVar(array &$vars, string $key, $value): void + /** + * @param array &$vars + */ + protected function setVar(array &$vars, string $key, mixed $value): void { if ($this->getPropertyAccessor()->isWritable($vars, $key)) { $this->getPropertyAccessor()->setValue($vars, $key, $value); @@ -141,7 +143,10 @@ protected function setVar(array &$vars, string $key, $value): void } } - protected function optionEquals(array $options, string $key, $value): bool + /** + * @param array $options + */ + protected function optionEquals(array $options, string $key, mixed $value): bool { if ($this->getPropertyAccessor()->isReadable($options, $key)) { return $this->getPropertyAccessor()->getValue($options, $key) === $value; diff --git a/Makefile b/Makefile index d6f34e8..f40d4ae 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,30 @@ -.PHONY: test - -PHP_CS_FIXER_VERSION=v3.10.0 +.SILENT: +.PHONY: test build ########### # Helpers # ########### +## Colors +COLOR_RESET = \033[0m +COLOR_INFO = \033[32m +COLOR_COMMENT = \033[33m + +## Help +help: + printf "${COLOR_COMMENT}Usage:${COLOR_RESET}\n" + printf " make [target]\n\n" + printf "${COLOR_COMMENT}Available targets:${COLOR_RESET}\n" + awk '/^[a-zA-Z\-\_0-9\.@]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + printf " ${COLOR_INFO}%-16s${COLOR_RESET} %s\n", helpCommand, helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) + define message_error printf "$(COLOR_ERROR)(╯°□°)╯︵ ┻━┻ $(strip $(1))$(COLOR_RESET)\n" endef @@ -13,39 +32,51 @@ endef php8: @php -r "exit (PHP_MAJOR_VERSION == 8 ? 0 : 1);" || ($(call message_error, Please use PHP 8) && exit 1) +########### +# Install # +########### + +## Install application +install: + # Composer + composer install --verbose + +############ +# Security # +############ + +## Run security checks +security: + symfony check:security + +security@test: export APP_ENV = test +security@test: security + ######## # Lint # ######## -lint: lint-phpcsfixer lint-phpstan lint-composer +## Run linters +lint: lint.phpcsfixer lint.phpstan lint.composer -lint-composer: +lint.composer: composer validate --strict -php-cs-fixer.phar: - wget --no-verbose https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/download/${PHP_CS_FIXER_VERSION}/php-cs-fixer.phar - chmod +x php-cs-fixer.phar - -update-php-cs-fixer.phar: - rm -f php-cs-fixer.phar - make php-cs-fixer.phar - -lint-phpcsfixer: php8 -lint-phpcsfixer: php-cs-fixer.phar -lint-phpcsfixer: - ./php-cs-fixer.phar fix --dry-run --diff +lint.phpcsfixer: export PHP_CS_FIXER_IGNORE_ENV = true +lint.phpcsfixer: php8 + vendor/bin/php-cs-fixer fix --dry-run --no-interaction --diff -fix-phpcsfixer: php8 -fix-phpcsfixer: php-cs-fixer.phar -fix-phpcsfixer: - ./php-cs-fixer.phar fix +lint.phpcsfixer-fix: export PHP_CS_FIXER_IGNORE_ENV = true +lint.phpcsfixer-fix: php8 + vendor/bin/php-cs-fixer fix -lint-phpstan: - vendor/bin/phpstan analyse --memory-limit=-1 +lint.phpstan: + vendor/bin/phpstan.phar analyse --memory-limit=-1 ######## # Test # ######## +## Run tests test: vendor/bin/simple-phpunit diff --git a/Model/FormTree.php b/Model/FormTree.php index 76192f5..613e4aa 100644 --- a/Model/FormTree.php +++ b/Model/FormTree.php @@ -14,11 +14,16 @@ * A form Tree * * @author Thomas Jarrand + * + * @implements \Iterator + * @implements \ArrayAccess */ class FormTree implements \Iterator, \Countable, \ArrayAccess { /** * The FormTreeNode elements + * + * @var array */ private array $nodes; @@ -27,6 +32,9 @@ class FormTree implements \Iterator, \Countable, \ArrayAccess */ private int $position = 0; + /** + * @param array $nodes + */ public function __construct(array $nodes = []) { $this->nodes = $nodes; @@ -111,8 +119,6 @@ public function valid(): bool /** * Return whether or not the given offset exists - * - * @param mixed $offset */ #[\ReturnTypeWillChange] public function offsetExists($offset): bool @@ -122,20 +128,15 @@ public function offsetExists($offset): bool /** * Get the node at the given offset - * - * @param mixed $offset */ #[\ReturnTypeWillChange] - public function offsetGet($offset): FormTreeNode + public function offsetGet($offset): ?FormTreeNode { return $this->offsetExists($offset) ? $this->nodes[$offset] : null; } /** * Set the node at the given offset - * - * @param mixed $offset - * @param mixed $value */ #[\ReturnTypeWillChange] public function offsetSet($offset, $value): void @@ -145,8 +146,6 @@ public function offsetSet($offset, $value): void /** * Unset node at the given offset - * - * @param mixed $offset */ #[\ReturnTypeWillChange] public function offsetUnset($offset): void diff --git a/Tests/Builders/FormTreeBuilderTest.php b/Tests/Builders/FormTreeBuilderTest.php index 486b13f..5c53466 100644 --- a/Tests/Builders/FormTreeBuilderTest.php +++ b/Tests/Builders/FormTreeBuilderTest.php @@ -33,13 +33,16 @@ public function testSimpleTreeBuilder(): void $barTree = $treeBuilder->getTree($formView['bar']); $this->assertEquals(1, \count($fooTree)); + $this->assertNotNull($fooTree[0]); $this->assertEquals('foo', $fooTree[0]->getName()); $this->assertEquals(true, $fooTree[0]->hasChildren()); $this->assertEquals(2, \count($barTree)); + $this->assertNotNull($barTree[0]); $this->assertEquals('foo', $barTree[0]->getName()); - $this->assertEquals('bar', $barTree[1]->getName()); $this->assertEquals(true, $barTree[0]->hasChildren()); + $this->assertNotNull($barTree[1]); + $this->assertEquals('bar', $barTree[1]->getName()); $this->assertEquals(false, $barTree[1]->hasChildren()); } @@ -64,11 +67,13 @@ public function testCollectionTreeBuilder(): void $formView = $form->createView(); $tree = $treeBuilder->getTree($formView['bar']->vars['prototype']); + $this->assertNotNull($tree[1]); $this->assertEquals(true, $tree[1]->hasChildren()); $this->assertEquals(true, $tree[1]->isCollection()); $this->assertEquals(false, $tree[1]->isPrototype()); $this->assertEquals(3, \count($tree)); + $this->assertNotNull($tree[2]); $this->assertEquals(false, $tree[2]->hasChildren()); $this->assertEquals(false, $tree[2]->isCollection()); $this->assertEquals(true, $tree[2]->isPrototype()); diff --git a/Tests/FormTranslationTestCase.php b/Tests/FormTranslationTestCase.php index 946802a..67087a0 100644 --- a/Tests/FormTranslationTestCase.php +++ b/Tests/FormTranslationTestCase.php @@ -12,18 +12,14 @@ use Elao\Bundle\FormTranslationBundle\Form\Extension; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\Forms; +use Symfony\Component\Form\FormTypeExtensionInterface; abstract class FormTranslationTestCase extends TestCase { - /** - * @var \Symfony\Component\Form\FormFactoryInterface - */ - protected $factory; + protected FormFactoryInterface $factory; - /** - * {@inheritdoc} - */ protected function setUp(): void { $this->factory = Forms::createFormFactoryBuilder() @@ -34,17 +30,15 @@ protected function setUp(): void /** * Get Form Type Extensions * - * @return array + * @return array */ - protected function getTypeExtensions() + protected function getTypeExtensions(): array { - $extensions = [ + return [ new Extension\ButtonTypeExtension(), new Extension\ChoiceTypeExtension(), new Extension\CollectionTypeExtension(), new Extension\FormTypeExtension(), ]; - - return $extensions; } } diff --git a/composer.json b/composer.json index 10e0929..e81694e 100644 --- a/composer.json +++ b/composer.json @@ -16,10 +16,10 @@ } ], "require": { - "php": ">=7.4", - "symfony/framework-bundle": "~4.4|^5.1|^6.0", - "symfony/form": "~2.8|~3.0|~4.4|^5.1|^6.0", - "symfony/property-access": "~4.4|^5.1|^6.0" + "php": "^7.4|^8.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0" }, "require-dev": { "ekino/phpstan-banned-code": "^1.0", @@ -41,5 +41,10 @@ "branch-alias": { "dev-master": "4.x-dev" } + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true + } } } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index ee007f0..4af2a3b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 5 + level: 8 paths: - "./"