From 3c4dcee183257696a8e373ace3f6a92dcda4bff3 Mon Sep 17 00:00:00 2001 From: Dominic Tubach Date: Mon, 8 Sep 2025 15:25:14 +0200 Subject: [PATCH] Add support for Drupal 11 Drop support for Drupal 9. --- .github/workflows/phpcs.yml | 2 +- .github/workflows/phpstan.yml | 4 ++-- composer.json | 6 +++--- json_forms.info.yml | 4 ++-- .../json_forms_example.info.yml | 4 ++-- phpstan.ci.neon | 9 +++++++++ phpstan.neon.dist | 1 - src/Form/AbstractJsonFormsForm.php | 1 + src/Form/Control/ArrayArrayFactory.php | 2 -- src/Form/Control/Callbacks/ArrayCallbacks.php | 1 + .../Control/Callbacks/NumberValueCallback.php | 1 + .../Callbacks/Util/RecalculateCallbackUtil.php | 1 + src/Form/Control/CheckboxesArrayFactory.php | 2 -- src/Form/Control/HtmlArrayFactory.php | 2 -- src/Form/Control/NumberArrayFactory.php | 2 -- src/Form/Control/Rule/StatesBuilder.php | 2 +- src/Form/Control/StringArrayFactory.php | 2 -- .../Control/Util/BasicFormPropertiesFactory.php | 1 + src/Form/Layout/AbstractLayoutArrayFactory.php | 1 - src/Form/Layout/TableArrayFactory.php | 1 + src/Form/Util/DescriptionDisplayUtil.php | 2 +- src/Form/Validation/FormValidationMapper.php | 2 +- .../Definition/Control/ControlDefinition.php | 10 +++------- tools/phpstan/composer.json | 16 ++++++++-------- 24 files changed, 39 insertions(+), 40 deletions(-) create mode 100644 phpstan.ci.neon diff --git a/.github/workflows/phpcs.yml b/.github/workflows/phpcs.yml index 74f05dc..ecb07da 100644 --- a/.github/workflows/phpcs.yml +++ b/.github/workflows/phpcs.yml @@ -16,7 +16,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.2 + php-version: 8.4 coverage: none tools: cs2pr env: diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index dc22495..e8323d8 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php-versions: ['7.4', '8.0', '8.2'] + php-versions: ['8.1', '8.4'] prefer: ['prefer-stable', 'prefer-lowest'] name: PHPStan with PHP ${{ matrix.php-versions }} ${{ matrix.prefer }} @@ -42,4 +42,4 @@ jobs: composer composer-phpstan -- update --no-progress --prefer-dist --optimize-autoloader - name: Run PHPStan - run: composer phpstan -- analyse -c phpstan.neon.dist + run: composer phpstan -- analyze -c phpstan.ci.neon diff --git a/composer.json b/composer.json index 08f3ef2..6d52fb0 100644 --- a/composer.json +++ b/composer.json @@ -36,13 +36,13 @@ } }, "require": { - "php": "^7.4 || ^8", + "php": "^8.1", "systopia/expression-language-ext": "~0.1", "systopia/opis-json-schema-ext": "~0.2" }, "require-dev": { - "drupal/core": "^9.5 || ^10", - "drupal/core-dev": "^9.5 || ^10" + "drupal/core": "^10 || ^11", + "drupal/core-dev": "^10 || ^11" }, "scripts": { "composer-phpstan": [ diff --git a/json_forms.info.yml b/json_forms.info.yml index e8253a8..0c1bcc4 100644 --- a/json_forms.info.yml +++ b/json_forms.info.yml @@ -2,8 +2,8 @@ name: JSONForms type: module description: Create a Drupal form from a JSONForms definition. package: JSONForms -core_version_requirement: ^9.5 || ^10 -php: 7.4 +core_version_requirement: ^10 || ^11 +php: 8.1 hidden: true version: 0.7.1-dev 'interface translation project': json_forms diff --git a/modules/json_forms_example/json_forms_example.info.yml b/modules/json_forms_example/json_forms_example.info.yml index 55e3cb5..76bc486 100644 --- a/modules/json_forms_example/json_forms_example.info.yml +++ b/modules/json_forms_example/json_forms_example.info.yml @@ -2,8 +2,8 @@ name: JSONForms example type: module description: Demonstrates how to use JSONForms. package: JSONForms -core_version_requirement: ^9.5 || ^10 -php: 7.4 +core_version_requirement: ^10 || ^11 +php: 8.1 dependencies: - json_forms:json_forms version: 0.7.1-dev diff --git a/phpstan.ci.neon b/phpstan.ci.neon new file mode 100644 index 0000000..e7cf188 --- /dev/null +++ b/phpstan.ci.neon @@ -0,0 +1,9 @@ +includes: + - phpstan.neon.dist + +parameters: + # Because we test with different versions in CI we have unmatched errors + reportUnmatchedIgnoredErrors: false + ignoreErrors: + # Required for Drupal 10. + - '#^Method Drupal\\Core\\Form\\FormBuilderInterface::getForm\(\) invoked with \d+ parameters, 1 required.$#' diff --git a/phpstan.neon.dist b/phpstan.neon.dist index d65f579..632f1ec 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -24,7 +24,6 @@ parameters: # https://youtrack.jetbrains.com/issue/WI-63891/PHPStan-ignoreErrors-configuration-isnt-working-with-inspections # Wrong phpdoc type hint in Drupal - '/^Parameter #1 \$key of method Drupal\\Core\\Form\\FormStateInterface::hasTemporaryValue\(\) expects string, array given.$/' - - '#^Method Drupal\\Core\\Form\\FormBuilderInterface::getForm\(\) invoked with \d+ parameters, 1 required.$#' - message: '#^Variable property access on mixed.$#' paths: diff --git a/src/Form/AbstractJsonFormsForm.php b/src/Form/AbstractJsonFormsForm.php index a2426dd..a962794 100644 --- a/src/Form/AbstractJsonFormsForm.php +++ b/src/Form/AbstractJsonFormsForm.php @@ -108,6 +108,7 @@ protected function buildJsonFormsForm( $formState->set('uiSchema', $uiSchema); $formState->set('recalculateOnChange', $recalculateOnChange); + // @phpstan-ignore equal.notAllowed if (new \stdClass() == $uiSchema) { return []; } diff --git a/src/Form/Control/ArrayArrayFactory.php b/src/Form/Control/ArrayArrayFactory.php index 19bcb17..369b7f2 100644 --- a/src/Form/Control/ArrayArrayFactory.php +++ b/src/Form/Control/ArrayArrayFactory.php @@ -49,9 +49,7 @@ public function createFormArray( FormArrayFactoryInterface $formArrayFactory ): array { Assertion::isInstanceOf($definition, ControlDefinition::class); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\ControlDefinition $definition */ $definition = ArrayControlDefinition::fromDefinition($definition); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\ArrayControlDefinition $definition */ $fieldsetWrapperId = 'array-wrapper-' . str_replace('.', '__', implode('_', $definition->getPropertyPath())); // phpcs:disable Drupal.Commenting.InlineComment.DocBlock diff --git a/src/Form/Control/Callbacks/ArrayCallbacks.php b/src/Form/Control/Callbacks/ArrayCallbacks.php index 8747dc3..a0790e7 100644 --- a/src/Form/Control/Callbacks/ArrayCallbacks.php +++ b/src/Form/Control/Callbacks/ArrayCallbacks.php @@ -102,6 +102,7 @@ public static function ajaxRemove(array &$form, FormStateInterface $formState): $propertyPath = $triggeringElement['#_controlPropertyPath']; $arrayForm = &self::getArrayForm($form, $triggeringElement); + // @phpstan-ignore argument.type FormValueAccessor::setValue($arrayForm['items'], $propertyPath, $formState->getTemporaryValue($propertyPath)); /** @var \Drupal\Core\Render\MainContent\AjaxRenderer $ajaxRenderer */ diff --git a/src/Form/Control/Callbacks/NumberValueCallback.php b/src/Form/Control/Callbacks/NumberValueCallback.php index 7da87ed..a75019e 100644 --- a/src/Form/Control/Callbacks/NumberValueCallback.php +++ b/src/Form/Control/Callbacks/NumberValueCallback.php @@ -62,6 +62,7 @@ private static function isIntegerish($value): bool { $value = \trim($value); } + // @phpstan-ignore equal.notAllowed return \is_numeric($value) && $value == (string) $value; } diff --git a/src/Form/Control/Callbacks/Util/RecalculateCallbackUtil.php b/src/Form/Control/Callbacks/Util/RecalculateCallbackUtil.php index f886752..cfd05ce 100644 --- a/src/Form/Control/Callbacks/Util/RecalculateCallbackUtil.php +++ b/src/Form/Control/Callbacks/Util/RecalculateCallbackUtil.php @@ -69,6 +69,7 @@ private static function doAddAjaxCommands( if ($oldData === $newData || NULL === $newData && '' === $oldData || \is_numeric($newData) && \is_numeric($oldData) && (float) $newData === (float) $oldData + // @phpstan-ignore equal.notAllowed || (is_bool($newData) && !$strictBooleanComparison && $newData == $oldData) ) { return; diff --git a/src/Form/Control/CheckboxesArrayFactory.php b/src/Form/Control/CheckboxesArrayFactory.php index fdfda92..aa046dc 100644 --- a/src/Form/Control/CheckboxesArrayFactory.php +++ b/src/Form/Control/CheckboxesArrayFactory.php @@ -48,9 +48,7 @@ public function createFormArray( FormArrayFactoryInterface $formArrayFactory ): array { Assertion::isInstanceOf($definition, ControlDefinition::class); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\ControlDefinition $definition */ $definition = ArrayControlDefinition::fromDefinition($definition); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\ArrayControlDefinition $definition */ $form = [ '#type' => 'checkboxes', // @todo Handle non-string values and integerish strings. diff --git a/src/Form/Control/HtmlArrayFactory.php b/src/Form/Control/HtmlArrayFactory.php index d90037d..89f6300 100644 --- a/src/Form/Control/HtmlArrayFactory.php +++ b/src/Form/Control/HtmlArrayFactory.php @@ -49,9 +49,7 @@ public function createFormArray( FormArrayFactoryInterface $formArrayFactory ): array { Assertion::isInstanceOf($definition, ControlDefinition::class); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\ControlDefinition $definition */ $definition = StringControlDefinition::fromDefinition($definition); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\StringControlDefinition $definition */ $form = [ '#type' => 'text_format', diff --git a/src/Form/Control/NumberArrayFactory.php b/src/Form/Control/NumberArrayFactory.php index 5f3f267..bcfdc7c 100644 --- a/src/Form/Control/NumberArrayFactory.php +++ b/src/Form/Control/NumberArrayFactory.php @@ -42,9 +42,7 @@ public function createFormArray( FormArrayFactoryInterface $formArrayFactory ): array { Assertion::isInstanceOf($definition, ControlDefinition::class); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\ControlDefinition $definition */ $definition = NumberControlDefinition::fromDefinition($definition); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\NumberControlDefinition $definition */ $form = [ '#type' => 'number', diff --git a/src/Form/Control/Rule/StatesBuilder.php b/src/Form/Control/Rule/StatesBuilder.php index 7e3464d..a0aa21a 100644 --- a/src/Form/Control/Rule/StatesBuilder.php +++ b/src/Form/Control/Rule/StatesBuilder.php @@ -150,7 +150,7 @@ private function buildCondition(ControlDefinition $definition, $value): array { /** * @phpstan-param scalar|array|null $value * - * @phpstan-return array> + * @phpstan-return array */ private function buildContainsCondition(string $fieldName, $value): array { if (!is_array($value)) { diff --git a/src/Form/Control/StringArrayFactory.php b/src/Form/Control/StringArrayFactory.php index 506e9b4..b2179cc 100644 --- a/src/Form/Control/StringArrayFactory.php +++ b/src/Form/Control/StringArrayFactory.php @@ -42,9 +42,7 @@ public function createFormArray( FormArrayFactoryInterface $formArrayFactory ): array { Assertion::isInstanceOf($definition, ControlDefinition::class); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\ControlDefinition $definition */ $definition = StringControlDefinition::fromDefinition($definition); - /** @var \Drupal\json_forms\JsonForms\Definition\Control\StringControlDefinition $definition */ $form = [ '#type' => TRUE === $definition->getOptionsValue('multi', FALSE) ? 'textarea' : 'textfield', diff --git a/src/Form/Control/Util/BasicFormPropertiesFactory.php b/src/Form/Control/Util/BasicFormPropertiesFactory.php index a0f3fda..b81dc5c 100644 --- a/src/Form/Control/Util/BasicFormPropertiesFactory.php +++ b/src/Form/Control/Util/BasicFormPropertiesFactory.php @@ -53,6 +53,7 @@ public static function createBasicProperties(ControlDefinition $definition): arr DescriptionDisplayUtil::handleDescriptionDisplay($form, $definition->getOptionsValue('descriptionDisplay')); if (NULL !== $definition->getOptionsValue('placeholder')) { + // @phpstan-ignore offsetAccess.nonOffsetAccessible $form['#attributes']['placeholder'] = $definition->getOptionsValue('placeholder'); } diff --git a/src/Form/Layout/AbstractLayoutArrayFactory.php b/src/Form/Layout/AbstractLayoutArrayFactory.php index a546434..6159a98 100644 --- a/src/Form/Layout/AbstractLayoutArrayFactory.php +++ b/src/Form/Layout/AbstractLayoutArrayFactory.php @@ -48,7 +48,6 @@ public function createFormArray( FormArrayFactoryInterface $formArrayFactory ): array { Assertion::isInstanceOf($definition, LayoutDefinition::class); - /** @var \Drupal\json_forms\JsonForms\Definition\Layout\LayoutDefinition $definition */ $form = $this->createBasicFormArray($definition); // @phpstan-ignore argument.type diff --git a/src/Form/Layout/TableArrayFactory.php b/src/Form/Layout/TableArrayFactory.php index ad42186..e251084 100644 --- a/src/Form/Layout/TableArrayFactory.php +++ b/src/Form/Layout/TableArrayFactory.php @@ -59,6 +59,7 @@ private function getHeader(LayoutDefinition $definition): array { } /** @phpstan-var array> $header */ + // @phpstan-ignore varTag.type return $header; } diff --git a/src/Form/Util/DescriptionDisplayUtil.php b/src/Form/Util/DescriptionDisplayUtil.php index 529d3df..f57dd64 100644 --- a/src/Form/Util/DescriptionDisplayUtil.php +++ b/src/Form/Util/DescriptionDisplayUtil.php @@ -24,7 +24,7 @@ final class DescriptionDisplayUtil { /** - * @phpstan-param array $form + * @phpstan-param array $form */ public static function handleDescriptionDisplay(array &$form, ?string $descriptionDisplay): void { if (NULL !== $descriptionDisplay) { diff --git a/src/Form/Validation/FormValidationMapper.php b/src/Form/Validation/FormValidationMapper.php index 9650307..09f8162 100644 --- a/src/Form/Validation/FormValidationMapper.php +++ b/src/Form/Validation/FormValidationMapper.php @@ -44,7 +44,7 @@ public function mapErrors(ValidationResult $validationResult, FormStateInterface $element = [ '#parents' => FormValidationUtil::getFormErrorMapping( $formState, - // @phpstan-ignore argument.type + // @phpstan-ignore argument.type, argument.type FieldNameUtil::toFormParents($pointer->absolutePath()) ), ]; diff --git a/src/JsonForms/Definition/Control/ControlDefinition.php b/src/JsonForms/Definition/Control/ControlDefinition.php index a1cb0bb..4dc11d2 100644 --- a/src/JsonForms/Definition/Control/ControlDefinition.php +++ b/src/JsonForms/Definition/Control/ControlDefinition.php @@ -46,12 +46,7 @@ class ControlDefinition implements DefinitionInterface { private ?string $scopePrefix; - /** - * @param \Drupal\json_forms\JsonForms\Definition\Control\ControlDefinition $definition - * - * @return static - */ - public static function fromDefinition(ControlDefinition $definition): self { + public static function fromDefinition(ControlDefinition $definition): static { return new static( $definition->controlSchema, $definition->objectSchema, @@ -263,7 +258,7 @@ public function getPropertyKeywordValue(string $keyword, $default = NULL) { * @return string Value of the attribute "name" in HTML. */ public function getPropertyFormName(): string { - if (NULL == $this->propertyFormName) { + if (NULL === $this->propertyFormName) { $this->propertyFormName = FormPropertyUtil::getFormNameForPropertyPath($this->getPropertyPath()); } @@ -326,6 +321,7 @@ public function getSuffix(): ?string { */ public function getType(): string { if (is_array($this->propertySchema->type)) { + /** @var string $type */ foreach ($this->propertySchema->type as $type) { if ('null' !== $type) { return $type; diff --git a/tools/phpstan/composer.json b/tools/phpstan/composer.json index 0a77baa..d47036f 100644 --- a/tools/phpstan/composer.json +++ b/tools/phpstan/composer.json @@ -1,13 +1,13 @@ { "require": { - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.7", - "phpstan/phpstan-beberlei-assert": "^1.0", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.2", - "thecodingmachine/phpstan-strict-rules": "^1.0", - "voku/phpstan-rules": "^3" + "kcs/phpstan-strict-rules": "^2", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2", + "phpstan/phpstan-beberlei-assert": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-phpunit": "^2", + "phpstan/phpstan-strict-rules": "^2", + "voku/phpstan-rules": "^3.6" }, "config": { "allow-plugins": {