From 77841b6f734e4ed6e7fa1d7b1225354b929c93cd Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Mon, 9 Mar 2026 15:39:26 +0100 Subject: [PATCH 01/12] chore: Uncomment new method on interface + remove deprecated methods (#FRAM-221) --- .github/workflows/php.yml | 6 ++-- composer.json | 8 ++--- polyfill/WeakReference.php | 50 -------------------------- src/Aggregate/FormBuilderInterface.php | 5 +-- src/Choice/LazyChoice.php | 2 +- src/Choice/LazzyChoice.php | 13 ------- src/ElementInterface.php | 5 +-- src/Registry/RegistryInterface.php | 37 ------------------- src/RootElementInterface.php | 7 ++-- src/Util/ValidatorBuilderTrait.php | 18 ---------- src/View/ElementViewInterface.php | 5 +-- src/View/FieldSetViewInterface.php | 5 +-- src/View/FieldViewInterface.php | 5 +-- src/View/Renderable.php | 5 +-- 14 files changed, 15 insertions(+), 156 deletions(-) delete mode 100644 polyfill/WeakReference.php delete mode 100644 src/Choice/LazzyChoice.php diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index bf42e19..e9cdc05 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] + php-versions: ['8.4', '8.5'] name: PHP ${{ matrix.php-versions }} steps: @@ -58,7 +58,7 @@ jobs: - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.4 extensions: json ini-values: date.timezone=Europe/Paris @@ -100,7 +100,7 @@ jobs: - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: 8.4 extensions: json ini-values: date.timezone=Europe/Paris diff --git a/composer.json b/composer.json index 0c93755..22ca7b1 100755 --- a/composer.json +++ b/composer.json @@ -11,8 +11,7 @@ "autoload": { "psr-4": { "Bdf\\Form\\": "src" - }, - "classmap": ["polyfill/WeakReference.php"] + } }, "autoload-dev": { "psr-4": { @@ -20,10 +19,9 @@ } }, "require": { - "php": ">=7.4", + "php": "~8.4", "symfony/property-access": "~4.3|~5.0|~6.0|~7.0", - "symfony/validator": "~4.3|~5.0|~6.0|~7.0", - "symfony/polyfill-php80": "~1.22" + "symfony/validator": "~4.3|~5.0|~6.0|~7.0" }, "require-dev": { "symfony/security-csrf": "~4.3|~5.0|~6.0|~7.0", diff --git a/polyfill/WeakReference.php b/polyfill/WeakReference.php deleted file mode 100644 index ca73df0..0000000 --- a/polyfill/WeakReference.php +++ /dev/null @@ -1,50 +0,0 @@ -obj = $obj; - } - - /** - * Get a weakly referenced Object - * - * @return T|null - */ - public function get() - { - return $this->obj; - } - - /** - * Create a new weak reference - * - * @param T $obj - * - * @return WeakReference - */ - public static function create($obj): WeakReference - { - return new self($obj); - } - } -} diff --git a/src/Aggregate/FormBuilderInterface.php b/src/Aggregate/FormBuilderInterface.php index fda02db..8f8d81a 100644 --- a/src/Aggregate/FormBuilderInterface.php +++ b/src/Aggregate/FormBuilderInterface.php @@ -37,8 +37,6 @@ * * * @extends ElementBuilderInterface - * - * @method ChildBuilderInterface any(string $name) */ interface FormBuilderInterface extends ElementBuilderInterface { @@ -74,9 +72,8 @@ public function add(string $name, string $element): ChildBuilderInterface; * @return ChildBuilderInterface The child builder * * @since 1.5 - * @todo uncomment in 2.0 */ - //public function any(string $name): ChildBuilderInterface; + public function any(string $name): ChildBuilderInterface; /** * Add a new string element on the form diff --git a/src/Choice/LazyChoice.php b/src/Choice/LazyChoice.php index a6f2ea5..4ba9332 100644 --- a/src/Choice/LazyChoice.php +++ b/src/Choice/LazyChoice.php @@ -10,7 +10,7 @@ * * @final */ -/*final*/ class LazyChoice implements ChoiceInterface +final class LazyChoice implements ChoiceInterface { /** * The lazy callback with returns choices diff --git a/src/Choice/LazzyChoice.php b/src/Choice/LazzyChoice.php deleted file mode 100644 index e822d33..0000000 --- a/src/Choice/LazzyChoice.php +++ /dev/null @@ -1,13 +0,0 @@ - * * @template T - * - * @method bool failed() */ interface ElementInterface { @@ -138,9 +136,8 @@ public function valid(): bool; * * @see ElementInterface::error() To get error * @since 1.5 - * @todo uncomment in 2.0 */ - //public function failed(): bool; + public function failed(): bool; /** * Get the errors related to the element diff --git a/src/Registry/RegistryInterface.php b/src/Registry/RegistryInterface.php index d5b22b3..ab46583 100644 --- a/src/Registry/RegistryInterface.php +++ b/src/Registry/RegistryInterface.php @@ -5,49 +5,12 @@ use Bdf\Form\Button\ButtonBuilderInterface; use Bdf\Form\Child\ChildBuilderInterface; use Bdf\Form\ElementBuilderInterface; -use Bdf\Form\Filter\FilterInterface; -use Bdf\Form\Transformer\TransformerInterface; -use LogicException; -use Symfony\Component\Form\DataTransformerInterface; -use Symfony\Component\Validator\Constraint; /** * Registry for form components */ interface RegistryInterface { - /** - * Create the filter - * - * @param FilterInterface|callable|string $filter - * - * @return FilterInterface - * @deprecated Since 1.7. Instantiate the filter directly instead of using the registry. - */ - public function filter($filter): FilterInterface; - - /** - * Create the constraint - * - * @param Constraint|callable|array|string $constraint - * - * @return Constraint - * @deprecated Since 1.7. Instantiate the constraint directly instead of using the registry. - */ - public function constraint($constraint): Constraint; - - /** - * Create a view transformer - * - * @param callable|TransformerInterface|DataTransformerInterface $transformer - * - * @return TransformerInterface - * - * @throws LogicException If the transformer is invalid - * @deprecated Since 1.7. Instantiate the transformer directly instead of using the registry. - */ - public function transformer($transformer): TransformerInterface; - /** * Create the child builder * diff --git a/src/RootElementInterface.php b/src/RootElementInterface.php index 2469ab2..2a64abc 100644 --- a/src/RootElementInterface.php +++ b/src/RootElementInterface.php @@ -12,9 +12,6 @@ * * @see ElementInterface::root() To get the root instance * - * @method void set(string $flag, mixed $value) Define a flag value - * @method bool is(string $flag) Check if a flag is defined - * * @extends ElementInterface */ interface RootElementInterface extends ElementInterface @@ -94,7 +91,7 @@ public function constraintGroups(): array; * * @return void */ - //public function set(string $flag, bool $value): void; + public function set(string $flag, bool $value): void; /** * Check a flag value @@ -104,5 +101,5 @@ public function constraintGroups(): array; * * @return bool Flag value */ - //public function is(string $flag): bool; + public function is(string $flag): bool; } diff --git a/src/Util/ValidatorBuilderTrait.php b/src/Util/ValidatorBuilderTrait.php index a99a7be..916f705 100644 --- a/src/Util/ValidatorBuilderTrait.php +++ b/src/Util/ValidatorBuilderTrait.php @@ -257,30 +257,12 @@ private function getTransformerExceptionConstraint(): TransformerExceptionConstr return $this->transformerExceptionConstraint = $this->defaultTransformerExceptionConstraint(); } - /** - * Define the default constraints options for the TransformerExceptionConstraint - * This method should be overridden for define options - * - * @return array - * @deprecated Use {@see ValidatorBuilderTrait::defaultTransformerExceptionConstraint()} instead to define the default constraint with options. Will be removed in bdf-form 2.0 - */ - protected function defaultTransformerExceptionConstraintOptions(): array - { - return []; - } - /** * Define the default TransformerExceptionConstraint * This method should be overridden to define options */ protected function defaultTransformerExceptionConstraint(): TransformerExceptionConstraint { - $options = $this->defaultTransformerExceptionConstraintOptions(); - - if ($options !== []) { - @trigger_error(sprintf('The %s::defaultTransformerExceptionConstraintOptions() method is deprecated since 1.7. Override %s::defaultTransformerExceptionConstraint() instead to define the default constraint with options.', static::class, static::class), E_USER_DEPRECATED); - } - return new TransformerExceptionConstraint( $options['exception'] ?? null, $options['message'] ?? null, diff --git a/src/View/ElementViewInterface.php b/src/View/ElementViewInterface.php index d4bded2..4033c8f 100644 --- a/src/View/ElementViewInterface.php +++ b/src/View/ElementViewInterface.php @@ -4,8 +4,6 @@ /** * Base form element view type - * - * @method self setError(?string $error) */ interface ElementViewInterface { @@ -35,9 +33,8 @@ public function error(): ?string; * * @return $this * @since 1.5 - * @todo uncomment in 2.0 */ - //public function setError(?string $error): self; + public function setError(?string $error): self; /** * Check if the current element is on error diff --git a/src/View/FieldSetViewInterface.php b/src/View/FieldSetViewInterface.php index ba688e8..a9accaf 100644 --- a/src/View/FieldSetViewInterface.php +++ b/src/View/FieldSetViewInterface.php @@ -28,8 +28,6 @@ * * @extends ArrayAccess * @extends Traversable - * - * @method array errors() */ interface FieldSetViewInterface extends ElementViewInterface, ArrayAccess, Traversable { @@ -42,7 +40,6 @@ interface FieldSetViewInterface extends ElementViewInterface, ArrayAccess, Trave * * @return array * @since 1.5 - * @todo uncomment in 2.0 */ - //public function errors(): array; + public function errors(): array; } diff --git a/src/View/FieldViewInterface.php b/src/View/FieldViewInterface.php index e8f5383..dbd6864 100644 --- a/src/View/FieldViewInterface.php +++ b/src/View/FieldViewInterface.php @@ -9,8 +9,6 @@ /** * Base type for HTTP input / field * The implementations must be renderable - * - * @method self setValue($value) Override the value */ interface FieldViewInterface extends ElementViewInterface, Renderable { @@ -36,9 +34,8 @@ public function value(); * * @return $this Return the current instance * @since 1.5 - * @todo uncomment in 2.0 */ - //public function setValue($value): self; + public function setValue($value): self; /** * Does the current field is required (i.e. the value must not be empty) diff --git a/src/View/Renderable.php b/src/View/Renderable.php index 071d9cf..2fd14ee 100644 --- a/src/View/Renderable.php +++ b/src/View/Renderable.php @@ -7,8 +7,6 @@ /** * Base type for a renderable element of the form view tree - * - * @method self with(array $attributes) */ interface Renderable extends Stringable { @@ -44,9 +42,8 @@ public function set(string $name, $value); * @param array $attributes * @return $this * @since 1.5 - * @todo uncomment in 2.0 */ - //public function with(array $attributes); + public function with(array $attributes); /** * Remove an attribute From 9b0b227b609c3b634546d89a27b714dee6c8bbe9 Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Mon, 9 Mar 2026 15:41:57 +0100 Subject: [PATCH 02/12] ci: fix failing test --- tests/Util/ValidatorBuilderTraitTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Util/ValidatorBuilderTraitTest.php b/tests/Util/ValidatorBuilderTraitTest.php index 7b6394c..d072076 100644 --- a/tests/Util/ValidatorBuilderTraitTest.php +++ b/tests/Util/ValidatorBuilderTraitTest.php @@ -225,9 +225,9 @@ public function test_transformerExceptionValidation() public function test_defaultTransformerExceptionConstraintOptions() { $builder = new class extends StringElementBuilder { - protected function defaultTransformerExceptionConstraintOptions(): array + protected function defaultTransformerExceptionConstraint(): TransformerExceptionConstraint { - return ['message' => 'my error message', 'code' => 'MY_ERROR']; + return new TransformerExceptionConstraint(message: 'my error message', code: 'MY_ERROR'); } }; From 2eb22f52f9eb279751b17caf4a84d152dbf31574 Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Tue, 10 Mar 2026 09:47:54 +0100 Subject: [PATCH 03/12] chore: Remove deprecated code and old SF compatibility (#FRAM-221) --- composer.json | 14 +-- src/Aggregate/ArrayElementBuilder.php | 96 ++++----------- src/Aggregate/Form.php | 4 +- src/Child/ChildBuilder.php | 18 +-- src/Child/ChildBuilderInterface.php | 6 +- src/Choice/ChoiceBuilderTrait.php | 47 +++----- src/Constraint/Closure.php | 25 +--- src/Constraint/FieldComparisonTrait.php | 27 +---- src/Csrf/CsrfConstraint.php | 26 +---- src/Csrf/CsrfElementBuilder.php | 6 +- src/Csrf/CsrfValueValidator.php | 13 +-- src/ElementBuilderInterface.php | 19 ++- src/Leaf/Helper/EmailElementBuilder.php | 33 ++---- src/Leaf/Helper/UrlElementBuilder.php | 34 ++---- src/Leaf/NumberElementBuilder.php | 70 ++--------- src/Leaf/StringElementBuilder.php | 110 +++++------------- src/Phone/PhoneElementBuilder.php | 67 ++--------- src/Phone/ValidPhoneNumber.php | 16 +-- src/Registry/Registry.php | 84 ------------- src/Util/DelegateElementBuilderTrait.php | 3 +- src/Util/TransformerBuilderTrait.php | 31 ++--- src/Util/ValidatorBuilderTrait.php | 81 ++----------- .../TransformerExceptionConstraint.php | 17 +-- src/View/ConstraintsNormalizer.php | 7 +- tests/Aggregate/ArrayElementBuilderTest.php | 13 +-- tests/Aggregate/ArrayElementTest.php | 4 +- tests/Aggregate/FormTest.php | 4 +- tests/Csrf/CsrfElementBuilderTest.php | 6 +- tests/CyclicReferenceTest.php | 2 +- tests/Error/ImplodeErrorPrinterTest.php | 4 +- tests/Error/StringErrorPrinterTest.php | 10 +- tests/Filter/FilterVarTest.php | 2 +- tests/Leaf/AnyElementBuilderTest.php | 11 -- tests/Leaf/AnyElementTest.php | 4 +- tests/Leaf/BooleanElementTest.php | 4 +- tests/Leaf/BooleanStringElementTest.php | 4 +- tests/Leaf/Date/DateTimeElementTest.php | 2 +- tests/Leaf/FloatElementTest.php | 4 +- tests/Leaf/Helper/EmailElementBuilderTest.php | 17 --- tests/Leaf/Helper/UrlElementBuilderTest.php | 2 +- tests/Leaf/IntegerElementTest.php | 4 +- tests/Leaf/StringElementBuilderTest.php | 22 ---- tests/Leaf/StringElementTest.php | 4 +- tests/Registry/RegistryTest.php | 98 ---------------- tests/Util/ValidatorBuilderTraitTest.php | 11 -- .../ConstraintValueValidatorTest.php | 4 +- 46 files changed, 202 insertions(+), 888 deletions(-) diff --git a/composer.json b/composer.json index 22ca7b1..2360e6e 100755 --- a/composer.json +++ b/composer.json @@ -20,16 +20,16 @@ }, "require": { "php": "~8.4", - "symfony/property-access": "~4.3|~5.0|~6.0|~7.0", - "symfony/validator": "~4.3|~5.0|~6.0|~7.0" + "symfony/property-access": "~6.4|~7.0", + "symfony/validator": "~6.4|~7.0" }, "require-dev": { - "symfony/security-csrf": "~4.3|~5.0|~6.0|~7.0", + "symfony/security-csrf": "~6.4|~7.0", "giggsey/libphonenumber-for-php": "~8.0|~9.0", - "phpunit/phpunit": "~7.0|~8.0|~9.0", - "vimeo/psalm": "~4.30|~5.22", - "symfony/http-foundation": "~4.3|~5.0|~6.0|~7.0", - "symfony/form": "~4.3|~5.0|~6.0|~7.0" + "phpunit/phpunit": "~9.0", + "vimeo/psalm": "~6.15.1", + "symfony/http-foundation": "~6.4|~7.0", + "symfony/form": "~6.4|~7.0" }, "suggest": { "symfony/security-csrf": "For enable CSRF element", diff --git a/src/Aggregate/ArrayElementBuilder.php b/src/Aggregate/ArrayElementBuilder.php index bb14dcb..a73c9c1 100644 --- a/src/Aggregate/ArrayElementBuilder.php +++ b/src/Aggregate/ArrayElementBuilder.php @@ -2,10 +2,7 @@ namespace Bdf\Form\Aggregate; -use Bdf\Form\Choice\ArrayChoice; use Bdf\Form\Choice\ChoiceBuilderTrait; -use Bdf\Form\Choice\ChoiceInterface; -use Bdf\Form\Choice\LazyChoice; use Bdf\Form\ElementBuilderInterface; use Bdf\Form\ElementInterface; use Bdf\Form\Leaf\BooleanElement; @@ -16,23 +13,14 @@ use Bdf\Form\Phone\PhoneElement; use Bdf\Form\Registry\Registry; use Bdf\Form\Registry\RegistryInterface; +use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Util\MagicCallForwarding; use Bdf\Form\Util\TransformerBuilderTrait; use Bdf\Form\Util\ValidatorBuilderTrait; -use ReflectionClass; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Choice as ChoiceConstraint; use Symfony\Component\Validator\Constraints\Count; use Symfony\Component\Validator\Constraints\NotBlank; -use TypeError; - -use function func_get_arg; -use function func_num_args; -use function is_array; -use function is_bool; -use function is_callable; -use function sprintf; -use function trigger_error; /** * Builder for the array element @@ -110,7 +98,7 @@ public function satisfy($constraint, $options = null, bool $append = true) * * Define a transformer on the inner element */ - public function transformer($transformer, bool $append = true) + public function transformer(callable|TransformerInterface $transformer, bool $append = true) { $this->getElementBuilder()->transformer($transformer, $append); @@ -307,7 +295,7 @@ public function form(?callable $configurator = null): ArrayElementBuilder * * Ex: `$builder->count(['min' => 3, 'max' => 5])` * - * @param array|int|null $exactly The exact expected number of elements, or an array of options (deprecated since 1.7) + * @param int|null $exactly The exact expected number of elements * @param int|null $min Minimum expected number of elements * @param int|null $max Maximum expected number of elements * @param string|null $exactMessage @@ -318,30 +306,17 @@ public function form(?callable $configurator = null): ArrayElementBuilder * * @see Count For the list of options */ - public function count($exactly = null, ?int $min = null, ?int $max = null, ?string $exactMessage = null, ?string $minMessage = null, ?string $maxMessage = null): ArrayElementBuilder + public function count(?int $exactly = null, ?int $min = null, ?int $max = null, ?string $exactMessage = null, ?string $minMessage = null, ?string $maxMessage = null): ArrayElementBuilder { - if (is_array($exactly)) { - @trigger_error('Passing an array of options to count() is deprecated since 1.7. Pass the options as individual parameters instead.', E_USER_DEPRECATED); - - $min = $exactly['min'] ?? null; - $max = $exactly['max'] ?? null; - $exactMessage = $exactly['exactMessage'] ?? null; - $minMessage = $exactly['minMessage'] ?? null; - $maxMessage = $exactly['maxMessage'] ?? null; - $exactly = $exactly['exactly'] ?? null; - } - - static $isSf4 = null; - - if ($isSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(Count::class))->getConstructor()->getNumberOfParameters() === 1; - } - return $this->arrayConstraint( - $isSf4 - ? new Count(['exactly' => $exactly, 'min' => $min, 'max' => $max, 'exactMessage' => $exactMessage, 'minMessage' => $minMessage, 'maxMessage' => $maxMessage]) - : new Count($exactly, $min, $max, null, $exactMessage, $minMessage, $maxMessage) // The constructor is consistent from sf 5 to 8, so we can safely use ordered parameters. + new Count( + exactly: $exactly, + min: $min, + max: $max, + exactMessage: $exactMessage, + minMessage: $minMessage, + maxMessage: $maxMessage + ) ); } @@ -350,48 +325,17 @@ public function count($exactly = null, ?int $min = null, ?int $max = null, ?stri * * @return $this */ - final public function required($options = null/*, ?bool $allowNull = null, ?callable $normalizer = null*/) + final public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null) { - // @todo rename $options to $message on bdf-form 2.0 - if (is_array($options)) { - @trigger_error('Passing an array of options to required() is deprecated since 1.7. Pass the options as individual parameters instead.', E_USER_DEPRECATED); - } - - // @todo declare allowNull and normalizer as actual parameters on bdf-form 2.0 - $allowNull = func_num_args() > 1 ? func_get_arg(1) : null; - $normalizer = func_num_args() > 2 ? func_get_arg(2) : null; - - if ($allowNull !== null && !is_bool($allowNull)) { - throw new TypeError(sprintf('The "allowNull" option of required() must be a boolean or null, "%s" given.', get_debug_type($allowNull))); - } - - if ($normalizer !== null && !is_callable($normalizer)) { - throw new TypeError(sprintf('The "normalizer" option of required() must be a valid callable or null, "%s" given.', get_debug_type($normalizer))); - } - - if (!$options instanceof Constraint) { - static $isSf4 = null; - - if ($isSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(NotBlank::class))->getConstructor()->getNumberOfParameters() === 1; - } - - if (is_array($options)) { - $message = $options['message'] ?? null; - $allowNull ??= $options['allowNull'] ?? null; - $normalizer ??= $options['normalizer'] ?? null; - } else { - $message = $options; - } - - $options = $isSf4 - ? new NotBlank(['message' => $message, 'allowNull' => $allowNull, 'normalizer' => $normalizer]) - : new NotBlank(null, $message, $allowNull, $normalizer) // The constructor is consistent from sf 5 to 8, so we can safely use ordered parameters. - ; + if (!$message instanceof Constraint) { + $message = new NotBlank( + message: $message, + allowNull: $allowNull, + normalizer: $normalizer + ); } - return $this->arrayConstraint($options); + return $this->arrayConstraint($message); } /** diff --git a/src/Aggregate/Form.php b/src/Aggregate/Form.php index 4b615c9..b380694 100644 --- a/src/Aggregate/Form.php +++ b/src/Aggregate/Form.php @@ -280,12 +280,12 @@ public function root(): RootElementInterface * * @return FormView */ - public function view(?HttpFieldPath $field = null): ElementViewInterface + public function view(?HttpFieldPath $fieldPath = null): ElementViewInterface { $elements = []; foreach ($this->children as $child) { - $elements[$child->name()] = $child->view($field); + $elements[$child->name()] = $child->view($fieldPath); } return new FormView(self::class, $this->error->global(), $elements); diff --git a/src/Child/ChildBuilder.php b/src/Child/ChildBuilder.php index 1bc9676..cd5edf2 100644 --- a/src/Child/ChildBuilder.php +++ b/src/Child/ChildBuilder.php @@ -21,7 +21,6 @@ use Symfony\Component\Form\DataTransformerInterface; use function is_callable; -use function trigger_error; /** * Base builder for a child @@ -76,7 +75,7 @@ class ChildBuilder implements ChildBuilderInterface private $default; /** - * @var array + * @var array */ private $filters = []; @@ -161,16 +160,12 @@ final public function extractor(ExtractorInterface $extractor) /** * {@inheritdoc} */ - final public function filter($filter, bool $append = true) + final public function filter(FilterInterface|callable $filter, bool $append = true) { if (is_callable($filter)) { $filter = new ClosureFilter($filter); } - if (!$filter instanceof FilterInterface) { - @trigger_error('Not passing a callable or a filter instance is deprecated since 1.7 and will be removed in 2.0.', E_USER_DEPRECATED); - } - if ($append === true) { $this->filters[] = $filter; } else { @@ -454,7 +449,7 @@ final public function trim(bool $active = true): self * * * $builder->string('foo')->configure(function (StringElementBuilder $builder) { - * $builder->length(['min' => 3]); + * $builder->length(min: 3); * }); * * @@ -532,13 +527,10 @@ private function buildParameters(): ChildParameters $parameters->className = $this->childClassName; $parameters->filters = $this->trim ? [TrimFilter::instance()] : []; - - foreach ($this->filters as $filter) { - $parameters->filters[] = $this->registry->filter($filter); - } + $parameters->filters = [...$parameters->filters, ...$this->filters]; foreach ($this->filtersProviders as $provider) { - $parameters->filters = array_merge($parameters->filters, $provider($this->registry)); + $parameters->filters = [...$parameters->filters, ...$provider($this->registry)]; } $parameters->fields = $this->fields ?: new ArrayOffsetHttpFields($this->name); diff --git a/src/Child/ChildBuilderInterface.php b/src/Child/ChildBuilderInterface.php index dc66dc2..b174281 100644 --- a/src/Child/ChildBuilderInterface.php +++ b/src/Child/ChildBuilderInterface.php @@ -67,7 +67,7 @@ public function extractor(ExtractorInterface $extractor); * * @see FilterInterface */ - public function filter($filter, bool $append = true); + public function filter(FilterInterface|callable $filter, bool $append = true); /** * Define the default value @@ -160,14 +160,14 @@ public function depends(string ...$inputNames); * }); * * - * @param callable|TransformerInterface|DataTransformerInterface $transformer The transformer. Symfony transformer can be used + * @param callable|TransformerInterface $transformer The transformer * @param bool $append Append the transformer. Prepend if false * * @return $this * * @see TransformerInterface */ - public function modelTransformer($transformer, bool $append = true); + public function modelTransformer(callable|TransformerInterface $transformer, bool $append = true); /** * Creates the child instance diff --git a/src/Choice/ChoiceBuilderTrait.php b/src/Choice/ChoiceBuilderTrait.php index 87b6b52..fbc4612 100644 --- a/src/Choice/ChoiceBuilderTrait.php +++ b/src/Choice/ChoiceBuilderTrait.php @@ -3,12 +3,10 @@ namespace Bdf\Form\Choice; use Bdf\Form\ElementBuilderInterface; -use ReflectionClass; +use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Choice as ChoiceConstraint; use function is_array; -use function sprintf; -use function trigger_error; /** * Trait for configure choices on an element @@ -45,43 +43,32 @@ trait ChoiceBuilderTrait * * * @param ChoiceInterface|array|callable $choices The allowed values in PHP form. - * @param null|string|array $message The error message. + * @param string|null $message The error message. * * @return $this * @see ChoiceConstraint */ - final public function choices($choices, $message = null, ?bool $multiple = null, ?bool $strict = null, ?int $min = null, ?int $max = null, ?string $minMessage = null, ?string $maxMessage = null): self + final public function choices(ChoiceInterface|array|callable $choices, ?string $message = null, ?bool $multiple = null, ?bool $strict = null, ?int $min = null, ?int $max = null, ?string $minMessage = null, ?string $maxMessage = null): self { if (!$choices instanceof ChoiceInterface) { $choices = is_array($choices) ? new ArrayChoice($choices) : new LazyChoice($choices); } - if (is_array($message)) { - @trigger_error(sprintf('Passing an array of options on %s is deprecated since 1.7 and will be removed on 2.0, use named arguments instead.', __METHOD__), E_USER_DEPRECATED); - - $multiple = $multiple ?? $message['multiple'] ?? null; - $strict = $strict ?? $message['strict'] ?? null; - $min = $min ?? $message['min'] ?? null; - $max = $max ?? $message['max'] ?? null; - $minMessage = $minMessage ?? $message['minMessage'] ?? null; - $maxMessage = $maxMessage ?? $message['maxMessage'] ?? null; - $message = $message['message'] ?? null; - } - - static $isSf4 = null; - - if ($isSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(ChoiceConstraint::class))->getConstructor()->getNumberOfParameters() === 1; - } - - $callback = [$choices, 'values']; - + $callback = $choices->values(...); $this->choices = $choices; - return $this->satisfy($isSf4 - ? new ChoiceConstraint(['callback' => $callback, 'message' => $message, 'multipleMessage' => $message, 'multiple' => $multiple, 'strict' => $strict, 'min' => $min, 'max' => $max, 'minMessage' => $minMessage, 'maxMessage' => $maxMessage]) - : new ChoiceConstraint([], null, $callback, $multiple, $strict, $min, $max, $message, $message, $minMessage, $maxMessage) + return $this->satisfy( + new ChoiceConstraint( + callback: $callback, + multiple: $multiple, + strict: $strict, + min: $min, + max: $max, + message: $message, + multipleMessage: $message, + minMessage: $minMessage, + maxMessage: $maxMessage + ) ); } @@ -101,5 +88,5 @@ final protected function getChoices(): ?ChoiceInterface * * @see ElementBuilderInterface::satisfy() */ - abstract public function satisfy($constraint, $options = null, bool $append = true); + abstract public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true); } diff --git a/src/Constraint/Closure.php b/src/Constraint/Closure.php index 2ad71d3..6535096 100755 --- a/src/Constraint/Closure.php +++ b/src/Constraint/Closure.php @@ -5,11 +5,6 @@ use Attribute; use Symfony\Component\Validator\Constraint; -use function is_array; -use function is_callable; -use function sprintf; -use function trigger_error; - /** * Handle custom constraint using a callback * @@ -50,17 +45,9 @@ class Closure extends Constraint */ public $callback; - public function __construct($callback, ?string $message = null) + public function __construct(callable $callback, ?string $message = null) { - if (!is_callable($callback) && is_array($callback)) { - @trigger_error(sprintf('Passing an array of options to %s is deprecated since 1.7. Pass the callback as first parameter and the message as second parameter instead.', self::class), E_USER_DEPRECATED); - - $options = $callback; - $callback = $options['callback'] ?? null; - $message ??= $options['message'] ?? null; - } - - parent::__construct($options ?? null); + parent::__construct(); $this->callback = $callback; @@ -68,12 +55,4 @@ public function __construct($callback, ?string $message = null) $this->message = $message; } } - - /** - * {@inheritdoc} - */ - public function getDefaultOption(): ?string - { - return 'callback'; - } } diff --git a/src/Constraint/FieldComparisonTrait.php b/src/Constraint/FieldComparisonTrait.php index 49fe85a..19e01de 100644 --- a/src/Constraint/FieldComparisonTrait.php +++ b/src/Constraint/FieldComparisonTrait.php @@ -5,10 +5,6 @@ use Bdf\Form\Util\FieldPath; use Symfony\Component\Validator\Constraint; -use function is_array; -use function sprintf; -use function trigger_error; - /** * Add field option on comparison class * The class must extends a subclass of AbstractComparison @@ -24,27 +20,12 @@ trait FieldComparisonTrait /** * FieldComparisonTrait constructor. - * @param string|FieldPath|array $field + * @param string|FieldPath $field */ - public function __construct($field) + public function __construct(string|FieldPath $field) { - if (is_array($field)) { - @trigger_error(sprintf('Passing an array of options to "%s" is deprecated since version 1.2 and will not be supported in 2.0. Use named arguments instead.', static::class), E_USER_DEPRECATED); - - $options = $field; - $field = $options['field'] ?? null; - } - - Constraint::__construct($options ?? null); - - $this->field = $field ?? $this->field; - } + Constraint::__construct(); - /** - * {@inheritdoc} - */ - public function getDefaultOption(): ?string - { - return 'field'; + $this->field = $field; } } diff --git a/src/Csrf/CsrfConstraint.php b/src/Csrf/CsrfConstraint.php index f775277..89a907d 100644 --- a/src/Csrf/CsrfConstraint.php +++ b/src/Csrf/CsrfConstraint.php @@ -5,10 +5,6 @@ use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Validator\Constraint; -use function is_array; -use function sprintf; -use function trigger_error; - /** * @internal */ @@ -17,7 +13,6 @@ class CsrfConstraint extends Constraint const INVALID_TOKEN_ERROR = 'cd108896-d12a-4455-a6cc-ba13708c8e7f'; protected const ERROR_NAMES = [self::INVALID_TOKEN_ERROR => 'INVALID_TOKEN_ERROR']; - protected static $errorNames = self::ERROR_NAMES; /** * The constraint message @@ -31,26 +26,11 @@ class CsrfConstraint extends Constraint */ public $manager; - public function __construct($manager = null, ?string $message = null) + public function __construct(CsrfTokenManagerInterface $manager, ?string $message = null) { - if (is_array($manager)) { - @trigger_error(sprintf('Passing an array of options on %s is deprecated since 1.7 and will be removed on 2.0, use named arguments instead.', __METHOD__), E_USER_DEPRECATED); - $options = $manager; - $manager = $options['manager'] ?? null; - $message = $message ?? $options['message'] ?? null; - } - - parent::__construct($options ?? null); + parent::__construct(); - $this->manager = $manager ?? $this->manager; + $this->manager = $manager; $this->message = $message ?? $this->message; } - - /** - * {@inheritdoc} - */ - public function getDefaultOption(): ?string - { - return 'manager'; - } } diff --git a/src/Csrf/CsrfElementBuilder.php b/src/Csrf/CsrfElementBuilder.php index eaba81d..b85e18d 100644 --- a/src/Csrf/CsrfElementBuilder.php +++ b/src/Csrf/CsrfElementBuilder.php @@ -6,8 +6,10 @@ use Bdf\Form\Aggregate\FormBuilderInterface; use Bdf\Form\ElementBuilderInterface; use Bdf\Form\ElementInterface; +use Bdf\Form\Transformer\TransformerInterface; use LogicException; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; +use Symfony\Component\Validator\Constraint; /** * Builder for a CsrfElement @@ -146,7 +148,7 @@ public function validateOnSubForms(bool $validateOnSubForms = true): self /** * {@inheritdoc} */ - public function satisfy($constraint, $options = null, bool $append = true) + public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) { throw new BadMethodCallException(); } @@ -154,7 +156,7 @@ public function satisfy($constraint, $options = null, bool $append = true) /** * {@inheritdoc} */ - public function transformer($transformer, bool $append = true) + public function transformer(callable|TransformerInterface $transformer, bool $append = true) { throw new BadMethodCallException(); } diff --git a/src/Csrf/CsrfValueValidator.php b/src/Csrf/CsrfValueValidator.php index 7f74685..21888bf 100644 --- a/src/Csrf/CsrfValueValidator.php +++ b/src/Csrf/CsrfValueValidator.php @@ -9,10 +9,7 @@ use Bdf\Form\Validator\ValueValidatorInterface; use Exception; -use function is_array; use function method_exists; -use function sprintf; -use function trigger_error; /** * Class CsrfValueValidator @@ -58,17 +55,11 @@ final class CsrfValueValidator implements ValueValidatorInterface * CsrfValueValidator constructor. * * @param bool $invalidate Always invalidate the token after validation - * @param array|string|null $message The error message + * @param string|null $message The error message * @param bool $onlyValidateRoot Only validate the csrf token if the element is on the root form */ - public function __construct(bool $invalidate = false, $message = null, bool $onlyValidateRoot = false) + public function __construct(bool $invalidate = false, ?string $message = null, bool $onlyValidateRoot = false) { - if (is_array($message)) { - @trigger_error(sprintf('Passing an array of options on %s is deprecated since 1.7 and will be removed on 2.0, use named arguments instead.', __METHOD__), E_USER_DEPRECATED); - - $message = $message['message'] ?? null; - } - $this->invalidate = $invalidate; $this->message = $message; $this->onlyValidateRoot = $onlyValidateRoot; diff --git a/src/ElementBuilderInterface.php b/src/ElementBuilderInterface.php index e6540f1..26ebd47 100644 --- a/src/ElementBuilderInterface.php +++ b/src/ElementBuilderInterface.php @@ -22,17 +22,12 @@ interface ElementBuilderInterface * * Prototypes: * function satisfy(Constraint $constraint, null, bool $append = true) - Add a constraint object. The 2nd parameter is ignored - * function satisfy(string $constraintClassName, ?array $options = null, bool $append = true) - Equivalent to satisfy(new $constraintClassName($options), null, $append) - * function satisfy(string $constraintClassName, ?string $errorMessage = null, bool $append = true) - Equivalent to satisfy(new $constraintClassName(['message' => $errorMessage]), null, $append) - * function satisfy(callable $inlineConstraint, null, bool $append = true) - Create a new constraint using a callback. The 2nd parameter is ignored + * function satisfy(callable $inlineConstraint, ?string $message = null, bool $append = true) - Create a new constraint using a callback. The 2nd parameter is the error message * * Usage: * * $builder->satisfy(new MyConstraint()); // Add a constraint * $builder->satisfy(new MyConstraint(), null, false); // Prepend the constraint (it will be validated first) - * $builder->satisfy(MyConstraint::class); // Use class name (will be used by the registry to make the constraint) - * $builder->satisfy(MyConstraint::class, ['foo' => 'bar']); // Same as above, but with options - * $builder->satisfy(MyConstraint::class, 'my error'); // Same as above, but with the option "message" defined to "my error" * * // Register a custom constraint * // Take the value as first parameter, and the input element as second @@ -53,14 +48,14 @@ interface ElementBuilderInterface * // You can also return a simple boolean * $builder->satisfy(function ($value, ElementInterface $input) { * return is_valid($value); - * }); + * }, 'my error'); * * // Use method reference also works, but the method must be public * $builder->satisfy([$this, 'checkElement']); * * - * @param Constraint|string|callable $constraint The constraint - * @param array|string|null $options Constraint options if a class name is given as first parameter. If a string is given, it will be used as message option + * @param Constraint|callable $constraint The constraint + * @param string|null $message The error message if the first parameter is a callable. * @param bool $append Append the validator. Prepend if false * * @return $this @@ -68,7 +63,7 @@ interface ElementBuilderInterface * @see RegistryInterface::constraint() For make the constraint * @see Closure When use callback as first parameter */ - public function satisfy($constraint, $options = null, bool $append = true); + public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true); /** * Add a view transformer @@ -95,14 +90,14 @@ public function satisfy($constraint, $options = null, bool $append = true); * }); * * - * @param callable|TransformerInterface|DataTransformerInterface $transformer The transformer. Symfony transformer can be used + * @param callable|TransformerInterface $transformer The transformer. * @param bool $append Append the transformer. Prepend if false * * @return $this * * @see TransformerInterface */ - public function transformer($transformer, bool $append = true); + public function transformer(callable|TransformerInterface $transformer, bool $append = true); /** * Define the initial value of the element diff --git a/src/Leaf/Helper/EmailElementBuilder.php b/src/Leaf/Helper/EmailElementBuilder.php index d44602f..5fcd532 100644 --- a/src/Leaf/Helper/EmailElementBuilder.php +++ b/src/Leaf/Helper/EmailElementBuilder.php @@ -7,11 +7,8 @@ use Bdf\Form\Registry\RegistryInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; -use ReflectionClass; use Symfony\Component\Validator\Constraints\Email; -use function is_array; - /** * Provide email constraint builder for a StringElementBuilder * @@ -125,27 +122,16 @@ public function disableConstraint(): self * Define the email validation constraint options * * - * $builder->email('contact')->useConstraint(['mode' => Email::VALIDATION_MODE_HTML5, 'message' => 'my error']); + * $builder->email('contact')->useConstraint(mode: Email::VALIDATION_MODE_HTML5, message: 'my error'); * * - * @param string|array|null $message - * * @return $this * * @see Email for list of options */ - public function useConstraint($message = null, ?string $mode = null, ?string $normalizer = null): self + public function useConstraint(?string $message = null, ?string $mode = null, ?string $normalizer = null): self { $this->useConstraint = true; - - if (is_array($message)) { - @trigger_error(sprintf('Passing an array of options on %s is deprecated since 1.7 and will be removed on 2.0, use named arguments instead.', __METHOD__), E_USER_DEPRECATED); - - $mode = $mode ?? $message['mode'] ?? null; - $normalizer = $normalizer ?? $message['normalizer'] ?? null; - $message = $message['message'] ?? null; - } - $this->errorMessage = $message; $this->mode = $mode; $this->normalizer = $normalizer; @@ -162,17 +148,12 @@ protected function createEmailConstraint(RegistryInterface $registry): array return []; } - static $isSf4 = null; - - if (null === $isSf4) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(Email::class))->getConstructor()->getNumberOfParameters() === 1; - } - return [ - $isSf4 - ? new Email(['mode' => $this->mode, 'message' => $this->errorMessage, 'normalizer' => $this->normalizer]) - : new Email(null, $this->errorMessage, $this->mode, $this->normalizer) + new Email( + message: $this->errorMessage, + mode: $this->mode, + normalizer: $this->normalizer + ), ]; } diff --git a/src/Leaf/Helper/UrlElementBuilder.php b/src/Leaf/Helper/UrlElementBuilder.php index dcde5be..343f105 100644 --- a/src/Leaf/Helper/UrlElementBuilder.php +++ b/src/Leaf/Helper/UrlElementBuilder.php @@ -7,13 +7,9 @@ use Bdf\Form\Registry\RegistryInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; -use ReflectionClass; use Symfony\Component\Validator\Constraints\Url; -use function is_array; use function is_string; -use function sprintf; -use function trigger_error; /** * Provide URL constraint builder for a StringElementBuilder @@ -153,19 +149,10 @@ public function disableConstraint(): self * * @see Url for list of options */ - public function useConstraint($message = null, $protocols = null, ?bool $relativeProtocol = null, ?callable $normalizer = null): self + public function useConstraint(?string $message = null, string|array|null $protocols = null, ?bool $relativeProtocol = null, ?callable $normalizer = null): self { $this->useConstraint = true; - if (is_array($message)) { - @trigger_error(sprintf('Passing an array of options to "%s" is deprecated since 1.7, use named arguments instead.', __METHOD__), E_USER_DEPRECATED); - - $protocols ??= $message['protocols'] ?? null; - $relativeProtocol ??= $message['relativeProtocol'] ?? null; - $normalizer ??= $message['normalizer'] ?? null; - $message = $message['message'] ?? null; - } - $this->errorMessage = $message; $this->protocols = is_string($protocols) ? [$protocols] : $protocols; $this->relativeProtocol = $relativeProtocol; @@ -184,18 +171,15 @@ protected function createUrlConstraint(RegistryInterface $registry): array return []; } - static $isSf4 = null; - - if ($isSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(Url::class))->getConstructor()->getNumberOfParameters() === 1; - } - return [ - $isSf4 - ? new Url(['protocols' => $this->protocols, 'relativeProtocol' => $this->relativeProtocol, 'normalizer' => $this->normalizer, 'message' => $this->errorMessage]) - : new Url(null, $this->errorMessage, $this->protocols, $this->relativeProtocol, $this->normalizer, null, null, $this->requireTld, $this->tldMessage) - , + new Url( + message: $this->errorMessage, + protocols: $this->protocols, + relativeProtocol: $this->relativeProtocol, + normalizer: $this->normalizer, + requireTld: $this->requireTld, + tldMessage: $this->tldMessage + ), ]; } diff --git a/src/Leaf/NumberElementBuilder.php b/src/Leaf/NumberElementBuilder.php index 63930f0..cf9866d 100644 --- a/src/Leaf/NumberElementBuilder.php +++ b/src/Leaf/NumberElementBuilder.php @@ -7,15 +7,10 @@ use Bdf\Form\Registry\RegistryInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\TransformerExceptionConstraint; -use ReflectionClass; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\LessThanOrEqual; use Symfony\Component\Validator\Constraints\Positive; -use function is_array; -use function sprintf; -use function trigger_error; - /** * Base builder for an number element * @@ -52,19 +47,9 @@ public function __construct(?RegistryInterface $registry = null) * * @return $this */ - public function min($min, ?string $message = null): self + public function min(int|float $min, ?string $message = null): self { - static $isSf4 = null; - - if ($isSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(GreaterThanOrEqual::class))->getConstructor()->getNumberOfParameters() === 1; - } - - $this->satisfy($isSf4 - ? new GreaterThanOrEqual(['value' => $min, 'message' => $message]) - : new GreaterThanOrEqual($min, null, $message) - ); + $this->satisfy(new GreaterThanOrEqual(value: $min, message: $message)); return $this; } @@ -77,19 +62,9 @@ public function min($min, ?string $message = null): self * * @return $this */ - public function max($max, ?string $message = null): self + public function max(int|float $max, ?string $message = null): self { - static $isSf4 = null; - - if ($isSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(LessThanOrEqual::class))->getConstructor()->getNumberOfParameters() === 1; - } - - $this->satisfy($isSf4 - ? new LessThanOrEqual(['value' => $max, 'message' => $message]) - : new LessThanOrEqual($max, null, $message) - ); + $this->satisfy(new LessThanOrEqual(value: $max, message: $message)); return $this; } @@ -97,29 +72,14 @@ public function max($max, ?string $message = null): self /** * The number must be positive * - * @param array|string|null $message The error message + * @param string|null $message The error message * * @return $this * @see Positive */ - public function positive($message = null): self + public function positive(?string $message = null): self { - static $isSf4 = null; - - if ($isSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(Positive::class))->getConstructor()->getNumberOfParameters() === 1; - } - - if (is_array($message)) { - @trigger_error(sprintf('Passing an array of options on %s is deprecated since 1.7 and will be removed on 2.0, use named arguments instead.', __METHOD__), E_USER_DEPRECATED); - $message = $message['message'] ?? null; - } - - return $this->satisfy($isSf4 - ? new Positive(['message' => $message]) - : new Positive(null, $message) - ); + return $this->satisfy(new Positive(message: $message)); } /** @@ -139,26 +99,14 @@ public function raw(bool $flag = true): self return $this; } - /** - * {@inheritdoc} - */ - protected function defaultTransformerExceptionConstraintOptions(): array - { - return [ - 'message' => 'The value is not a valid number.', - 'code' => 'INVALID_NUMBER_ERROR', - ]; - } - /** * {@inheritdoc} */ protected function defaultTransformerExceptionConstraint(): TransformerExceptionConstraint { return new TransformerExceptionConstraint( - null, - /*message:*/ 'The value is not a valid number.', - /*code:*/ 'INVALID_NUMBER_ERROR', + message: 'The value is not a valid number.', + code: 'INVALID_NUMBER_ERROR', ); } diff --git a/src/Leaf/StringElementBuilder.php b/src/Leaf/StringElementBuilder.php index 8c244b1..92c2a7c 100644 --- a/src/Leaf/StringElementBuilder.php +++ b/src/Leaf/StringElementBuilder.php @@ -8,24 +8,16 @@ use Bdf\Form\ElementInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; -use InvalidArgumentException; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\Regex; -use function get_debug_type; -use function is_array; -use function is_string; -use function property_exists; -use function sprintf; -use function trigger_error; - /** * Builder for string element * * * $builder->string('username') * ->required() - * ->length(['min' => 6, 'max' => 32]) + * ->length(min: 6, max: 32) * ->regex('/[a-z_-]+/i') * ; * @@ -42,65 +34,31 @@ class StringElementBuilder extends AbstractElementBuilder /** * Add a string length constraint * - * Options are keys are : min, max, minMessage, maxMessage - * * Usage: * - * $builder->length(['max' => 256]); + * $builder->length(max: 256); * * - * @param array|int|null $exactly - * * @return $this * * @see Length For options */ - public function length($exactly = null, ?int $min = null, ?int $max = null, ?string $charset = null, ?callable $normalizer = null, ?string $countUnit = null, ?string $exactMessage = null, ?string $minMessage = null, ?string $maxMessage = null, ?string $charsetMessage = null): self + public function length(?int $exactly = null, ?int $min = null, ?int $max = null, ?string $charset = null, ?callable $normalizer = null, ?string $countUnit = null, ?string $exactMessage = null, ?string $minMessage = null, ?string $maxMessage = null, ?string $charsetMessage = null): self { - static $sfVersion = null; - - if ($sfVersion === null) { - /** @psalm-suppress PossiblyNullReference */ - if ((new \ReflectionClass(Length::class))->getConstructor()->getNumberOfParameters() === 1) { - $sfVersion = 43; - } elseif (!property_exists(Length::class, 'countUnit')) { - // Count unit parameter has been added in SF 6.3 - $sfVersion = 53; - } else { - $sfVersion = 63; - } - } - - if (is_array($exactly)) { - @trigger_error(sprintf('Passing an array of options on %s is deprecated since 1.7 and will be removed on 2.0, use named arguments instead.', __METHOD__), E_USER_DEPRECATED); - - $min ??= $exactly['min'] ?? null; - $max ??= $exactly['max'] ?? null; - $charset ??= $exactly['charset'] ?? null; - $normalizer ??= $exactly['normalizer'] ?? null; - $countUnit ??= $exactly['countUnit'] ?? null; - $exactMessage ??= $exactly['exactMessage'] ?? null; - $minMessage ??= $exactly['minMessage'] ?? null; - $maxMessage ??= $exactly['maxMessage'] ?? null; - $charsetMessage ??= $exactly['charsetMessage'] ?? null; - $exactly = $exactly['exactly'] ?? null; - } - - switch ($sfVersion) { - case 43: - $constraint = new Length(['value' => $exactly, 'min' => $min, 'max' => $max, 'charset' => $charset, 'normalizer' => $normalizer, 'exactMessage' => $exactMessage, 'minMessage' => $minMessage, 'maxMessage' => $maxMessage, 'charsetMessage' => $charsetMessage]); - break; - - case 53: - $constraint = new Length($exactly, $min, $max, $charset, $normalizer, $exactMessage, $minMessage, $maxMessage, $charsetMessage); - break; - - default: - /** @psalm-suppress PossiblyInvalidArgument */ - $constraint = new Length($exactly, $min, $max, $charset, $normalizer, $countUnit, $exactMessage, $minMessage, $maxMessage, $charsetMessage); - } - - return $this->satisfy($constraint); + return $this->satisfy( + new Length( + exactly: $exactly, + min: $min, + max: $max, + charset: $charset, + normalizer: $normalizer, + countUnit: $countUnit, + exactMessage: $exactMessage, + minMessage: $minMessage, + maxMessage: $maxMessage, + charsetMessage: $charsetMessage, + ) + ); } /** @@ -117,32 +75,16 @@ public function length($exactly = null, ?int $min = null, ?int $max = null, ?str * * @see Regex */ - public function regex($pattern, ?string $message = null, ?string $htmlPattern = null, ?bool $match = null, ?callable $normalizer = null): self + public function regex(string $pattern, ?string $message = null, ?string $htmlPattern = null, ?bool $match = null, ?callable $normalizer = null): self { - if (is_array($pattern)) { - @trigger_error(sprintf('Passing an array of options on %s is deprecated since 1.7 and will be removed on 2.0, use named arguments instead.', __METHOD__), E_USER_DEPRECATED); - - $message ??= $pattern['message'] ?? null; - $htmlPattern ??= $pattern['htmlPattern'] ?? null; - $match ??= $pattern['match'] ?? null; - $normalizer ??= $pattern['normalizer'] ?? null; - $pattern = $pattern['pattern'] ?? null; - } - - static $ifSf4 = null; - - if ($ifSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $ifSf4 = (new \ReflectionClass(Regex::class))->getConstructor()->getNumberOfParameters() === 1; - } - - if (!is_string($pattern)) { - throw new InvalidArgumentException(sprintf('The "pattern" option of the regex constraint must be a string, "%s" given.', get_debug_type($pattern))); - } - - return $this->satisfy($ifSf4 - ? new Regex(['pattern' => $pattern, 'message' => $message, 'htmlPattern' => $htmlPattern, 'match' => $match, 'normalizer' => $normalizer]) - : new Regex($pattern, $message, $htmlPattern, $match, $normalizer) + return $this->satisfy( + new Regex( + pattern: $pattern, + message: $message, + htmlPattern: $htmlPattern, + match: $match, + normalizer: $normalizer, + ) ); } diff --git a/src/Phone/PhoneElementBuilder.php b/src/Phone/PhoneElementBuilder.php index ddf7792..3badba3 100644 --- a/src/Phone/PhoneElementBuilder.php +++ b/src/Phone/PhoneElementBuilder.php @@ -12,17 +12,7 @@ use Bdf\Form\Validator\ValueValidatorInterface; use libphonenumber\PhoneNumberUtil; use libphonenumber\RegionCode; -use ReflectionClass; use Symfony\Component\Validator\Constraint; -use TypeError; - -use function func_get_arg; -use function func_num_args; -use function is_array; -use function is_bool; -use function is_callable; -use function sprintf; -use function trigger_error; /** * Builder for a phone element @@ -85,48 +75,17 @@ public function __construct(?RegistryInterface $registry = null) * * @return $this */ - public function required($options = null/*, ?bool $allowNull = null, ?callable $normalizer = null*/) + public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null) { - // @todo rename $options to $message on bdf-form 2.0 - if (is_array($options)) { - @trigger_error('Passing an array of options to required() is deprecated since 1.7. Pass the options as individual parameters instead.', E_USER_DEPRECATED); - } - - // @todo declare allowNull and normalizer as actual parameters on bdf-form 2.0 - $allowNull = func_num_args() > 1 ? func_get_arg(1) : null; - $normalizer = func_num_args() > 2 ? func_get_arg(2) : null; - - if ($allowNull !== null && !is_bool($allowNull)) { - throw new TypeError(sprintf('The "allowNull" option of required() must be a boolean or null, "%s" given.', get_debug_type($allowNull))); - } - - if ($normalizer !== null && !is_callable($normalizer)) { - throw new TypeError(sprintf('The "normalizer" option of required() must be a valid callable or null, "%s" given.', get_debug_type($normalizer))); - } - - if (!$options instanceof Constraint) { - static $isSf4 = null; - - if ($isSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(NotEmptyPhoneNumber::class))->getConstructor()->getNumberOfParameters() === 1; - } - - if (is_array($options)) { - $message = $options['message'] ?? null; - $allowNull ??= $options['allowNull'] ?? null; - $normalizer ??= $options['normalizer'] ?? null; - } else { - $message = $options; - } - - $options = $isSf4 - ? new NotEmptyPhoneNumber(['message' => $message, 'allowNull' => $allowNull, 'normalizer' => $normalizer]) - : new NotEmptyPhoneNumber(null, $message, $allowNull, $normalizer) // The constructor is consistent from sf 5 to 8, so we can safely use ordered parameters. - ; + if (!$message instanceof Constraint) { + $message = new NotEmptyPhoneNumber( + message: $message, + allowNull: $allowNull, + normalizer: $normalizer, + ); } - return $this->satisfy($options); + return $this->satisfy($message); } /** @@ -232,19 +191,13 @@ public function allowInvalidNumber(bool $allowInvalidNumber = true): self * $builder->validateNumber(['message' => 'My error']); // Also accept array of options * * - * @param array|string|null $message The error message or options for the ValidPhoneNumber constraint if the phone number is invalid + * @param string|null $message The error message if the phone number is invalid * * @return $this * @see ValidPhoneNumber */ - public function validateNumber($message = null): self + public function validateNumber(?string $message = null): self { - if (is_array($message)) { - @trigger_error(sprintf('Passing an array of options on %s is deprecated since 1.7 and will be removed on 2.0, use named arguments instead.', __METHOD__), E_USER_DEPRECATED); - - $message = $message['message'] ?? null; - } - $this->allowInvalidNumber = false; $this->invalidPhoneErrorMessage = $message; diff --git a/src/Phone/ValidPhoneNumber.php b/src/Phone/ValidPhoneNumber.php index f18f3cd..403bc51 100644 --- a/src/Phone/ValidPhoneNumber.php +++ b/src/Phone/ValidPhoneNumber.php @@ -4,10 +4,6 @@ use Symfony\Component\Validator\Constraint; -use function is_array; -use function sprintf; -use function trigger_error; - /** * Check if the phone number is valid */ @@ -16,7 +12,6 @@ class ValidPhoneNumber extends Constraint const INVALID_PHONE_NUMBER_ERROR = '5169f03c-ec96-4e62-8651-9ee6766e0b5a'; protected const ERROR_NAMES = [self::INVALID_PHONE_NUMBER_ERROR => 'INVALID_PHONE_NUMBER_ERROR']; - protected static $errorNames = self::ERROR_NAMES; /** * The error message @@ -25,16 +20,9 @@ class ValidPhoneNumber extends Constraint */ public $message = 'The phone number is not valid.'; - public function __construct($message = null) + public function __construct(?string $message = null) { - if (is_array($message)) { - @trigger_error(sprintf('Passing an array of options to the "%s" constraint is deprecated since version 1.7 and support for it will be removed in 2.0. Use named arguments instead.', __CLASS__), E_USER_DEPRECATED); - - $options = $message; - $message = $options['message'] ?? null; - } - - parent::__construct($options ?? null); + parent::__construct(); $this->message = $message ?? $this->message; } diff --git a/src/Registry/Registry.php b/src/Registry/Registry.php index 4b68f6e..fe4e94c 100755 --- a/src/Registry/Registry.php +++ b/src/Registry/Registry.php @@ -11,14 +11,11 @@ use Bdf\Form\Button\SubmitButtonBuilder; use Bdf\Form\Child\ChildBuilder; use Bdf\Form\Child\ChildBuilderInterface; -use Bdf\Form\Constraint\Closure; use Bdf\Form\Csrf\CsrfElement; use Bdf\Form\Csrf\CsrfElementBuilder; use Bdf\Form\Custom\CustomForm; use Bdf\Form\Custom\CustomFormBuilder; use Bdf\Form\ElementBuilderInterface; -use Bdf\Form\Filter\ClosureFilter; -use Bdf\Form\Filter\FilterInterface; use Bdf\Form\Leaf\AnyElement; use Bdf\Form\Leaf\AnyElementBuilder; use Bdf\Form\Leaf\BooleanElement; @@ -39,15 +36,7 @@ use Bdf\Form\Phone\PhoneChildBuilder; use Bdf\Form\Phone\PhoneElement; use Bdf\Form\Phone\PhoneElementBuilder; -use Bdf\Form\Transformer\ClosureTransformer; -use Bdf\Form\Transformer\DataTransformerAdapter; -use Bdf\Form\Transformer\TransformerInterface; use InvalidArgumentException; -use LogicException; -use Symfony\Component\Form\DataTransformerInterface; -use Symfony\Component\Validator\Constraint; - -use function trigger_error; /** * Base registry interface @@ -96,79 +85,6 @@ public function __construct() }); } - /** - * {@inheritdoc} - */ - public function filter($filter): FilterInterface - { - if ($filter instanceof FilterInterface) { - return $filter; - } - - @trigger_error('Using the registry to create filters is deprecated since 1.7. Instantiate the filter directly instead of using the registry.', E_USER_DEPRECATED); - - if (is_callable($filter)) { - return new ClosureFilter($filter); - } - - // @todo container ? - /** @var class-string $filter */ - return new $filter(); - } - - /** - * {@inheritdoc} - */ - public function constraint($constraint): Constraint - { - if ($constraint instanceof Constraint) { - return $constraint; - } - - @trigger_error('Using the registry to create constraints is deprecated since 1.7. Instantiate the constraint directly instead of using the registry.', E_USER_DEPRECATED); - - if (is_callable($constraint)) { - return new Closure(['callback' => $constraint]); - } - - if (is_array($constraint)) { - $options = $constraint[1]; - $constraint = $constraint[0]; - - if (is_string($options)) { - $options = ['message' => $options]; - } - - /** @var class-string $constraint */ - return new $constraint($options); - } - - /** @var class-string $constraint */ - return new $constraint(); - } - - /** - * {@inheritdoc} - */ - public function transformer($transformer): TransformerInterface - { - if ($transformer instanceof TransformerInterface) { - return $transformer; - } - - @trigger_error('Using the registry to create transformers is deprecated since 1.7. Instantiate the transformer directly instead of using the registry.', E_USER_DEPRECATED); - - if ($transformer instanceof DataTransformerInterface) { - return new DataTransformerAdapter($transformer); - } - - if (is_callable($transformer)) { - return new ClosureTransformer($transformer); - } - - throw new LogicException('Invalid view transformer given for input '.var_export($transformer, true)); - } - /** * {@inheritdoc} */ diff --git a/src/Util/DelegateElementBuilderTrait.php b/src/Util/DelegateElementBuilderTrait.php index f738d07..a1cb44b 100644 --- a/src/Util/DelegateElementBuilderTrait.php +++ b/src/Util/DelegateElementBuilderTrait.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Util; use Bdf\Form\ElementInterface; +use Bdf\Form\Transformer\TransformerInterface; /** * Simple implementation of delegated element builder @@ -26,7 +27,7 @@ final public function satisfy($constraint, $options = null, bool $append = true) /** * {@inheritdoc} */ - final public function transformer($transformer, bool $append = true) + final public function transformer(callable|TransformerInterface $transformer, bool $append = true) { $this->getElementBuilder()->transformer($transformer, $append); diff --git a/src/Util/TransformerBuilderTrait.php b/src/Util/TransformerBuilderTrait.php index 3669f2b..66386da 100644 --- a/src/Util/TransformerBuilderTrait.php +++ b/src/Util/TransformerBuilderTrait.php @@ -9,8 +9,8 @@ use Bdf\Form\Transformer\TransformerAggregate; use Bdf\Form\Transformer\TransformerInterface; +use function count; use function is_callable; -use function trigger_error; /** * Trait for implements builder of transformer @@ -18,7 +18,7 @@ trait TransformerBuilderTrait { /** - * @var array + * @var array */ private $transformers = []; @@ -32,16 +32,12 @@ trait TransformerBuilderTrait * * @see ElementBuilderInterface::transformer() */ - final public function transformer($transformer, bool $append = true) + final public function transformer(callable|TransformerInterface $transformer, bool $append = true) { if (is_callable($transformer)) { $transformer = new ClosureTransformer($transformer); } - if (!$transformer instanceof TransformerInterface) { - @trigger_error('Passing a non transformer to transformer() is deprecated since 1.7. Pass a transformer instance, or a callback, instead of a class name.', E_USER_DEPRECATED); - } - if ($append === true) { $this->transformers[] = $transformer; } else { @@ -91,24 +87,19 @@ private function buildTransformer(): TransformerInterface $providedTransformers = []; foreach ($this->transformerProviders as $provider) { - $providedTransformers = array_merge($providedTransformers, $provider($this->registry())); + $providedTransformers = [...$providedTransformers, ...$provider($this->registry())]; } - $transformers = array_map([$this->registry(), 'transformer'], $this->transformers); + $transformers = $this->transformers; if (!empty($providedTransformers)) { - $transformers = array_merge($providedTransformers, $transformers); + $transformers = [...$providedTransformers, ...$transformers]; } - switch (count($transformers)) { - case 0: - return NullTransformer::instance(); - - case 1: - return $transformers[0]; - - default: - return new TransformerAggregate($transformers); - } + return match (count($transformers)) { + 0 => NullTransformer::instance(), + 1 => $transformers[0], + default => new TransformerAggregate($transformers), + }; } } diff --git a/src/Util/ValidatorBuilderTrait.php b/src/Util/ValidatorBuilderTrait.php index 916f705..6c0c89f 100644 --- a/src/Util/ValidatorBuilderTrait.php +++ b/src/Util/ValidatorBuilderTrait.php @@ -8,17 +8,10 @@ use Bdf\Form\Validator\ConstraintValueValidator; use Bdf\Form\Validator\TransformerExceptionConstraint; use Bdf\Form\Validator\ValueValidatorInterface; -use ReflectionClass; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\NotBlank; -use TypeError; -use function get_debug_type; -use function is_array; -use function is_bool; use function is_callable; -use function sprintf; -use function trigger_error; /** * Trait for implements build of constraint validator @@ -28,7 +21,7 @@ trait ValidatorBuilderTrait { /** - * @var array + * @var array */ private $constraints = []; @@ -56,7 +49,7 @@ trait ValidatorBuilderTrait * $builder->required(['allowNull' => true]); // With custom options * * - * @param array|string|null $options The constraint option. Is a string is given, it will be used as error message + * @param string|Constraint|null $message The error message. A custom constraint can be passed. * @param bool|null $allowNull Allow null value (default false). * @param callable|null $normalizer A normalizer callback to apply on the value before validation. * @@ -64,48 +57,13 @@ trait ValidatorBuilderTrait * * @see NotBlank The used constraint */ - public function required($options = null/*, ?bool $allowNull = null, ?callable $normalizer = null*/) + public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null) { - // @todo rename $options to $message on bdf-form 2.0 - if (is_array($options)) { - @trigger_error('Passing an array of options to required() is deprecated since 1.7. Pass the options as individual parameters instead.', E_USER_DEPRECATED); + if (!$message instanceof Constraint) { + $message = new NotBlank(message: $message, allowNull: $allowNull, normalizer: $normalizer); } - // @todo declare allowNull and normalizer as actual parameters on bdf-form 2.0 - $allowNull = func_num_args() > 1 ? func_get_arg(1) : null; - $normalizer = func_num_args() > 2 ? func_get_arg(2) : null; - - if ($allowNull !== null && !is_bool($allowNull)) { - throw new TypeError(sprintf('The "allowNull" option of required() must be a boolean or null, "%s" given.', get_debug_type($allowNull))); - } - - if ($normalizer !== null && !is_callable($normalizer)) { - throw new TypeError(sprintf('The "normalizer" option of required() must be a valid callable or null, "%s" given.', get_debug_type($normalizer))); - } - - if (!$options instanceof Constraint) { - static $isSf4 = null; - - if ($isSf4 === null) { - /** @psalm-suppress PossiblyNullReference */ - $isSf4 = (new ReflectionClass(NotBlank::class))->getConstructor()->getNumberOfParameters() === 1; - } - - if (is_array($options)) { - $message = $options['message'] ?? null; - $allowNull ??= $options['allowNull'] ?? null; - $normalizer ??= $options['normalizer'] ?? null; - } else { - $message = $options; - } - - $options = $isSf4 - ? new NotBlank(['message' => $message, 'allowNull' => $allowNull, 'normalizer' => $normalizer]) - : new NotBlank(null, $message, $allowNull, $normalizer) // The constructor is consistent from sf 5 to 8, so we can safely use ordered parameters. - ; - } - - return $this->satisfy($options); + return $this->satisfy($message); } /** @@ -113,19 +71,10 @@ public function required($options = null/*, ?bool $allowNull = null, ?callable $ * * @see ElementBuilderInterface::satisfy() */ - final public function satisfy($constraint, $options = null, bool $append = true) + final public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) { - // @todo rename $options to $message in bdf-form 2.0 if (is_callable($constraint)) { - $constraint = new Closure($constraint, $options); - } - - if (!$constraint instanceof Constraint) { - @trigger_error('Passing a non constraint to satisfy() is deprecated since 1.7. Pass a constraint instance, or a callback, instead of a class name.', E_USER_DEPRECATED); - } - - if ($options !== null) { - $constraint = [$constraint, $options]; + $constraint = new Closure($constraint, $message); } if ($append === true) { @@ -263,13 +212,7 @@ private function getTransformerExceptionConstraint(): TransformerExceptionConstr */ protected function defaultTransformerExceptionConstraint(): TransformerExceptionConstraint { - return new TransformerExceptionConstraint( - $options['exception'] ?? null, - $options['message'] ?? null, - $options['code'] ?? null, - $options['validationCallback'] ?? null, - $options['ignoreException'] ?? null, - ); + return new TransformerExceptionConstraint(); } /** @@ -290,12 +233,10 @@ private function buildValidator(): ValueValidatorInterface $constraints = []; foreach ($this->constraintsProviders as $provider) { - $constraints = array_merge($constraints, $provider($registry)); + $constraints = [...$constraints, ...$provider($registry)]; } - foreach ($this->constraints as $constraint) { - $constraints[] = $registry->constraint($constraint); - } + $constraints = [...$constraints, ...$this->constraints]; return new ConstraintValueValidator($constraints, $this->getTransformerExceptionConstraint()); } diff --git a/src/Validator/TransformerExceptionConstraint.php b/src/Validator/TransformerExceptionConstraint.php index f0a4cdf..c0220e0 100644 --- a/src/Validator/TransformerExceptionConstraint.php +++ b/src/Validator/TransformerExceptionConstraint.php @@ -5,10 +5,6 @@ use Exception; use Symfony\Component\Validator\Constraint; -use function is_array; -use function sprintf; -use function trigger_error; - /** * @internal */ @@ -17,7 +13,6 @@ final class TransformerExceptionConstraint extends Constraint const TRANSFORM_ERROR = 'b5acab45-80b0-4808-8784-6577e37ac869'; protected const ERROR_NAMES = [self::TRANSFORM_ERROR => 'TRANSFORM_ERROR']; - protected static $errorNames = self::ERROR_NAMES; /** * The error message. If null, the exception's message will be taken @@ -36,7 +31,7 @@ final class TransformerExceptionConstraint extends Constraint /** * The transformer exception * - * @var Exception + * @var Exception|null */ public $exception; @@ -58,15 +53,9 @@ final class TransformerExceptionConstraint extends Constraint */ public $ignoreException = false; - public function __construct($exception = null, ?string $message = null, ?string $code = null, ?callable $validationCallback = null, ?bool $ignoreException = null) + public function __construct(?Exception $exception = null, ?string $message = null, ?string $code = null, ?callable $validationCallback = null, ?bool $ignoreException = null) { - if (is_array($exception)) { - @trigger_error(sprintf('Passing an array of options to %s is deprecated since 1.7 and will not be supported in 2.0. Use named parameters instead.', __METHOD__), E_USER_DEPRECATED); - - $options = $exception; - } - - parent::__construct($options ?? null); + parent::__construct(); $this->exception = $exception ?? $this->exception; $this->message = $message ?? $this->message; diff --git a/src/View/ConstraintsNormalizer.php b/src/View/ConstraintsNormalizer.php index 455555c..53b4b53 100644 --- a/src/View/ConstraintsNormalizer.php +++ b/src/View/ConstraintsNormalizer.php @@ -73,12 +73,9 @@ private static function getDefaultOption(Constraint $constraint): ?array assert($ctor !== null); $firstParam = $ctor->getParameters()[0] ?? null; - $firstParamName = $firstParam ? $firstParam->getName() : null; + $firstParamName = $firstParam?->getName(); - // Sf < 5.3 - if ($ctor->getNumberOfParameters() === 1 && $firstParamName === 'options') { - $option = $constraint->getDefaultOption(); - } elseif ($firstParamName !== 'options') { + if ($firstParamName !== 'options' && $firstParamName !== 'message') { $option = $firstParamName; } else { return null; diff --git a/tests/Aggregate/ArrayElementBuilderTest.php b/tests/Aggregate/ArrayElementBuilderTest.php index 51b7b98..73b3d9b 100644 --- a/tests/Aggregate/ArrayElementBuilderTest.php +++ b/tests/Aggregate/ArrayElementBuilderTest.php @@ -57,7 +57,7 @@ public function test_defaults() */ public function test_calling_undefined_method_should_be_forwarded_to_inner_element_builder() { - $element = $this->builder->length(['min' => 2])->buildElement(); + $element = $this->builder->length(min: 2)->buildElement(); $this->assertFalse($element->submit(['a', 'bb'])->valid()); $this->assertEquals(['This value is too short. It should have 2 characters or more.'], $element->error()->toArray()); @@ -214,17 +214,6 @@ public function test_arrayTransformer() $this->assertSame(['bar' => 'foo'], $element->submit(['foo' => 'bar'])->value()); } - /** - * - */ - public function test_count_legacy() - { - $element = $this->builder->count(['min' => 3])->buildElement(); - - $this->assertFalse($element->submit(['foo', 'bar'])->valid()); - $this->assertTrue($element->submit(['foo', 'bar', 'baz'])->valid()); - } - /** * */ diff --git a/tests/Aggregate/ArrayElementTest.php b/tests/Aggregate/ArrayElementTest.php index 0f45ea8..03f6b4c 100644 --- a/tests/Aggregate/ArrayElementTest.php +++ b/tests/Aggregate/ArrayElementTest.php @@ -154,7 +154,7 @@ public function test_submit_with_transformer_error_ignored() $element = new ArrayElement( new StringElement(), new ClosureTransformer(function () { throw new Exception('My error'); }), - new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])) + new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)) ); $this->assertTrue($element->submit(['foo', 'bar'])->valid()); @@ -169,7 +169,7 @@ public function test_submit_with_transformer_error_ignored_should_apply_other_co $element = new ArrayElement( new StringElement(), new ClosureTransformer(function () { throw new Exception('My error'); }), - new ConstraintValueValidator([new Closure(function () {return 'error';})], new TransformerExceptionConstraint(['ignoreException' => true])) + new ConstraintValueValidator([new Closure(function () {return 'error';})], new TransformerExceptionConstraint(ignoreException: true)) ); $this->assertFalse($element->submit(['foo', 'bar'])->valid()); diff --git a/tests/Aggregate/FormTest.php b/tests/Aggregate/FormTest.php index 7398a7d..4fef6b7 100644 --- a/tests/Aggregate/FormTest.php +++ b/tests/Aggregate/FormTest.php @@ -218,7 +218,7 @@ public function test_submit_with_transformer_exception_ignored() $this->registry->childBuilder(StringElement::class, 'firstName')->getter()->length(null, /*min:*/ 2)->buildChild(), $this->registry->childBuilder(StringElement::class, 'lastName')->getter()->length(null, /*min:*/ 2)->buildChild(), $this->registry->childBuilder(IntegerElement::class, 'id')->getter()->buildChild(), - ]), new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])), new ClosureTransformer(function () { throw new \Exception('my error'); })); + ]), new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)), new ClosureTransformer(function () { throw new \Exception('my error'); })); $form->import([ 'firstName' => 'John', @@ -244,7 +244,7 @@ public function test_submit_with_transformer_exception_ignored_should_validate_o $this->registry->childBuilder(StringElement::class, 'firstName')->getter()->required()->length(null, /*min:*/ 2)->buildChild(), $this->registry->childBuilder(StringElement::class, 'lastName')->getter()->required()->length(null, /*min:*/ 2)->buildChild(), $this->registry->childBuilder(IntegerElement::class, 'id')->getter()->required()->buildChild(), - ]), new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])), new ClosureTransformer(function () { throw new \Exception('my error'); })); + ]), new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)), new ClosureTransformer(function () { throw new \Exception('my error'); })); $form->import([ 'firstName' => 'John', diff --git a/tests/Csrf/CsrfElementBuilderTest.php b/tests/Csrf/CsrfElementBuilderTest.php index e121b37..f0000ca 100644 --- a/tests/Csrf/CsrfElementBuilderTest.php +++ b/tests/Csrf/CsrfElementBuilderTest.php @@ -2,6 +2,7 @@ namespace Bdf\Form\Csrf; +use Bdf\Form\Transformer\TransformerInterface; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; @@ -11,6 +12,7 @@ use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage; use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface; +use Symfony\Component\Validator\Constraints\NotBlank; /** * Class CsrfElementBuilderTest @@ -104,7 +106,7 @@ public function test_tokenManager() public function test_satisfy() { $this->expectException(\BadMethodCallException::class); - $this->builder->satisfy(null); + $this->builder->satisfy(new NotBlank()); } /** @@ -113,7 +115,7 @@ public function test_satisfy() public function test_transformer() { $this->expectException(\BadMethodCallException::class); - $this->builder->transformer(null); + $this->builder->transformer($this->createMock(TransformerInterface::class)); } /** diff --git a/tests/CyclicReferenceTest.php b/tests/CyclicReferenceTest.php index 17b42e6..04b172e 100644 --- a/tests/CyclicReferenceTest.php +++ b/tests/CyclicReferenceTest.php @@ -132,7 +132,7 @@ protected function configure(FormBuilderInterface $builder): void $builder ->string('foo') - ->length(['min' => 3]) + ->length(min: 3) ->setter()->getter() ; diff --git a/tests/Error/ImplodeErrorPrinterTest.php b/tests/Error/ImplodeErrorPrinterTest.php index 510179c..c013c93 100644 --- a/tests/Error/ImplodeErrorPrinterTest.php +++ b/tests/Error/ImplodeErrorPrinterTest.php @@ -31,7 +31,7 @@ public function test_functional_with_children_error() $builder->string('foo')->required(); $builder->integer('bar')->min(5); $builder->embedded('embedded', function ($builder) { - $builder->string('inner')->length(['min' => 5]); + $builder->string('inner')->length(min: 5); }); $element = $builder->buildElement(); @@ -51,7 +51,7 @@ public function test_functional_with_custom_separator() $builder->string('foo')->required(); $builder->integer('bar')->min(5); $builder->embedded('embedded', function ($builder) { - $builder->string('inner')->length(['min' => 5]); + $builder->string('inner')->length(min: 5); }); $element = $builder->buildElement(); diff --git a/tests/Error/StringErrorPrinterTest.php b/tests/Error/StringErrorPrinterTest.php index bfe9b86..c57a272 100644 --- a/tests/Error/StringErrorPrinterTest.php +++ b/tests/Error/StringErrorPrinterTest.php @@ -31,7 +31,7 @@ public function test_functional_with_children_error() $builder->string('foo')->required(); $builder->integer('bar')->min(5); $builder->embedded('embedded', function ($builder) { - $builder->string('inner')->length(['min' => 5]); + $builder->string('inner')->length(min: 5); }); $element = $builder->buildElement(); @@ -57,7 +57,7 @@ public function test_functional_lineSeparator() $builder->string('foo')->required(); $builder->integer('bar')->min(5); $builder->embedded('embedded', function ($builder) { - $builder->string('inner')->length(['min' => 5]); + $builder->string('inner')->length(min: 5); }); $element = $builder->buildElement(); @@ -80,7 +80,7 @@ public function test_functional_indentString() $builder->string('foo')->required(); $builder->integer('bar')->min(5); $builder->embedded('embedded', function ($builder) { - $builder->string('inner')->length(['min' => 5]); + $builder->string('inner')->length(min: 5); }); $element = $builder->buildElement(); @@ -106,7 +106,7 @@ public function test_functional_nameSeparator() $builder->string('foo')->required(); $builder->integer('bar')->min(5); $builder->embedded('embedded', function ($builder) { - $builder->string('inner')->length(['min' => 5]); + $builder->string('inner')->length(min: 5); }); $element = $builder->buildElement(); @@ -132,7 +132,7 @@ public function test_functional_maxDepth() $builder->string('foo')->required(); $builder->integer('bar')->min(5); $builder->embedded('embedded', function ($builder) { - $builder->string('inner')->length(['min' => 5]); + $builder->string('inner')->length(min: 5); }); $element = $builder->buildElement(); diff --git a/tests/Filter/FilterVarTest.php b/tests/Filter/FilterVarTest.php index ebb0265..e1ad44c 100644 --- a/tests/Filter/FilterVarTest.php +++ b/tests/Filter/FilterVarTest.php @@ -61,7 +61,7 @@ public function test_filter_array() public function test_functionnal() { $builder = new FormBuilder(); - $builder->string('foo')->filter(FilterVar::class); + $builder->string('foo')->filter(new FilterVar()); $form = $builder->buildElement(); $form->submit(['foo' => '"Test"']); diff --git a/tests/Leaf/AnyElementBuilderTest.php b/tests/Leaf/AnyElementBuilderTest.php index 666a4ce..00713f6 100644 --- a/tests/Leaf/AnyElementBuilderTest.php +++ b/tests/Leaf/AnyElementBuilderTest.php @@ -62,17 +62,6 @@ public function test_satisfy_order() $this->assertEquals('error 3', $element->error()->global()); } - /** - * - */ - public function test_satisfy_with_className_and_options() - { - $element = $this->builder->satisfy(NotEqualTo::class, ['value' => 'hello'])->buildElement(); - - $this->assertFalse($element->submit('hello')->valid()); - $this->assertTrue($element->submit('world')->valid()); - } - /** * */ diff --git a/tests/Leaf/AnyElementTest.php b/tests/Leaf/AnyElementTest.php index 515c9f9..6ba9ee7 100644 --- a/tests/Leaf/AnyElementTest.php +++ b/tests/Leaf/AnyElementTest.php @@ -101,7 +101,7 @@ public function test_submit_with_transformer_exception_ignored() $transformer = $this->createMock(TransformerInterface::class); $transformer->expects($this->once())->method('transformFromHttp')->willThrowException(new TransformationFailedException('my error')); $element = new AnyElement( - new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])), + new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)), $transformer ); @@ -120,7 +120,7 @@ public function test_submit_with_transformer_exception_ignored_should_validate_o $element = new AnyElement( new ConstraintValueValidator( [new Closure(function () { return 'validation error'; })], - new TransformerExceptionConstraint(['ignoreException' => true]) + new TransformerExceptionConstraint(ignoreException: true) ), $transformer ); diff --git a/tests/Leaf/BooleanElementTest.php b/tests/Leaf/BooleanElementTest.php index b7c45c5..56394cb 100644 --- a/tests/Leaf/BooleanElementTest.php +++ b/tests/Leaf/BooleanElementTest.php @@ -99,7 +99,7 @@ public function test_submit_with_transformer_exception_ignored() $transformer = $this->createMock(TransformerInterface::class); $transformer->expects($this->once())->method('transformFromHttp')->willThrowException(new TransformationFailedException('my error')); $element = new BooleanElement( - new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])), + new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)), $transformer ); @@ -117,7 +117,7 @@ public function test_submit_with_transformer_exception_ignored_should_validate_o $element = new BooleanElement( new ConstraintValueValidator( [new Closure(function () { return 'validation error'; })], - new TransformerExceptionConstraint(['ignoreException' => true]) + new TransformerExceptionConstraint(ignoreException: true) ), $transformer ); diff --git a/tests/Leaf/BooleanStringElementTest.php b/tests/Leaf/BooleanStringElementTest.php index 8617663..7b3409a 100644 --- a/tests/Leaf/BooleanStringElementTest.php +++ b/tests/Leaf/BooleanStringElementTest.php @@ -145,7 +145,7 @@ public function test_submit_with_transformer_exception_ignored() $transformer = $this->createMock(TransformerInterface::class); $transformer->expects($this->once())->method('transformFromHttp')->willThrowException(new TransformationFailedException('my error')); $element = new BooleanStringElement( - new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])), + new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)), $transformer ); @@ -163,7 +163,7 @@ public function test_submit_with_transformer_exception_ignored_should_validate_o $element = new BooleanStringElement( new ConstraintValueValidator( [new Closure(function () { return 'validation error'; })], - new TransformerExceptionConstraint(['ignoreException' => true]) + new TransformerExceptionConstraint(ignoreException: true) ), $transformer ); diff --git a/tests/Leaf/Date/DateTimeElementTest.php b/tests/Leaf/Date/DateTimeElementTest.php index aa5920e..230cc99 100644 --- a/tests/Leaf/Date/DateTimeElementTest.php +++ b/tests/Leaf/Date/DateTimeElementTest.php @@ -178,7 +178,7 @@ public function test_submit_with_transformer_exception_ignored_should_validate_o $element = new DateTimeElement( new ConstraintValueValidator( [new Closure(function () { return 'validation error'; })], - new TransformerExceptionConstraint(['ignoreException' => true]) + new TransformerExceptionConstraint(ignoreException: true) ), $transformer ); diff --git a/tests/Leaf/FloatElementTest.php b/tests/Leaf/FloatElementTest.php index 7a0e3f9..57166cc 100644 --- a/tests/Leaf/FloatElementTest.php +++ b/tests/Leaf/FloatElementTest.php @@ -102,7 +102,7 @@ public function test_submit_with_transformer_exception_ignored() $transformer = $this->createMock(TransformerInterface::class); $transformer->expects($this->once())->method('transformFromHttp')->willThrowException(new TransformationFailedException('my error')); $element = new FloatElement( - new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])), + new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)), $transformer ); @@ -120,7 +120,7 @@ public function test_submit_with_transformer_exception_ignored_should_validate_o $element = new FloatElement( new ConstraintValueValidator( [new Closure(function () { return 'validation error'; })], - new TransformerExceptionConstraint(['ignoreException' => true]) + new TransformerExceptionConstraint(ignoreException: true) ), $transformer ); diff --git a/tests/Leaf/Helper/EmailElementBuilderTest.php b/tests/Leaf/Helper/EmailElementBuilderTest.php index 084c890..26e3aa8 100644 --- a/tests/Leaf/Helper/EmailElementBuilderTest.php +++ b/tests/Leaf/Helper/EmailElementBuilderTest.php @@ -85,23 +85,6 @@ public function test_disableConstraint() $this->assertTrue($element->submit('foo')->valid()); } - /** - * - */ - public function test_useConstraint_legacy() - { - $element = $this->builder - ->disableConstraint() - ->useConstraint(['message' => 'my error']) - ->buildElement() - ; - - $this->assertInstanceOf(EmailElement::class, $element); - - $this->assertFalse($element->submit('foo')->valid()); - $this->assertEquals('my error', $element->error()->global()); - } - /** * */ diff --git a/tests/Leaf/Helper/UrlElementBuilderTest.php b/tests/Leaf/Helper/UrlElementBuilderTest.php index d65a247..d0d4d58 100644 --- a/tests/Leaf/Helper/UrlElementBuilderTest.php +++ b/tests/Leaf/Helper/UrlElementBuilderTest.php @@ -103,7 +103,7 @@ public function test_useConstraint_legacy() { $element = $this->builder ->disableConstraint() - ->useConstraint(['message' => 'my error']) + ->useConstraint(message: 'my error') ->buildElement() ; diff --git a/tests/Leaf/IntegerElementTest.php b/tests/Leaf/IntegerElementTest.php index e59773b..9509a2d 100644 --- a/tests/Leaf/IntegerElementTest.php +++ b/tests/Leaf/IntegerElementTest.php @@ -102,7 +102,7 @@ public function test_submit_with_transformer_exception_ignored() $transformer = $this->createMock(TransformerInterface::class); $transformer->expects($this->once())->method('transformFromHttp')->willThrowException(new TransformationFailedException('my error')); $element = new IntegerElement( - new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])), + new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)), $transformer ); @@ -120,7 +120,7 @@ public function test_submit_with_transformer_exception_ignored_should_validate_o $element = new IntegerElement( new ConstraintValueValidator( [new Closure(function () { return 'validation error'; })], - new TransformerExceptionConstraint(['ignoreException' => true]) + new TransformerExceptionConstraint(ignoreException: true) ), $transformer ); diff --git a/tests/Leaf/StringElementBuilderTest.php b/tests/Leaf/StringElementBuilderTest.php index 312af14..8463906 100644 --- a/tests/Leaf/StringElementBuilderTest.php +++ b/tests/Leaf/StringElementBuilderTest.php @@ -62,17 +62,6 @@ public function test_satisfy_order() $this->assertEquals('error 3', $element->error()->global()); } - /** - * - */ - public function test_satisfy_with_className_and_options() - { - $element = $this->builder->satisfy(NotEqualTo::class, ['value' => 'hello'])->buildElement(); - - $this->assertFalse($element->submit('hello')->valid()); - $this->assertTrue($element->submit('world')->valid()); - } - /** * */ @@ -111,17 +100,6 @@ public function test_value() $this->assertSame('default', $element->value()); } - /** - * - */ - public function test_length_legacy() - { - $element = $this->builder->length(['max' => 3])->buildElement(); - - $this->assertFalse($element->submit('aaaa')->valid()); - $this->assertTrue($element->submit('aaa')->valid()); - } - /** * */ diff --git a/tests/Leaf/StringElementTest.php b/tests/Leaf/StringElementTest.php index f48028f..051e767 100644 --- a/tests/Leaf/StringElementTest.php +++ b/tests/Leaf/StringElementTest.php @@ -100,7 +100,7 @@ public function test_submit_with_transformer_exception_ignored() $transformer = $this->createMock(TransformerInterface::class); $transformer->expects($this->once())->method('transformFromHttp')->willThrowException(new TransformationFailedException('my error')); $element = new StringElement( - new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])), + new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)), $transformer ); @@ -118,7 +118,7 @@ public function test_submit_with_transformer_exception_ignored_should_validate_o $element = new StringElement( new ConstraintValueValidator( [new Closure(function () { return 'validation error'; })], - new TransformerExceptionConstraint(['ignoreException' => true]) + new TransformerExceptionConstraint(ignoreException: true) ), $transformer ); diff --git a/tests/Registry/RegistryTest.php b/tests/Registry/RegistryTest.php index e736581..2715219 100644 --- a/tests/Registry/RegistryTest.php +++ b/tests/Registry/RegistryTest.php @@ -68,104 +68,6 @@ protected function setUp(): void $this->registry = new Registry(); } - /** - * - */ - public function test_filter_with_instance_of_filter() - { - $filter = new TrimFilter(); - - $this->assertSame($filter, $this->registry->filter($filter)); - } - - /** - * - */ - public function test_filter_with_classname() - { - $this->assertInstanceOf(TrimFilter::class, $this->registry->filter(TrimFilter::class)); - } - - /** - * - */ - public function test_filter_with_callback() - { - $this->assertInstanceOf(ClosureFilter::class, $this->registry->filter(function () {})); - } - - /** - * - */ - public function test_constraint_with_constraint_instance() - { - $constraint = new NotBlank(); - - $this->assertSame($constraint, $this->registry->constraint($constraint)); - } - - /** - * - */ - public function test_constraint_with_classname() - { - $this->assertInstanceOf(NotBlank::class, $this->registry->constraint(NotBlank::class)); - } - - /** - * - */ - public function test_constraint_with_classname_and_options() - { - $this->assertEquals(new NotBlank(['message' => 'error']), $this->registry->constraint([NotBlank::class, 'error'])); - $this->assertEquals(new NotBlank(['message' => 'error']), $this->registry->constraint([NotBlank::class, ['message' => 'error']])); - } - - /** - * - */ - public function test_constraint_with_callback() - { - $this->assertInstanceOf(Closure::class, $this->registry->constraint(function () {})); - } - - /** - * - */ - public function test_transformer_with_instance() - { - $transformer = new TransformerAggregate([]); - - $this->assertSame($transformer, $this->registry->transformer($transformer)); - } - - /** - * - */ - public function test_transformer_with_symfony_DataTransformer() - { - $this->assertInstanceOf(DataTransformerAdapter::class, $this->registry->transformer(new IntegerToLocalizedStringTransformer())); - } - - /** - * - */ - public function test_transformer_with_callable() - { - $this->assertInstanceOf(ClosureTransformer::class, $this->registry->transformer(function () {})); - } - - /** - * - */ - public function test_transformer_invalid() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Invalid view transformer given for input \'foo\''); - - $this->registry->transformer('foo'); - } - /** * */ diff --git a/tests/Util/ValidatorBuilderTraitTest.php b/tests/Util/ValidatorBuilderTraitTest.php index d072076..3bc3005 100644 --- a/tests/Util/ValidatorBuilderTraitTest.php +++ b/tests/Util/ValidatorBuilderTraitTest.php @@ -57,17 +57,6 @@ public function test_satisfy_order() $this->assertEquals('error 3', $element->error()->global()); } - /** - * - */ - public function test_satisfy_with_className_and_options() - { - $element = $this->builder->satisfy(NotEqualTo::class, ['value' => 'hello'])->buildElement(); - - $this->assertFalse($element->submit('hello')->valid()); - $this->assertTrue($element->submit('world')->valid()); - } - /** * */ diff --git a/tests/Validator/ConstraintValueValidatorTest.php b/tests/Validator/ConstraintValueValidatorTest.php index dfdf142..cc13a96 100644 --- a/tests/Validator/ConstraintValueValidatorTest.php +++ b/tests/Validator/ConstraintValueValidatorTest.php @@ -105,7 +105,7 @@ public function test_onTransformerException() public function test_onTransformerException_ignoreException() { $element = new StringElement(); - $validator = new ConstraintValueValidator([], new TransformerExceptionConstraint(['ignoreException' => true])); + $validator = new ConstraintValueValidator([], new TransformerExceptionConstraint(ignoreException: true)); $error = $validator->onTransformerException(new \Exception('my error'), 'foo', $element); @@ -118,7 +118,7 @@ public function test_onTransformerException_ignoreException() public function test_onTransformerException_custom_message_and_code() { $element = new StringElement(); - $validator = new ConstraintValueValidator([], new TransformerExceptionConstraint(['message' => 'message', 'code' => 'CODE_ERROR'])); + $validator = new ConstraintValueValidator([], new TransformerExceptionConstraint(message: 'message', code: 'CODE_ERROR')); $error = $validator->onTransformerException(new \Exception('my error'), 'foo', $element); From cf4ce463fbfaf68f25f5964f3218a22a27cc79fb Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Tue, 10 Mar 2026 11:49:39 +0100 Subject: [PATCH 04/12] chore: Add Override attributes + fix psalm errors (#FRAM-221) --- src/AbstractElementBuilder.php | 13 +- src/Aggregate/ArrayElement.php | 69 +++-------- src/Aggregate/ArrayElementBuilder.php | 45 +++++-- src/Aggregate/ChildAggregateInterface.php | 6 + .../Collection/ChildrenCollection.php | 55 +++------ .../ChildrenCollectionInterface.php | 1 + .../Collection/DependencyIterator.php | 37 ++---- src/Aggregate/Collection/DependencyTree.php | 61 +++------- src/Aggregate/Collection/Level.php | 2 + src/Aggregate/Form.php | 70 ++++------- src/Aggregate/FormBuilder.php | 21 +++- src/Aggregate/FormBuilderInterface.php | 4 +- src/Aggregate/FormInterface.php | 9 +- src/Aggregate/RootForm.php | 113 +++++------------- src/Aggregate/Value/ValueGenerator.php | 9 +- src/Aggregate/View/ArrayElementView.php | 13 +- .../View/ArrayElementViewRenderer.php | 13 +- src/Aggregate/View/FormView.php | 14 +-- src/Button/SubmitButton.php | 25 ++-- src/Button/SubmitButtonBuilder.php | 13 +- src/Button/View/ButtonView.php | 17 +-- src/Button/View/ButtonViewInterface.php | 1 + src/Button/View/ButtonViewRenderer.php | 5 +- src/Child/Child.php | 59 +++------ src/Child/ChildBuilder.php | 39 ++---- src/Child/Http/ArrayOffsetHttpFields.php | 18 +-- src/Child/Http/HttpFieldPath.php | 2 + src/Child/Http/PrefixedHttpFields.php | 18 +-- src/Choice/ArrayChoice.php | 10 +- src/Choice/ChoiceBuilderTrait.php | 2 + src/Choice/LazyChoice.php | 10 +- src/Constraint/ClosureValidator.php | 5 +- src/Csrf/CsrfConstraintValidator.php | 5 +- src/Csrf/CsrfElement.php | 43 ++----- src/Csrf/CsrfElementBuilder.php | 4 + src/Csrf/CsrfValueValidator.php | 17 ++- src/Custom/CustomForm.php | 83 ++++--------- src/Custom/CustomFormBuilder.php | 14 +-- src/Error/FormError.php | 4 +- src/Error/ImplodeErrorPrinter.php | 21 +--- src/Error/StringErrorPrinter.php | 21 +--- src/Filter/ClosureFilter.php | 5 +- src/Filter/EmptyArrayValuesFilter.php | 5 +- src/Filter/FilterVar.php | 6 +- src/Filter/TrimFilter.php | 5 +- src/Leaf/AbstractBooleanElement.php | 7 +- src/Leaf/AnyElement.php | 14 +-- src/Leaf/AnyElementBuilder.php | 7 +- src/Leaf/BooleanElement.php | 19 +-- src/Leaf/BooleanElementBuilder.php | 7 +- src/Leaf/BooleanStringElement.php | 15 +-- src/Leaf/Date/DateTimeElement.php | 15 +-- src/Leaf/Date/DateTimeElementBuilder.php | 30 +---- .../DateTimeToTimestampTransformer.php | 17 ++- src/Leaf/FloatElement.php | 17 +-- src/Leaf/FloatElementBuilder.php | 11 +- src/Leaf/Helper/EmailElementBuilder.php | 17 ++- src/Leaf/Helper/UrlElementBuilder.php | 8 +- src/Leaf/IntegerElement.php | 17 +-- src/Leaf/IntegerElementBuilder.php | 11 +- src/Leaf/LeafElement.php | 50 +++----- src/Leaf/LeafRootElement.php | 69 +++-------- src/Leaf/NumberElementBuilder.php | 5 +- src/Leaf/StringElement.php | 18 +-- src/Leaf/StringElementBuilder.php | 12 +- .../LocalizedIntegerTransformer.php | 5 +- .../LocalizedNumberTransformer.php | 11 +- src/Leaf/View/BooleanElementView.php | 5 +- src/Leaf/View/CheckboxHtmlRenderer.php | 7 +- src/Leaf/View/SelectHtmlRenderer.php | 5 +- src/Leaf/View/SimpleElementView.php | 5 +- src/Leaf/View/SimpleFieldHtmlRenderer.php | 5 +- src/Phone/NotEmptyPhoneNumberValidator.php | 5 +- src/Phone/PhoneElement.php | 19 +-- src/Phone/PhoneElementBuilder.php | 13 +- .../PhoneNumberToStringTransformer.php | 9 +- src/Phone/ValidPhoneNumberValidator.php | 5 +- src/PropertyAccess/AbstractAccessor.php | 9 +- src/PropertyAccess/Getter.php | 5 +- src/PropertyAccess/Setter.php | 5 +- src/Registry/Registry.php | 10 +- src/Transformer/ClosureTransformer.php | 9 +- src/Transformer/DataTransformerAdapter.php | 11 +- src/Transformer/NullTransformer.php | 9 +- src/Transformer/TransformerAggregate.php | 9 +- src/Util/ContainerTrait.php | 2 +- src/Util/DelegateElementBuilderTrait.php | 5 +- src/Util/TransformerBuilderTrait.php | 2 +- src/Util/ValidatorBuilderTrait.php | 2 +- src/Validator/ConstraintValueValidator.php | 17 +-- .../TransformerExceptionConstraint.php | 8 -- ...ransformerExceptionConstraintValidator.php | 8 +- src/View/ElementViewTrait.php | 2 +- src/View/FieldSetViewTrait.php | 4 +- src/View/FieldViewInterface.php | 2 + src/View/FieldViewTrait.php | 2 +- tests/Leaf/LeafElementTest.php | 3 +- .../StaticAnalysis/ArrayElementConfigure.php | 1 + tests/StaticAnalysis/MyCustomForm.php | 5 +- .../SubClassChildBuilderForm.php | 1 + 100 files changed, 564 insertions(+), 1039 deletions(-) diff --git a/src/AbstractElementBuilder.php b/src/AbstractElementBuilder.php index 9591af4..e884178 100644 --- a/src/AbstractElementBuilder.php +++ b/src/AbstractElementBuilder.php @@ -8,6 +8,7 @@ use Bdf\Form\Util\TransformerBuilderTrait; use Bdf\Form\Util\ValidatorBuilderTrait; use Bdf\Form\Validator\ValueValidatorInterface; +use Override; /** * Base builder for elements @@ -41,9 +42,7 @@ public function __construct(?RegistryInterface $registry = null) $this->registry = $registry ?: new Registry(); } - /** - * {@inheritdoc} - */ + #[Override] final public function value($value) { $this->value = $value; @@ -51,9 +50,7 @@ final public function value($value) return $this; } - /** - * {@inheritdoc} - */ + #[Override] final public function buildElement(): ElementInterface { $element = $this->createElement($this->buildValidator(), $this->buildTransformer()); @@ -75,9 +72,7 @@ final public function buildElement(): ElementInterface */ abstract protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface; - /** - * {@inheritdoc} - */ + #[Override] final protected function registry(): RegistryInterface { return $this->registry; diff --git a/src/Aggregate/ArrayElement.php b/src/Aggregate/ArrayElement.php index 951188a..38a7ef2 100644 --- a/src/Aggregate/ArrayElement.php +++ b/src/Aggregate/ArrayElement.php @@ -25,6 +25,7 @@ use Countable; use Exception; use Iterator; +use Override; use Symfony\Component\Validator\Constraints\NotBlank; use TypeError; @@ -99,65 +100,49 @@ public function __construct(ElementInterface $templateElement, ?TransformerInter $this->choices = $choices; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetGet($offset): ChildInterface { return $this->children[$offset]; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetExists($offset): bool { return isset($this->children[$offset]); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetSet($offset, $value): void { throw new BadMethodCallException('Use import() or submit() for set an offset value'); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetUnset($offset): void { throw new BadMethodCallException('Use import() or submit() for set an offset value'); } - /** - * {@inheritdoc} - */ + #[Override] public function getIterator(): Iterator { return new ArrayIterator($this->children); } - /** - * {@inheritdoc} - */ + #[Override] public function count(): int { return count($this->children); } - /** - * {@inheritdoc} - */ + #[Override] public function choices(): ?ChoiceInterface { return $this->choices; } - /** - * {@inheritdoc} - */ + #[Override] public function submit($data): ElementInterface { $this->valid = true; @@ -204,9 +189,7 @@ public function submit($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function patch($data): ElementInterface { $this->valid = true; @@ -231,9 +214,7 @@ public function patch($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function import($entity): ElementInterface { if ($entity === null) { @@ -261,6 +242,7 @@ public function import($entity): ElementInterface * * @return T[] */ + #[Override] public function value(): array { $value = []; @@ -272,9 +254,7 @@ public function value(): array return $value; } - /** - * {@inheritdoc} - */ + #[Override] public function httpValue() { $value = []; @@ -286,33 +266,25 @@ public function httpValue() return $this->transformer->transformToHttp($value, $this); } - /** - * {@inheritdoc} - */ + #[Override] public function valid(): bool { return $this->valid; } - /** - * {@inheritdoc} - */ + #[Override] public function failed(): bool { return !$this->valid; } - /** - * {@inheritdoc} - */ + #[Override] public function error(?HttpFieldPath $field = null): FormError { return $field ? $this->error->withField($field) : $this->error; } - /** - * {@inheritdoc} - */ + #[Override] public function root(): RootElementInterface { if ($container = $this->container()) { @@ -323,9 +295,7 @@ public function root(): RootElementInterface return new LeafRootElement($this); } - /** - * {@inheritdoc} - */ + #[Override] public function view(?HttpFieldPath $field = null): ElementViewInterface { $elements = []; @@ -348,9 +318,6 @@ public function view(?HttpFieldPath $field = null): ElementViewInterface ); } - /** - * {@inheritdoc} - */ public function __clone() { $children = $this->children; diff --git a/src/Aggregate/ArrayElementBuilder.php b/src/Aggregate/ArrayElementBuilder.php index a73c9c1..27da190 100644 --- a/src/Aggregate/ArrayElementBuilder.php +++ b/src/Aggregate/ArrayElementBuilder.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Aggregate; use Bdf\Form\Choice\ChoiceBuilderTrait; +use Bdf\Form\Choice\ChoiceInterface; use Bdf\Form\ElementBuilderInterface; use Bdf\Form\ElementInterface; use Bdf\Form\Leaf\BooleanElement; @@ -17,11 +18,14 @@ use Bdf\Form\Util\MagicCallForwarding; use Bdf\Form\Util\TransformerBuilderTrait; use Bdf\Form\Util\ValidatorBuilderTrait; +use Override; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Choice as ChoiceConstraint; use Symfony\Component\Validator\Constraints\Count; use Symfony\Component\Validator\Constraints\NotBlank; +use function assert; + /** * Builder for the array element * @@ -86,9 +90,10 @@ public function __construct(?RegistryInterface $registry = null) * * Define a constraint on the inner element */ - public function satisfy($constraint, $options = null, bool $append = true) + #[Override] + public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) { - $this->getElementBuilder()->satisfy($constraint, $options, $append); + $this->getElementBuilder()->satisfy($constraint, $message, $append); return $this; } @@ -98,6 +103,7 @@ public function satisfy($constraint, $options = null, bool $append = true) * * Define a transformer on the inner element */ + #[Override] public function transformer(callable|TransformerInterface $transformer, bool $append = true) { $this->getElementBuilder()->transformer($transformer, $append); @@ -108,6 +114,7 @@ public function transformer(callable|TransformerInterface $transformer, bool $ap /** * {@inheritdoc} */ + #[Override] public function value($value) { $this->value = $value; @@ -153,6 +160,7 @@ public function element(string $element, ?callable $configurator = null): ArrayE * @return ElementBuilderInterface> * @psalm-suppress InvalidNullableReturnType */ + #[Override] public function getElementBuilder(): ElementBuilderInterface { if (!$this->element) { @@ -295,9 +303,9 @@ public function form(?callable $configurator = null): ArrayElementBuilder * * Ex: `$builder->count(['min' => 3, 'max' => 5])` * - * @param int|null $exactly The exact expected number of elements - * @param int|null $min Minimum expected number of elements - * @param int|null $max Maximum expected number of elements + * @param positive-int|null $exactly The exact expected number of elements + * @param non-negative-int|null $min Minimum expected number of elements + * @param positive-int|null $max Maximum expected number of elements * @param string|null $exactMessage * @param string|null $minMessage * @param string|null $maxMessage @@ -340,8 +348,13 @@ final public function required(string|Constraint|null $message = null, ?bool $al /** * {@inheritdoc} + * + * @param ChoiceInterface|array|callable $choices The allowed values in PHP form. + * @param string|null $message The error message. + * @param non-negative-int $min + * @param positive-int $max */ - final public function choices($choices, $message = null, ?bool $multiple = null, ?bool $strict = null, ?int $min = null, ?int $max = null, ?string $minMessage = null, ?string $maxMessage = null): self + final public function choices(ChoiceInterface|array|callable $choices, ?string $message = null, ?bool $multiple = null, ?bool $strict = null, ?int $min = null, ?int $max = null, ?string $minMessage = null, ?string $maxMessage = null): self { $builder = new class { use ChoiceBuilderTrait { @@ -350,15 +363,26 @@ final public function choices($choices, $message = null, ?bool $multiple = null, public ChoiceConstraint $constraint; - public function satisfy($constraint, $options = null, bool $append = true) + #[Override] + public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) { + assert($constraint instanceof ChoiceConstraint); $this->constraint = $constraint; return $this; } }; // Force the multiple option to true - $builder->choices($choices, $message, true, $strict, $min, $max, $minMessage, $maxMessage); + $builder->choices( + choices: $choices, + message: $message, + multiple: true, + strict: $strict, + min: $min, + max: $max, + minMessage: $minMessage, + maxMessage: $maxMessage + ); $this->arrayConstraint($builder->constraint); $this->choices = $builder->getChoices(); @@ -371,6 +395,7 @@ public function satisfy($constraint, $options = null, bool $append = true) * * @return ArrayElement */ + #[Override] public function buildElement(): ElementInterface { $element = new ArrayElement( @@ -387,9 +412,7 @@ public function buildElement(): ElementInterface return $element; } - /** - * {@inheritdoc} - */ + #[Override] protected function registry(): RegistryInterface { return $this->registry; diff --git a/src/Aggregate/ChildAggregateInterface.php b/src/Aggregate/ChildAggregateInterface.php index 12a4c8a..3265e58 100644 --- a/src/Aggregate/ChildAggregateInterface.php +++ b/src/Aggregate/ChildAggregateInterface.php @@ -7,6 +7,7 @@ use Bdf\Form\ElementInterface; use Iterator; use IteratorAggregate; +use Override; /** * Form element consists of an aggregation of sub-elements wrapped into a ChildInterface @@ -27,6 +28,7 @@ interface ChildAggregateInterface extends ElementInterface, ArrayAccess, Iterato * * @param string $offset The child name */ + #[Override] public function offsetGet($offset): ChildInterface; /** @@ -36,6 +38,7 @@ public function offsetGet($offset): ChildInterface; * * @param string $offset The child name */ + #[Override] public function offsetExists($offset): bool; /** @@ -48,6 +51,7 @@ public function offsetExists($offset): bool; * * @throws \BadMethodCallException */ + #[Override] public function offsetSet($offset, $value): void; /** @@ -57,6 +61,7 @@ public function offsetSet($offset, $value): void; * * @throws \BadMethodCallException */ + #[Override] public function offsetUnset($offset): void; /** @@ -66,5 +71,6 @@ public function offsetUnset($offset): void; * * @return Iterator */ + #[Override] public function getIterator(): Iterator; } diff --git a/src/Aggregate/Collection/ChildrenCollection.php b/src/Aggregate/Collection/ChildrenCollection.php index a898c0e..9b6a3d2 100644 --- a/src/Aggregate/Collection/ChildrenCollection.php +++ b/src/Aggregate/Collection/ChildrenCollection.php @@ -8,6 +8,7 @@ use Countable; use Iterator; use IteratorAggregate; +use Override; /** * Simple implementation of children collection for handle dependencies order @@ -42,25 +43,19 @@ public function __construct(array $children = []) } } - /** - * {@inheritdoc} - */ + #[Override] public function add(ChildInterface $child): void { $this->addNamed($child->name(), $child); } - /** - * {@inheritdoc} - */ + #[Override] public function has(string $name): bool { return isset($this->children[$name]); } - /** - * {@inheritdoc} - */ + #[Override] public function remove(string $name): bool { if (!$this->has($name)) { @@ -72,81 +67,61 @@ public function remove(string $name): bool return true; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetExists($offset): bool { return $this->has($offset); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetGet($offset): ChildInterface { return $this->children[$offset]; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetSet($offset, $value): void { $this->add($value); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetUnset($offset): void { $this->remove($offset); } - /** - * {@inheritdoc} - */ + #[Override] public function count(): int { return count($this->children); } - /** - * {@inheritdoc} - */ + #[Override] public function getIterator(): Iterator { return new ArrayIterator($this->children); } - /** - * {@inheritdoc} - */ + #[Override] public function reverseIterator(): Iterator { return new ArrayIterator($this->hasViewDependencies ? array_reverse($this->children) : $this->children); } - /** - * {@inheritdoc} - */ + #[Override] public function forwardIterator(): Iterator { return new ArrayIterator($this->children); } - /** - * {@inheritdoc} - */ + #[Override] public function all(): array { return $this->children; } - /** - * {@inheritdoc} - */ + #[Override] public function duplicate(ChildAggregateInterface $newParent): ChildrenCollectionInterface { $children = []; @@ -169,7 +144,7 @@ public function duplicate(ChildAggregateInterface $newParent): ChildrenCollectio * @param string $name * @param ChildInterface $child */ - private function addNamed($name, ChildInterface $child): void + private function addNamed(string $name, ChildInterface $child): void { $this->children[$name] = $child; $this->orderDependencies($child); diff --git a/src/Aggregate/Collection/ChildrenCollectionInterface.php b/src/Aggregate/Collection/ChildrenCollectionInterface.php index 7757f31..7d8418a 100644 --- a/src/Aggregate/Collection/ChildrenCollectionInterface.php +++ b/src/Aggregate/Collection/ChildrenCollectionInterface.php @@ -65,6 +65,7 @@ public function forwardIterator(): Iterator; * * @return Iterator */ + #[\Override] public function getIterator(): Iterator; /** diff --git a/src/Aggregate/Collection/DependencyIterator.php b/src/Aggregate/Collection/DependencyIterator.php index 7a0733e..91a2fe1 100644 --- a/src/Aggregate/Collection/DependencyIterator.php +++ b/src/Aggregate/Collection/DependencyIterator.php @@ -4,6 +4,9 @@ use Bdf\Form\Child\ChildInterface; use Iterator; +use Override; + +use function assert; /** * Iterate over @see DependencyTree @@ -54,31 +57,23 @@ public function __construct(array $children, Level $first, $reverse = true) $this->reverse = $reverse; } - /** - * {@inheritdoc} - * - * @return ChildInterface - */ + #[Override] public function current(): ChildInterface { return $this->children[$this->key()]; } - /** - * {@inheritdoc} - * - * @psalm-suppress PossiblyNullReference - * @psalm-suppress PossiblyNullReference - */ + #[Override] public function next(): void { + assert($this->levelIterator !== null); $this->levelIterator->next(); // The level iterator can be invalid if the level is empty // We need to skip empty levels while (!$this->levelIterator->valid()) { $this->levelIterator = null; - $this->currentLevel = $this->reverse ? $this->currentLevel->prev() : $this->currentLevel->next(); + $this->currentLevel = $this->reverse ? $this->currentLevel?->prev() : $this->currentLevel?->next(); // There is no more level, the iterator will be "invalid" if ($this->currentLevel === null) { @@ -97,28 +92,20 @@ public function next(): void } } - /** - * {@inheritdoc} - * - * @psalm-suppress PossiblyNullReference - */ - #[\ReturnTypeWillChange] - public function key() + #[Override] + public function key(): string|int { + assert($this->levelIterator !== null); return $this->levelIterator->key(); } - /** - * {@inheritdoc} - */ + #[Override] public function valid(): bool { return $this->levelIterator !== null && $this->levelIterator->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function rewind(): void { $this->currentLevel = $this->first; diff --git a/src/Aggregate/Collection/DependencyTree.php b/src/Aggregate/Collection/DependencyTree.php index c07630c..e5a60b3 100644 --- a/src/Aggregate/Collection/DependencyTree.php +++ b/src/Aggregate/Collection/DependencyTree.php @@ -6,6 +6,7 @@ use Bdf\Form\Aggregate\ChildAggregateInterface; use Bdf\Form\Child\ChildInterface; use Iterator; +use Override; /** * Handle form children dependencies @@ -67,27 +68,19 @@ public function __construct() $this->last = $this->root; } - /** - * {@inheritdoc} - */ + #[Override] public function add(ChildInterface $child): void { $this->addNamed($child->name(), $child); } - /** - * {@inheritdoc} - */ + #[Override] public function has(string $name): bool { return isset($this->children[$name]); } - /** - * {@inheritdoc} - * - * @psalm-suppress PossiblyNullReference - */ + #[Override] public function remove(string $name): bool { if (!$this->has($name)) { @@ -112,81 +105,61 @@ public function remove(string $name): bool return true; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetExists($offset): bool { return $this->has($offset); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetGet($offset): ChildInterface { return $this->children[$offset]; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetSet($offset, $value): void { $this->add($value); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetUnset($offset): void { $this->remove($offset); } - /** - * {@inheritdoc} - */ + #[Override] public function count(): int { return count($this->children); } - /** - * {@inheritdoc} - */ + #[Override] public function getIterator(): Iterator { return new ArrayIterator($this->children); } - /** - * {@inheritdoc} - */ + #[Override] public function reverseIterator(): Iterator { return new DependencyIterator($this->children, $this->last, true); } - /** - * {@inheritdoc} - */ + #[Override] public function forwardIterator(): Iterator { return new DependencyIterator($this->children, $this->root, false); } - /** - * {@inheritdoc} - */ + #[Override] public function all(): array { return $this->children; } - /** - * {@inheritdoc} - */ + #[Override] public function duplicate(ChildAggregateInterface $newParent): ChildrenCollectionInterface { $children = []; @@ -212,7 +185,7 @@ public function duplicate(ChildAggregateInterface $newParent): ChildrenCollectio * @psalm-suppress InvalidNullableReturnType * @psalm-suppress NullableReturnStatement */ - private function level($child) + private function level(ChildInterface|string $child): Level { if (!is_string($child)) { $child = $child->name(); @@ -238,7 +211,7 @@ private function level($child) * @param string $name * @param ChildInterface $child */ - private function addNamed($name, ChildInterface $child): void + private function addNamed(string $name, ChildInterface $child): void { $this->children[$name] = $child; @@ -261,7 +234,7 @@ private function addNamed($name, ChildInterface $child): void * * @return string[] */ - private function extractDependencies(ChildInterface $child, Level $level) + private function extractDependencies(ChildInterface $child, Level $level): array { $dependencies = []; diff --git a/src/Aggregate/Collection/Level.php b/src/Aggregate/Collection/Level.php index 2b7adfe..cf67050 100644 --- a/src/Aggregate/Collection/Level.php +++ b/src/Aggregate/Collection/Level.php @@ -5,6 +5,7 @@ use ArrayIterator; use Iterator; use IteratorAggregate; +use Override; /** * The dependency tree level @@ -164,6 +165,7 @@ public function next() * * @return Iterator */ + #[Override] public function getIterator(): Iterator { return new ArrayIterator($this->elements); diff --git a/src/Aggregate/Form.php b/src/Aggregate/Form.php index b380694..c2e65d1 100644 --- a/src/Aggregate/Form.php +++ b/src/Aggregate/Form.php @@ -17,9 +17,9 @@ use Bdf\Form\Util\ContainerTrait; use Bdf\Form\Validator\ConstraintValueValidator; use Bdf\Form\Validator\ValueValidatorInterface; -use Bdf\Form\View\ElementViewInterface; use Exception; use Iterator; +use Override; /** * The base form element @@ -134,9 +134,7 @@ public function __construct(ChildrenCollectionInterface $children, ?ValueValidat $this->optional = $optional; } - /** - * {@inheritdoc} - */ + #[Override] public function submit($data): ElementInterface { $this->valid = true; @@ -154,9 +152,7 @@ public function submit($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function patch($data): ElementInterface { $this->valid = true; @@ -176,25 +172,19 @@ public function patch($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function valid(): bool { return $this->valid; } - /** - * {@inheritdoc} - */ + #[Override] public function failed(): bool { return !$this->valid; } - /** - * {@inheritdoc} - */ + #[Override] public function error(?HttpFieldPath $field = null): FormError { return $field ? $this->error->withField($field) : $this->error; @@ -206,6 +196,7 @@ public function error(?HttpFieldPath $field = null): FormError * @param T|null $entity * @return $this */ + #[Override] public function import($entity): ElementInterface { if ($entity) { @@ -226,6 +217,7 @@ public function import($entity): ElementInterface * * @return T */ + #[Override] public function value() { if ($this->value !== null) { @@ -245,9 +237,7 @@ public function value() return $this->value; } - /** - * {@inheritdoc} - */ + #[Override] public function httpValue() { $http = []; @@ -259,9 +249,7 @@ public function httpValue() return $this->transformer->transformToHttp($http, $this); } - /** - * {@inheritdoc} - */ + #[Override] public function root(): RootElementInterface { if ($container = $this->container()) { @@ -275,73 +263,55 @@ public function root(): RootElementInterface return $this->root = new RootForm($this); } - /** - * {@inheritdoc} - * - * @return FormView - */ - public function view(?HttpFieldPath $fieldPath = null): ElementViewInterface + #[Override] + public function view(?HttpFieldPath $field = null): FormView { $elements = []; foreach ($this->children as $child) { - $elements[$child->name()] = $child->view($fieldPath); + $elements[$child->name()] = $child->view($field); } return new FormView(self::class, $this->error->global(), $elements); } - /** - * {@inheritdoc} - */ + #[Override] public function getIterator(): Iterator { return $this->children->forwardIterator(); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetExists($offset): bool { return isset($this->children[$offset]); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetGet($offset): ChildInterface { + /** @var ChildInterface */ return $this->children[$offset]; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetSet($offset, $value): void { throw new BadMethodCallException(__CLASS__.' is immutable'); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetUnset($offset): void { throw new BadMethodCallException(__CLASS__.' is immutable'); } - /** - * {@inheritdoc} - */ public function __clone() { $this->children = $this->children->duplicate($this); } - /** - * {@inheritdoc} - */ + #[Override] public function attach($entity): FormInterface { $this->generator->attach($entity); diff --git a/src/Aggregate/FormBuilder.php b/src/Aggregate/FormBuilder.php index cf7688f..541eabf 100644 --- a/src/Aggregate/FormBuilder.php +++ b/src/Aggregate/FormBuilder.php @@ -36,6 +36,7 @@ use Bdf\Form\RootElementInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; +use Override; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -125,6 +126,7 @@ public function __construct(?RegistryInterface $registry = null) * @psalm-suppress LessSpecificReturnStatement * @psalm-suppress PropertyTypeCoercion */ + #[Override] public function add(string $name, string $element): ChildBuilderInterface { return $this->children[$name] = $this->registry()->childBuilder($element, $name); @@ -139,6 +141,7 @@ public function add(string $name, string $element): ChildBuilderInterface * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function any(string $name): ChildBuilderInterface { return $this->add($name, AnyElement::class); @@ -153,6 +156,7 @@ public function any(string $name): ChildBuilderInterface * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function string(string $name, ?string $default = null): ChildBuilderInterface { return $this->add($name, StringElement::class)->default($default); @@ -167,6 +171,7 @@ public function string(string $name, ?string $default = null): ChildBuilderInter * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function integer(string $name, ?int $default = null): ChildBuilderInterface { return $this->add($name, IntegerElement::class)->default($default); @@ -181,6 +186,7 @@ public function integer(string $name, ?int $default = null): ChildBuilderInterfa * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function float(string $name, ?float $default = null): ChildBuilderInterface { return $this->add($name, FloatElement::class)->default($default); @@ -195,6 +201,7 @@ public function float(string $name, ?float $default = null): ChildBuilderInterfa * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function boolean(string $name): ChildBuilderInterface { return $this->add($name, BooleanElement::class); @@ -209,6 +216,7 @@ public function boolean(string $name): ChildBuilderInterface * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function dateTime(string $name): ChildBuilderInterface { return $this->add($name, DateTimeElement::class); @@ -223,6 +231,7 @@ public function dateTime(string $name): ChildBuilderInterface * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function phone(string $name): ChildBuilderInterface { return $this->add($name, PhoneElement::class); @@ -237,6 +246,7 @@ public function phone(string $name): ChildBuilderInterface * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function csrf(string $name = '_token'): ChildBuilderInterface { return $this->add($name, CsrfElement::class); @@ -296,6 +306,7 @@ public function url(string $name): ChildBuilderInterface * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function embedded(string $name, ?callable $configurator = null): ChildBuilderInterface { $builder = $this->add($name, Form::class); @@ -318,6 +329,7 @@ public function embedded(string $name, ?callable $configurator = null): ChildBui * @psalm-suppress MoreSpecificReturnType * @psalm-suppress LessSpecificReturnStatement */ + #[Override] public function array(string $name, ?string $elementType = null, ?callable $elementConfigurator = null): ChildBuilderInterface { /** @var ChildBuilderInterface&ArrayChildBuilder $builder */ @@ -333,6 +345,7 @@ public function array(string $name, ?string $elementType = null, ?callable $elem /** * {@inheritdoc} */ + #[Override] public function submit(string $name): ButtonBuilderInterface { return $this->buttons[$name] = $this->registry()->buttonBuilder($name); @@ -341,6 +354,7 @@ public function submit(string $name): ButtonBuilderInterface /** * {@inheritdoc} */ + #[Override] public function propertyAccessor(PropertyAccessorInterface $propertyAccessor): FormBuilderInterface { $this->propertyAccessor = $propertyAccessor; @@ -351,6 +365,7 @@ public function propertyAccessor(PropertyAccessorInterface $propertyAccessor): F /** * {@inheritdoc} */ + #[Override] public function validator(ValidatorInterface $validator): FormBuilderInterface { $this->validator = $validator; @@ -361,6 +376,7 @@ public function validator(ValidatorInterface $validator): FormBuilderInterface /** * {@inheritdoc} */ + #[Override] public function generator(ValueGeneratorInterface $generator): FormBuilderInterface { $this->generator = $generator; @@ -371,6 +387,7 @@ public function generator(ValueGeneratorInterface $generator): FormBuilderInterf /** * {@inheritdoc} */ + #[Override] public function generates($entity): FormBuilderInterface { return $this->generator(new ValueGenerator($entity)); @@ -379,6 +396,7 @@ public function generates($entity): FormBuilderInterface /** * {@inheritdoc} */ + #[Override] public function optional(bool $flag = true): FormBuilderInterface { $this->optional = $flag; @@ -389,7 +407,8 @@ public function optional(bool $flag = true): FormBuilderInterface /** * {@inheritdoc} */ - final protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + #[Override] + final protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): Form { $children = new ChildrenCollection(); diff --git a/src/Aggregate/FormBuilderInterface.php b/src/Aggregate/FormBuilderInterface.php index 8f8d81a..bab2139 100644 --- a/src/Aggregate/FormBuilderInterface.php +++ b/src/Aggregate/FormBuilderInterface.php @@ -18,6 +18,7 @@ use Bdf\Form\Leaf\StringElementBuilder; use Bdf\Form\Phone\PhoneChildBuilder; use Bdf\Form\Phone\PhoneElementBuilder; +use Override; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -69,7 +70,7 @@ public function add(string $name, string $element): ChildBuilderInterface; * @param non-empty-string $name The child name * * @return ChildBuilder|AnyElementBuilder - * @return ChildBuilderInterface The child builder + * @psalm-return ChildBuilderInterface The child builder * * @since 1.5 */ @@ -332,5 +333,6 @@ public function optional(bool $flag = true): FormBuilderInterface; * * @return FormInterface */ + #[Override] public function buildElement(): ElementInterface; } diff --git a/src/Aggregate/FormInterface.php b/src/Aggregate/FormInterface.php index ae2b561..f08a1df 100644 --- a/src/Aggregate/FormInterface.php +++ b/src/Aggregate/FormInterface.php @@ -2,11 +2,13 @@ namespace Bdf\Form\Aggregate; +use Bdf\Form\Aggregate\View\FormView; +use Bdf\Form\Child\Http\HttpFieldPath; +use Override; + /** * The base form element type * - * @method \Bdf\Form\Aggregate\View\FormView view(?\Bdf\Form\Child\Http\HttpFieldPath $fieldPath = null) - * * @template T * @extends ChildAggregateInterface */ @@ -38,4 +40,7 @@ interface FormInterface extends ChildAggregateInterface * @see Form::import() For attach and extract values from properties */ public function attach($entity): FormInterface; + + #[Override] + public function view(?HttpFieldPath $field = null): FormView; } diff --git a/src/Aggregate/RootForm.php b/src/Aggregate/RootForm.php index 97e392b..62b5be1 100644 --- a/src/Aggregate/RootForm.php +++ b/src/Aggregate/RootForm.php @@ -12,7 +12,9 @@ use Bdf\Form\Util\RootFlagsTrait; use Bdf\Form\View\ElementViewInterface; use Iterator; +use LogicException; use OutOfBoundsException; +use Override; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Validator\Constraint; @@ -97,33 +99,25 @@ public function __construct(Form $form, array $buttons = [], ?PropertyAccessorIn $this->validator = $validator; } - /** - * {@inheritdoc} - */ + #[Override] public function submit($data): ElementInterface { $this->submitToButtons($data); - /** @psalm-suppress PossiblyNullReference */ - $this->form->get()->submit($data); + $this->form?->get()->submit($data); return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function patch($data): ElementInterface { $this->submitToButtons($data); - /** @psalm-suppress PossiblyNullReference */ - $this->form->get()->patch($data); + $this->form?->get()->patch($data); return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function import($entity): ElementInterface { /** @psalm-suppress PossiblyNullReference */ @@ -132,22 +126,16 @@ public function import($entity): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function value() { - /** @psalm-suppress PossiblyNullReference */ - return $this->form->get()->value(); + return $this->form?->get()->value(); } - /** - * {@inheritdoc} - */ + #[Override] public function httpValue() { - /** @psalm-suppress PossiblyNullReference */ - $httpValue = $this->form->get()->httpValue(); + $httpValue = $this->form?->get()->httpValue(); if (empty($this->buttons)) { return $httpValue; @@ -162,60 +150,45 @@ public function httpValue() return $httpValue; } - /** - * {@inheritdoc} - */ + #[Override] public function valid(): bool { /** @psalm-suppress PossiblyNullReference */ return $this->form->get()->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function failed(): bool { // Do not use $this->form->get()->failed() because it may be not implemented return !$this->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function error(?HttpFieldPath $field = null): FormError { - /** @psalm-suppress PossiblyNullReference */ - return $this->form->get()->error($field); + return $this->form?->get()->error($field); } - /** - * {@inheritdoc} - */ + #[Override] public function container(): ?ChildInterface { return null; // root cannot have a container } - /** - * {@inheritdoc} - */ + #[Override] public function setContainer(ChildInterface $container): ElementInterface { throw new BadMethodCallException('Cannot wrap a root element into a container'); } - /** - * {@inheritdoc} - */ + #[Override] public function root(): RootElementInterface { return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function view(?HttpFieldPath $field = null): ElementViewInterface { $buttons = []; @@ -231,17 +204,13 @@ public function view(?HttpFieldPath $field = null): ElementViewInterface return $view; } - /** - * {@inheritdoc} - */ + #[Override] public function submitButton(): ?ButtonInterface { return $this->submitButton; } - /** - * {@inheritdoc} - */ + #[Override] public function button(string $name): ButtonInterface { if ($btn = $this->buttons[$name] ?? null) { @@ -251,9 +220,7 @@ public function button(string $name): ButtonInterface throw new OutOfBoundsException("The button '{$name}' is not found"); } - /** - * {@inheritdoc} - */ + #[Override] public function getValidator(): ValidatorInterface { if ($this->validator === null) { @@ -263,9 +230,7 @@ public function getValidator(): ValidatorInterface return $this->validator; } - /** - * {@inheritdoc} - */ + #[Override] public function getPropertyAccessor(): PropertyAccessorInterface { if ($this->propertyAccessor === null) { @@ -275,9 +240,7 @@ public function getPropertyAccessor(): PropertyAccessorInterface return $this->propertyAccessor; } - /** - * {@inheritdoc} - */ + #[Override] public function constraintGroups(): array { if (!$button = $this->submitButton) { @@ -295,47 +258,37 @@ public function constraintGroups(): array * @psalm-suppress PossiblyNullArrayAccess * @psalm-suppress NullableReturnStatement */ + #[Override] public function offsetGet($offset): ChildInterface { return $this->form->get()[$offset]; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetExists($offset): bool { - /** @psalm-suppress PossiblyNullReference */ return isset($this->form->get()[$offset]); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetSet($offset, $value): void { /** @psalm-suppress PossiblyNullReference */ $this->form->get()[$offset] = $value; } - /** - * {@inheritdoc} - * - * @psalm-suppress PossiblyNullReference - * @psalm-suppress PossiblyNullArrayAccess - */ + #[Override] public function offsetUnset($offset): void { - unset($this->form->get()[$offset]); + if ($form = $this->form->get()) { + unset($form[$offset]); + } } - /** - * {@inheritdoc} - */ + #[Override] public function getIterator(): Iterator { - /** @psalm-suppress PossiblyNullReference */ - return $this->form->get()->getIterator(); + return $this->form->get()?->getIterator() ?? throw new LogicException(); } /** diff --git a/src/Aggregate/Value/ValueGenerator.php b/src/Aggregate/Value/ValueGenerator.php index a281be1..88765f6 100644 --- a/src/Aggregate/Value/ValueGenerator.php +++ b/src/Aggregate/Value/ValueGenerator.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Aggregate\Value; use Bdf\Form\ElementInterface; +use Override; /** * The base value generator implementation @@ -40,18 +41,14 @@ public function __construct($value = []) $this->value = $value; } - /** - * {@inheritdoc} - */ + #[Override] public function attach($entity): void { /** @psalm-suppress PropertyTypeCoercion */ $this->attachment = $entity; } - /** - * {@inheritdoc} - */ + #[Override] public function generate(ElementInterface $element) { $value = $this->attachment ?? $this->value; diff --git a/src/Aggregate/View/ArrayElementView.php b/src/Aggregate/View/ArrayElementView.php index f42a6e6..df2444f 100644 --- a/src/Aggregate/View/ArrayElementView.php +++ b/src/Aggregate/View/ArrayElementView.php @@ -13,6 +13,7 @@ use Bdf\Form\View\FieldViewTrait; use Countable; use IteratorAggregate; +use Override; /** * View object for the ArrayElement @@ -78,17 +79,13 @@ public function isCsv(): bool return is_scalar($this->value); } - /** - * {@inheritdoc} - */ + #[Override] public function count(): int { return count($this->elements); } - /** - * {@inheritdoc} - */ + #[Override] protected function defaultRenderer(): FieldViewRendererInterface { return ArrayElementViewRenderer::instance(); @@ -96,10 +93,8 @@ protected function defaultRenderer(): FieldViewRendererInterface /** * Ignore property "attributes" - * - * @return array */ - public function __sleep() + public function __sleep(): array { return ['type', 'name', 'error', 'value', 'elements', 'required', 'constraints', 'choices']; } diff --git a/src/Aggregate/View/ArrayElementViewRenderer.php b/src/Aggregate/View/ArrayElementViewRenderer.php index e79010e..5078339 100644 --- a/src/Aggregate/View/ArrayElementViewRenderer.php +++ b/src/Aggregate/View/ArrayElementViewRenderer.php @@ -6,6 +6,7 @@ use Bdf\Form\Leaf\View\SimpleFieldHtmlRenderer; use Bdf\Form\View\FieldViewInterface; use Bdf\Form\View\FieldViewRendererInterface; +use Override; /** * Default renderer for @see ArrayElementView @@ -41,11 +42,7 @@ public function __construct(?FieldViewRendererInterface $csvRenderer = null, ?Fi $this->selectRenderer = $selectRenderer ?? SelectHtmlRenderer::instance(); } - /** - * {@inheritdoc} - * - * @param ArrayElementView $view - */ + #[Override] public function render(FieldViewInterface $view, array $attributes): string { if ($view->isCsv()) { @@ -62,10 +59,6 @@ public function render(FieldViewInterface $view, array $attributes): string */ public static function instance(): self { - if (self::$instance) { - return self::$instance; - } - - return self::$instance = new self(); + return self::$instance ??= new self(); } } diff --git a/src/Aggregate/View/FormView.php b/src/Aggregate/View/FormView.php index 9cd3b7f..e4f8cf7 100644 --- a/src/Aggregate/View/FormView.php +++ b/src/Aggregate/View/FormView.php @@ -11,6 +11,7 @@ use Bdf\Form\View\FieldSetViewTrait; use Bdf\Form\View\FieldViewInterface; use IteratorAggregate; +use Override; /** * View for a form element @@ -59,20 +60,13 @@ public function __construct(string $type, ?string $error, array $elements) $this->elements = $elements; } - /** - * {@inheritdoc} - * - * @return ElementViewInterface|ButtonViewInterface - */ - #[\ReturnTypeWillChange] - public function offsetGet($offset) + #[Override] + public function offsetGet($offset): ElementViewInterface|ButtonViewInterface { return $this->elements[$offset] ?? $this->buttons[$offset]; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetExists($offset): bool { return isset($this->elements[$offset]) || isset($this->buttons[$offset]); diff --git a/src/Button/SubmitButton.php b/src/Button/SubmitButton.php index aa77720..6eb94b4 100644 --- a/src/Button/SubmitButton.php +++ b/src/Button/SubmitButton.php @@ -5,6 +5,7 @@ use Bdf\Form\Button\View\ButtonView; use Bdf\Form\Button\View\ButtonViewInterface; use Bdf\Form\Child\Http\HttpFieldPath; +use Override; /** * Simple button implementation @@ -47,41 +48,31 @@ public function __construct(string $name, string $value = 'ok', array $groups = $this->groups = $groups; } - /** - * {@inheritdoc} - */ + #[Override] public function name(): string { return $this->name; } - /** - * {@inheritdoc} - */ + #[Override] public function clicked(): bool { return $this->clicked; } - /** - * {@inheritdoc} - */ + #[Override] public function constraintGroups(): array { return $this->groups; } - /** - * {@inheritdoc} - */ + #[Override] public function submit($data): bool { return $this->clicked = isset($data[$this->name]) && (string) $data[$this->name] === $this->value; } - /** - * {@inheritdoc} - */ + #[Override] public function toHttp(): array { if (!$this->clicked) { @@ -91,9 +82,7 @@ public function toHttp(): array return [$this->name => $this->value]; } - /** - * {@inheritdoc} - */ + #[Override] public function view(?HttpFieldPath $parent = null): ButtonViewInterface { return new ButtonView($parent ? $parent->add($this->name)->get() : $this->name, $this->value, $this->clicked()); diff --git a/src/Button/SubmitButtonBuilder.php b/src/Button/SubmitButtonBuilder.php index c556571..b8797a1 100644 --- a/src/Button/SubmitButtonBuilder.php +++ b/src/Button/SubmitButtonBuilder.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Button; use Bdf\Form\Aggregate\FormBuilderInterface; +use Override; /** * Builder for a submit button @@ -53,9 +54,7 @@ public function __construct(string $name, string $buttonClass = SubmitButton::cl $this->buttonClass = $buttonClass; } - /** - * {@inheritdoc} - */ + #[Override] public function value(string $value): ButtonBuilderInterface { $this->value = $value; @@ -63,9 +62,7 @@ public function value(string $value): ButtonBuilderInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function groups(array $groups): ButtonBuilderInterface { $this->groups = $groups; @@ -73,9 +70,7 @@ public function groups(array $groups): ButtonBuilderInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function buildButton(): ButtonInterface { return new $this->buttonClass($this->name, $this->value, $this->groups); diff --git a/src/Button/View/ButtonView.php b/src/Button/View/ButtonView.php index d124980..52be7b0 100644 --- a/src/Button/View/ButtonView.php +++ b/src/Button/View/ButtonView.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Button\View; use Bdf\Form\View\RenderableTrait; +use Override; /** * Base view object for buttons @@ -45,33 +46,25 @@ public function __construct(string $name, string $value, bool $clicked) $this->clicked = $clicked; } - /** - * {@inheritdoc} - */ + #[Override] public function name(): string { return $this->name; } - /** - * {@inheritdoc} - */ + #[Override] public function value(): string { return $this->value; } - /** - * {@inheritdoc} - */ + #[Override] public function clicked(): bool { return $this->clicked; } - /** - * {@inheritdoc} - */ + #[Override] public function render(?ButtonViewRendererInterface $renderer = null): string { return ($renderer ?? ButtonViewRenderer::instance())->render($this, $this->attributes); diff --git a/src/Button/View/ButtonViewInterface.php b/src/Button/View/ButtonViewInterface.php index c908ddb..d90d94b 100644 --- a/src/Button/View/ButtonViewInterface.php +++ b/src/Button/View/ButtonViewInterface.php @@ -43,5 +43,6 @@ public function clicked(): bool; * * @return string */ + #[\Override] public function render(?ButtonViewRendererInterface $renderer = null): string; } diff --git a/src/Button/View/ButtonViewRenderer.php b/src/Button/View/ButtonViewRenderer.php index 739b206..9bfa6da 100644 --- a/src/Button/View/ButtonViewRenderer.php +++ b/src/Button/View/ButtonViewRenderer.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Button\View; use Bdf\Form\View\HtmlRenderer; +use Override; /** * Renderer for @see ButtonViewInterface @@ -14,9 +15,7 @@ final class ButtonViewRenderer implements ButtonViewRendererInterface */ private static $instance; - /** - * {@inheritdoc} - */ + #[Override] public function render(ButtonViewInterface $view, array $attributes): string { if (!isset($attributes['type'])) { diff --git a/src/Child/Child.php b/src/Child/Child.php index a980d95..093e0be 100644 --- a/src/Child/Child.php +++ b/src/Child/Child.php @@ -15,8 +15,11 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Util\HttpValue; use Bdf\Form\View\ElementViewInterface; +use Override; use WeakReference; +use function assert; + /** * Child which extract HTTP field value from a simple array access */ @@ -98,9 +101,7 @@ public function __construct(string $name, ElementInterface $element, ?HttpFields $this->transformer = $transformer ?? NullTransformer::instance(); } - /** - * {@inheritdoc} - */ + #[Override] public function element(): ElementInterface { return $this->element; @@ -112,14 +113,13 @@ public function element(): ElementInterface * @psalm-suppress NullableReturnStatement * @psalm-suppress InvalidNullableReturnType */ + #[Override] public function parent(): ChildAggregateInterface { return $this->parent->get(); } - /** - * {@inheritdoc} - */ + #[Override] public function setParent(ChildAggregateInterface $parent): ChildInterface { if ($this->parent === null) { @@ -133,33 +133,27 @@ public function setParent(ChildAggregateInterface $parent): ChildInterface return $child; } - /** - * {@inheritdoc} - */ + #[Override] public function name(): string { return $this->name; } - /** - * {@inheritdoc} - */ + #[Override] public function dependencies(): array { return $this->dependencies; } - /** - * {@inheritdoc} - */ + #[Override] public function import($entity): void { if (!$this->extractor) { return; } - /** @psalm-suppress PossiblyNullReference */ - $propertyAccessor = $this->parent->get()->root()->getPropertyAccessor(); + $propertyAccessor = $this->parent->get()?->root()?->getPropertyAccessor(); + assert($propertyAccessor !== null); $this->extractor->setPropertyAccessor($propertyAccessor); $this->extractor->setFormElement($this); @@ -171,17 +165,15 @@ public function import($entity): void $this->element->import($value); } - /** - * {@inheritdoc} - */ + #[Override] public function fill(&$entity): void { if (!$this->hydrator) { return; } - /** @psalm-suppress PossiblyNullReference */ - $propertyAccessor = $this->parent->get()->root()->getPropertyAccessor(); + $propertyAccessor = $this->parent->get()?->root()?->getPropertyAccessor(); + assert($propertyAccessor !== null); $this->hydrator->setPropertyAccessor($propertyAccessor); $this->hydrator->setFormElement($this); @@ -193,9 +185,7 @@ public function fill(&$entity): void $this->hydrator->setFormElement(null); } - /** - * {@inheritdoc} - */ + #[Override] public function submit($data): bool { $value = $this->extractValue($data); @@ -203,9 +193,7 @@ public function submit($data): bool return $this->element->submit($value)->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function patch($data): bool { $value = $data !== null && $this->fields->contains($data) @@ -216,33 +204,24 @@ public function patch($data): bool return $this->element->patch($value)->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function httpFields(): array { return $this->fields->format($this->element->httpValue()); } - /** - * {@inheritdoc} - */ + #[Override] public function error(?HttpFieldPath $field = null): FormError { return $this->element->error($this->fields->get($field)); } - /** - * {@inheritdoc} - */ + #[Override] public function view(?HttpFieldPath $field = null): ElementViewInterface { return $this->element->view($this->fields->get($field)); } - /** - * {@inheritdoc} - */ public function __clone() { $this->element = $this->element->setContainer($this); diff --git a/src/Child/ChildBuilder.php b/src/Child/ChildBuilder.php index cd5edf2..332af70 100644 --- a/src/Child/ChildBuilder.php +++ b/src/Child/ChildBuilder.php @@ -18,7 +18,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Util\MagicCallForwarding; use Bdf\Form\Util\TransformerBuilderTrait; -use Symfony\Component\Form\DataTransformerInterface; +use Override; use function is_callable; @@ -137,9 +137,7 @@ public function __construct(string $name, ElementBuilderInterface $elementBuilde $this->registry = $registry ?: new Registry(); } - /** - * {@inheritdoc} - */ + #[Override] final public function hydrator(HydratorInterface $hydrator) { $this->hydrator = $hydrator; @@ -147,9 +145,7 @@ final public function hydrator(HydratorInterface $hydrator) return $this; } - /** - * {@inheritdoc} - */ + #[Override] final public function extractor(ExtractorInterface $extractor) { $this->extractor = $extractor; @@ -157,9 +153,7 @@ final public function extractor(ExtractorInterface $extractor) return $this; } - /** - * {@inheritdoc} - */ + #[Override] final public function filter(FilterInterface|callable $filter, bool $append = true) { if (is_callable($filter)) { @@ -175,9 +169,7 @@ final public function filter(FilterInterface|callable $filter, bool $append = tr return $this; } - /** - * {@inheritdoc} - */ + #[Override] final public function default($default) { $this->default = $default; @@ -185,9 +177,7 @@ final public function default($default) return $this; } - /** - * {@inheritdoc} - */ + #[Override] final public function depends(string ...$inputNames) { foreach ($inputNames as $inputName) { @@ -197,9 +187,7 @@ final public function depends(string ...$inputNames) return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function addParametersConfigurator(callable $configurator) { $this->parametersConfigurators[] = $configurator; @@ -207,9 +195,7 @@ public function addParametersConfigurator(callable $configurator) return $this; } - /** - * {@inheritdoc} - */ + #[Override] final public function buildChild(): ChildInterface { $parameters = $this->buildParameters(); @@ -467,13 +453,13 @@ final public function configure(callable $configurator): self /** * Forward call to element builder * - * @param callable|TransformerInterface|DataTransformerInterface $transformer + * @param callable|TransformerInterface $transformer * @param bool $append * @return $this * * @see ElementBuilderInterface::transformer() */ - public function transformer($transformer, bool $append = true) + public function transformer(callable|TransformerInterface $transformer, bool $append = true) { $this->elementBuilder->transformer($transformer, $append); @@ -485,14 +471,13 @@ public function transformer($transformer, bool $append = true) * * @return B */ + #[Override] final protected function getElementBuilder(): ElementBuilderInterface { return $this->elementBuilder; } - /** - * {@inheritdoc} - */ + #[Override] final protected function registry(): RegistryInterface { return $this->registry; diff --git a/src/Child/Http/ArrayOffsetHttpFields.php b/src/Child/Http/ArrayOffsetHttpFields.php index c60ab73..5cfdf9e 100644 --- a/src/Child/Http/ArrayOffsetHttpFields.php +++ b/src/Child/Http/ArrayOffsetHttpFields.php @@ -2,6 +2,8 @@ namespace Bdf\Form\Child\Http; +use Override; + /** * Extract HTTP fields value using a simple array offset * This is the default http fields implementation @@ -31,9 +33,7 @@ public function __construct(string $offset) $this->offset = $offset; } - /** - * {@inheritdoc} - */ + #[Override] public function extract($httpFields) { if (!is_array($httpFields) || !isset($httpFields[$this->offset])) { @@ -43,25 +43,19 @@ public function extract($httpFields) return $httpFields[$this->offset]; } - /** - * {@inheritdoc} - */ + #[Override] public function contains($httpFields): bool { return isset($httpFields[$this->offset]); } - /** - * {@inheritdoc} - */ + #[Override] public function format($value) { return [$this->offset => $value]; } - /** - * {@inheritdoc} - */ + #[Override] public function get(?HttpFieldPath $path = null): HttpFieldPath { return $path === null ? HttpFieldPath::named($this->offset) : $path->add($this->offset); diff --git a/src/Child/Http/HttpFieldPath.php b/src/Child/Http/HttpFieldPath.php index 5d76c3f..d3fbd6a 100644 --- a/src/Child/Http/HttpFieldPath.php +++ b/src/Child/Http/HttpFieldPath.php @@ -2,6 +2,7 @@ namespace Bdf\Form\Child\Http; +use Override; use Stringable; /** @@ -173,6 +174,7 @@ public function isRootField(): bool * * @return string */ + #[Override] public function __toString(): string { return $this->get(); diff --git a/src/Child/Http/PrefixedHttpFields.php b/src/Child/Http/PrefixedHttpFields.php index b660b17..3afdd0e 100644 --- a/src/Child/Http/PrefixedHttpFields.php +++ b/src/Child/Http/PrefixedHttpFields.php @@ -2,6 +2,8 @@ namespace Bdf\Form\Child\Http; +use Override; + /** * Extract HTTP fields value prefixed by a given string * @@ -32,9 +34,7 @@ public function __construct(string $prefix) $this->prefix = $prefix; } - /** - * {@inheritdoc} - */ + #[Override] public function extract($httpFields) { $data = (array) $httpFields; @@ -55,17 +55,13 @@ public function extract($httpFields) return $value; } - /** - * {@inheritdoc} - */ + #[Override] public function contains($httpFields): bool { return true; // Always true ? } - /** - * {@inheritdoc} - */ + #[Override] public function format($value) { $http = []; @@ -77,9 +73,7 @@ public function format($value) return $http; } - /** - * {@inheritdoc} - */ + #[Override] public function get(?HttpFieldPath $path = null): HttpFieldPath { return $path === null ? HttpFieldPath::prefixed($this->prefix) : $path->prefix($this->prefix); diff --git a/src/Choice/ArrayChoice.php b/src/Choice/ArrayChoice.php index eb86a9d..1754b24 100644 --- a/src/Choice/ArrayChoice.php +++ b/src/Choice/ArrayChoice.php @@ -2,6 +2,8 @@ namespace Bdf\Form\Choice; +use Override; + /** * Implementation of choice using an array * @@ -30,17 +32,13 @@ public function __construct(array $choices) $this->choices = $choices; } - /** - * {@inheritdoc} - */ + #[Override] public function values(): array { return $this->choices; } - /** - * {@inheritdoc} - */ + #[Override] public function view(?callable $configuration = null): array { $view = []; diff --git a/src/Choice/ChoiceBuilderTrait.php b/src/Choice/ChoiceBuilderTrait.php index fbc4612..e69cd1a 100644 --- a/src/Choice/ChoiceBuilderTrait.php +++ b/src/Choice/ChoiceBuilderTrait.php @@ -44,6 +44,8 @@ trait ChoiceBuilderTrait * * @param ChoiceInterface|array|callable $choices The allowed values in PHP form. * @param string|null $message The error message. + * @param non-negative-int $min + * @param positive-int $max * * @return $this * @see ChoiceConstraint diff --git a/src/Choice/LazyChoice.php b/src/Choice/LazyChoice.php index 4ba9332..8ddd9aa 100644 --- a/src/Choice/LazyChoice.php +++ b/src/Choice/LazyChoice.php @@ -2,6 +2,8 @@ namespace Bdf\Form\Choice; +use Override; + /** * Proxy choice using a callback for generate the choices array * @@ -36,17 +38,13 @@ public function __construct(callable $resolver) $this->resolver = $resolver; } - /** - * {@inheritdoc} - */ + #[Override] public function values(): array { return $this->build()->values(); } - /** - * {@inheritdoc} - */ + #[Override] public function view(?callable $configuration = null): array { return $this->build()->view($configuration); diff --git a/src/Constraint/ClosureValidator.php b/src/Constraint/ClosureValidator.php index 7bad05a..f100c57 100755 --- a/src/Constraint/ClosureValidator.php +++ b/src/Constraint/ClosureValidator.php @@ -2,6 +2,7 @@ namespace Bdf\Form\Constraint; +use Override; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; @@ -12,9 +13,7 @@ */ class ClosureValidator extends ConstraintValidator { - /** - * {@inheritdoc} - */ + #[Override] public function validate($value, Constraint $constraint): void { if (!$constraint instanceof Closure) { diff --git a/src/Csrf/CsrfConstraintValidator.php b/src/Csrf/CsrfConstraintValidator.php index 59bfaf6..a7c826a 100644 --- a/src/Csrf/CsrfConstraintValidator.php +++ b/src/Csrf/CsrfConstraintValidator.php @@ -2,6 +2,7 @@ namespace Bdf\Form\Csrf; +use Override; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -12,9 +13,7 @@ */ class CsrfConstraintValidator extends ConstraintValidator { - /** - * {@inheritdoc} - */ + #[Override] public function validate($value, Constraint $constraint): void { if (!$constraint instanceof CsrfConstraint) { diff --git a/src/Csrf/CsrfElement.php b/src/Csrf/CsrfElement.php index 11e11d0..b1efab3 100644 --- a/src/Csrf/CsrfElement.php +++ b/src/Csrf/CsrfElement.php @@ -11,6 +11,7 @@ use Bdf\Form\RootElementInterface; use Bdf\Form\Util\ContainerTrait; use Bdf\Form\View\ElementViewInterface; +use Override; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManager; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; @@ -72,9 +73,7 @@ public function __construct(?string $tokenId = null, ?CsrfValueValidator $valida $this->error = FormError::null(); } - /** - * {@inheritdoc} - */ + #[Override] public function submit($data): ElementInterface { $this->value = new CsrfToken($this->tokenId, $data); @@ -83,28 +82,20 @@ public function submit($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function patch($data): ElementInterface { // CSRF element must be submitted return $this->submit($data); } - /** - * {@inheritdoc} - */ + #[Override] public function import($entity): ElementInterface { throw new BadMethodCallException('Cannot set a Csrf token value'); } - /** - * {@inheritdoc} - * - * @return CsrfToken - */ + #[Override] public function value(): CsrfToken { if ($this->value) { @@ -114,49 +105,37 @@ public function value(): CsrfToken return $this->value = $this->tokenManager->getToken($this->tokenId); } - /** - * {@inheritdoc} - */ + #[Override] public function httpValue(): string { return $this->value()->getValue(); } - /** - * {@inheritdoc} - */ + #[Override] public function valid(): bool { return $this->value && $this->error->empty(); } - /** - * {@inheritdoc} - */ + #[Override] public function failed(): bool { return !$this->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function error(?HttpFieldPath $field = null): FormError { return $field ? $this->error->withField($field) : $this->error; } - /** - * {@inheritdoc} - */ + #[Override] public function root(): RootElementInterface { return ($container = $this->container()) ? $container->parent()->root() : new LeafRootElement($this); } - /** - * {@inheritdoc} - */ + #[Override] public function view(?HttpFieldPath $field = null): ElementViewInterface { return new SimpleElementView( diff --git a/src/Csrf/CsrfElementBuilder.php b/src/Csrf/CsrfElementBuilder.php index b85e18d..5565f47 100644 --- a/src/Csrf/CsrfElementBuilder.php +++ b/src/Csrf/CsrfElementBuilder.php @@ -148,6 +148,7 @@ public function validateOnSubForms(bool $validateOnSubForms = true): self /** * {@inheritdoc} */ + #[\Override] public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) { throw new BadMethodCallException(); @@ -156,6 +157,7 @@ public function satisfy(Constraint|callable $constraint, ?string $message = null /** * {@inheritdoc} */ + #[\Override] public function transformer(callable|TransformerInterface $transformer, bool $append = true) { throw new BadMethodCallException(); @@ -164,6 +166,7 @@ public function transformer(callable|TransformerInterface $transformer, bool $ap /** * {@inheritdoc} */ + #[\Override] public function value($value) { throw new BadMethodCallException(); @@ -172,6 +175,7 @@ public function value($value) /** * {@inheritdoc} */ + #[\Override] public function buildElement(): ElementInterface { return new CsrfElement( diff --git a/src/Csrf/CsrfValueValidator.php b/src/Csrf/CsrfValueValidator.php index 21888bf..15f6fe9 100644 --- a/src/Csrf/CsrfValueValidator.php +++ b/src/Csrf/CsrfValueValidator.php @@ -9,6 +9,8 @@ use Bdf\Form\Validator\ValueValidatorInterface; use Exception; +use Override; + use function method_exists; /** @@ -71,11 +73,12 @@ public function __construct(bool $invalidate = false, ?string $message = null, b * @param CsrfElement $element * @psalm-suppress MoreSpecificImplementedParamType */ + #[Override] public function validate($value, ElementInterface $element): FormError { $root = $element->root(); - if (method_exists($root, 'is') && $root->is(self::FLAG_DISABLE_CSRF_VALIDATION)) { + if ($root->is(self::FLAG_DISABLE_CSRF_VALIDATION)) { return FormError::null(); } @@ -92,26 +95,20 @@ public function validate($value, ElementInterface $element): FormError } } - /** - * {@inheritdoc} - */ + #[Override] public function onTransformerException(Exception $exception, $value, ElementInterface $element): FormError { // Ignore transformer exception: the CSRF token will be validated after return FormError::null(); } - /** - * {@inheritdoc} - */ + #[Override] public function constraints(): array { return []; // Does CsrfConstraint should be returns ? } - /** - * {@inheritdoc} - */ + #[Override] public function hasConstraints(): bool { return true; diff --git a/src/Custom/CustomForm.php b/src/Custom/CustomForm.php index af7916d..187201f 100644 --- a/src/Custom/CustomForm.php +++ b/src/Custom/CustomForm.php @@ -14,6 +14,7 @@ use Bdf\Form\RootElementInterface; use Bdf\Form\View\ElementViewInterface; use Iterator; +use Override; use WeakReference; use function method_exists; @@ -89,49 +90,37 @@ public function __construct(?FormBuilderInterface $builder = null) $this->builder = $builder ?? new FormBuilder(); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetGet($offset): ChildInterface { return $this->form()[$offset]; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetExists($offset): bool { return isset($this->form()[$offset]); } - /** - * {@inheritdoc} - */ + #[Override] public function offsetSet($offset, $value): void { $this->form()[$offset] = $value; } - /** - * {@inheritdoc} - */ + #[Override] public function offsetUnset($offset): void { unset($this->form()[$offset]); } - /** - * {@inheritdoc} - */ + #[Override] public function getIterator(): Iterator { return $this->form()->getIterator(); } - /** - * {@inheritdoc} - */ + #[Override] public function submit($data): ElementInterface { $this->submitTarget()->submit($data); @@ -139,9 +128,7 @@ public function submit($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function patch($data): ElementInterface { $this->submitTarget()->patch($data); @@ -149,9 +136,7 @@ public function patch($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function import($entity): ElementInterface { $this->form()->import($entity); @@ -159,58 +144,44 @@ public function import($entity): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function value() { return $this->form()->value(); } - /** - * {@inheritdoc} - */ + #[Override] public function httpValue() { return $this->form()->httpValue(); } - /** - * {@inheritdoc} - */ + #[Override] public function valid(): bool { return $this->form()->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function failed(): bool { // Do not use $this->form()->failed() because it may be not implemented return !$this->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function error(?HttpFieldPath $field = null): FormError { return $this->form()->error($field); } - /** - * {@inheritdoc} - */ + #[Override] public function container(): ?ChildInterface { - return $this->container ? $this->container->get() : null; + return $this->container?->get(); } - /** - * {@inheritdoc} - */ + #[Override] public function setContainer(ChildInterface $container): ElementInterface { $form = clone $this; @@ -220,18 +191,14 @@ public function setContainer(ChildInterface $container): ElementInterface return $form; } - /** - * {@inheritdoc} - */ + #[Override] public function root(): RootElementInterface { // @todo bad root form ? return $this->form()->root(); } - /** - * {@inheritdoc} - */ + #[Override] public function attach($entity): FormInterface { $this->form()->attach($entity); @@ -239,10 +206,8 @@ public function attach($entity): FormInterface return $this; } - /** - * {@inheritdoc} - */ - public function view(?HttpFieldPath $field = null): ElementViewInterface + #[Override] + public function view(?HttpFieldPath $field = null): FormView { $form = $this->form(); /** @var FormView $view */ @@ -322,11 +287,7 @@ final public function setPostConfigureHooks(array $hooks): void */ final public function disableCsrfValidation(): void { - $root = $this->root(); - - if (method_exists($root, 'set')) { - $root->set(CsrfValueValidator::FLAG_DISABLE_CSRF_VALIDATION, true); - } + $this->root()->set(CsrfValueValidator::FLAG_DISABLE_CSRF_VALIDATION, true); } /** diff --git a/src/Custom/CustomFormBuilder.php b/src/Custom/CustomFormBuilder.php index 7ae5ad4..261d8bc 100644 --- a/src/Custom/CustomFormBuilder.php +++ b/src/Custom/CustomFormBuilder.php @@ -6,9 +6,9 @@ use Bdf\Form\Aggregate\FormBuilderInterface; use Bdf\Form\Aggregate\FormInterface; use Bdf\Form\ElementBuilderInterface; -use Bdf\Form\ElementInterface; use Bdf\Form\Registry\RegistryInterface; use Bdf\Form\Util\DelegateElementBuilderTrait; +use Override; use function is_string; @@ -66,12 +66,8 @@ public function __construct($formFactory, ?FormBuilderInterface $builder = null) $this->builder = $builder ?: new FormBuilder(); } - /** - * {@inheritdoc} - * - * @return CustomForm - */ - public function buildElement(): ElementInterface + #[Override] + public function buildElement(): CustomForm { if (is_string($this->formFactory)) { /** @var class-string $className */ @@ -128,9 +124,7 @@ public function postConfigure(callable $hook): self return $this; } - /** - * {@inheritdoc} - */ + #[Override] protected function getElementBuilder(): ElementBuilderInterface { return $this->builder; diff --git a/src/Error/FormError.php b/src/Error/FormError.php index 6ea6909..a0ee840 100644 --- a/src/Error/FormError.php +++ b/src/Error/FormError.php @@ -6,6 +6,7 @@ use Bdf\Form\Child\Http\HttpFieldPath; use Bdf\Form\ElementInterface; use InvalidArgumentException; +use Override; use Stringable; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationInterface; @@ -129,7 +130,7 @@ public function get(string $child): ?string { $child = $this->children[$child] ?? null; - return $child ? $child->global : null; + return $child?->global; } /** @@ -207,6 +208,7 @@ public function print(FormErrorPrinterInterface $printer) * * @return string */ + #[Override] public function __toString(): string { return $this->print(new StringErrorPrinter()); diff --git a/src/Error/ImplodeErrorPrinter.php b/src/Error/ImplodeErrorPrinter.php index 98810e8..c11edf0 100644 --- a/src/Error/ImplodeErrorPrinter.php +++ b/src/Error/ImplodeErrorPrinter.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Error; use Bdf\Form\Child\Http\HttpFieldPath; +use Override; /** * Implode all errors into a string @@ -43,33 +44,25 @@ public function __construct(string $separator = PHP_EOL) $this->separator = $separator; } - /** - * {@inheritdoc} - */ + #[Override] public function field(HttpFieldPath $field): void { // Ignore field name } - /** - * {@inheritdoc} - */ + #[Override] public function global(string $error): void { $this->lines[] = $error; } - /** - * {@inheritdoc} - */ + #[Override] public function code(string $code): void { // Ignore code } - /** - * {@inheritdoc} - */ + #[Override] public function child(string $name, FormError $error): void { $this->inChild = true; @@ -77,9 +70,7 @@ public function child(string $name, FormError $error): void $this->inChild = false; } - /** - * {@inheritdoc} - */ + #[Override] public function print() { return $this->inChild ? null : implode($this->separator, $this->lines); diff --git a/src/Error/StringErrorPrinter.php b/src/Error/StringErrorPrinter.php index c522a2c..93d9b00 100644 --- a/src/Error/StringErrorPrinter.php +++ b/src/Error/StringErrorPrinter.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Error; use Bdf\Form\Child\Http\HttpFieldPath; +use Override; /** * Format errors as a string @@ -39,33 +40,25 @@ final class StringErrorPrinter implements FormErrorPrinterInterface */ private $output = ''; - /** - * {@inheritdoc} - */ + #[Override] public function field(HttpFieldPath $field): void { // Ignore the field name } - /** - * {@inheritdoc} - */ + #[Override] public function global(string $error): void { $this->output .= $error; } - /** - * {@inheritdoc} - */ + #[Override] public function code(string $code): void { // Ignore code } - /** - * {@inheritdoc} - */ + #[Override] public function child(string $name, FormError $error): void { if ($this->maxDepth <= $this->depth) { @@ -83,9 +76,7 @@ public function child(string $name, FormError $error): void --$this->depth; } - /** - * {@inheritdoc} - */ + #[Override] public function print() { return $this->output; diff --git a/src/Filter/ClosureFilter.php b/src/Filter/ClosureFilter.php index ad30011..1e416d1 100755 --- a/src/Filter/ClosureFilter.php +++ b/src/Filter/ClosureFilter.php @@ -4,6 +4,7 @@ use Bdf\Form\Child\ChildBuilderInterface; use Bdf\Form\Child\ChildInterface; +use Override; /** * Adapt a simple callback to FilterInterface @@ -33,9 +34,7 @@ public function __construct(callable $callback) $this->callback = $callback; } - /** - * {@inheritdoc} - */ + #[Override] public function filter($value, ChildInterface $input, $default) { return ($this->callback)($value, $input, $default); diff --git a/src/Filter/EmptyArrayValuesFilter.php b/src/Filter/EmptyArrayValuesFilter.php index 3910b7a..e177f5e 100644 --- a/src/Filter/EmptyArrayValuesFilter.php +++ b/src/Filter/EmptyArrayValuesFilter.php @@ -5,6 +5,7 @@ use Attribute; use Bdf\Form\Aggregate\ArrayChildBuilder; use Bdf\Form\Child\ChildInterface; +use Override; /** * Filter empty values from an array @@ -19,9 +20,7 @@ final class EmptyArrayValuesFilter implements FilterInterface */ private static $instance; - /** - * {@inheritdoc} - */ + #[Override] public function filter($value, ChildInterface $input, $default) { if (!is_array($value)) { diff --git a/src/Filter/FilterVar.php b/src/Filter/FilterVar.php index f2d37fc..b0083b6 100644 --- a/src/Filter/FilterVar.php +++ b/src/Filter/FilterVar.php @@ -5,6 +5,8 @@ use Attribute; use Bdf\Form\Child\ChildInterface; +use Override; + use function filter_var; use function is_array; use function is_scalar; @@ -48,9 +50,7 @@ public function __construct(int $filter = self::HTML_FILTER, int $flags = FILTER $this->flags = $flags; } - /** - * {@inheritdoc} - */ + #[Override] public function filter($value, ChildInterface $input, $default) { if (!is_array($value)) { diff --git a/src/Filter/TrimFilter.php b/src/Filter/TrimFilter.php index e1d9865..33c2bc8 100644 --- a/src/Filter/TrimFilter.php +++ b/src/Filter/TrimFilter.php @@ -5,6 +5,7 @@ use Attribute; use Bdf\Form\Child\ChildBuilder; use Bdf\Form\Child\ChildInterface; +use Override; /** * Perform a trim on the input value @@ -20,9 +21,7 @@ final class TrimFilter implements FilterInterface */ private static $instance; - /** - * {@inheritdoc} - */ + #[Override] public function filter($value, ChildInterface $input, $default) { if (!is_string($value)) { diff --git a/src/Leaf/AbstractBooleanElement.php b/src/Leaf/AbstractBooleanElement.php index 1bab391..4b19716 100644 --- a/src/Leaf/AbstractBooleanElement.php +++ b/src/Leaf/AbstractBooleanElement.php @@ -2,6 +2,7 @@ namespace Bdf\Form\Leaf; +use Override; use TypeError; use function is_scalar; @@ -16,11 +17,7 @@ */ abstract class AbstractBooleanElement extends LeafElement { - /** - * {@inheritdoc} - * - * @return bool|null - */ + #[Override] final protected function tryCast($value): ?bool { if ($value === null) { diff --git a/src/Leaf/AnyElement.php b/src/Leaf/AnyElement.php index 31accc0..6378b58 100644 --- a/src/Leaf/AnyElement.php +++ b/src/Leaf/AnyElement.php @@ -2,6 +2,8 @@ namespace Bdf\Form\Leaf; +use Override; + /** * Element which supports any type of values * This element allow to perform any type transformation from transformers on the form declaration @@ -13,25 +15,19 @@ */ class AnyElement extends LeafElement { - /** - * {@inheritdoc} - */ + #[Override] protected function toPhp($httpValue) { return $httpValue; } - /** - * {@inheritdoc} - */ + #[Override] protected function toHttp($phpValue) { return $phpValue; } - /** - * {@inheritdoc} - */ + #[Override] protected function sanitize($rawValue) { return $rawValue; diff --git a/src/Leaf/AnyElementBuilder.php b/src/Leaf/AnyElementBuilder.php index 9b1d0bb..bbf1c5a 100644 --- a/src/Leaf/AnyElementBuilder.php +++ b/src/Leaf/AnyElementBuilder.php @@ -7,6 +7,7 @@ use Bdf\Form\ElementInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; +use Override; /** * Builder for any element @@ -19,10 +20,8 @@ class AnyElementBuilder extends AbstractElementBuilder { use ChoiceBuilderTrait; - /** - * {@inheritdoc} - */ - protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + #[Override] + protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): AnyElement { return new AnyElement($validator, $transformer, $this->getChoices()); } diff --git a/src/Leaf/BooleanElement.php b/src/Leaf/BooleanElement.php index b8494d5..30f9a8f 100644 --- a/src/Leaf/BooleanElement.php +++ b/src/Leaf/BooleanElement.php @@ -8,6 +8,7 @@ use Bdf\Form\Validator\ValueValidatorInterface; use Bdf\Form\View\ElementViewInterface; use Bdf\Form\View\FieldViewInterface; +use Override; /** * Handle a boolean value, like with checkbox input @@ -36,28 +37,20 @@ public function __construct(?ValueValidatorInterface $validator = null, ?Transfo $this->httpValue = $httpValue; } - /** - * {@inheritdoc} - */ - protected function toPhp($httpValue) + #[Override] + protected function toPhp($httpValue): bool { return (bool) $httpValue; } - /** - * {@inheritdoc} - */ + #[Override] protected function toHttp($phpValue) { return $phpValue ? $this->httpValue : null; } - /** - * {@inheritdoc} - * - * @return FieldViewInterface - */ - public function view(?HttpFieldPath $field = null): ElementViewInterface + #[Override] + public function view(?HttpFieldPath $field = null): FieldViewInterface { return new BooleanElementView(self::class, (string) $field, $this->httpValue(), $this->httpValue, (bool) $this->value(), $this->error()->global()); } diff --git a/src/Leaf/BooleanElementBuilder.php b/src/Leaf/BooleanElementBuilder.php index c70759c..73cbbf8 100644 --- a/src/Leaf/BooleanElementBuilder.php +++ b/src/Leaf/BooleanElementBuilder.php @@ -8,6 +8,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; use InvalidArgumentException; +use Override; /** * Builder for a boolean element @@ -83,10 +84,8 @@ public function booleanString(bool $flag = true): self return $this; } - /** - * {@inheritdoc} - */ - protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + #[Override] + protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): BooleanStringElement|BooleanElement { return $this->booleanString ? new BooleanStringElement($validator, $transformer) diff --git a/src/Leaf/BooleanStringElement.php b/src/Leaf/BooleanStringElement.php index b50b3b1..a794a8d 100644 --- a/src/Leaf/BooleanStringElement.php +++ b/src/Leaf/BooleanStringElement.php @@ -2,6 +2,8 @@ namespace Bdf\Form\Leaf; +use Override; + use function filter_var; use function is_bool; @@ -25,17 +27,14 @@ class BooleanStringElement extends AbstractBooleanElement * @psalm-suppress ImplementedReturnTypeMismatch * @psalm-suppress LessSpecificImplementedReturnType */ - protected function sanitize($rawValue) + #[Override] + protected function sanitize($rawValue): int|float|string|bool|null { // Does not cast to string, to allow boolean value return is_scalar($rawValue) ? $rawValue : null; } - /** - * {@inheritdoc} - * - * @return bool|null - */ + #[Override] protected function toPhp($httpValue): ?bool { if ($httpValue === null || $httpValue === '') { @@ -50,9 +49,7 @@ protected function toPhp($httpValue): ?bool return filter_var((string) $httpValue, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); } - /** - * {@inheritdoc} - */ + #[Override] protected function toHttp($phpValue): ?string { if ($phpValue === null) { diff --git a/src/Leaf/Date/DateTimeElement.php b/src/Leaf/Date/DateTimeElement.php index 8c5c141..5bc27aa 100644 --- a/src/Leaf/Date/DateTimeElement.php +++ b/src/Leaf/Date/DateTimeElement.php @@ -10,6 +10,7 @@ use DateTimeInterface; use DateTimeZone; use InvalidArgumentException; +use Override; use TypeError; /** @@ -84,9 +85,7 @@ public function dateTimeClassName(): string return $this->className; } - /** - * {@inheritdoc} - */ + #[Override] protected function toPhp($httpValue): ?DateTimeInterface { if ($httpValue === null || $httpValue === '') { @@ -129,9 +128,7 @@ protected function toPhp($httpValue): ?DateTimeInterface return $dateTime; } - /** - * {@inheritdoc} - */ + #[Override] protected function toHttp($phpValue) { // Because of legacy behavior, the raw value can be saved when a transformer failed @@ -148,11 +145,7 @@ protected function toHttp($phpValue) return $phpValue->format($this->format); } - /** - * {@inheritdoc} - * - * @return DateTimeInterface|null - */ + #[Override] protected function tryCast($value): ?DateTimeInterface { if ($value === null) { diff --git a/src/Leaf/Date/DateTimeElementBuilder.php b/src/Leaf/Date/DateTimeElementBuilder.php index e101d46..7d41545 100644 --- a/src/Leaf/Date/DateTimeElementBuilder.php +++ b/src/Leaf/Date/DateTimeElementBuilder.php @@ -9,7 +9,6 @@ use Bdf\Form\Constraint\GreaterThanOrEqualField; use Bdf\Form\Constraint\LessThanField; use Bdf\Form\Constraint\LessThanOrEqualField; -use Bdf\Form\ElementInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Util\FieldPath; use Bdf\Form\Validator\TransformerExceptionConstraint; @@ -18,6 +17,7 @@ use DateTimeImmutable; use DateTimeInterface; use DateTimeZone; +use Override; use Symfony\Component\Validator\Constraints\GreaterThan; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\LessThan; @@ -290,35 +290,17 @@ public function resetNotProvidedFields(bool $flag = true): self return $this; } - /** - * {@inheritdoc} - */ - protected function defaultTransformerExceptionConstraintOptions(): array - { - return [ - 'message' => 'This value is not a valid datetime.', - 'code' => 'INVALID_DATETIME_ERROR', - ]; - } - - /** - * {@inheritdoc} - */ + #[Override] protected function defaultTransformerExceptionConstraint(): TransformerExceptionConstraint { return new TransformerExceptionConstraint( - null, - /*message:*/ 'This value is not a valid datetime.', - /*code:*/ 'INVALID_DATETIME_ERROR', + message: 'This value is not a valid datetime.', + code: 'INVALID_DATETIME_ERROR', ); } - /** - * {@inheritdoc} - * - * @return DateTimeElement - */ - protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + #[Override] + protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): DateTimeElement { return new DateTimeElement( $validator, diff --git a/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php b/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php index 4a10163..7580d3b 100644 --- a/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php +++ b/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php @@ -10,6 +10,10 @@ use DateTimeInterface; use DateTimeZone; use InvalidArgumentException; +use Override; + +use function assert; +use function method_exists; /** * Transform a DateTime instance from a form element to a timestamp to a model @@ -40,12 +44,7 @@ public function __construct(?string $className = null, ?DateTimeZone $timezone = $this->timezone = $timezone; } - /** - * {@inheritdoc} - * - * @psalm-suppress UndefinedInterfaceMethod - * @psalm-suppress PossiblyUndefinedMethod - */ + #[Override] public function transformToHttp($value, ElementInterface $input): ?DateTimeInterface { if ($value === null) { @@ -63,15 +62,15 @@ public function transformToHttp($value, ElementInterface $input): ?DateTimeInter $dateTime = new $className; if ($timezone) { + assert(method_exists($dateTime, 'setTimezone')); $dateTime = $dateTime->setTimezone($timezone); } + assert(method_exists($dateTime, 'setTimestamp')); return $dateTime->setTimestamp($value); } - /** - * {@inheritdoc} - */ + #[Override] public function transformFromHttp($value, ElementInterface $input): ?int { if (!$value instanceof DateTimeInterface) { diff --git a/src/Leaf/FloatElement.php b/src/Leaf/FloatElement.php index b6ec00c..2d4f5fd 100644 --- a/src/Leaf/FloatElement.php +++ b/src/Leaf/FloatElement.php @@ -2,6 +2,7 @@ namespace Bdf\Form\Leaf; +use Override; use TypeError; /** @@ -13,29 +14,19 @@ */ class FloatElement extends LeafElement { - /** - * {@inheritdoc} - * - * @return float|null - */ + #[Override] protected function toPhp($httpValue): ?float { return $httpValue === null || $httpValue === '' ? null : (float) $httpValue; } - /** - * {@inheritdoc} - */ + #[Override] protected function toHttp($phpValue): ?string { return $phpValue === null ? null : (string) $phpValue; } - /** - * {@inheritdoc} - * - * @return float|null - */ + #[Override] protected function tryCast($value): ?float { if ($value === null) { diff --git a/src/Leaf/FloatElementBuilder.php b/src/Leaf/FloatElementBuilder.php index 158a622..ce4a072 100644 --- a/src/Leaf/FloatElementBuilder.php +++ b/src/Leaf/FloatElementBuilder.php @@ -8,6 +8,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; use NumberFormatter; +use Override; /** * Builder for a float element @@ -91,17 +92,13 @@ public function scale(int $scale): self return $this; } - /** - * {@inheritdoc} - */ - protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + #[Override] + protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): FloatElement { return new FloatElement($validator, $transformer, $this->getChoices()); } - /** - * {@inheritdoc} - */ + #[Override] protected function numberTransformer(): TransformerInterface { return new LocalizedNumberTransformer($this->scale, $this->grouping, $this->roundingMode); diff --git a/src/Leaf/Helper/EmailElementBuilder.php b/src/Leaf/Helper/EmailElementBuilder.php index 5fcd532..fea2172 100644 --- a/src/Leaf/Helper/EmailElementBuilder.php +++ b/src/Leaf/Helper/EmailElementBuilder.php @@ -7,6 +7,7 @@ use Bdf\Form\Registry\RegistryInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; +use Override; use Symfony\Component\Validator\Constraints\Email; /** @@ -29,6 +30,10 @@ class EmailElementBuilder extends StringElementBuilder private $useConstraint = true; private ?string $errorMessage = null; + + /** + * @var value-of|null + */ private ?string $mode = null; /** @@ -52,7 +57,7 @@ public function __construct(?RegistryInterface $registry = null) * The validation mode * See Email::VALIDATION_MODE_* constants * - * @param string $mode + * @param value-of $mode * * @return $this * @@ -125,11 +130,13 @@ public function disableConstraint(): self * $builder->email('contact')->useConstraint(mode: Email::VALIDATION_MODE_HTML5, message: 'my error'); * * + * @param value-of $mode + * * @return $this * * @see Email for list of options */ - public function useConstraint(?string $message = null, ?string $mode = null, ?string $normalizer = null): self + public function useConstraint(?string $message = null, ?string $mode = null, ?callable $normalizer = null): self { $this->useConstraint = true; $this->errorMessage = $message; @@ -157,10 +164,8 @@ protected function createEmailConstraint(RegistryInterface $registry): array ]; } - /** - * {@inheritdoc} - */ - protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + #[Override] + protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): EmailElement { return new EmailElement($validator, $transformer, $this->getChoices()); } diff --git a/src/Leaf/Helper/UrlElementBuilder.php b/src/Leaf/Helper/UrlElementBuilder.php index 343f105..8f25339 100644 --- a/src/Leaf/Helper/UrlElementBuilder.php +++ b/src/Leaf/Helper/UrlElementBuilder.php @@ -7,6 +7,7 @@ use Bdf\Form\Registry\RegistryInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; +use Override; use Symfony\Component\Validator\Constraints\Url; use function is_string; @@ -163,7 +164,6 @@ public function useConstraint(?string $message = null, string|array|null $protoc /** * @return \Symfony\Component\Validator\Constraint[] - * @psalm-suppress TooManyArguments */ protected function createUrlConstraint(RegistryInterface $registry): array { @@ -183,10 +183,8 @@ protected function createUrlConstraint(RegistryInterface $registry): array ]; } - /** - * {@inheritdoc} - */ - protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + #[Override] + protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): UrlElement { return new UrlElement($validator, $transformer, $this->getChoices()); } diff --git a/src/Leaf/IntegerElement.php b/src/Leaf/IntegerElement.php index 250bf4c..cae3fcf 100644 --- a/src/Leaf/IntegerElement.php +++ b/src/Leaf/IntegerElement.php @@ -2,6 +2,7 @@ namespace Bdf\Form\Leaf; +use Override; use TypeError; /** @@ -13,29 +14,19 @@ */ class IntegerElement extends LeafElement { - /** - * {@inheritdoc} - * - * @return int|null - */ + #[Override] protected function toPhp($httpValue): ?int { return $httpValue === null || $httpValue === '' ? null : (int) $httpValue; } - /** - * {@inheritdoc} - */ + #[Override] protected function toHttp($phpValue): ?string { return $phpValue === null ? null : (string) $phpValue; } - /** - * {@inheritdoc} - * - * @return int|null - */ + #[Override] protected function tryCast($value): ?int { if ($value === null) { diff --git a/src/Leaf/IntegerElementBuilder.php b/src/Leaf/IntegerElementBuilder.php index 247ece0..c1da565 100644 --- a/src/Leaf/IntegerElementBuilder.php +++ b/src/Leaf/IntegerElementBuilder.php @@ -8,6 +8,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; use NumberFormatter; +use Override; /** * Builder for an integer element @@ -70,17 +71,13 @@ public function roundingMode(int $mode): self return $this; } - /** - * {@inheritdoc} - */ - protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + #[Override] + protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): IntegerElement { return new IntegerElement($validator, $transformer, $this->getChoices()); } - /** - * {@inheritdoc} - */ + #[Override] protected function numberTransformer(): TransformerInterface { return new LocalizedIntegerTransformer($this->grouping, $this->roundingMode); diff --git a/src/Leaf/LeafElement.php b/src/Leaf/LeafElement.php index 8ea0f80..08acc75 100644 --- a/src/Leaf/LeafElement.php +++ b/src/Leaf/LeafElement.php @@ -19,6 +19,7 @@ use Bdf\Form\View\ElementViewInterface; use Bdf\Form\View\FieldViewInterface; use Exception; +use Override; use Symfony\Component\Validator\Constraints\NotBlank; /** @@ -81,9 +82,7 @@ public function __construct(?ValueValidatorInterface $validator = null, ?Transfo $this->choices = $choices; } - /** - * {@inheritdoc} - */ + #[Override] final public function submit($data): ElementInterface { $shouldBeValidated = true; @@ -105,9 +104,7 @@ final public function submit($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] final public function patch($data): ElementInterface { // A data is provided : simply submit the data @@ -122,33 +119,25 @@ final public function patch($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] final public function valid(): bool { return $this->submitted && $this->error->empty(); } - /** - * {@inheritdoc} - */ + #[Override] final public function failed(): bool { return !$this->valid(); } - /** - * {@inheritdoc} - */ + #[Override] final public function error(?HttpFieldPath $field = null): FormError { return $field ? $this->error->withField($field) : $this->error; } - /** - * {@inheritdoc} - */ + #[Override] final public function import($entity): ElementInterface { $this->value = $this->tryCast($entity); @@ -156,17 +145,13 @@ final public function import($entity): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] final public function value() { return $this->value; } - /** - * {@inheritdoc} - */ + #[Override] final public function httpValue() { try { @@ -176,9 +161,7 @@ final public function httpValue() } } - /** - * {@inheritdoc} - */ + #[Override] final public function root(): RootElementInterface { if ($container = $this->container()) { @@ -189,12 +172,8 @@ final public function root(): RootElementInterface return new LeafRootElement($this); } - /** - * {@inheritdoc} - * - * @return FieldViewInterface - */ - public function view(?HttpFieldPath $field = null): ElementViewInterface + #[Override] + public function view(?HttpFieldPath $field = null): FieldViewInterface { [$required, $normalizedConstraints] = $this->parseConstraints($this->validator); @@ -209,9 +188,7 @@ public function view(?HttpFieldPath $field = null): ElementViewInterface ); } - /** - * {@inheritdoc} - */ + #[Override] final public function choices(): ?ChoiceInterface { return $this->choices; @@ -258,6 +235,7 @@ protected function tryCast($value) * @param mixed $rawValue The raw HTTP value * * @return string|null + * @todo return mixed ? */ protected function sanitize($rawValue) { diff --git a/src/Leaf/LeafRootElement.php b/src/Leaf/LeafRootElement.php index f9faf9d..7869383 100644 --- a/src/Leaf/LeafRootElement.php +++ b/src/Leaf/LeafRootElement.php @@ -12,6 +12,7 @@ use Bdf\Form\Util\RootFlagsTrait; use Bdf\Form\View\ElementViewInterface; use OutOfBoundsException; +use Override; use Symfony\Component\PropertyAccess\PropertyAccessor; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Validator\Constraint; @@ -42,9 +43,7 @@ public function __construct(ElementInterface $element) $this->element = $element; } - /** - * {@inheritdoc} - */ + #[Override] public function submit($data): ElementInterface { $this->element->submit($data); @@ -52,9 +51,7 @@ public function submit($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function patch($data): ElementInterface { $this->element->patch($data); @@ -62,9 +59,7 @@ public function patch($data): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function import($entity): ElementInterface { $this->element->import($entity); @@ -72,114 +67,86 @@ public function import($entity): ElementInterface return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function value() { return $this->element->value(); } - /** - * {@inheritdoc} - */ + #[Override] public function httpValue() { return $this->element->httpValue(); } - /** - * {@inheritdoc} - */ + #[Override] public function valid(): bool { return $this->element->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function failed(): bool { // Do not use $this->element->failed() because it may be not implemented return !$this->valid(); } - /** - * {@inheritdoc} - */ + #[Override] public function error(?HttpFieldPath $field = null): FormError { return $this->element->error($field); } - /** - * {@inheritdoc} - */ + #[Override] public function container(): ?ChildInterface { return null; } - /** - * {@inheritdoc} - */ + #[Override] public function setContainer(ChildInterface $container): ElementInterface { throw new BadMethodCallException('Cannot set a container on a root element'); } - /** - * {@inheritdoc} - */ + #[Override] public function root(): RootElementInterface { return $this; } - /** - * {@inheritdoc} - */ + #[Override] public function view(?HttpFieldPath $field = null): ElementViewInterface { return $this->element->view($field); } - /** - * {@inheritdoc} - */ + #[Override] public function submitButton(): ?ButtonInterface { return null; } - /** - * {@inheritdoc} - */ + #[Override] public function button(string $name): ButtonInterface { throw new OutOfBoundsException('A leaf element do not have any buttons'); } - /** - * {@inheritdoc} - */ + #[Override] public function getValidator(): ValidatorInterface { return (new ValidatorBuilder())->getValidator(); } - /** - * {@inheritdoc} - */ + #[Override] public function getPropertyAccessor(): PropertyAccessorInterface { return new PropertyAccessor(); } - /** - * {@inheritdoc} - */ + #[Override] public function constraintGroups(): array { return [Constraint::DEFAULT_GROUP]; diff --git a/src/Leaf/NumberElementBuilder.php b/src/Leaf/NumberElementBuilder.php index cf9866d..f759902 100644 --- a/src/Leaf/NumberElementBuilder.php +++ b/src/Leaf/NumberElementBuilder.php @@ -7,6 +7,7 @@ use Bdf\Form\Registry\RegistryInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\TransformerExceptionConstraint; +use Override; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\LessThanOrEqual; use Symfony\Component\Validator\Constraints\Positive; @@ -99,9 +100,7 @@ public function raw(bool $flag = true): self return $this; } - /** - * {@inheritdoc} - */ + #[Override] protected function defaultTransformerExceptionConstraint(): TransformerExceptionConstraint { return new TransformerExceptionConstraint( diff --git a/src/Leaf/StringElement.php b/src/Leaf/StringElement.php index 457d2f9..82d1592 100644 --- a/src/Leaf/StringElement.php +++ b/src/Leaf/StringElement.php @@ -2,8 +2,8 @@ namespace Bdf\Form\Leaf; +use Override; use TypeError; -use function Webmozart\Assert\Tests\StaticAnalysis\string; /** * Element for a simple string field @@ -14,11 +14,7 @@ */ class StringElement extends LeafElement { - /** - * {@inheritdoc} - * - * @return string|null - */ + #[Override] protected function toPhp($httpValue): ?string { if (!is_scalar($httpValue)) { @@ -28,19 +24,13 @@ protected function toPhp($httpValue): ?string return (string) $httpValue; } - /** - * {@inheritdoc} - */ + #[Override] protected function toHttp($phpValue): ?string { return $phpValue; } - /** - * {@inheritdoc} - * - * @return string|null - */ + #[Override] protected function tryCast($value): ?string { if ($value === null) { diff --git a/src/Leaf/StringElementBuilder.php b/src/Leaf/StringElementBuilder.php index 92c2a7c..4fadb76 100644 --- a/src/Leaf/StringElementBuilder.php +++ b/src/Leaf/StringElementBuilder.php @@ -8,6 +8,7 @@ use Bdf\Form\ElementInterface; use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ValueValidatorInterface; +use Override; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\Regex; @@ -39,6 +40,11 @@ class StringElementBuilder extends AbstractElementBuilder * $builder->length(max: 256); * * + * @param positive-int $exactly + * @param non-negative-int $min + * @param positive-int $max + * @param value-of|null $countUnit + * * @return $this * * @see Length For options @@ -69,7 +75,7 @@ public function length(?int $exactly = null, ?int $min = null, ?int $max = null, * $builder->regex('/[a-z_-]+/', message: 'Invalid value'); // With custom options * * - * @param string|array $pattern + * @param string $pattern * * @return $this * @@ -88,9 +94,7 @@ public function regex(string $pattern, ?string $message = null, ?string $htmlPat ); } - /** - * {@inheritdoc} - */ + #[Override] protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface { return new StringElement($validator, $transformer, $this->getChoices()); diff --git a/src/Leaf/Transformer/LocalizedIntegerTransformer.php b/src/Leaf/Transformer/LocalizedIntegerTransformer.php index ccbf4fd..3925822 100644 --- a/src/Leaf/Transformer/LocalizedIntegerTransformer.php +++ b/src/Leaf/Transformer/LocalizedIntegerTransformer.php @@ -4,6 +4,7 @@ use Attribute; use NumberFormatter; +use Override; /** * Localized number transformer for integer value @@ -25,9 +26,7 @@ public function __construct(bool $grouping = false, int $roundingMode = NumberFo parent::__construct(0, $grouping, $roundingMode, $locale); } - /** - * {@inheritdoc} - */ + #[Override] protected function cast($value): int { return $value; diff --git a/src/Leaf/Transformer/LocalizedNumberTransformer.php b/src/Leaf/Transformer/LocalizedNumberTransformer.php index f3700e3..5c170c4 100644 --- a/src/Leaf/Transformer/LocalizedNumberTransformer.php +++ b/src/Leaf/Transformer/LocalizedNumberTransformer.php @@ -9,6 +9,9 @@ use Locale; use NumberFormatter; +use Override; + +use function is_int; use function is_string; /** @@ -70,6 +73,7 @@ public function __construct(?int $scale = null, bool $grouping = false, int $rou * * @throws InvalidArgumentException If the given value is not numeric or cannot be formatted */ + #[Override] final public function transformToHttp($value, ElementInterface $input): ?string { if ($value === null) { @@ -102,6 +106,7 @@ final public function transformToHttp($value, ElementInterface $input): ?string * * @throws InvalidArgumentException If the given value is not scalar or cannot be parsed */ + #[Override] final public function transformFromHttp($value, ElementInterface $input) { if ($value !== null && !is_int($value) && !is_float($value) && !is_string($value)) { @@ -158,7 +163,7 @@ private function getNumberFormatter(): NumberFormatter * * @return T */ - protected function cast($value) + protected function cast($value): float|int|string { return $value; } @@ -170,7 +175,7 @@ protected function cast($value) * * @return int|float The rounded number */ - private function round($number) + private function round(int|float $number): int|float { if (is_int($number) || $this->scale === null) { return $number; @@ -185,7 +190,7 @@ private function round($number) return round($number, $this->scale, PHP_ROUND_HALF_DOWN); } - $coef = 10 ** $this->scale; + $coef = (float) (10 ** $this->scale); $number *= $coef; switch ($this->roundingMode) { diff --git a/src/Leaf/View/BooleanElementView.php b/src/Leaf/View/BooleanElementView.php index c46f5d03..78758b3 100644 --- a/src/Leaf/View/BooleanElementView.php +++ b/src/Leaf/View/BooleanElementView.php @@ -7,6 +7,7 @@ use Bdf\Form\View\FieldViewInterface; use Bdf\Form\View\FieldViewRendererInterface; use Bdf\Form\View\FieldViewTrait; +use Override; /** * Element view for boolean / checkbox @@ -70,9 +71,7 @@ public function checked(): bool return $this->checked; } - /** - * {@inheritdoc} - */ + #[Override] protected function defaultRenderer(): FieldViewRendererInterface { return CheckboxHtmlRenderer::instance(); diff --git a/src/Leaf/View/CheckboxHtmlRenderer.php b/src/Leaf/View/CheckboxHtmlRenderer.php index 473e216..079898c 100644 --- a/src/Leaf/View/CheckboxHtmlRenderer.php +++ b/src/Leaf/View/CheckboxHtmlRenderer.php @@ -5,6 +5,7 @@ use Bdf\Form\View\FieldViewInterface; use Bdf\Form\View\FieldViewRendererInterface; use Bdf\Form\View\HtmlRenderer; +use Override; /** * Default renderer for @see BooleanElementView @@ -18,11 +19,7 @@ final class CheckboxHtmlRenderer implements FieldViewRendererInterface */ private static $instance; - /** - * {@inheritdoc} - * - * @param BooleanElementView $view - */ + #[Override] public function render(FieldViewInterface $view, array $attributes): string { if (!isset($attributes['type'])) { diff --git a/src/Leaf/View/SelectHtmlRenderer.php b/src/Leaf/View/SelectHtmlRenderer.php index 72b493a..07380d4 100644 --- a/src/Leaf/View/SelectHtmlRenderer.php +++ b/src/Leaf/View/SelectHtmlRenderer.php @@ -6,6 +6,7 @@ use Bdf\Form\View\FieldViewRendererInterface; use Bdf\Form\View\HtmlRenderer; use InvalidArgumentException; +use Override; /** * Renderer for select element @@ -20,9 +21,7 @@ final class SelectHtmlRenderer implements FieldViewRendererInterface */ private static $instance; - /** - * {@inheritdoc} - */ + #[Override] public function render(FieldViewInterface $view, array $attributes): string { if (!$choices = $view->choices()) { diff --git a/src/Leaf/View/SimpleElementView.php b/src/Leaf/View/SimpleElementView.php index 00c821f..dc8951d 100644 --- a/src/Leaf/View/SimpleElementView.php +++ b/src/Leaf/View/SimpleElementView.php @@ -8,6 +8,7 @@ use Bdf\Form\View\FieldViewInterface; use Bdf\Form\View\FieldViewRendererInterface; use Bdf\Form\View\FieldViewTrait; +use Override; /** * View for simple input fields @@ -41,9 +42,7 @@ public function __construct(string $type, string $name, $value, ?string $error, $this->choices = $choices; } - /** - * {@inheritdoc} - */ + #[Override] protected function defaultRenderer(): FieldViewRendererInterface { return $this->choices ? SelectHtmlRenderer::instance() : SimpleFieldHtmlRenderer::instance(); diff --git a/src/Leaf/View/SimpleFieldHtmlRenderer.php b/src/Leaf/View/SimpleFieldHtmlRenderer.php index d630fa5..3558bac 100644 --- a/src/Leaf/View/SimpleFieldHtmlRenderer.php +++ b/src/Leaf/View/SimpleFieldHtmlRenderer.php @@ -9,6 +9,7 @@ use Bdf\Form\View\FieldViewInterface; use Bdf\Form\View\FieldViewRendererInterface; use Bdf\Form\View\HtmlRenderer; +use Override; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\LessThanOrEqual; @@ -51,9 +52,7 @@ final class SimpleFieldHtmlRenderer implements FieldViewRendererInterface EmailElement::class => 'email', ]; - /** - * {@inheritdoc} - */ + #[Override] public function render(FieldViewInterface $view, array $attributes): string { if (!isset($attributes['type'])) { diff --git a/src/Phone/NotEmptyPhoneNumberValidator.php b/src/Phone/NotEmptyPhoneNumberValidator.php index 885b9ac..c9b4225 100644 --- a/src/Phone/NotEmptyPhoneNumberValidator.php +++ b/src/Phone/NotEmptyPhoneNumberValidator.php @@ -4,6 +4,7 @@ use libphonenumber\PhoneNumber; use libphonenumber\PhoneNumberUtil; +use Override; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\NotBlankValidator; @@ -27,9 +28,7 @@ public function __construct(?PhoneNumberUtil $formatter = null) $this->formatter = $formatter ?? PhoneNumberUtil::getInstance(); } - /** - * {@inheritdoc} - */ + #[Override] public function validate($value, Constraint $constraint): void { if ($value instanceof PhoneNumber) { diff --git a/src/Phone/PhoneElement.php b/src/Phone/PhoneElement.php index 3887da3..99f44c5 100644 --- a/src/Phone/PhoneElement.php +++ b/src/Phone/PhoneElement.php @@ -9,6 +9,7 @@ use libphonenumber\PhoneNumber; use libphonenumber\PhoneNumberFormat; use libphonenumber\PhoneNumberUtil; +use Override; use TypeError; use function strtoupper; @@ -51,9 +52,7 @@ public function __construct(?ValueValidatorInterface $validator = null, ?Transfo $this->formatter = $formatter ?? PhoneNumberUtil::getInstance(); } - /** - * {@inheritdoc} - */ + #[Override] protected function toPhp($httpValue) { if ($httpValue === null || $httpValue === '') { @@ -63,9 +62,7 @@ protected function toPhp($httpValue) return $this->parseValue($httpValue); } - /** - * {@inheritdoc} - */ + #[Override] protected function toHttp($phpValue) { if (!$phpValue) { @@ -75,11 +72,7 @@ protected function toHttp($phpValue) return $phpValue->getRawInput() ?? $this->formatter->format($phpValue, PhoneNumberFormat::E164); } - /** - * {@inheritdoc} - * - * @return PhoneNumber|null - */ + #[Override] protected function tryCast($value): ?PhoneNumber { if ($value === null) { @@ -134,9 +127,7 @@ public function parseValue(string $rawPhoneNumber): PhoneNumber } } - /** - * {@inheritdoc} - */ + #[Override] protected function parseConstraints(ValueValidatorInterface $validator): array { $result = parent::parseConstraints($validator); diff --git a/src/Phone/PhoneElementBuilder.php b/src/Phone/PhoneElementBuilder.php index 3badba3..8de750d 100644 --- a/src/Phone/PhoneElementBuilder.php +++ b/src/Phone/PhoneElementBuilder.php @@ -12,6 +12,7 @@ use Bdf\Form\Validator\ValueValidatorInterface; use libphonenumber\PhoneNumberUtil; use libphonenumber\RegionCode; +use Override; use Symfony\Component\Validator\Constraint; /** @@ -70,11 +71,7 @@ public function __construct(?RegistryInterface $registry = null) $this->addConstraintsProvider([$this, 'providePhoneConstraint']); } - /** - * {@inheritdoc} - * - * @return $this - */ + #[Override] public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null) { if (!$message instanceof Constraint) { @@ -219,10 +216,8 @@ public function errorMessage(string $message): self return $this; } - /** - * {@inheritdoc} - */ - protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + #[Override] + protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): PhoneElement { return new PhoneElement($validator, $transformer, $this->regionResolver, $this->formatter); } diff --git a/src/Phone/Transformer/PhoneNumberToStringTransformer.php b/src/Phone/Transformer/PhoneNumberToStringTransformer.php index fe97eef..f07a125 100644 --- a/src/Phone/Transformer/PhoneNumberToStringTransformer.php +++ b/src/Phone/Transformer/PhoneNumberToStringTransformer.php @@ -10,6 +10,7 @@ use libphonenumber\PhoneNumber; use libphonenumber\PhoneNumberFormat; use libphonenumber\PhoneNumberUtil; +use Override; /** * Transformer PhoneNumber instance to string with a format @@ -46,9 +47,7 @@ public function __construct($format = PhoneNumberFormat::E164, bool $formatIfInv $this->formatter = $formatter; } - /** - * {@inheritdoc} - */ + #[Override] public function transformToHttp($value, ElementInterface $input): ?PhoneNumber { if ($value === null) { @@ -64,9 +63,7 @@ public function transformToHttp($value, ElementInterface $input): ?PhoneNumber return $formatter->parse($value, null, null, true); } - /** - * {@inheritdoc} - */ + #[Override] public function transformFromHttp($value, ElementInterface $input): ?string { if (!$value instanceof PhoneNumber) { diff --git a/src/Phone/ValidPhoneNumberValidator.php b/src/Phone/ValidPhoneNumberValidator.php index c7a8fea..4085e3b 100644 --- a/src/Phone/ValidPhoneNumberValidator.php +++ b/src/Phone/ValidPhoneNumberValidator.php @@ -4,6 +4,7 @@ use libphonenumber\PhoneNumber as PhoneNumberValue; use libphonenumber\PhoneNumberUtil; +use Override; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; @@ -28,9 +29,7 @@ public function __construct(?PhoneNumberUtil $formatter = null) $this->formatter = $formatter ?? PhoneNumberUtil::getInstance(); } - /** - * {@inheritdoc} - */ + #[Override] public function validate($value, Constraint $constraint): void { if (!$constraint instanceof ValidPhoneNumber) { diff --git a/src/PropertyAccess/AbstractAccessor.php b/src/PropertyAccess/AbstractAccessor.php index bc196d6..3acabd3 100644 --- a/src/PropertyAccess/AbstractAccessor.php +++ b/src/PropertyAccess/AbstractAccessor.php @@ -3,6 +3,7 @@ namespace Bdf\Form\PropertyAccess; use Bdf\Form\Child\ChildInterface; +use Override; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** @@ -56,17 +57,13 @@ public function __construct($propertyName = null, ?callable $transformer = null, $this->customAccessor = $customAccessor; } - /** - * {@inheritdoc} - */ + #[Override] final public function setPropertyAccessor(PropertyAccessorInterface $propertyAccessor): void { $this->propertyAccessor = $propertyAccessor; } - /** - * {@inheritdoc} - */ + #[Override] final public function setFormElement(?ChildInterface $formElement): void { $this->input = $formElement; diff --git a/src/PropertyAccess/Getter.php b/src/PropertyAccess/Getter.php index 302c7a4..2c1eefc 100644 --- a/src/PropertyAccess/Getter.php +++ b/src/PropertyAccess/Getter.php @@ -3,6 +3,7 @@ namespace Bdf\Form\PropertyAccess; use Attribute; +use Override; /** * Extract a property value and import it into the form element @@ -35,9 +36,7 @@ #[Attribute(Attribute::TARGET_PROPERTY)] final class Getter extends AbstractAccessor implements ExtractorInterface { - /** - * {@inheritdoc} - */ + #[Override] public function extract($source) { if ($this->customAccessor !== null) { diff --git a/src/PropertyAccess/Setter.php b/src/PropertyAccess/Setter.php index 5d11130..d5314f6 100644 --- a/src/PropertyAccess/Setter.php +++ b/src/PropertyAccess/Setter.php @@ -3,6 +3,7 @@ namespace Bdf\Form\PropertyAccess; use Attribute; +use Override; /** * Set the property value using the element value @@ -35,9 +36,7 @@ #[Attribute(Attribute::TARGET_PROPERTY)] final class Setter extends AbstractAccessor implements HydratorInterface { - /** - * {@inheritdoc} - */ + #[Override] public function hydrate(&$target, $value): void { if ($this->transformer) { diff --git a/src/Registry/Registry.php b/src/Registry/Registry.php index fe4e94c..a57328a 100755 --- a/src/Registry/Registry.php +++ b/src/Registry/Registry.php @@ -37,6 +37,7 @@ use Bdf\Form\Phone\PhoneElement; use Bdf\Form\Phone\PhoneElementBuilder; use InvalidArgumentException; +use Override; /** * Base registry interface @@ -85,9 +86,7 @@ public function __construct() }); } - /** - * {@inheritdoc} - */ + #[Override] public function childBuilder(string $element, string $name): ChildBuilderInterface { $elementBuilder = $this->elementBuilder($element); @@ -109,6 +108,7 @@ public function childBuilder(string $element, string $name): ChildBuilderInterfa * @psalm-template E as \Bdf\Form\ElementInterface * @psalm-return ElementBuilderInterface */ + #[Override] public function elementBuilder(string $element): ElementBuilderInterface { $builderFactory = null; @@ -136,9 +136,7 @@ public function elementBuilder(string $element): ElementBuilderInterface return ($builderFactory)($this, $element); } - /** - * {@inheritdoc} - */ + #[Override] public function buttonBuilder(string $name): ButtonBuilderInterface { return new SubmitButtonBuilder($name); diff --git a/src/Transformer/ClosureTransformer.php b/src/Transformer/ClosureTransformer.php index 42eba03..3c25992 100755 --- a/src/Transformer/ClosureTransformer.php +++ b/src/Transformer/ClosureTransformer.php @@ -5,6 +5,7 @@ use Bdf\Form\ElementBuilderInterface; use Bdf\Form\ElementInterface; use Bdf\Form\Registry\RegistryInterface; +use Override; /** * Wrap a closure into a Transformer @@ -34,17 +35,13 @@ public function __construct(callable $callback) $this->callback = $callback; } - /** - * {@inheritdoc} - */ + #[Override] public function transformToHttp($value, ElementInterface $input) { return ($this->callback)($value, $input, false); } - /** - * {@inheritdoc} - */ + #[Override] public function transformFromHttp($value, ElementInterface $input) { return ($this->callback)($value, $input, true); diff --git a/src/Transformer/DataTransformerAdapter.php b/src/Transformer/DataTransformerAdapter.php index 259310f..2f3090f 100755 --- a/src/Transformer/DataTransformerAdapter.php +++ b/src/Transformer/DataTransformerAdapter.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Transformer; use Bdf\Form\ElementInterface; +use Override; use Symfony\Component\Form\DataTransformerInterface; /** @@ -27,18 +28,14 @@ public function __construct(DataTransformerInterface $transformer) { $this->transformer = $transformer; } - - /** - * {@inheritdoc} - */ + + #[Override] public function transformToHttp($value, ElementInterface $input) { return $this->transformer->transform($value); } - /** - * {@inheritdoc} - */ + #[Override] public function transformFromHttp($value, ElementInterface $input) { return $this->transformer->reverseTransform($value); diff --git a/src/Transformer/NullTransformer.php b/src/Transformer/NullTransformer.php index 1aeeaf0..599d916 100644 --- a/src/Transformer/NullTransformer.php +++ b/src/Transformer/NullTransformer.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Transformer; use Bdf\Form\ElementInterface; +use Override; /** * Null object for form transformer @@ -14,17 +15,13 @@ final class NullTransformer implements TransformerInterface */ private static $instance; - /** - * {@inheritdoc} - */ + #[Override] public function transformToHttp($value, ElementInterface $input) { return $value; } - /** - * {@inheritdoc} - */ + #[Override] public function transformFromHttp($value, ElementInterface $input) { return $value; diff --git a/src/Transformer/TransformerAggregate.php b/src/Transformer/TransformerAggregate.php index 2e95c01..1633b23 100644 --- a/src/Transformer/TransformerAggregate.php +++ b/src/Transformer/TransformerAggregate.php @@ -3,6 +3,7 @@ namespace Bdf\Form\Transformer; use Bdf\Form\ElementInterface; +use Override; /** * Aggregation of transformers @@ -28,9 +29,7 @@ public function __construct(array $transformers) $this->transformers = $transformers; } - /** - * {@inheritdoc} - */ + #[Override] public function transformToHttp($value, ElementInterface $input) { foreach ($this->transformers as $transformer) { @@ -40,9 +39,7 @@ public function transformToHttp($value, ElementInterface $input) return $value; } - /** - * {@inheritdoc} - */ + #[Override] public function transformFromHttp($value, ElementInterface $input) { for ($i = count($this->transformers) - 1; $i >= 0; --$i) { diff --git a/src/Util/ContainerTrait.php b/src/Util/ContainerTrait.php index 48703fa..687f2ed 100644 --- a/src/Util/ContainerTrait.php +++ b/src/Util/ContainerTrait.php @@ -22,7 +22,7 @@ trait ContainerTrait */ final public function container(): ?ChildInterface { - return $this->container ? $this->container->get() : null; + return $this->container?->get(); } /** diff --git a/src/Util/DelegateElementBuilderTrait.php b/src/Util/DelegateElementBuilderTrait.php index a1cb44b..6da115a 100644 --- a/src/Util/DelegateElementBuilderTrait.php +++ b/src/Util/DelegateElementBuilderTrait.php @@ -4,6 +4,7 @@ use Bdf\Form\ElementInterface; use Bdf\Form\Transformer\TransformerInterface; +use Symfony\Component\Validator\Constraint; /** * Simple implementation of delegated element builder @@ -17,9 +18,9 @@ trait DelegateElementBuilderTrait /** * {@inheritdoc} */ - final public function satisfy($constraint, $options = null, bool $append = true) + final public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) { - $this->getElementBuilder()->satisfy($constraint, $options, $append); + $this->getElementBuilder()->satisfy($constraint, $message, $append); return $this; } diff --git a/src/Util/TransformerBuilderTrait.php b/src/Util/TransformerBuilderTrait.php index 66386da..0723c52 100644 --- a/src/Util/TransformerBuilderTrait.php +++ b/src/Util/TransformerBuilderTrait.php @@ -23,7 +23,7 @@ trait TransformerBuilderTrait private $transformers = []; /** - * @var callable[] + * @var array */ private $transformerProviders = []; diff --git a/src/Util/ValidatorBuilderTrait.php b/src/Util/ValidatorBuilderTrait.php index 6c0c89f..79451a9 100644 --- a/src/Util/ValidatorBuilderTrait.php +++ b/src/Util/ValidatorBuilderTrait.php @@ -31,7 +31,7 @@ trait ValidatorBuilderTrait private $transformerExceptionConstraint; /** - * @var callable[] + * @var array */ private $constraintsProviders = []; diff --git a/src/Validator/ConstraintValueValidator.php b/src/Validator/ConstraintValueValidator.php index 64dc28f..aafb36c 100644 --- a/src/Validator/ConstraintValueValidator.php +++ b/src/Validator/ConstraintValueValidator.php @@ -5,6 +5,7 @@ use Bdf\Form\ElementInterface; use Bdf\Form\Error\FormError; use Exception; +use Override; use Symfony\Component\Validator\Constraint; /** @@ -44,9 +45,7 @@ public function __construct(array $constraints = [], ?TransformerExceptionConstr $this->transformerExceptionConstraint = $transformerExceptionConstraint ?? new TransformerExceptionConstraint(); } - /** - * {@inheritdoc} - */ + #[Override] public function validate($value, ElementInterface $element): FormError { if (!$this->constraints) { @@ -71,9 +70,7 @@ public function validate($value, ElementInterface $element): FormError return FormError::null(); } - /** - * {@inheritdoc} - */ + #[Override] public function onTransformerException(Exception $exception, $value, ElementInterface $element): FormError { if ($this->transformerExceptionConstraint->ignoreException) { @@ -95,17 +92,13 @@ public function onTransformerException(Exception $exception, $value, ElementInte return FormError::null(); } - /** - * {@inheritdoc} - */ + #[Override] public function constraints(): array { return $this->constraints; } - /** - * {@inheritdoc} - */ + #[Override] public function hasConstraints(): bool { return !empty($this->constraints); diff --git a/src/Validator/TransformerExceptionConstraint.php b/src/Validator/TransformerExceptionConstraint.php index c0220e0..330e1ad 100644 --- a/src/Validator/TransformerExceptionConstraint.php +++ b/src/Validator/TransformerExceptionConstraint.php @@ -64,14 +64,6 @@ public function __construct(?Exception $exception = null, ?string $message = nul $this->ignoreException = $ignoreException ?? $this->ignoreException; } - /** - * {@inheritdoc} - */ - public function getDefaultOption(): ?string - { - return 'exception'; - } - /** * Set the exception on the constraint * diff --git a/src/Validator/TransformerExceptionConstraintValidator.php b/src/Validator/TransformerExceptionConstraintValidator.php index 36eb211..f6daf1c 100644 --- a/src/Validator/TransformerExceptionConstraintValidator.php +++ b/src/Validator/TransformerExceptionConstraintValidator.php @@ -2,6 +2,8 @@ namespace Bdf\Form\Validator; +use LogicException; +use Override; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; @@ -11,9 +13,7 @@ */ final class TransformerExceptionConstraintValidator extends ConstraintValidator { - /** - * {@inheritdoc} - */ + #[Override] public function validate($value, Constraint $constraint): void { if (!$constraint instanceof TransformerExceptionConstraint) { @@ -26,7 +26,7 @@ public function validate($value, Constraint $constraint): void } } - $this->context->buildViolation($constraint->message ?: $constraint->exception->getMessage()) + $this->context->buildViolation($constraint->message ?? $constraint->exception?->getMessage() ?? throw new LogicException('TransformerExceptionConstraint must have a message or an exception')) ->setCode($constraint->code) ->setParameter('{{ value }}', $this->formatValue($value)) ->addViolation() diff --git a/src/View/ElementViewTrait.php b/src/View/ElementViewTrait.php index 4f29b15..dfa00d3 100644 --- a/src/View/ElementViewTrait.php +++ b/src/View/ElementViewTrait.php @@ -40,7 +40,7 @@ public function error(): ?string /** * {@inheritdoc} */ - public function setError(?string $error): ElementViewInterface + public function setError(?string $error): static { $this->error = $error; diff --git a/src/View/FieldSetViewTrait.php b/src/View/FieldSetViewTrait.php index e3af4c8..03baa30 100644 --- a/src/View/FieldSetViewTrait.php +++ b/src/View/FieldSetViewTrait.php @@ -72,6 +72,8 @@ public function hasError(): bool /** * {@inheritdoc} + * + * @return array */ public function errors(): array { @@ -82,7 +84,7 @@ public function errors(): array continue; } - if ($element instanceof FieldSetViewInterface && method_exists($element, 'errors')) { + if ($element instanceof FieldSetViewInterface) { $errors[$name] = $element->errors(); } elseif ($error = $element->error()) { $errors[$name] = $error; diff --git a/src/View/FieldViewInterface.php b/src/View/FieldViewInterface.php index dbd6864..405ab12 100644 --- a/src/View/FieldViewInterface.php +++ b/src/View/FieldViewInterface.php @@ -5,6 +5,7 @@ use Bdf\Form\Choice\Choiceable; use Bdf\Form\Choice\ChoiceInterface; use Bdf\Form\Choice\ChoiceView; +use Override; /** * Base type for HTTP input / field @@ -91,5 +92,6 @@ public function choices(): ?array; * * @return string */ + #[Override] public function render(?FieldViewRendererInterface $renderer = null): string; } diff --git a/src/View/FieldViewTrait.php b/src/View/FieldViewTrait.php index ede5ae9..937fb13 100644 --- a/src/View/FieldViewTrait.php +++ b/src/View/FieldViewTrait.php @@ -57,7 +57,7 @@ public function value() /** * {@inheritdoc} */ - public function setValue($value): FieldViewInterface + public function setValue($value): static { $this->value = $value; diff --git a/tests/Leaf/LeafElementTest.php b/tests/Leaf/LeafElementTest.php index 3a6d32a..a36e301 100644 --- a/tests/Leaf/LeafElementTest.php +++ b/tests/Leaf/LeafElementTest.php @@ -4,6 +4,7 @@ use Bdf\Form\Child\Http\HttpFieldPath; use Bdf\Form\View\ElementViewInterface; +use Bdf\Form\View\FieldViewInterface; use PHPUnit\Framework\TestCase; class LeafElementTest extends TestCase @@ -34,7 +35,7 @@ protected function choiceView(): ?array return []; } - public function view(?HttpFieldPath $field = null): ElementViewInterface + public function view(?HttpFieldPath $field = null): FieldViewInterface { $view = parent::view($field); diff --git a/tests/StaticAnalysis/ArrayElementConfigure.php b/tests/StaticAnalysis/ArrayElementConfigure.php index b2a7195..2f55eb8 100644 --- a/tests/StaticAnalysis/ArrayElementConfigure.php +++ b/tests/StaticAnalysis/ArrayElementConfigure.php @@ -15,6 +15,7 @@ class ArrayElementConfigure extends CustomForm /** * {@inheritdoc} */ + #[\Override] protected function configure(FormBuilderInterface $builder): void { $builder->array('values')->element( diff --git a/tests/StaticAnalysis/MyCustomForm.php b/tests/StaticAnalysis/MyCustomForm.php index 47d3270..72253e9 100644 --- a/tests/StaticAnalysis/MyCustomForm.php +++ b/tests/StaticAnalysis/MyCustomForm.php @@ -13,15 +13,16 @@ class MyCustomForm extends CustomForm /** * {@inheritdoc} */ + #[\Override] protected function configure(FormBuilderInterface $builder): void { $builder->generates(MyGeneratedEntity::class); - $builder->string('foo')->length(['min' => 1])->getter()->setter(); + $builder->string('foo')->length(min: 1)->getter()->setter(); $builder->string('bar')->required()->getter()->setter(); } - public static function test() + public static function test(): void { $form = new MyCustomForm(); $form->submit(['foo' => 'a', 'bar' => 'b']); diff --git a/tests/StaticAnalysis/SubClassChildBuilderForm.php b/tests/StaticAnalysis/SubClassChildBuilderForm.php index 8d9796d..fe43b47 100644 --- a/tests/StaticAnalysis/SubClassChildBuilderForm.php +++ b/tests/StaticAnalysis/SubClassChildBuilderForm.php @@ -13,6 +13,7 @@ class SubClassChildBuilderForm extends CustomForm /** * {@inheritdoc} */ + #[\Override] protected function configure(FormBuilderInterface $builder): void { $builder->dateTime('foo') From 793c2fd9abc32c0f99df7deb3085bd00e4ba86f8 Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Tue, 10 Mar 2026 11:53:55 +0100 Subject: [PATCH 05/12] ci: update infection for php 8.4 compatibility --- .github/workflows/php.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index e9cdc05..0f38e8d 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -64,8 +64,8 @@ jobs: - name: Install Infection run: | - wget https://github.com/infection/infection/releases/download/0.21.5/infection.phar - wget https://github.com/infection/infection/releases/download/0.21.5/infection.phar.asc + wget https://github.com/infection/infection/releases/download/0.32.6/infection.phar + wget https://github.com/infection/infection/releases/download/0.32.6/infection.phar.asc chmod +x infection.phar gpg --recv-keys C6D76C329EBADE2FB9C458CFC5095986493B4AA0 gpg --with-fingerprint --verify infection.phar.asc infection.phar From c7e05af32f0862890d6efbc0f3da4c33d17e569f Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Tue, 10 Mar 2026 11:57:25 +0100 Subject: [PATCH 06/12] ci: fix infection options --- .github/workflows/php.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 0f38e8d..c7544ec 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -83,7 +83,7 @@ jobs: - name: Run Infection run: | git fetch --depth=1 origin $GITHUB_BASE_REF - ./infection.phar --logger-github --git-diff-filter=AM --min-msi=80 + ./infection.phar --logger-github --git-diff-base=origin/$GITHUB_BASE_REF --git-diff-filter=AM --min-msi=80 coverage: name: Test coverage From 9958d14fd834861ed18ce6285aa390847cff636f Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Wed, 11 Mar 2026 15:38:43 +0100 Subject: [PATCH 07/12] chore: Add type on properties and methods (#FRAM-221) --- psalm.xml | 4 + src/AbstractElementBuilder.php | 13 +- src/Aggregate/ArrayChildBuilder.php | 7 +- src/Aggregate/ArrayElement.php | 52 ++---- src/Aggregate/ArrayElementBuilder.php | 77 ++++----- src/Aggregate/ChildAggregateInterface.php | 8 +- .../Collection/ChildrenCollection.php | 16 +- .../ChildrenCollectionInterface.php | 4 +- .../Collection/DependencyIterator.php | 28 +--- src/Aggregate/Collection/DependencyTree.php | 21 +-- src/Aggregate/Collection/Level.php | 45 ++---- src/Aggregate/Form.php | 82 ++++------ src/Aggregate/FormBuilder.php | 28 +--- src/Aggregate/FormBuilderInterface.php | 2 +- src/Aggregate/FormInterface.php | 6 +- src/Aggregate/RootForm.php | 73 ++++----- src/Aggregate/Value/ValueGenerator.php | 14 +- .../Value/ValueGeneratorInterface.php | 4 +- src/Aggregate/View/ArrayElementView.php | 2 +- .../View/ArrayElementViewRenderer.php | 22 +-- src/Aggregate/View/FormView.php | 6 +- src/Button/ButtonBuilderInterface.php | 4 +- src/Button/ButtonInterface.php | 2 +- src/Button/SubmitButton.php | 22 +-- src/Button/SubmitButtonBuilder.php | 17 +- src/Button/View/ButtonView.php | 17 +- src/Child/Child.php | 70 +++----- src/Child/ChildBuilder.php | 99 +++++------- src/Child/ChildBuilderInterface.php | 14 +- src/Child/ChildCreationStrategyInterface.php | 2 +- src/Child/ChildInterface.php | 14 +- src/Child/ChildParameters.php | 150 +++++++++--------- src/Child/Http/ArrayOffsetHttpFields.php | 29 ++-- src/Child/Http/HttpFieldPath.php | 30 +--- src/Child/Http/HttpFieldsInterface.php | 6 +- src/Child/Http/PrefixedHttpFields.php | 33 ++-- src/Choice/ArrayChoice.php | 32 ++-- src/Choice/ChoiceBuilderTrait.php | 10 +- src/Choice/ChoiceView.php | 14 +- src/Choice/LazyChoice.php | 4 +- src/Constraint/Closure.php | 4 +- src/Constraint/FieldComparisonTrait.php | 2 +- src/Csrf/CsrfConstraint.php | 8 +- src/Csrf/CsrfElement.php | 41 ++--- src/Csrf/CsrfElementBuilder.php | 48 ++---- src/Csrf/CsrfValueValidator.php | 16 +- src/Custom/CustomForm.php | 38 ++--- src/Custom/CustomFormBuilder.php | 11 +- src/ElementBuilderInterface.php | 6 +- src/ElementInterface.php | 10 +- src/Error/FormError.php | 12 +- src/Error/FormErrorPrinterInterface.php | 2 +- src/Error/ImplodeErrorPrinter.php | 8 +- src/Error/StringErrorPrinter.php | 37 +---- src/Filter/ClosureFilter.php | 7 +- src/Filter/EmptyArrayValuesFilter.php | 2 +- src/Filter/FilterInterface.php | 2 +- src/Filter/FilterVar.php | 10 +- src/Filter/TrimFilter.php | 6 +- src/Leaf/AbstractBooleanElement.php | 2 +- src/Leaf/AnyElement.php | 6 +- src/Leaf/BooleanElement.php | 9 +- src/Leaf/BooleanElementBuilder.php | 11 +- src/Leaf/BooleanStringElement.php | 8 +- src/Leaf/Date/DateTimeElement.php | 24 +-- src/Leaf/Date/DateTimeElementBuilder.php | 36 ++--- .../DateTimeToTimestampTransformer.php | 8 +- src/Leaf/FloatElement.php | 8 +- src/Leaf/FloatElementBuilder.php | 13 +- src/Leaf/Helper/EmailElementBuilder.php | 16 +- src/Leaf/Helper/UrlElementBuilder.php | 25 ++- src/Leaf/IntegerElement.php | 8 +- src/Leaf/IntegerElementBuilder.php | 7 +- src/Leaf/LeafElement.php | 51 ++---- src/Leaf/LeafRootElement.php | 30 ++-- src/Leaf/NumberElementBuilder.php | 7 +- src/Leaf/StringElement.php | 10 +- src/Leaf/StringElementBuilder.php | 12 +- .../LocalizedIntegerTransformer.php | 2 +- .../LocalizedNumberTransformer.php | 8 +- src/Leaf/View/BooleanElementView.php | 13 +- src/Leaf/View/CheckboxHtmlRenderer.php | 11 +- src/Leaf/View/SelectHtmlRenderer.php | 11 +- src/Leaf/View/SimpleElementView.php | 2 +- src/Leaf/View/SimpleFieldHtmlRenderer.php | 15 +- src/Phone/NotEmptyPhoneNumberValidator.php | 7 +- src/Phone/PhoneChildBuilder.php | 14 +- src/Phone/PhoneElement.php | 14 +- src/Phone/PhoneElementBuilder.php | 39 ++--- .../PhoneNumberToStringTransformer.php | 22 +-- src/Phone/ValidPhoneNumber.php | 2 +- src/Phone/ValidPhoneNumberValidator.php | 9 +- src/PropertyAccess/AbstractAccessor.php | 36 ++--- src/PropertyAccess/ExtractorInterface.php | 4 +- src/PropertyAccess/Getter.php | 7 +- src/PropertyAccess/HydratorInterface.php | 4 +- src/PropertyAccess/Setter.php | 7 +- src/Registry/Registry.php | 13 +- src/Transformer/ClosureTransformer.php | 9 +- src/Transformer/DataTransformerAdapter.php | 29 ++-- src/Transformer/NullTransformer.php | 17 +- src/Transformer/TransformerAggregate.php | 36 ++--- src/Transformer/TransformerInterface.php | 4 +- src/Util/ContainerTrait.php | 2 +- src/Util/DelegateElementBuilderTrait.php | 6 +- src/Util/FieldFinderTrait.php | 2 +- src/Util/FieldPath.php | 18 +-- src/Util/HttpValue.php | 4 +- src/Util/MagicCallForwarding.php | 2 +- src/Util/RootFlagsTrait.php | 2 +- src/Util/TransformerBuilderTrait.php | 13 +- src/Util/ValidatorBuilderTrait.php | 27 ++-- src/Validator/ConstraintValueValidator.php | 19 +-- .../TransformerExceptionConstraint.php | 10 +- ...ransformerExceptionConstraintValidator.php | 4 +- src/Validator/ValueValidatorInterface.php | 4 +- src/View/ConstraintsNormalizer.php | 9 +- src/View/ElementViewInterface.php | 4 +- src/View/ElementViewTrait.php | 6 +- src/View/FieldSetViewTrait.php | 12 +- src/View/FieldViewInterface.php | 4 +- src/View/FieldViewTrait.php | 25 +-- src/View/Renderable.php | 10 +- src/View/RenderableTrait.php | 16 +- tests/Aggregate/FormTest.php | 29 ++++ tests/Child/ChildBuilderTest.php | 2 +- tests/Child/ChildTest.php | 12 ++ tests/Custom/CustomFormTest.php | 2 +- 128 files changed, 891 insertions(+), 1332 deletions(-) diff --git a/psalm.xml b/psalm.xml index 21a9869..c6a52c6 100644 --- a/psalm.xml +++ b/psalm.xml @@ -15,4 +15,8 @@ + + + + diff --git a/src/AbstractElementBuilder.php b/src/AbstractElementBuilder.php index e884178..ad537a9 100644 --- a/src/AbstractElementBuilder.php +++ b/src/AbstractElementBuilder.php @@ -21,15 +21,8 @@ abstract class AbstractElementBuilder implements ElementBuilderInterface use TransformerBuilderTrait; use ValidatorBuilderTrait; - /** - * @var RegistryInterface - */ - private $registry; - - /** - * @var mixed - */ - private $value; + private readonly RegistryInterface $registry; + private mixed $value = null; /** @@ -43,7 +36,7 @@ public function __construct(?RegistryInterface $registry = null) } #[Override] - final public function value($value) + final public function value(mixed $value): static { $this->value = $value; diff --git a/src/Aggregate/ArrayChildBuilder.php b/src/Aggregate/ArrayChildBuilder.php index 1cc0806..a057adc 100644 --- a/src/Aggregate/ArrayChildBuilder.php +++ b/src/Aggregate/ArrayChildBuilder.php @@ -14,10 +14,7 @@ */ class ArrayChildBuilder extends ChildBuilder { - /** - * @var bool - */ - private $filterEmptyValues = true; + private bool $filterEmptyValues = true; /** * ArrayChildBuilder constructor. @@ -30,7 +27,7 @@ public function __construct(string $name, ElementBuilderInterface $elementBuilde { parent::__construct($name, $elementBuilder, $registry); - $this->addFilterProvider([$this, 'provideEmptyValueFilter']); + $this->addFilterProvider($this->provideEmptyValueFilter(...)); } /** diff --git a/src/Aggregate/ArrayElement.php b/src/Aggregate/ArrayElement.php index 38a7ef2..8701dd3 100644 --- a/src/Aggregate/ArrayElement.php +++ b/src/Aggregate/ArrayElement.php @@ -50,37 +50,17 @@ final class ArrayElement implements ChildAggregateInterface, Countable, Choiceab /** * @var ElementInterface */ - private $templateElement; - - /** - * @var TransformerInterface - */ - private $transformer; - - /** - * @var ValueValidatorInterface - */ - private $validator; - - /** - * @var ChoiceInterface|null - */ - private $choices; - - /** - * @var bool - */ - private $valid = false; - - /** - * @var FormError - */ - private $error; + private readonly ElementInterface $templateElement; + private readonly TransformerInterface $transformer; + private readonly ValueValidatorInterface $validator; + private readonly ?ChoiceInterface $choices; + private bool $valid = false; + private FormError $error; /** * @var ChildInterface[] */ - private $children = []; + private array $children = []; /** @@ -101,25 +81,25 @@ public function __construct(ElementInterface $templateElement, ?TransformerInter } #[Override] - public function offsetGet($offset): ChildInterface + public function offsetGet(mixed $offset): ChildInterface { return $this->children[$offset]; } #[Override] - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return isset($this->children[$offset]); } #[Override] - public function offsetSet($offset, $value): void + public function offsetSet(mixed $offset, mixed $value): void { throw new BadMethodCallException('Use import() or submit() for set an offset value'); } #[Override] - public function offsetUnset($offset): void + public function offsetUnset(mixed $offset): void { throw new BadMethodCallException('Use import() or submit() for set an offset value'); } @@ -143,7 +123,7 @@ public function choices(): ?ChoiceInterface } #[Override] - public function submit($data): ElementInterface + public function submit(mixed $data): static { $this->valid = true; @@ -165,7 +145,7 @@ public function submit($data): ElementInterface $errors = []; foreach ($data as $key => $value) { - $child = $lastChildren[$key] ?? (new Child($key, $this->templateElement))->setParent($this); + $child = $lastChildren[$key] ?? new Child($key, $this->templateElement)->setParent($this); $child->element()->submit($value); @@ -190,7 +170,7 @@ public function submit($data): ElementInterface } #[Override] - public function patch($data): ElementInterface + public function patch(mixed $data): static { $this->valid = true; @@ -215,7 +195,7 @@ public function patch($data): ElementInterface } #[Override] - public function import($entity): ElementInterface + public function import(mixed $entity): static { if ($entity === null) { $entity = []; @@ -255,7 +235,7 @@ public function value(): array } #[Override] - public function httpValue() + public function httpValue(): mixed { $value = []; diff --git a/src/Aggregate/ArrayElementBuilder.php b/src/Aggregate/ArrayElementBuilder.php index 27da190..92217c8 100644 --- a/src/Aggregate/ArrayElementBuilder.php +++ b/src/Aggregate/ArrayElementBuilder.php @@ -59,21 +59,13 @@ class ArrayElementBuilder implements ElementBuilderInterface ValidatorBuilderTrait::satisfy as arrayConstraint; } - /** - * @var RegistryInterface - */ - private $registry; + private readonly RegistryInterface $registry; /** * @var ElementBuilderInterface>|null */ - private $element; - - /** - * @var mixed - */ - private $value; - + private ?ElementBuilderInterface $element = null; + private mixed $value = null; /** * ArrayBuilder constructor. @@ -91,7 +83,7 @@ public function __construct(?RegistryInterface $registry = null) * Define a constraint on the inner element */ #[Override] - public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) + public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true): static { $this->getElementBuilder()->satisfy($constraint, $message, $append); @@ -104,7 +96,7 @@ public function satisfy(Constraint|callable $constraint, ?string $message = null * Define a transformer on the inner element */ #[Override] - public function transformer(callable|TransformerInterface $transformer, bool $append = true) + public function transformer(callable|TransformerInterface $transformer, bool $append = true): static { $this->getElementBuilder()->transformer($transformer, $append); @@ -115,7 +107,7 @@ public function transformer(callable|TransformerInterface $transformer, bool $ap * {@inheritdoc} */ #[Override] - public function value($value) + public function value($value): static { $this->value = $value; @@ -138,12 +130,13 @@ public function value($value) * @template E as ElementInterface * @template EB as ElementBuilderInterface * - * @return ArrayElementBuilder + * @return static + * @psalm-this-out ArrayElementBuilder */ - public function element(string $element, ?callable $configurator = null): ArrayElementBuilder + public function element(string $element, ?callable $configurator = null): static { - /** @var ArrayElementBuilder $this */ // @todo exception if already defined ? + /** @psalm-suppress InvalidPropertyAssignmentValue */ $this->element = $this->registry->elementBuilder($element); if ($configurator) { @@ -158,7 +151,6 @@ public function element(string $element, ?callable $configurator = null): ArrayE * {@inheritdoc} * * @return ElementBuilderInterface> - * @psalm-suppress InvalidNullableReturnType */ #[Override] public function getElementBuilder(): ElementBuilderInterface @@ -167,7 +159,9 @@ public function getElementBuilder(): ElementBuilderInterface $this->element(StringElement::class); } - /** @psalm-suppress NullableReturnStatement */ + assert($this->element !== null); + + /** @var ElementBuilderInterface> */ return $this->element; } @@ -182,9 +176,10 @@ public function getElementBuilder(): ElementBuilderInterface * * @param callable(ElementBuilderInterface):void|null $configurator Callback for configure the inner element builder * - * @return ArrayElementBuilder + * @return static + * @psalm-this-out ArrayElementBuilder */ - public function string(?callable $configurator = null): ArrayElementBuilder + public function string(?callable $configurator = null): static { return $this->element(StringElement::class, $configurator); } @@ -200,9 +195,10 @@ public function string(?callable $configurator = null): ArrayElementBuilder * * @param callable(ElementBuilderInterface):void|null $configurator Callback for configure the inner element builder * - * @return ArrayElementBuilder + * @return static + * @psalm-this-out ArrayElementBuilder */ - public function integer(?callable $configurator = null): ArrayElementBuilder + public function integer(?callable $configurator = null): static { return $this->element(IntegerElement::class, $configurator); } @@ -218,9 +214,10 @@ public function integer(?callable $configurator = null): ArrayElementBuilder * * @param callable(ElementBuilderInterface):void|null $configurator Callback for configure the inner element builder * - * @return ArrayElementBuilder + * @return static + * @psalm-this-out ArrayElementBuilder */ - public function float(?callable $configurator = null): ArrayElementBuilder + public function float(?callable $configurator = null): static { return $this->element(FloatElement::class, $configurator); } @@ -234,9 +231,10 @@ public function float(?callable $configurator = null): ArrayElementBuilder * * @param callable(ElementBuilderInterface):void|null $configurator Callback for configure the inner element builder * - * @return ArrayElementBuilder + * @return static + * @psalm-this-out ArrayElementBuilder */ - public function boolean(?callable $configurator = null): ArrayElementBuilder + public function boolean(?callable $configurator = null): static { return $this->element(BooleanElement::class, $configurator); } @@ -252,9 +250,10 @@ public function boolean(?callable $configurator = null): ArrayElementBuilder * * @param callable(ElementBuilderInterface>):void|null $configurator Callback for configure the inner element builder * - * @return ArrayElementBuilder<\DateTimeInterface> + * @return static + * @psalm-this-out ArrayElementBuilder<\DateTimeInterface> */ - public function dateTime(?callable $configurator = null): ArrayElementBuilder + public function dateTime(?callable $configurator = null): static { return $this->element(DateTimeElement::class, $configurator); } @@ -270,9 +269,10 @@ public function dateTime(?callable $configurator = null): ArrayElementBuilder * * @param callable(ElementBuilderInterface>):void|null $configurator Callback for configure the inner element builder * - * @return ArrayElementBuilder<\libphonenumber\PhoneNumber> + * @return static + * @psalm-this-out ArrayElementBuilder<\libphonenumber\PhoneNumber> */ - public function phone(?callable $configurator = null): ArrayElementBuilder + public function phone(?callable $configurator = null): static { return $this->element(PhoneElement::class, $configurator); } @@ -291,9 +291,10 @@ public function phone(?callable $configurator = null): ArrayElementBuilder * * @param callable|null $configurator Configure the embedded form * - * @return ArrayElementBuilder + * @return static + * @psalm-this-out ArrayElementBuilder */ - public function form(?callable $configurator = null): ArrayElementBuilder + public function form(?callable $configurator = null): static { return $this->element(Form::class, $configurator); } @@ -314,7 +315,7 @@ public function form(?callable $configurator = null): ArrayElementBuilder * * @see Count For the list of options */ - public function count(?int $exactly = null, ?int $min = null, ?int $max = null, ?string $exactMessage = null, ?string $minMessage = null, ?string $maxMessage = null): ArrayElementBuilder + public function count(?int $exactly = null, ?int $min = null, ?int $max = null, ?string $exactMessage = null, ?string $minMessage = null, ?string $maxMessage = null): static { return $this->arrayConstraint( new Count( @@ -333,7 +334,7 @@ public function count(?int $exactly = null, ?int $min = null, ?int $max = null, * * @return $this */ - final public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null) + final public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null): static { if (!$message instanceof Constraint) { $message = new NotBlank( @@ -354,7 +355,7 @@ final public function required(string|Constraint|null $message = null, ?bool $al * @param non-negative-int $min * @param positive-int $max */ - final public function choices(ChoiceInterface|array|callable $choices, ?string $message = null, ?bool $multiple = null, ?bool $strict = null, ?int $min = null, ?int $max = null, ?string $minMessage = null, ?string $maxMessage = null): self + final public function choices(ChoiceInterface|array|callable $choices, ?string $message = null, ?bool $multiple = null, ?bool $strict = null, ?int $min = null, ?int $max = null, ?string $minMessage = null, ?string $maxMessage = null): static { $builder = new class { use ChoiceBuilderTrait { @@ -364,7 +365,7 @@ final public function choices(ChoiceInterface|array|callable $choices, ?string $ public ChoiceConstraint $constraint; #[Override] - public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) + public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true): static { assert($constraint instanceof ChoiceConstraint); $this->constraint = $constraint; @@ -396,7 +397,7 @@ public function satisfy(Constraint|callable $constraint, ?string $message = null * @return ArrayElement */ #[Override] - public function buildElement(): ElementInterface + public function buildElement(): ArrayElement { $element = new ArrayElement( $this->getElementBuilder()->buildElement(), diff --git a/src/Aggregate/ChildAggregateInterface.php b/src/Aggregate/ChildAggregateInterface.php index 3265e58..7516cf7 100644 --- a/src/Aggregate/ChildAggregateInterface.php +++ b/src/Aggregate/ChildAggregateInterface.php @@ -29,7 +29,7 @@ interface ChildAggregateInterface extends ElementInterface, ArrayAccess, Iterato * @param string $offset The child name */ #[Override] - public function offsetGet($offset): ChildInterface; + public function offsetGet(mixed $offset): ChildInterface; /** * {@inheritdoc} @@ -39,7 +39,7 @@ public function offsetGet($offset): ChildInterface; * @param string $offset The child name */ #[Override] - public function offsetExists($offset): bool; + public function offsetExists(mixed $offset): bool; /** * {@inheritdoc} @@ -52,7 +52,7 @@ public function offsetExists($offset): bool; * @throws \BadMethodCallException */ #[Override] - public function offsetSet($offset, $value): void; + public function offsetSet(mixed $offset, mixed $value): void; /** * {@inheritdoc} @@ -62,7 +62,7 @@ public function offsetSet($offset, $value): void; * @throws \BadMethodCallException */ #[Override] - public function offsetUnset($offset): void; + public function offsetUnset(mixed $offset): void; /** * {@inheritdoc} diff --git a/src/Aggregate/Collection/ChildrenCollection.php b/src/Aggregate/Collection/ChildrenCollection.php index 9b6a3d2..66cfe7f 100644 --- a/src/Aggregate/Collection/ChildrenCollection.php +++ b/src/Aggregate/Collection/ChildrenCollection.php @@ -21,14 +21,12 @@ final class ChildrenCollection implements Countable, ChildrenCollectionInterface * * @var ChildInterface[] */ - private $children = []; + private array $children = []; /** * Flag to know if the form has view dependencies in its children - * - * @var boolean */ - private $hasViewDependencies = false; + private bool $hasViewDependencies = false; /** @@ -68,25 +66,25 @@ public function remove(string $name): bool } #[Override] - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return $this->has($offset); } #[Override] - public function offsetGet($offset): ChildInterface + public function offsetGet(mixed $offset): ChildInterface { return $this->children[$offset]; } #[Override] - public function offsetSet($offset, $value): void + public function offsetSet(mixed $offset, mixed $value): void { $this->add($value); } #[Override] - public function offsetUnset($offset): void + public function offsetUnset(mixed $offset): void { $this->remove($offset); } @@ -130,7 +128,7 @@ public function duplicate(ChildAggregateInterface $newParent): ChildrenCollectio $children[$key] = $child->setParent($newParent); } - $collection = new static(); + $collection = new self(); $collection->children = $children; $collection->hasViewDependencies = $this->hasViewDependencies; diff --git a/src/Aggregate/Collection/ChildrenCollectionInterface.php b/src/Aggregate/Collection/ChildrenCollectionInterface.php index 7d8418a..c56a02b 100644 --- a/src/Aggregate/Collection/ChildrenCollectionInterface.php +++ b/src/Aggregate/Collection/ChildrenCollectionInterface.php @@ -47,14 +47,14 @@ public function remove(string $name): bool; /** * Get the reverse iterator (i.e. iterate on higher dependencies in first) * - * @return Iterator + * @return Iterator */ public function reverseIterator(): Iterator; /** * Get the base iterator * - * @return Iterator + * @return Iterator */ public function forwardIterator(): Iterator; diff --git a/src/Aggregate/Collection/DependencyIterator.php b/src/Aggregate/Collection/DependencyIterator.php index 91a2fe1..df834f7 100644 --- a/src/Aggregate/Collection/DependencyIterator.php +++ b/src/Aggregate/Collection/DependencyIterator.php @@ -20,27 +20,11 @@ final class DependencyIterator implements Iterator /** * @var ChildInterface[] */ - private $children; - - /** - * @var Level - */ - private $first; - - /** - * @var bool - */ - private $reverse; - - /** - * @var Level|null - */ - private $currentLevel; - - /** - * @var Iterator|null - */ - private $levelIterator; + private array $children; + private Level $first; + private bool $reverse; + private ?Level $currentLevel = null; + private ?Iterator $levelIterator = null; /** @@ -50,7 +34,7 @@ final class DependencyIterator implements Iterator * @param Level $first * @param bool $reverse Does iterate on reverse order on levels ? */ - public function __construct(array $children, Level $first, $reverse = true) + public function __construct(array $children, Level $first, bool $reverse = true) { $this->children = $children; $this->first = $first; diff --git a/src/Aggregate/Collection/DependencyTree.php b/src/Aggregate/Collection/DependencyTree.php index e5a60b3..c9fa62c 100644 --- a/src/Aggregate/Collection/DependencyTree.php +++ b/src/Aggregate/Collection/DependencyTree.php @@ -34,21 +34,17 @@ final class DependencyTree implements \ArrayAccess, \IteratorAggregate, \Countab /** * @var ChildInterface[] */ - private $children = []; + private array $children = []; /** * The first level of dependencies - * - * @var Level */ - private $root; + private Level $root; /** * The last level of dependencies - * - * @var Level */ - private $last; + private Level $last; /** * Get the level of each elements @@ -56,8 +52,7 @@ final class DependencyTree implements \ArrayAccess, \IteratorAggregate, \Countab * * @var int[] */ - private $depth = []; - + private array $depth = []; /** * DependencyTree constructor. @@ -106,25 +101,25 @@ public function remove(string $name): bool } #[Override] - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return $this->has($offset); } #[Override] - public function offsetGet($offset): ChildInterface + public function offsetGet(mixed $offset): ChildInterface { return $this->children[$offset]; } #[Override] - public function offsetSet($offset, $value): void + public function offsetSet(mixed $offset, mixed $value): void { $this->add($value); } #[Override] - public function offsetUnset($offset): void + public function offsetUnset(mixed $offset): void { $this->remove($offset); } diff --git a/src/Aggregate/Collection/Level.php b/src/Aggregate/Collection/Level.php index cf67050..581466e 100644 --- a/src/Aggregate/Collection/Level.php +++ b/src/Aggregate/Collection/Level.php @@ -15,32 +15,17 @@ */ final class Level implements IteratorAggregate { - /** - * @var int - */ - private $number; - - /** - * @var Level|null - */ - private $prev; - - /** - * @var Level|null - */ - private $next; - - /** - * @var Level|null - */ - private $last; + private int $number; + private ?Level $prev; + private ?Level $next = null; + private ?Level $last = null; /** * Array of elements dependencies * * @var string[][] */ - private $elements = []; + private array $elements = []; /** @@ -49,7 +34,7 @@ final class Level implements IteratorAggregate * @param Level|null $prev * @param int $number */ - public function __construct(?Level $prev = null, $number = 0) + public function __construct(?Level $prev = null, int $number = 0) { $this->prev = $prev; $this->number = $number; @@ -63,7 +48,7 @@ public function __construct(?Level $prev = null, $number = 0) * * @return int[] Associative array, with element name as key, and element level as value */ - public function add($name, array $dependencies) + public function add(string $name, array $dependencies): array { $result = [ $name => $this->number @@ -85,7 +70,7 @@ public function add($name, array $dependencies) * * @return bool */ - public function has($element) + public function has(string $element): bool { return isset($this->elements[$element]); } @@ -97,7 +82,7 @@ public function has($element) * * @return int[] The result of add() */ - public function shift($element) + public function shift(string $element): array { if ($this->next === null) { $this->next = new self($this, $this->number + 1); @@ -123,7 +108,7 @@ public function shift($element) /** * @return int */ - public function number() + public function number(): int { return $this->number; } @@ -133,7 +118,7 @@ public function number() * * @return Level|null */ - public function prev() + public function prev(): ?Level { return $this->prev; } @@ -144,7 +129,7 @@ public function prev() * * @return Level|null */ - public function last() + public function last(): ?Level { return $this->last; } @@ -155,7 +140,7 @@ public function last() * * @return Level|null */ - public function next() + public function next(): ?Level { return $this->next; } @@ -176,7 +161,7 @@ public function getIterator(): Iterator * * @param string $name The element name */ - public function reset($name): void + public function reset(string $name): void { if ($this->has($name)) { $this->elements[$name] = []; @@ -188,7 +173,7 @@ public function reset($name): void * * @param string $name */ - public function remove($name): void + public function remove(string $name): void { unset($this->elements[$name]); } diff --git a/src/Aggregate/Form.php b/src/Aggregate/Form.php index c2e65d1..734b928 100644 --- a/src/Aggregate/Form.php +++ b/src/Aggregate/Form.php @@ -9,7 +9,6 @@ use Bdf\Form\Aggregate\View\FormView; use Bdf\Form\Child\ChildInterface; use Bdf\Form\Child\Http\HttpFieldPath; -use Bdf\Form\ElementInterface; use Bdf\Form\Error\FormError; use Bdf\Form\RootElementInterface; use Bdf\Form\Transformer\NullTransformer; @@ -21,6 +20,8 @@ use Iterator; use Override; +use function assert; + /** * The base form element * A form is an static aggregate of elements, unlike ArrayElement which is a dynamic aggregate @@ -46,7 +47,7 @@ * $entity = $form->attach($entity)->value(); * * - * @template T + * @template T as array|object * @implements FormInterface */ final class Form implements FormInterface @@ -56,24 +57,24 @@ final class Form implements FormInterface /** * @var ValueValidatorInterface */ - private $validator; + private readonly ValueValidatorInterface $validator; /** * Transformer to view value * * @var TransformerInterface */ - private $transformer; + private readonly TransformerInterface $transformer; /** * @var ChildrenCollectionInterface */ - private $children; + private readonly ChildrenCollectionInterface $children; /** * @var ValueGeneratorInterface */ - private $generator; + private readonly ValueGeneratorInterface $generator; /** * Does the form is optional ? @@ -81,22 +82,10 @@ final class Form implements FormInterface * * @var bool */ - private $optional; - - /** - * @var RootElementInterface|null - */ - private $root; - - /** - * @var FormError - */ - private $error; - - /** - * @var bool - */ - private $valid = false; + private readonly bool $optional; + private ?RootElementInterface $root = null; + private FormError $error; + private bool $valid = false; /** * The generated value @@ -104,7 +93,7 @@ final class Form implements FormInterface * * @var T|null */ - private $value; + private array|object|null $value = null; /** * Does the form has been submitted ? @@ -112,7 +101,7 @@ final class Form implements FormInterface * * @var bool */ - private $submitted = false; + private bool $submitted = false; /** * Form constructor. @@ -127,15 +116,15 @@ public function __construct(ChildrenCollectionInterface $children, ?ValueValidat { $this->children = $children->duplicate($this); $this->validator = $validator ?? ConstraintValueValidator::empty(); - $this->transformer = $transformer ?: NullTransformer::instance(); + $this->transformer = $transformer ?? NullTransformer::instance(); $this->error = FormError::null(); /** @var ValueGeneratorInterface */ - $this->generator = $generator ?: new ValueGenerator(); + $this->generator = $generator ?? new ValueGenerator(); $this->optional = $optional; } #[Override] - public function submit($data): ElementInterface + public function submit(mixed $data): static { $this->valid = true; $this->value = null; @@ -153,7 +142,7 @@ public function submit($data): ElementInterface } #[Override] - public function patch($data): ElementInterface + public function patch(mixed $data): static { $this->valid = true; $this->value = null; @@ -190,14 +179,8 @@ public function error(?HttpFieldPath $field = null): FormError return $field ? $this->error->withField($field) : $this->error; } - /** - * {@inheritdoc} - * - * @param T|null $entity - * @return $this - */ #[Override] - public function import($entity): ElementInterface + public function import(mixed $entity): static { if ($entity) { $this->generator->attach($entity); @@ -214,11 +197,9 @@ public function import($entity): ElementInterface /** * {@inheritdoc} - * - * @return T */ #[Override] - public function value() + public function value(): array|object|null { if ($this->value !== null) { return $this->value; @@ -228,17 +209,18 @@ public function value() return null; } - $this->value = $this->generator->generate($this); + $value = $this->generator->generate($this); foreach ($this->children->reverseIterator() as $child) { - $child->fill($this->value); + $child->fill($value); } - return $this->value; + /** @var T $value */ + return $this->value = $value; } #[Override] - public function httpValue() + public function httpValue(): mixed { $http = []; @@ -282,26 +264,26 @@ public function getIterator(): Iterator } #[Override] - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return isset($this->children[$offset]); } #[Override] - public function offsetGet($offset): ChildInterface + public function offsetGet(mixed $offset): ChildInterface { /** @var ChildInterface */ return $this->children[$offset]; } #[Override] - public function offsetSet($offset, $value): void + public function offsetSet(mixed $offset, mixed $value): void { throw new BadMethodCallException(__CLASS__.' is immutable'); } #[Override] - public function offsetUnset($offset): void + public function offsetUnset(mixed $offset): void { throw new BadMethodCallException(__CLASS__.' is immutable'); } @@ -340,7 +322,7 @@ public function setRoot(RootElementInterface $root): void * * @return mixed The transformed value */ - private function transformHttpValue($data) + private function transformHttpValue(mixed $data): mixed { try { $data = $this->transformer->transformFromHttp($data, $this); @@ -365,7 +347,7 @@ private function transformHttpValue($data) * @param mixed $data Data to submit * @param string $method The submit method to call. Should be "submit" or "patch" */ - private function submitToChildrenAndValidate($data, string $method): void + private function submitToChildrenAndValidate(mixed $data, string $method): void { if (!$this->submitToChildren($data, $method)) { return; @@ -388,7 +370,7 @@ private function submitToChildrenAndValidate($data, string $method): void * * @return bool false on fail, or true on success */ - private function submitToChildren($data, string $method): bool + private function submitToChildren(mixed $data, string $method): bool { if (!$this->valid) { return false; @@ -420,7 +402,7 @@ private function submitToChildren($data, string $method): bool * * @return bool true if the form is optional and not submitted, false otherwise */ - private function handleOptional($data): bool + private function handleOptional(mixed $data): bool { if (!$this->optional || $data !== null && $data !== [] && $data !== '') { return false; diff --git a/src/Aggregate/FormBuilder.php b/src/Aggregate/FormBuilder.php index 541eabf..ce9a0fb 100644 --- a/src/Aggregate/FormBuilder.php +++ b/src/Aggregate/FormBuilder.php @@ -74,32 +74,16 @@ class FormBuilder extends AbstractElementBuilder implements FormBuilderInterface /** * @var array */ - private $children = []; + private array $children = []; /** * @var array */ - private $buttons = []; - - /** - * @var PropertyAccessorInterface|null - */ - private $propertyAccessor; - - /** - * @var ValidatorInterface|null - */ - private $validator; - - /** - * @var ValueGeneratorInterface|null - */ - private $generator; - - /** - * @var bool - */ - private $optional = false; + private array $buttons = []; + private ?PropertyAccessorInterface $propertyAccessor = null; + private ?ValidatorInterface $validator = null; + private ?ValueGeneratorInterface $generator = null; + private bool $optional = false; /** diff --git a/src/Aggregate/FormBuilderInterface.php b/src/Aggregate/FormBuilderInterface.php index bab2139..f05c52a 100644 --- a/src/Aggregate/FormBuilderInterface.php +++ b/src/Aggregate/FormBuilderInterface.php @@ -303,7 +303,7 @@ public function generator(ValueGeneratorInterface $generator): FormBuilderInterf * @see ValueGenerator * @see ElementInterface::value() */ - public function generates($entity): FormBuilderInterface; + public function generates(mixed $entity): FormBuilderInterface; /** * Mark the form as optional diff --git a/src/Aggregate/FormInterface.php b/src/Aggregate/FormInterface.php index f08a1df..454c613 100644 --- a/src/Aggregate/FormInterface.php +++ b/src/Aggregate/FormInterface.php @@ -9,7 +9,7 @@ /** * The base form element type * - * @template T + * @template T as array|object * @extends ChildAggregateInterface */ interface FormInterface extends ChildAggregateInterface @@ -33,13 +33,13 @@ interface FormInterface extends ChildAggregateInterface * $this->repository->save($form->value()); * * - * @param T|class-string|callable():T $entity The entity object, or class name + * @param T|class-string|callable():T $entity The entity object, or class name * * @return $this * * @see Form::import() For attach and extract values from properties */ - public function attach($entity): FormInterface; + public function attach(mixed $entity): FormInterface; #[Override] public function view(?HttpFieldPath $field = null): FormView; diff --git a/src/Aggregate/RootForm.php b/src/Aggregate/RootForm.php index 62b5be1..ef9ab53 100644 --- a/src/Aggregate/RootForm.php +++ b/src/Aggregate/RootForm.php @@ -22,6 +22,8 @@ use Symfony\Component\Validator\ValidatorBuilder; use WeakReference; +use function assert; + /** * Adapt a form element as root element * The root form handle constraint group, validator and property accessor instances, and submit button @@ -60,28 +62,15 @@ final class RootForm implements RootElementInterface, ChildAggregateInterface /** * @var WeakReference
*/ - private $form; + private readonly WeakReference $form; /** * @var array */ - private $buttons; - - /** - * @var ButtonInterface|null - */ - private $submitButton; - - /** - * @var PropertyAccessorInterface|null - */ - private $propertyAccessor; - - /** - * @var ValidatorInterface|null - */ - private $validator; - + private readonly array $buttons; + private ?ButtonInterface $submitButton = null; + private ?PropertyAccessorInterface $propertyAccessor = null; + private ?ValidatorInterface $validator = null; /** * RootForm constructor. @@ -100,42 +89,41 @@ public function __construct(Form $form, array $buttons = [], ?PropertyAccessorIn } #[Override] - public function submit($data): ElementInterface + public function submit(mixed $data): static { $this->submitToButtons($data); - $this->form?->get()->submit($data); + $this->form->get()?->submit($data); return $this; } #[Override] - public function patch($data): ElementInterface + public function patch(mixed $data): static { $this->submitToButtons($data); - $this->form?->get()->patch($data); + $this->form->get()?->patch($data); return $this; } #[Override] - public function import($entity): ElementInterface + public function import(mixed $entity): static { - /** @psalm-suppress PossiblyNullReference */ - $this->form->get()->import($entity); + $this->form->get()?->import($entity); return $this; } #[Override] - public function value() + public function value(): mixed { - return $this->form?->get()->value(); + return $this->form->get()?->value(); } #[Override] - public function httpValue() + public function httpValue(): mixed { - $httpValue = $this->form?->get()->httpValue(); + $httpValue = $this->form->get()?->httpValue(); if (empty($this->buttons)) { return $httpValue; @@ -153,8 +141,7 @@ public function httpValue() #[Override] public function valid(): bool { - /** @psalm-suppress PossiblyNullReference */ - return $this->form->get()->valid(); + return $this->form->get()?->valid() ?? false; } #[Override] @@ -167,7 +154,7 @@ public function failed(): bool #[Override] public function error(?HttpFieldPath $field = null): FormError { - return $this->form?->get()->error($field); + return $this->form->get()?->error($field) ?? throw new LogicException('Invalid reference'); } #[Override] @@ -197,8 +184,8 @@ public function view(?HttpFieldPath $field = null): ElementViewInterface $buttons[$button->name()] = $button->view($field); } - /** @psalm-suppress PossiblyNullReference */ - $view = $this->form->get()->view($field); + $view = $this->form->get()?->view($field); + assert($view !== null); $view->setButtons($buttons); return $view; @@ -224,7 +211,7 @@ public function button(string $name): ButtonInterface public function getValidator(): ValidatorInterface { if ($this->validator === null) { - $this->validator = (new ValidatorBuilder())->getValidator(); + $this->validator = new ValidatorBuilder()->getValidator(); } return $this->validator; @@ -233,11 +220,7 @@ public function getValidator(): ValidatorInterface #[Override] public function getPropertyAccessor(): PropertyAccessorInterface { - if ($this->propertyAccessor === null) { - $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); - } - - return $this->propertyAccessor; + return $this->propertyAccessor ??= PropertyAccess::createPropertyAccessor(); } #[Override] @@ -259,26 +242,26 @@ public function constraintGroups(): array * @psalm-suppress NullableReturnStatement */ #[Override] - public function offsetGet($offset): ChildInterface + public function offsetGet(mixed $offset): ChildInterface { return $this->form->get()[$offset]; } #[Override] - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return isset($this->form->get()[$offset]); } #[Override] - public function offsetSet($offset, $value): void + public function offsetSet(mixed $offset, mixed $value): void { /** @psalm-suppress PossiblyNullReference */ $this->form->get()[$offset] = $value; } #[Override] - public function offsetUnset($offset): void + public function offsetUnset(mixed $offset): void { if ($form = $this->form->get()) { unset($form[$offset]); @@ -296,7 +279,7 @@ public function getIterator(): Iterator * * @param mixed $data The HTTP value */ - private function submitToButtons($data): void + private function submitToButtons(mixed $data): void { $this->submitButton = null; diff --git a/src/Aggregate/Value/ValueGenerator.php b/src/Aggregate/Value/ValueGenerator.php index 88765f6..2c78271 100644 --- a/src/Aggregate/Value/ValueGenerator.php +++ b/src/Aggregate/Value/ValueGenerator.php @@ -5,6 +5,10 @@ use Bdf\Form\ElementInterface; use Override; +use function is_callable; +use function is_object; +use function is_string; + /** * The base value generator implementation * @@ -23,33 +27,33 @@ final class ValueGenerator implements ValueGeneratorInterface /** * @var callable():T|T|class-string */ - private $value; + private mixed $value; /** * @var callable():T|T|class-string|null */ - private $attachment; + private mixed $attachment = null; /** * ValueGenerator constructor. * * @param callable():T|T|class-string $value */ - public function __construct($value = []) + public function __construct(mixed $value = []) { /** @psalm-suppress PropertyTypeCoercion */ $this->value = $value; } #[Override] - public function attach($entity): void + public function attach(mixed $entity): void { /** @psalm-suppress PropertyTypeCoercion */ $this->attachment = $entity; } #[Override] - public function generate(ElementInterface $element) + public function generate(ElementInterface $element): mixed { $value = $this->attachment ?? $this->value; diff --git a/src/Aggregate/Value/ValueGeneratorInterface.php b/src/Aggregate/Value/ValueGeneratorInterface.php index f50d3cc..f436d2a 100644 --- a/src/Aggregate/Value/ValueGeneratorInterface.php +++ b/src/Aggregate/Value/ValueGeneratorInterface.php @@ -23,7 +23,7 @@ interface ValueGeneratorInterface * @param T|callable():T|class-string $entity * @see FormInterface::attach() */ - public function attach($entity): void; + public function attach(mixed $entity): void; /** * Generate the value @@ -34,5 +34,5 @@ public function attach($entity): void; * @return T * @see FormInterface::value() */ - public function generate(ElementInterface $element); + public function generate(ElementInterface $element): mixed; } diff --git a/src/Aggregate/View/ArrayElementView.php b/src/Aggregate/View/ArrayElementView.php index df2444f..3922d5a 100644 --- a/src/Aggregate/View/ArrayElementView.php +++ b/src/Aggregate/View/ArrayElementView.php @@ -56,7 +56,7 @@ final class ArrayElementView implements IteratorAggregate, FieldViewInterface, F * @param array $constraints * @param ChoiceView[]|null $choices */ - public function __construct(string $type, string $name, $value, ?string $error, array $elements, bool $required, array $constraints, ?array $choices = []) + public function __construct(string $type, string $name, mixed $value, ?string $error, array $elements, bool $required, array $constraints, ?array $choices = []) { $this->type = $type; $this->name = $name; diff --git a/src/Aggregate/View/ArrayElementViewRenderer.php b/src/Aggregate/View/ArrayElementViewRenderer.php index 5078339..11424ff 100644 --- a/src/Aggregate/View/ArrayElementViewRenderer.php +++ b/src/Aggregate/View/ArrayElementViewRenderer.php @@ -13,22 +13,10 @@ * * @implements FieldViewRendererInterface */ -final class ArrayElementViewRenderer implements FieldViewRendererInterface +final readonly class ArrayElementViewRenderer implements FieldViewRendererInterface { - /** - * @var ArrayElementViewRenderer|null - */ - private static $instance; - - /** - * @var FieldViewRendererInterface - */ - private $csvRenderer; - - /** - * @var FieldViewRendererInterface - */ - private $selectRenderer; + private FieldViewRendererInterface $csvRenderer; + private FieldViewRendererInterface $selectRenderer; /** * ArrayElementViewRenderer constructor. @@ -59,6 +47,8 @@ public function render(FieldViewInterface $view, array $attributes): string */ public static function instance(): self { - return self::$instance ??= new self(); + static $instance = new self(); + + return $instance; } } diff --git a/src/Aggregate/View/FormView.php b/src/Aggregate/View/FormView.php index e4f8cf7..18ccdfe 100644 --- a/src/Aggregate/View/FormView.php +++ b/src/Aggregate/View/FormView.php @@ -44,7 +44,7 @@ final class FormView implements IteratorAggregate, FieldSetViewInterface /** * @var ButtonViewInterface[] */ - private $buttons = []; + private array $buttons = []; /** * FormView constructor. @@ -61,13 +61,13 @@ public function __construct(string $type, ?string $error, array $elements) } #[Override] - public function offsetGet($offset): ElementViewInterface|ButtonViewInterface + public function offsetGet(mixed $offset): ElementViewInterface|ButtonViewInterface { return $this->elements[$offset] ?? $this->buttons[$offset]; } #[Override] - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return isset($this->elements[$offset]) || isset($this->buttons[$offset]); } diff --git a/src/Button/ButtonBuilderInterface.php b/src/Button/ButtonBuilderInterface.php index 3748798..f79ee0d 100644 --- a/src/Button/ButtonBuilderInterface.php +++ b/src/Button/ButtonBuilderInterface.php @@ -15,7 +15,7 @@ interface ButtonBuilderInterface * * @return $this */ - public function value(string $value): ButtonBuilderInterface; + public function value(string $value): static; /** * Define the constraint groups to use when the button is clicked @@ -26,7 +26,7 @@ public function value(string $value): ButtonBuilderInterface; * * @see https://symfony.com/doc/current/validation/groups.html */ - public function groups(array $groups): ButtonBuilderInterface; + public function groups(array $groups): static; /** * Build the button element diff --git a/src/Button/ButtonInterface.php b/src/Button/ButtonInterface.php index 03621d4..1de9598 100644 --- a/src/Button/ButtonInterface.php +++ b/src/Button/ButtonInterface.php @@ -34,7 +34,7 @@ public function clicked(): bool; * * @return bool true is the button is clicked, or false */ - public function submit($data): bool; + public function submit(mixed $data): bool; /** * Get the http value of the button diff --git a/src/Button/SubmitButton.php b/src/Button/SubmitButton.php index 6eb94b4..36d63ba 100644 --- a/src/Button/SubmitButton.php +++ b/src/Button/SubmitButton.php @@ -13,26 +13,14 @@ */ final class SubmitButton implements ButtonInterface { - /** - * @var string - */ - private $name; - - /** - * @var string - */ - private $value; + private readonly string $name; + private readonly string $value; /** - * @var array + * @var string[] */ - private $groups; - - /** - * @var bool - */ - private $clicked = false; - + private readonly array $groups; + private bool $clicked = false; /** * SubmitButton constructor. diff --git a/src/Button/SubmitButtonBuilder.php b/src/Button/SubmitButtonBuilder.php index b8797a1..cdc0dfb 100644 --- a/src/Button/SubmitButtonBuilder.php +++ b/src/Button/SubmitButtonBuilder.php @@ -21,25 +21,22 @@ */ final class SubmitButtonBuilder implements ButtonBuilderInterface { - /** - * @var string - */ - private $name; + private readonly string $name; /** * @var class-string */ - private $buttonClass; + private string $buttonClass; /** * @var string */ - private $value = 'ok'; + private string $value = 'ok'; /** - * @var array + * @var string[] */ - private $groups = []; + private array $groups = []; /** @@ -55,7 +52,7 @@ public function __construct(string $name, string $buttonClass = SubmitButton::cl } #[Override] - public function value(string $value): ButtonBuilderInterface + public function value(string $value): static { $this->value = $value; @@ -63,7 +60,7 @@ public function value(string $value): ButtonBuilderInterface } #[Override] - public function groups(array $groups): ButtonBuilderInterface + public function groups(array $groups): static { $this->groups = $groups; diff --git a/src/Button/View/ButtonView.php b/src/Button/View/ButtonView.php index 52be7b0..efea048 100644 --- a/src/Button/View/ButtonView.php +++ b/src/Button/View/ButtonView.php @@ -17,20 +17,9 @@ final class ButtonView implements ButtonViewInterface { use RenderableTrait; - /** - * @var string - */ - private $name; - - /** - * @var string - */ - private $value; - - /** - * @var bool - */ - private $clicked; + public private(set) string $name; + public private(set) string $value; + public private(set) bool $clicked; /** * ButtonView constructor. diff --git a/src/Child/Child.php b/src/Child/Child.php index 093e0be..0e4269b 100644 --- a/src/Child/Child.php +++ b/src/Child/Child.php @@ -15,6 +15,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Util\HttpValue; use Bdf\Form\View\ElementViewInterface; +use LogicException; use Override; use WeakReference; @@ -25,55 +26,32 @@ */ final class Child implements ChildInterface { - /** - * @var ElementInterface - */ - private $element; + private readonly ElementInterface $element; /** * @var WeakReference */ - private $parent; - - /** - * @var string - */ - private $name; + private ?WeakReference $parent = null; + private readonly string $name; /** * @var HttpFieldsInterface */ - private $fields; - - /** - * @var mixed - */ - private $defaultValue; + private readonly HttpFieldsInterface $fields; + private readonly mixed $defaultValue; /** * @var FilterInterface[] */ - private $filters; - - /** - * @var HydratorInterface|null - */ - private $hydrator; - - /** - * @var ExtractorInterface|null - */ - private $extractor; + private readonly array $filters; + private readonly ?HydratorInterface $hydrator; + private readonly ?ExtractorInterface $extractor; /** * @var string[] */ - private $dependencies; - - /** - * @var TransformerInterface - */ - private $transformer; + private readonly array $dependencies; + private readonly TransformerInterface $transformer; /** @@ -109,18 +87,15 @@ public function element(): ElementInterface /** * {@inheritdoc} - * - * @psalm-suppress NullableReturnStatement - * @psalm-suppress InvalidNullableReturnType */ #[Override] public function parent(): ChildAggregateInterface { - return $this->parent->get(); + return $this->parent?->get() ?? throw new LogicException('No parent has been set.'); } #[Override] - public function setParent(ChildAggregateInterface $parent): ChildInterface + public function setParent(ChildAggregateInterface $parent): static { if ($this->parent === null) { $this->parent = WeakReference::create($parent); @@ -146,13 +121,18 @@ public function dependencies(): array } #[Override] - public function import($entity): void + public function import(array|object|null $entity): void { if (!$this->extractor) { return; } - $propertyAccessor = $this->parent->get()?->root()?->getPropertyAccessor(); + if ($entity === null) { + $this->element->import(null); + return; + } + + $propertyAccessor = $this->parent?->get()?->root()?->getPropertyAccessor(); assert($propertyAccessor !== null); $this->extractor->setPropertyAccessor($propertyAccessor); @@ -166,13 +146,13 @@ public function import($entity): void } #[Override] - public function fill(&$entity): void + public function fill(array|object &$entity): void { if (!$this->hydrator) { return; } - $propertyAccessor = $this->parent->get()?->root()?->getPropertyAccessor(); + $propertyAccessor = $this->parent?->get()?->root()?->getPropertyAccessor(); assert($propertyAccessor !== null); $this->hydrator->setPropertyAccessor($propertyAccessor); @@ -186,7 +166,7 @@ public function fill(&$entity): void } #[Override] - public function submit($data): bool + public function submit(mixed $data): bool { $value = $this->extractValue($data); @@ -194,7 +174,7 @@ public function submit($data): bool } #[Override] - public function patch($data): bool + public function patch(mixed $data): bool { $value = $data !== null && $this->fields->contains($data) ? $this->extractValue($data) @@ -233,7 +213,7 @@ public function __clone() * @param mixed $httpValue * @return mixed The filtered value */ - private function extractValue($httpValue) + private function extractValue(mixed $httpValue): mixed { $value = $this->fields->extract($httpValue); $default = $this->defaultValue; diff --git a/src/Child/ChildBuilder.php b/src/Child/ChildBuilder.php index 332af70..c378109 100644 --- a/src/Child/ChildBuilder.php +++ b/src/Child/ChildBuilder.php @@ -39,7 +39,6 @@ * * @method $this satisfy($constraint, $options = null, bool $append = true) * @method $this value($value) - * @method $this transformer($transformer, bool $append = true) * @method $this required($options = null) * * @template B as ElementBuilderInterface @@ -52,75 +51,56 @@ class ChildBuilder implements ChildBuilderInterface transformer as modelTransformer; } - /** - * @var string - */ - private $name; - - /** - * @var RegistryInterface - */ - private $registry; + private readonly string $name; + private readonly RegistryInterface $registry; /** * The list of input dependencies * * @var string[] */ - private $viewDependencies = []; - - /** - * @var mixed - */ - private $default; + private array $viewDependencies = []; + private mixed $default = null; /** * @var array */ - private $filters = []; + private array $filters = []; /** * @var list */ - private $filtersProviders = []; + private array $filtersProviders = []; /** * @var class-string */ - private $childClassName = Child::class; + private string $childClassName = Child::class; /** * @var list */ - private $parametersConfigurators = []; + private array $parametersConfigurators = []; /** * @var HttpFieldsInterface|null */ - private $fields; + private ?HttpFieldsInterface $fields = null; /** * @var ElementBuilderInterface * @psalm-var B */ - private $elementBuilder; - - /** - * @var HydratorInterface|null - */ - private $hydrator; - - /** - * @var ExtractorInterface|null - */ - private $extractor; + private readonly ElementBuilderInterface $elementBuilder; + private ?HydratorInterface $hydrator = null; + private ?ExtractorInterface $extractor = null; /** * Add the trim filter * * @var bool */ - private $trim = true; + private bool $trim = true; /** @@ -134,11 +114,11 @@ public function __construct(string $name, ElementBuilderInterface $elementBuilde { $this->name = $name; $this->elementBuilder = $elementBuilder; - $this->registry = $registry ?: new Registry(); + $this->registry = $registry ?? new Registry(); } #[Override] - final public function hydrator(HydratorInterface $hydrator) + final public function hydrator(HydratorInterface $hydrator): static { $this->hydrator = $hydrator; @@ -146,7 +126,7 @@ final public function hydrator(HydratorInterface $hydrator) } #[Override] - final public function extractor(ExtractorInterface $extractor) + final public function extractor(ExtractorInterface $extractor): static { $this->extractor = $extractor; @@ -154,7 +134,7 @@ final public function extractor(ExtractorInterface $extractor) } #[Override] - final public function filter(FilterInterface|callable $filter, bool $append = true) + final public function filter(FilterInterface|callable $filter, bool $append = true): static { if (is_callable($filter)) { $filter = new ClosureFilter($filter); @@ -170,7 +150,7 @@ final public function filter(FilterInterface|callable $filter, bool $append = tr } #[Override] - final public function default($default) + final public function default(mixed $default): static { $this->default = $default; @@ -178,7 +158,7 @@ final public function default($default) } #[Override] - final public function depends(string ...$inputNames) + final public function depends(string ...$inputNames): static { foreach ($inputNames as $inputName) { $this->viewDependencies[$inputName] = $inputName; @@ -188,7 +168,7 @@ final public function depends(string ...$inputNames) } #[Override] - public function addParametersConfigurator(callable $configurator) + public function addParametersConfigurator(callable $configurator): static { $this->parametersConfigurators[] = $configurator; @@ -271,7 +251,7 @@ final public function buildChild(): ChildInterface * @see ChildBuilderInterface::extractor() * @see ChildInterface::import() */ - final public function getter($propertyName = null, ?callable $transformer = null, ?callable $customAccessor = null): self + final public function getter(string|callable|null $propertyName = null, ?callable $transformer = null, ?callable $customAccessor = null): static { return $this->extractor(new Getter($propertyName, $transformer, $customAccessor)); } @@ -322,7 +302,7 @@ final public function getter($propertyName = null, ?callable $transformer = null * @see ChildBuilderInterface::hydrator() * @see ChildInterface::fill() */ - final public function setter($propertyName = null, ?callable $transformer = null, ?callable $customAccessor = null): self + final public function setter(string|callable|null $propertyName = null, ?callable $transformer = null, ?callable $customAccessor = null): static { return $this->hydrator(new Setter($propertyName, $transformer, $customAccessor)); } @@ -350,7 +330,7 @@ final public function setter($propertyName = null, ?callable $transformer = null * * @since 1.5 */ - final public function getset(?string $propertyName = null): self + final public function getset(?string $propertyName = null): static { return $this->getter($propertyName)->setter($propertyName); } @@ -362,7 +342,7 @@ final public function getset(?string $propertyName = null): self * * @return $this */ - final public function childClassName(string $factory): self + final public function childClassName(string $factory): static { $this->childClassName = $factory; @@ -376,7 +356,7 @@ final public function childClassName(string $factory): self * * @return $this */ - final public function httpFields(HttpFieldsInterface $fields): self + final public function httpFields(HttpFieldsInterface $fields): static { $this->fields = $fields; @@ -409,7 +389,7 @@ final public function httpFields(HttpFieldsInterface $fields): self * * @see PrefixedHttpFields */ - final public function prefix(?string $prefix = null): self + final public function prefix(?string $prefix = null): static { return $this->httpFields(new PrefixedHttpFields($prefix ?? $this->name.'_')); } @@ -423,7 +403,7 @@ final public function prefix(?string $prefix = null): self * * @return $this */ - final public function trim(bool $active = true): self + final public function trim(bool $active = true): static { $this->trim = $active; @@ -443,7 +423,7 @@ final public function trim(bool $active = true): self * * @return $this */ - final public function configure(callable $configurator): self + final public function configure(callable $configurator): static { $configurator($this->elementBuilder); @@ -459,7 +439,7 @@ final public function configure(callable $configurator): self * * @see ElementBuilderInterface::transformer() */ - public function transformer(callable|TransformerInterface $transformer, bool $append = true) + public function transformer(callable|TransformerInterface $transformer, bool $append = true): static { $this->elementBuilder->transformer($transformer, $append); @@ -502,14 +482,16 @@ final protected function addFilterProvider(callable $provider): void */ private function buildParameters(): ChildParameters { - $parameters = new ChildParameters(); - - $parameters->name = $this->name; - $parameters->hydrator = $this->hydrator; - $parameters->extractor = $this->extractor; - $parameters->dependencies = $this->viewDependencies; - $parameters->modelTransformer = $this->buildTransformer(); - $parameters->className = $this->childClassName; + $parameters = new ChildParameters( + name: $this->name, + element: $this->elementBuilder->buildElement(), + fields: $this->fields ?: new ArrayOffsetHttpFields($this->name), + hydrator: $this->hydrator, + extractor: $this->extractor, + dependencies: $this->viewDependencies, + modelTransformer: $this->buildTransformer(), + className: $this->childClassName, + ); $parameters->filters = $this->trim ? [TrimFilter::instance()] : []; $parameters->filters = [...$parameters->filters, ...$this->filters]; @@ -518,9 +500,6 @@ private function buildParameters(): ChildParameters $parameters->filters = [...$parameters->filters, ...$provider($this->registry)]; } - $parameters->fields = $this->fields ?: new ArrayOffsetHttpFields($this->name); - $parameters->element = $this->elementBuilder->buildElement(); - // Apply element transformation to the default value if ($this->default !== null) { $lastValue = $parameters->element->value(); diff --git a/src/Child/ChildBuilderInterface.php b/src/Child/ChildBuilderInterface.php index b174281..746c503 100644 --- a/src/Child/ChildBuilderInterface.php +++ b/src/Child/ChildBuilderInterface.php @@ -28,7 +28,7 @@ interface ChildBuilderInterface * @see ChildInterface::fill() * @see ChildBuilder::setter() For define simple hydrator */ - public function hydrator(HydratorInterface $hydrator); + public function hydrator(HydratorInterface $hydrator): static; /** * Define the extractor for the child @@ -41,7 +41,7 @@ public function hydrator(HydratorInterface $hydrator); * @see ChildInterface::import() * @see ChildBuilder::getter() For define simple extractor */ - public function extractor(ExtractorInterface $extractor); + public function extractor(ExtractorInterface $extractor): static; /** * Add a filter @@ -67,7 +67,7 @@ public function extractor(ExtractorInterface $extractor); * * @see FilterInterface */ - public function filter(FilterInterface|callable $filter, bool $append = true); + public function filter(FilterInterface|callable $filter, bool $append = true): static; /** * Define the default value @@ -87,7 +87,7 @@ public function filter(FilterInterface|callable $filter, bool $append = true); * * @see ElementBuilderInterface::value() For set the initial value */ - public function default($default); + public function default($default): static; /** * Add a configurator for child parameters @@ -110,7 +110,7 @@ public function default($default); * * @return $this */ - public function addParametersConfigurator(callable $configurator); + public function addParametersConfigurator(callable $configurator): static; /** * Add an input dependency @@ -133,7 +133,7 @@ public function addParametersConfigurator(callable $configurator); * * @return $this */ - public function depends(string ...$inputNames); + public function depends(string ...$inputNames): static; /** * Add a model transformer @@ -167,7 +167,7 @@ public function depends(string ...$inputNames); * * @see TransformerInterface */ - public function modelTransformer(callable|TransformerInterface $transformer, bool $append = true); + public function modelTransformer(callable|TransformerInterface $transformer, bool $append = true): static; /** * Creates the child instance diff --git a/src/Child/ChildCreationStrategyInterface.php b/src/Child/ChildCreationStrategyInterface.php index d4a60b9..3964a5a 100644 --- a/src/Child/ChildCreationStrategyInterface.php +++ b/src/Child/ChildCreationStrategyInterface.php @@ -29,5 +29,5 @@ interface ChildCreationStrategyInterface * * @return ChildInterface */ - public function __invoke(string $name, ElementInterface $element, HttpFieldsInterface $fields, array $filters, $defaultValue, ?HydratorInterface $hydrator, ?ExtractorInterface $extractor, array $dependencies, ?TransformerInterface $transformer): ChildInterface; + public function __invoke(string $name, ElementInterface $element, HttpFieldsInterface $fields, array $filters, mixed $defaultValue, ?HydratorInterface $hydrator, ?ExtractorInterface $extractor, array $dependencies, ?TransformerInterface $transformer): ChildInterface; } diff --git a/src/Child/ChildInterface.php b/src/Child/ChildInterface.php index c858670..f679ccb 100644 --- a/src/Child/ChildInterface.php +++ b/src/Child/ChildInterface.php @@ -49,7 +49,7 @@ public function parent(): ChildAggregateInterface; * * @return static The child instance linked with the parent */ - public function setParent(ChildAggregateInterface $parent): self; + public function setParent(ChildAggregateInterface $parent): static; /** * Get the element's name @@ -78,20 +78,20 @@ public function dependencies(): array; * Import values from the entity * Use a PropertyAccessor for extract related attributes * - * @param mixed $entity + * @param array|object|null $entity * * @see AccessorInterface */ - public function import($entity): void; + public function import(array|object|null $entity): void; /** * Hydrate entity with the child value * Use a PropertyAccessor for hydrate related attributes * This is the opposite operation of import() * - * @param mixed $entity + * @param array|object $entity */ - public function fill(&$entity): void; + public function fill(array|object &$entity): void; /** * Submit HTTP form data @@ -107,7 +107,7 @@ public function fill(&$entity): void; * * @see ElementInterface::submit() The element submit() method */ - public function submit($data): bool; + public function submit(mixed $data): bool; /** * Submit HTTP form data without override previous ones @@ -119,7 +119,7 @@ public function submit($data): bool; * * @see ElementInterface::patch() The element patch() method */ - public function patch($data): bool; + public function patch(mixed $data): bool; /** * Export the http value of the child as an array diff --git a/src/Child/ChildParameters.php b/src/Child/ChildParameters.php index 42c1572..83a44dd 100644 --- a/src/Child/ChildParameters.php +++ b/src/Child/ChildParameters.php @@ -14,89 +14,91 @@ */ final class ChildParameters { - /** - * The child name - * - * @var string - */ - public $name; + public function __construct( + /** + * The child name + * + * @var string + */ + public string $name, - /** - * The inner element instance - * - * @var ElementInterface - */ - public $element; + /** + * The inner element instance + * + * @var ElementInterface + */ + public ElementInterface $element, - /** - * Http Fields to use - * - * @var HttpFieldsInterface - */ - public $fields; + /** + * Http Fields to use + * + * @var HttpFieldsInterface + */ + public HttpFieldsInterface $fields, - /** - * @var FilterInterface[] - */ - public $filters; + /** + * @var HydratorInterface|null + */ + public ?HydratorInterface $hydrator, - /** - * @var mixed - */ - public $defaultValue; + /** + * @var ExtractorInterface|null + */ + public ?ExtractorInterface $extractor, - /** - * @var HydratorInterface|null - */ - public $hydrator; + /** + * Array of dependencies child names + * + * @var string[] + */ + public array $dependencies, - /** - * @var ExtractorInterface|null - */ - public $extractor; + /** + * @var TransformerInterface|null + */ + public ?TransformerInterface $modelTransformer, - /** - * Array of dependencies child names - * - * @var string[] - */ - public $dependencies; + /** + * The child class name + * + * @var class-string + */ + public string $className, - /** - * @var TransformerInterface|null - */ - public $modelTransformer; + /** + * @var mixed + */ + public mixed $defaultValue = null, - /** - * The child class name - * - * @var class-string - */ - public $className; + /** + * @var FilterInterface[] + */ + public array $filters = [], - /** - * The child instance - * Set a value to ignore the default child instantiation on the ChildBuilder - * - * @var ChildInterface|null - */ - public $child; + /** + * The child instance + * Set a value to ignore the default child instantiation on the ChildBuilder + * + * @var ChildInterface|null + */ + public ?ChildInterface $child = null, - /** - * List of child factories to apply - * The return value of each factories will fill the $this->child field - * - * This parameter can be used to decorate a child instance like : - * - * public function decorateChild(ChildParameters $parameters) - * { - * $parameters->factories[] = function (ChildParameters $parameters) { - * return new MyChildWrapper($parameters->child); - * }; - * } - * - * - * @var (callable(ChildParameters):ChildInterface)[] - */ - public $factories = []; + /** + * List of child factories to apply + * The return value of each factories will fill the $this->child field + * + * This parameter can be used to decorate a child instance like : + * + * public function decorateChild(ChildParameters $parameters) + * { + * $parameters->factories[] = function (ChildParameters $parameters) { + * return new MyChildWrapper($parameters->child); + * }; + * } + * + * + * @var (callable(ChildParameters):ChildInterface)[] + */ + public array $factories = [], + ) {} } diff --git a/src/Child/Http/ArrayOffsetHttpFields.php b/src/Child/Http/ArrayOffsetHttpFields.php index 5cfdf9e..e2a6464 100644 --- a/src/Child/Http/ArrayOffsetHttpFields.php +++ b/src/Child/Http/ArrayOffsetHttpFields.php @@ -4,6 +4,8 @@ use Override; +use function is_array; + /** * Extract HTTP fields value using a simple array offset * This is the default http fields implementation @@ -15,26 +17,17 @@ * $fields->extract(['other' => 'value'], 'not found'); // => 'not found' * */ -final class ArrayOffsetHttpFields implements HttpFieldsInterface +final readonly class ArrayOffsetHttpFields implements HttpFieldsInterface { - /** - * @var string - */ - private $offset; - - - /** - * ArrayOffsetHttpFields constructor. - * - * @param string $offset The field name - */ - public function __construct(string $offset) - { - $this->offset = $offset; - } + public function __construct( + /** + * The HTTP field name + */ + private string $offset, + ) {} #[Override] - public function extract($httpFields) + public function extract(mixed $httpFields): mixed { if (!is_array($httpFields) || !isset($httpFields[$this->offset])) { return null; @@ -50,7 +43,7 @@ public function contains($httpFields): bool } #[Override] - public function format($value) + public function format(mixed $value): array { return [$this->offset => $value]; } diff --git a/src/Child/Http/HttpFieldPath.php b/src/Child/Http/HttpFieldPath.php index d3fbd6a..49b413f 100644 --- a/src/Child/Http/HttpFieldPath.php +++ b/src/Child/Http/HttpFieldPath.php @@ -20,25 +20,10 @@ */ final class HttpFieldPath implements Stringable { - /** - * @var HttpFieldPath|null - */ - private static $empty; - - /** - * @var string - */ - private $root = ''; - - /** - * @var string - */ - private $path = ''; - - /** - * @var string - */ - private $prefix = ''; + private static ?self $empty = null; + private string $root = ''; + private string $path = ''; + private string $prefix = ''; /** * HttpFieldPath constructor. @@ -94,6 +79,7 @@ public function add(string $name): self */ public function concat(HttpFieldPath $other): self { + // @todo use clone with + readonly when support of PHP < 8.5 will be dropped $newPath = clone $this; if ($other->root !== '') { @@ -187,11 +173,7 @@ public function __toString(): string */ public static function empty(): HttpFieldPath { - if (self::$empty) { - return self::$empty; - } - - return self::$empty = new HttpFieldPath(); + return self::$empty ??= new HttpFieldPath(); } /** diff --git a/src/Child/Http/HttpFieldsInterface.php b/src/Child/Http/HttpFieldsInterface.php index 18fb1d3..0f87989 100644 --- a/src/Child/Http/HttpFieldsInterface.php +++ b/src/Child/Http/HttpFieldsInterface.php @@ -16,7 +16,7 @@ interface HttpFieldsInterface * * @return mixed */ - public function extract($httpFields); + public function extract(mixed $httpFields): mixed; /** * Does the required field is contained into given http fields @@ -26,7 +26,7 @@ public function extract($httpFields); * * @return bool true if the field is available */ - public function contains($httpFields): bool; + public function contains(mixed $httpFields): bool; /** * Format an element value to HTTP fields @@ -35,7 +35,7 @@ public function contains($httpFields): bool; * * @return mixed */ - public function format($value); + public function format(mixed $value): mixed; /** * Get the field path for the current child diff --git a/src/Child/Http/PrefixedHttpFields.php b/src/Child/Http/PrefixedHttpFields.php index 3afdd0e..ad63685 100644 --- a/src/Child/Http/PrefixedHttpFields.php +++ b/src/Child/Http/PrefixedHttpFields.php @@ -4,6 +4,10 @@ use Override; +use function str_starts_with; +use function strlen; +use function substr; + /** * Extract HTTP fields value prefixed by a given string * @@ -16,26 +20,17 @@ * $fields->extract(['other' => 'value'], ['not found']); // => ['not found'] * */ -final class PrefixedHttpFields implements HttpFieldsInterface +final readonly class PrefixedHttpFields implements HttpFieldsInterface { - /** - * @var string - */ - private $prefix; - - - /** - * ArrayOffsetHttpFields constructor. - * - * @param string $prefix The http fields prefix - */ - public function __construct(string $prefix) - { - $this->prefix = $prefix; - } + public function __construct( + /** + * The http fields prefix + */ + private string $prefix + ) {} #[Override] - public function extract($httpFields) + public function extract(mixed $httpFields): array { $data = (array) $httpFields; $prefixLen = strlen($this->prefix); @@ -62,11 +57,11 @@ public function contains($httpFields): bool } #[Override] - public function format($value) + public function format(mixed $value): array { $http = []; - foreach ($value as $field => $fieldValue) { + foreach ((array) $value as $field => $fieldValue) { $http[$this->prefix.$field] = $fieldValue; } diff --git a/src/Choice/ArrayChoice.php b/src/Choice/ArrayChoice.php index 1754b24..2c3abfa 100644 --- a/src/Choice/ArrayChoice.php +++ b/src/Choice/ArrayChoice.php @@ -10,27 +10,19 @@ * @template T * @implements ChoiceInterface */ -final class ArrayChoice implements ChoiceInterface +final readonly class ArrayChoice implements ChoiceInterface { - /** - * The list of choices - * - * Key: should be the label of the choice - * Value: the value - * - * @var T[] - */ - private $choices; - - /** - * ArrayChoice constructor. - * - * @param T[] $choices The choices. To declare label, use associative array with key as label - */ - public function __construct(array $choices) - { - $this->choices = $choices; - } + public function __construct( + /** + * The list of choices + * + * Key: should be the label of the choice + * Value: the value + * + * @var T[] + */ + private array $choices, + ) {} #[Override] public function values(): array diff --git a/src/Choice/ChoiceBuilderTrait.php b/src/Choice/ChoiceBuilderTrait.php index e69cd1a..3551251 100644 --- a/src/Choice/ChoiceBuilderTrait.php +++ b/src/Choice/ChoiceBuilderTrait.php @@ -16,7 +16,7 @@ trait ChoiceBuilderTrait /** * @var ChoiceInterface|null */ - private $choices; + protected private(set) ?ChoiceInterface $choices = null; /** * Define choices for the element @@ -44,13 +44,13 @@ trait ChoiceBuilderTrait * * @param ChoiceInterface|array|callable $choices The allowed values in PHP form. * @param string|null $message The error message. - * @param non-negative-int $min - * @param positive-int $max + * @param non-negative-int|null $min + * @param positive-int|null $max * * @return $this * @see ChoiceConstraint */ - final public function choices(ChoiceInterface|array|callable $choices, ?string $message = null, ?bool $multiple = null, ?bool $strict = null, ?int $min = null, ?int $max = null, ?string $minMessage = null, ?string $maxMessage = null): self + final public function choices(ChoiceInterface|array|callable $choices, ?string $message = null, ?bool $multiple = null, ?bool $strict = null, ?int $min = null, ?int $max = null, ?string $minMessage = null, ?string $maxMessage = null): static { if (!$choices instanceof ChoiceInterface) { $choices = is_array($choices) ? new ArrayChoice($choices) : new LazyChoice($choices); @@ -90,5 +90,5 @@ final protected function getChoices(): ?ChoiceInterface * * @see ElementBuilderInterface::satisfy() */ - abstract public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true); + abstract public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true): static; } diff --git a/src/Choice/ChoiceView.php b/src/Choice/ChoiceView.php index bb92a4b..adce368 100644 --- a/src/Choice/ChoiceView.php +++ b/src/Choice/ChoiceView.php @@ -18,24 +18,18 @@ class ChoiceView { /** * The label displayed to humans. - * - * @var string */ - private $label; + public string $label; /** * The view representation of the choice. - * - * @var mixed */ - private $value; + public mixed $value; /** * The view representation of the choice. - * - * @var boolean */ - private $selected; + public bool $selected; /** * Creates a new choice view. @@ -44,7 +38,7 @@ class ChoiceView * @param string|int $label The label displayed to humans * @param boolean $selected This choice is selected */ - public function __construct($value, $label, bool $selected = false) + public function __construct(mixed $value, int|string $label, bool $selected = false) { $this->value = $value; $this->selected = $selected; diff --git a/src/Choice/LazyChoice.php b/src/Choice/LazyChoice.php index 8ddd9aa..3ececca 100644 --- a/src/Choice/LazyChoice.php +++ b/src/Choice/LazyChoice.php @@ -19,14 +19,14 @@ final class LazyChoice implements ChoiceInterface * * @var callable():(T[]|ChoiceInterface) */ - private $resolver; + private readonly mixed $resolver; /** * The choice object * * @var ChoiceInterface|null */ - private $choices; + private ?ChoiceInterface $choices = null; /** * LazyChoice constructor. diff --git a/src/Constraint/Closure.php b/src/Constraint/Closure.php index 6535096..1edaa5f 100755 --- a/src/Constraint/Closure.php +++ b/src/Constraint/Closure.php @@ -38,12 +38,12 @@ class Closure extends Constraint /** * @var string */ - public $message = 'The value is invalid'; + public string $message = 'The value is invalid'; /** * @var callable(mixed,\Bdf\Form\ElementInterface,\Symfony\Component\Validator\Context\ExecutionContextInterface):(bool|string|array{code?: string, message?: string}) */ - public $callback; + public mixed $callback; public function __construct(callable $callback, ?string $message = null) { diff --git a/src/Constraint/FieldComparisonTrait.php b/src/Constraint/FieldComparisonTrait.php index 19e01de..0092b27 100644 --- a/src/Constraint/FieldComparisonTrait.php +++ b/src/Constraint/FieldComparisonTrait.php @@ -16,7 +16,7 @@ trait FieldComparisonTrait * * @var string|FieldPath */ - public $field; + public string|FieldPath $field; /** * FieldComparisonTrait constructor. diff --git a/src/Csrf/CsrfConstraint.php b/src/Csrf/CsrfConstraint.php index 89a907d..88b24cc 100644 --- a/src/Csrf/CsrfConstraint.php +++ b/src/Csrf/CsrfConstraint.php @@ -19,12 +19,8 @@ class CsrfConstraint extends Constraint * * @var string */ - public $message = 'The CSRF token is invalid.'; - - /** - * @var CsrfTokenManagerInterface - */ - public $manager; + public string $message = 'The CSRF token is invalid.'; + public CsrfTokenManagerInterface $manager; public function __construct(CsrfTokenManagerInterface $manager, ?string $message = null) { diff --git a/src/Csrf/CsrfElement.php b/src/Csrf/CsrfElement.php index b1efab3..e0b2a5d 100644 --- a/src/Csrf/CsrfElement.php +++ b/src/Csrf/CsrfElement.php @@ -32,30 +32,11 @@ final class CsrfElement implements ElementInterface { use ContainerTrait; - /** - * @var string - */ - private $tokenId; - - /** - * @var CsrfValueValidator - */ - private $validator; - - /** - * @var CsrfTokenManagerInterface - */ - private $tokenManager; - - /** - * @var CsrfToken|null - */ - private $value = null; - - /** - * @var FormError - */ - private $error; + private readonly string $tokenId; + private readonly CsrfValueValidator $validator; + private readonly CsrfTokenManagerInterface $tokenManager; + private ?CsrfToken $value = null; + private FormError $error; /** * CsrfElement constructor. @@ -66,15 +47,15 @@ final class CsrfElement implements ElementInterface */ public function __construct(?string $tokenId = null, ?CsrfValueValidator $validator = null, ?CsrfTokenManagerInterface $tokenManager = null) { - $this->tokenId = $tokenId ?: self::class; - $this->validator = $validator ?: new CsrfValueValidator(); - $this->tokenManager = $tokenManager ?: new CsrfTokenManager(); + $this->tokenId = $tokenId ?? self::class; + $this->validator = $validator ?? new CsrfValueValidator(); + $this->tokenManager = $tokenManager ?? new CsrfTokenManager(); $this->error = FormError::null(); } #[Override] - public function submit($data): ElementInterface + public function submit(mixed $data): static { $this->value = new CsrfToken($this->tokenId, $data); $this->error = $this->validator->validate($this->value, $this); @@ -83,14 +64,14 @@ public function submit($data): ElementInterface } #[Override] - public function patch($data): ElementInterface + public function patch(mixed $data): static { // CSRF element must be submitted return $this->submit($data); } #[Override] - public function import($entity): ElementInterface + public function import(mixed $entity): static { throw new BadMethodCallException('Cannot set a Csrf token value'); } diff --git a/src/Csrf/CsrfElementBuilder.php b/src/Csrf/CsrfElementBuilder.php index 5565f47..1285127 100644 --- a/src/Csrf/CsrfElementBuilder.php +++ b/src/Csrf/CsrfElementBuilder.php @@ -8,6 +8,7 @@ use Bdf\Form\ElementInterface; use Bdf\Form\Transformer\TransformerInterface; use LogicException; +use Override; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Validator\Constraint; @@ -31,33 +32,16 @@ */ class CsrfElementBuilder implements ElementBuilderInterface { - /** - * @var string - */ - private $tokenId = CsrfElement::class; - - /** - * @var string|null - */ - private $message = null; - - /** - * @var bool - */ - private $invalidate = false; - - /** - * @var CsrfTokenManagerInterface - */ - private $tokenManager; + private string $tokenId = CsrfElement::class; + private ?string $message = null; + private bool $invalidate = false; + private ?CsrfTokenManagerInterface $tokenManager = null; /** * Only validate the csrf token if the element is on the root form * If false, all csrf tokens on sub forms will be validated - * - * @var bool */ - private $onlyValidateRoot = true; + private bool $onlyValidateRoot = true; /** * CsrfElementBuilder constructor. @@ -145,20 +129,14 @@ public function validateOnSubForms(bool $validateOnSubForms = true): self return $this; } - /** - * {@inheritdoc} - */ - #[\Override] - public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) + #[Override] + public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true): static { throw new BadMethodCallException(); } - /** - * {@inheritdoc} - */ - #[\Override] - public function transformer(callable|TransformerInterface $transformer, bool $append = true) + #[Override] + public function transformer(callable|TransformerInterface $transformer, bool $append = true): static { throw new BadMethodCallException(); } @@ -166,8 +144,8 @@ public function transformer(callable|TransformerInterface $transformer, bool $ap /** * {@inheritdoc} */ - #[\Override] - public function value($value) + #[Override] + public function value(mixed $value): static { throw new BadMethodCallException(); } @@ -175,7 +153,7 @@ public function value($value) /** * {@inheritdoc} */ - #[\Override] + #[Override] public function buildElement(): ElementInterface { return new CsrfElement( diff --git a/src/Csrf/CsrfValueValidator.php b/src/Csrf/CsrfValueValidator.php index 15f6fe9..b57b4aa 100644 --- a/src/Csrf/CsrfValueValidator.php +++ b/src/Csrf/CsrfValueValidator.php @@ -18,7 +18,7 @@ * * @implements ValueValidatorInterface<\Symfony\Component\Security\Csrf\CsrfToken> */ -final class CsrfValueValidator implements ValueValidatorInterface +final readonly class CsrfValueValidator implements ValueValidatorInterface { /** * Flag for disable the CSRF validation @@ -33,25 +33,19 @@ final class CsrfValueValidator implements ValueValidatorInterface /** * Invalidate the token after verification ? - * - * @var boolean */ - private $invalidate; + private bool $invalidate; /** * The error message - * - * @var string|null */ - private $message; + private ?string $message; /** * Only validate the csrf token if the element is on the root form * If false, all csrf tokens on sub forms will be validated - * - * @var bool */ - private $onlyValidateRoot; + private bool $onlyValidateRoot; /** * CsrfValueValidator constructor. @@ -87,7 +81,7 @@ public function validate($value, ElementInterface $element): FormError } try { - return (new ConstraintValueValidator([new CsrfConstraint($element->getTokenManager(), $this->message)]))->validate($value, $element); + return new ConstraintValueValidator([new CsrfConstraint($element->getTokenManager(), $this->message)])->validate($value, $element); } finally { if ($this->invalidate) { $element->invalidateToken(); diff --git a/src/Custom/CustomForm.php b/src/Custom/CustomForm.php index 187201f..798432d 100644 --- a/src/Custom/CustomForm.php +++ b/src/Custom/CustomForm.php @@ -48,37 +48,34 @@ * * * @todo implements root form interface ? - * @template T + * @template T as array|object * @implements FormInterface */ abstract class CustomForm implements FormInterface { - /** - * @var FormBuilderInterface - */ - private $builder; + private readonly FormBuilderInterface $builder; /** * The inner form * * @var FormInterface|null */ - private $form; + private ?FormInterface $form = null; /** * @var WeakReference|null */ - private $container; + private ?WeakReference $container = null; /** * @var list */ - private $preConfigureHooks = []; + private array $preConfigureHooks = []; /** * @var list): void> */ - private $postConfigureHooks = []; + private array $postConfigureHooks = []; /** * CustomForm constructor. @@ -91,25 +88,25 @@ public function __construct(?FormBuilderInterface $builder = null) } #[Override] - public function offsetGet($offset): ChildInterface + public function offsetGet(mixed $offset): ChildInterface { return $this->form()[$offset]; } #[Override] - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return isset($this->form()[$offset]); } #[Override] - public function offsetSet($offset, $value): void + public function offsetSet(mixed $offset, mixed $value): void { $this->form()[$offset] = $value; } #[Override] - public function offsetUnset($offset): void + public function offsetUnset(mixed $offset): void { unset($this->form()[$offset]); } @@ -121,7 +118,7 @@ public function getIterator(): Iterator } #[Override] - public function submit($data): ElementInterface + public function submit(mixed $data): static { $this->submitTarget()->submit($data); @@ -129,7 +126,7 @@ public function submit($data): ElementInterface } #[Override] - public function patch($data): ElementInterface + public function patch(mixed $data): static { $this->submitTarget()->patch($data); @@ -137,7 +134,7 @@ public function patch($data): ElementInterface } #[Override] - public function import($entity): ElementInterface + public function import($entity): static { $this->form()->import($entity); @@ -145,13 +142,13 @@ public function import($entity): ElementInterface } #[Override] - public function value() + public function value(): array|object|null { return $this->form()->value(); } #[Override] - public function httpValue() + public function httpValue(): mixed { return $this->form()->httpValue(); } @@ -199,7 +196,7 @@ public function root(): RootElementInterface } #[Override] - public function attach($entity): FormInterface + public function attach(mixed $entity): FormInterface { $this->form()->attach($entity); @@ -304,8 +301,6 @@ final protected function form(): FormInterface // Form can be rebuilt, so we need to clone the builder to avoid side effects $builder = clone $this->builder; - /** @var static $this Psalm cannot infer this type */ - foreach ($this->preConfigureHooks as $hook) { $hook($this, $builder); } @@ -313,6 +308,7 @@ final protected function form(): FormInterface /** @psalm-suppress ArgumentTypeCoercion */ $this->configure($builder); + /** @var FormInterface $form */ $form = $builder->buildElement(); if ($this->container && $container = $this->container->get()) { diff --git a/src/Custom/CustomFormBuilder.php b/src/Custom/CustomFormBuilder.php index 261d8bc..f6f7444 100644 --- a/src/Custom/CustomFormBuilder.php +++ b/src/Custom/CustomFormBuilder.php @@ -33,25 +33,22 @@ class CustomFormBuilder implements ElementBuilderInterface { use DelegateElementBuilderTrait; - /** - * @var FormBuilderInterface - */ - private $builder; + private readonly FormBuilderInterface $builder; /** * @var class-string|callable(FormBuilderInterface):CustomForm */ - private $formFactory; + private readonly mixed $formFactory; /** * @var list */ - private $preConfigureHooks = []; + private array $preConfigureHooks = []; /** * @var list */ - private $postConfigureHooks = []; + private array $postConfigureHooks = []; /** diff --git a/src/ElementBuilderInterface.php b/src/ElementBuilderInterface.php index 26ebd47..de3cd55 100644 --- a/src/ElementBuilderInterface.php +++ b/src/ElementBuilderInterface.php @@ -63,7 +63,7 @@ interface ElementBuilderInterface * @see RegistryInterface::constraint() For make the constraint * @see Closure When use callback as first parameter */ - public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true); + public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true): static; /** * Add a view transformer @@ -97,7 +97,7 @@ public function satisfy(Constraint|callable $constraint, ?string $message = null * * @see TransformerInterface */ - public function transformer(callable|TransformerInterface $transformer, bool $append = true); + public function transformer(callable|TransformerInterface $transformer, bool $append = true): static; /** * Define the initial value of the element @@ -112,7 +112,7 @@ public function transformer(callable|TransformerInterface $transformer, bool $ap * * @see ChildBuilderInterface::default() For setting the default value */ - public function value($value); + public function value(mixed $value): static; /** * Build the element diff --git a/src/ElementInterface.php b/src/ElementInterface.php index 6016700..035eaca 100644 --- a/src/ElementInterface.php +++ b/src/ElementInterface.php @@ -45,7 +45,7 @@ interface ElementInterface * @see ElementInterface::valid() For validates the element after submition * @see ElementInterface::patch() For submit value without overrides previous ones */ - public function submit($data): self; + public function submit(mixed $data): static; /** * Submit HTTP data without override previous ones @@ -68,7 +68,7 @@ public function submit($data): self; * * @see ElementInterface::submit() For submit data with override old values */ - public function patch($data): self; + public function patch(mixed $data): static; /** * Set the PHP value of the element @@ -87,7 +87,7 @@ public function patch($data): self; * * @see ElementInterface::submit() For import HTTP data */ - public function import($entity): self; + public function import(mixed $entity): static; /** * Get the element's value @@ -98,7 +98,7 @@ public function import($entity): self; * * @see ElementInterface::httpValue() For get the raw HTTP value */ - public function value(); + public function value(): mixed; /** * Get the raw HTTP value @@ -110,7 +110,7 @@ public function value(); * * @see ElementInterface::value() For get the PHP value */ - public function httpValue(); + public function httpValue(): mixed; /** * Validates the element value diff --git a/src/Error/FormError.php b/src/Error/FormError.php index a0ee840..88237da 100644 --- a/src/Error/FormError.php +++ b/src/Error/FormError.php @@ -27,22 +27,22 @@ final class FormError implements Stringable /** * @var HttpFieldPath|null */ - private $field; + private ?HttpFieldPath $field = null; /** * @var string|null */ - private $global; + private ?string $global; /** * @var string|null */ - private $code; + private ?string $code; /** * @var FormError[] */ - private $children; + private array $children; /** @@ -182,7 +182,7 @@ public function toArray(): array * * @return mixed The printer result */ - public function print(FormErrorPrinterInterface $printer) + public function print(FormErrorPrinterInterface $printer): mixed { if ($this->field) { $printer->field($this->field); @@ -287,7 +287,7 @@ public static function violation(ConstraintViolationInterface $violation): FormE $message = (string) $violation->getMessage(); $code = $violation->getCode(); - if ($code !== null && $violation instanceof ConstraintViolation && ($constraint = $violation->getConstraint()) !== null) { + if ($code !== null && ($constraint = $violation->getConstraint()) !== null) { try { $code = $constraint->getErrorName($code); } catch (InvalidArgumentException $e) { diff --git a/src/Error/FormErrorPrinterInterface.php b/src/Error/FormErrorPrinterInterface.php index 3ec6bb7..31f3806 100644 --- a/src/Error/FormErrorPrinterInterface.php +++ b/src/Error/FormErrorPrinterInterface.php @@ -55,5 +55,5 @@ public function child(string $name, FormError $error): void; * * @return mixed */ - public function print(); + public function print(): mixed; } diff --git a/src/Error/ImplodeErrorPrinter.php b/src/Error/ImplodeErrorPrinter.php index c11edf0..e31e6a8 100644 --- a/src/Error/ImplodeErrorPrinter.php +++ b/src/Error/ImplodeErrorPrinter.php @@ -16,14 +16,14 @@ final class ImplodeErrorPrinter implements FormErrorPrinterInterface * * @var string */ - private $separator; + private readonly string $separator; /** * Lines of errors * * @var string[] */ - private $lines = []; + private array $lines = []; /** * Does the printer is visiting a child ? @@ -31,7 +31,7 @@ final class ImplodeErrorPrinter implements FormErrorPrinterInterface * * @var bool */ - private $inChild = false; + private bool $inChild = false; /** @@ -71,7 +71,7 @@ public function child(string $name, FormError $error): void } #[Override] - public function print() + public function print(): ?string { return $this->inChild ? null : implode($this->separator, $this->lines); } diff --git a/src/Error/StringErrorPrinter.php b/src/Error/StringErrorPrinter.php index 93d9b00..0fc9438 100644 --- a/src/Error/StringErrorPrinter.php +++ b/src/Error/StringErrorPrinter.php @@ -10,35 +10,12 @@ */ final class StringErrorPrinter implements FormErrorPrinterInterface { - /** - * @var string - */ - private $lineSeparator = PHP_EOL; - - /** - * @var string - */ - private $indentString = ' '; - - /** - * @var string - */ - private $nameSeparator = ' : '; - - /** - * @var int - */ - private $maxDepth = PHP_INT_MAX; - - /** - * @var integer - */ - private $depth = 0; - - /** - * @var string - */ - private $output = ''; + private string $lineSeparator = PHP_EOL; + private string $indentString = ' '; + private string $nameSeparator = ' : '; + private int $maxDepth = PHP_INT_MAX; + private int $depth = 0; + private string $output = ''; #[Override] public function field(HttpFieldPath $field): void @@ -77,7 +54,7 @@ public function child(string $name, FormError $error): void } #[Override] - public function print() + public function print(): string { return $this->output; } diff --git a/src/Filter/ClosureFilter.php b/src/Filter/ClosureFilter.php index 1e416d1..362263c 100755 --- a/src/Filter/ClosureFilter.php +++ b/src/Filter/ClosureFilter.php @@ -18,13 +18,12 @@ * * @see ChildBuilderInterface::filter() */ -final class ClosureFilter implements FilterInterface +final readonly class ClosureFilter implements FilterInterface { /** * @var callable(mixed, ChildInterface, mixed):mixed */ - protected $callback; - + private mixed $callback; /** * @param callable(mixed, ChildInterface, mixed):mixed $callback @@ -35,7 +34,7 @@ public function __construct(callable $callback) } #[Override] - public function filter($value, ChildInterface $input, $default) + public function filter(mixed $value, ChildInterface $input, mixed $default): mixed { return ($this->callback)($value, $input, $default); } diff --git a/src/Filter/EmptyArrayValuesFilter.php b/src/Filter/EmptyArrayValuesFilter.php index e177f5e..cdbea52 100644 --- a/src/Filter/EmptyArrayValuesFilter.php +++ b/src/Filter/EmptyArrayValuesFilter.php @@ -21,7 +21,7 @@ final class EmptyArrayValuesFilter implements FilterInterface private static $instance; #[Override] - public function filter($value, ChildInterface $input, $default) + public function filter(mixed $value, ChildInterface $input, mixed $default): mixed { if (!is_array($value)) { return $value; diff --git a/src/Filter/FilterInterface.php b/src/Filter/FilterInterface.php index d14f532..19ff769 100755 --- a/src/Filter/FilterInterface.php +++ b/src/Filter/FilterInterface.php @@ -22,5 +22,5 @@ interface FilterInterface * * @return mixed Returns the filtered value */ - public function filter($value, ChildInterface $input, $default); + public function filter(mixed $value, ChildInterface $input, mixed $default)/*: mixed*/; } diff --git a/src/Filter/FilterVar.php b/src/Filter/FilterVar.php index b0083b6..73779d3 100644 --- a/src/Filter/FilterVar.php +++ b/src/Filter/FilterVar.php @@ -20,7 +20,7 @@ * @see filter_var() */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] -final class FilterVar implements FilterInterface +final readonly class FilterVar implements FilterInterface { const HTML_FILTER = -1; @@ -29,14 +29,14 @@ final class FilterVar implements FilterInterface * * @var int */ - private $filter; + private int $filter; /** * The flag option of the filter given to filter_var * * @var int */ - private $flags; + private int $flags; /** * FilterVar constructor. @@ -51,7 +51,7 @@ public function __construct(int $filter = self::HTML_FILTER, int $flags = FILTER } #[Override] - public function filter($value, ChildInterface $input, $default) + public function filter(mixed $value, ChildInterface $input, mixed $default): mixed { if (!is_array($value)) { return $this->apply($value); @@ -64,7 +64,7 @@ public function filter($value, ChildInterface $input, $default) return $value; } - private function apply($value) + private function apply(mixed $value): mixed { $value = is_scalar($value) ? (string) $value : ''; diff --git a/src/Filter/TrimFilter.php b/src/Filter/TrimFilter.php index 33c2bc8..9b62960 100644 --- a/src/Filter/TrimFilter.php +++ b/src/Filter/TrimFilter.php @@ -7,6 +7,10 @@ use Bdf\Form\Child\ChildInterface; use Override; +use function is_string; +use function preg_replace; +use function trim; + /** * Perform a trim on the input value * Supports trim of utf-8 white spaces @@ -22,7 +26,7 @@ final class TrimFilter implements FilterInterface private static $instance; #[Override] - public function filter($value, ChildInterface $input, $default) + public function filter(mixed $value, ChildInterface $input, mixed $default): mixed { if (!is_string($value)) { return $value; diff --git a/src/Leaf/AbstractBooleanElement.php b/src/Leaf/AbstractBooleanElement.php index 4b19716..fcc1fef 100644 --- a/src/Leaf/AbstractBooleanElement.php +++ b/src/Leaf/AbstractBooleanElement.php @@ -18,7 +18,7 @@ abstract class AbstractBooleanElement extends LeafElement { #[Override] - final protected function tryCast($value): ?bool + final protected function tryCast(mixed $value): ?bool { if ($value === null) { return null; diff --git a/src/Leaf/AnyElement.php b/src/Leaf/AnyElement.php index 6378b58..5ec8a55 100644 --- a/src/Leaf/AnyElement.php +++ b/src/Leaf/AnyElement.php @@ -16,19 +16,19 @@ class AnyElement extends LeafElement { #[Override] - protected function toPhp($httpValue) + protected function toPhp(mixed $httpValue): mixed { return $httpValue; } #[Override] - protected function toHttp($phpValue) + protected function toHttp(mixed $phpValue): mixed { return $phpValue; } #[Override] - protected function sanitize($rawValue) + protected function sanitize(mixed $rawValue): mixed { return $rawValue; } diff --git a/src/Leaf/BooleanElement.php b/src/Leaf/BooleanElement.php index 30f9a8f..4e7f97d 100644 --- a/src/Leaf/BooleanElement.php +++ b/src/Leaf/BooleanElement.php @@ -18,10 +18,7 @@ */ class BooleanElement extends AbstractBooleanElement { - /** - * @var string - */ - private $httpValue = '1'; + private string $httpValue = '1'; /** * BooleanElement constructor. @@ -38,13 +35,13 @@ public function __construct(?ValueValidatorInterface $validator = null, ?Transfo } #[Override] - protected function toPhp($httpValue): bool + protected function toPhp(mixed $httpValue): bool { return (bool) $httpValue; } #[Override] - protected function toHttp($phpValue) + protected function toHttp(mixed $phpValue): ?string { return $phpValue ? $this->httpValue : null; } diff --git a/src/Leaf/BooleanElementBuilder.php b/src/Leaf/BooleanElementBuilder.php index 73cbbf8..6709248 100644 --- a/src/Leaf/BooleanElementBuilder.php +++ b/src/Leaf/BooleanElementBuilder.php @@ -29,15 +29,8 @@ */ class BooleanElementBuilder extends AbstractElementBuilder { - /** - * @var string - */ - private $httpValue = '1'; - - /** - * @var bool - */ - private $booleanString = false; + private string $httpValue = '1'; + private bool $booleanString = false; /** * Define the HTTP value used for represent the true value diff --git a/src/Leaf/BooleanStringElement.php b/src/Leaf/BooleanStringElement.php index a794a8d..4314a96 100644 --- a/src/Leaf/BooleanStringElement.php +++ b/src/Leaf/BooleanStringElement.php @@ -24,18 +24,16 @@ class BooleanStringElement extends AbstractBooleanElement * {@inheritdoc} * * @return scalar|null - * @psalm-suppress ImplementedReturnTypeMismatch - * @psalm-suppress LessSpecificImplementedReturnType */ #[Override] - protected function sanitize($rawValue): int|float|string|bool|null + protected function sanitize(mixed $rawValue): int|float|string|bool|null { // Does not cast to string, to allow boolean value return is_scalar($rawValue) ? $rawValue : null; } #[Override] - protected function toPhp($httpValue): ?bool + protected function toPhp(mixed $httpValue): ?bool { if ($httpValue === null || $httpValue === '') { return null; @@ -50,7 +48,7 @@ protected function toPhp($httpValue): ?bool } #[Override] - protected function toHttp($phpValue): ?string + protected function toHttp(mixed $phpValue): ?string { if ($phpValue === null) { return null; diff --git a/src/Leaf/Date/DateTimeElement.php b/src/Leaf/Date/DateTimeElement.php index 5bc27aa..11f3229 100644 --- a/src/Leaf/Date/DateTimeElement.php +++ b/src/Leaf/Date/DateTimeElement.php @@ -25,24 +25,14 @@ final class DateTimeElement extends LeafElement /** * @var class-string */ - private $className; - - /** - * @var string - */ - private $format; - - /** - * @var DateTimeZone|null - */ - private $timezone; + private readonly string $className; + private readonly string $format; + private readonly ?DateTimeZone $timezone; /** * Reset the fields value which are not provided by the format - * - * @var bool */ - private $resetNotProvidedFields; + private bool $resetNotProvidedFields; /** * DateTimeType constructor. @@ -86,7 +76,7 @@ public function dateTimeClassName(): string } #[Override] - protected function toPhp($httpValue): ?DateTimeInterface + protected function toPhp(mixed $httpValue): ?DateTimeInterface { if ($httpValue === null || $httpValue === '') { return null; @@ -129,7 +119,7 @@ protected function toPhp($httpValue): ?DateTimeInterface } #[Override] - protected function toHttp($phpValue) + protected function toHttp(mixed $phpValue): mixed { // Because of legacy behavior, the raw value can be saved when a transformer failed // So the raw string is kept as is @@ -146,7 +136,7 @@ protected function toHttp($phpValue) } #[Override] - protected function tryCast($value): ?DateTimeInterface + protected function tryCast(mixed $value): ?DateTimeInterface { if ($value === null) { return null; diff --git a/src/Leaf/Date/DateTimeElementBuilder.php b/src/Leaf/Date/DateTimeElementBuilder.php index 7d41545..979d1c7 100644 --- a/src/Leaf/Date/DateTimeElementBuilder.php +++ b/src/Leaf/Date/DateTimeElementBuilder.php @@ -48,24 +48,14 @@ class DateTimeElementBuilder extends AbstractElementBuilder /** * @var class-string */ - private $dateTimeClassName = DateTime::class; - - /** - * @var string - */ - private $dateFormat = DateTime::ATOM; - - /** - * @var DateTimeZone|null - */ - private $timezone; + private string $dateTimeClassName = DateTime::class; + private string $dateFormat = DateTime::ATOM; + private ?DateTimeZone $timezone = null; /** * Reset the fields value which are not provided by the format - * - * @var bool */ - private $resetNotProvidedFields = true; + private bool $resetNotProvidedFields = true; /** * Define the date time class name to use @@ -80,7 +70,7 @@ class DateTimeElementBuilder extends AbstractElementBuilder * * @see DateTimeElementBuilder::immutable() For use DateTimeImmutable */ - public function className(string $dateTimeClassName): self + public function className(string $dateTimeClassName): static { $this->dateTimeClassName = $dateTimeClassName; @@ -96,7 +86,7 @@ public function className(string $dateTimeClassName): self * @see DateTimeImmutable * @see DateTimeElementBuilder::className() */ - public function immutable(): self + public function immutable(): static { return $this->className(DateTimeImmutable::class); } @@ -115,7 +105,7 @@ public function immutable(): self * * @see https://www.php.net/manual/en/datetime.createfromformat.php#refsect1-datetime.createfromformat-parameters For the format */ - public function format(string $format): self + public function format(string $format): static { $this->dateFormat = $format; @@ -136,7 +126,7 @@ public function format(string $format): self * * @return $this */ - public function timezone($timezone): self + public function timezone(string|DateTimeZone|null $timezone): static { if (is_string($timezone)) { $timezone = new DateTimeZone($timezone); @@ -160,7 +150,7 @@ public function timezone($timezone): self * * @return $this */ - public function before(DateTimeInterface $dateTime, ?string $message = null, bool $orEqual = false): self + public function before(DateTimeInterface $dateTime, ?string $message = null, bool $orEqual = false): static { $constraint = $orEqual ? new LessThanOrEqual($dateTime) : new LessThan($dateTime); @@ -192,7 +182,7 @@ public function before(DateTimeInterface $dateTime, ?string $message = null, boo * * @see FieldPath::parse() For the field path syntax */ - public function beforeField(string $field, ?string $message = null, bool $orEqual = false): self + public function beforeField(string $field, ?string $message = null, bool $orEqual = false): static { $constraint = $orEqual ? new LessThanOrEqualField($field) : new LessThanField($field); @@ -216,7 +206,7 @@ public function beforeField(string $field, ?string $message = null, bool $orEqua * * @return $this */ - public function after(DateTimeInterface $dateTime, ?string $message = null, bool $orEqual = false): self + public function after(DateTimeInterface $dateTime, ?string $message = null, bool $orEqual = false): static { $constraint = $orEqual ? new GreaterThanOrEqual($dateTime) : new GreaterThan($dateTime); @@ -248,7 +238,7 @@ public function after(DateTimeInterface $dateTime, ?string $message = null, bool * * @see FieldPath::parse() For the field path syntax */ - public function afterField(string $field, ?string $message = null, bool $orEqual = false): self + public function afterField(string $field, ?string $message = null, bool $orEqual = false): static { $constraint = $orEqual ? new GreaterThanOrEqualField($field) : new GreaterThanField($field); @@ -283,7 +273,7 @@ public function afterField(string $field, ?string $message = null, bool $orEqual * * @return $this */ - public function resetNotProvidedFields(bool $flag = true): self + public function resetNotProvidedFields(bool $flag = true): static { $this->resetNotProvidedFields = $flag; diff --git a/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php b/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php index 7580d3b..24493d9 100644 --- a/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php +++ b/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php @@ -19,17 +19,17 @@ * Transform a DateTime instance from a form element to a timestamp to a model */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] -final class DateTimeToTimestampTransformer implements TransformerInterface +final readonly class DateTimeToTimestampTransformer implements TransformerInterface { /** * @var class-string|null */ - private $className; + private ?string $className; /** * @var DateTimeZone|null */ - private $timezone; + private ?DateTimeZone $timezone; /** @@ -45,7 +45,7 @@ public function __construct(?string $className = null, ?DateTimeZone $timezone = } #[Override] - public function transformToHttp($value, ElementInterface $input): ?DateTimeInterface + public function transformToHttp(mixed $value, ElementInterface $input): ?DateTimeInterface { if ($value === null) { return null; diff --git a/src/Leaf/FloatElement.php b/src/Leaf/FloatElement.php index 2d4f5fd..191da1e 100644 --- a/src/Leaf/FloatElement.php +++ b/src/Leaf/FloatElement.php @@ -5,6 +5,8 @@ use Override; use TypeError; +use function is_numeric; + /** * Element for a float value * @@ -15,19 +17,19 @@ class FloatElement extends LeafElement { #[Override] - protected function toPhp($httpValue): ?float + protected function toPhp(mixed $httpValue): ?float { return $httpValue === null || $httpValue === '' ? null : (float) $httpValue; } #[Override] - protected function toHttp($phpValue): ?string + protected function toHttp(mixed $phpValue): ?string { return $phpValue === null ? null : (string) $phpValue; } #[Override] - protected function tryCast($value): ?float + protected function tryCast(mixed $value): ?float { if ($value === null) { return null; diff --git a/src/Leaf/FloatElementBuilder.php b/src/Leaf/FloatElementBuilder.php index ce4a072..3234664 100644 --- a/src/Leaf/FloatElementBuilder.php +++ b/src/Leaf/FloatElementBuilder.php @@ -28,20 +28,13 @@ */ class FloatElementBuilder extends NumberElementBuilder { - /** - * @var int|null - */ - private $scale = null; - - /** - * @var bool - */ - private $grouping = false; + private ?int $scale = null; + private bool $grouping = false; /** * @var NumberFormatter::ROUND_* */ - private $roundingMode = NumberFormatter::ROUND_DOWN; + private int $roundingMode = NumberFormatter::ROUND_DOWN; /** diff --git a/src/Leaf/Helper/EmailElementBuilder.php b/src/Leaf/Helper/EmailElementBuilder.php index fea2172..6ab02e1 100644 --- a/src/Leaf/Helper/EmailElementBuilder.php +++ b/src/Leaf/Helper/EmailElementBuilder.php @@ -27,7 +27,7 @@ class EmailElementBuilder extends StringElementBuilder /** * @var bool */ - private $useConstraint = true; + private bool $useConstraint = true; private ?string $errorMessage = null; @@ -39,7 +39,7 @@ class EmailElementBuilder extends StringElementBuilder /** * @var (callable(string):string)|null */ - private $normalizer = null; + private mixed $normalizer = null; /** * EmailElementBuilder constructor. @@ -50,7 +50,7 @@ public function __construct(?RegistryInterface $registry = null) { parent::__construct($registry); - $this->addConstraintsProvider([$this, 'createEmailConstraint']); + $this->addConstraintsProvider($this->createEmailConstraint(...)); } /** @@ -65,7 +65,7 @@ public function __construct(?RegistryInterface $registry = null) * @see Email::VALIDATION_MODE_LOOSE * @see Email::VALIDATION_MODE_STRICT */ - public function mode(string $mode): self + public function mode(string $mode): static { $this->mode = $mode; @@ -79,7 +79,7 @@ public function mode(string $mode): self * * @return $this */ - public function errorMessage(string $message): self + public function errorMessage(string $message): static { $this->errorMessage = $message; @@ -104,7 +104,7 @@ public function errorMessage(string $message): self * * @return $this */ - public function normalizer(callable $normalizer): self + public function normalizer(callable $normalizer): static { $this->normalizer = $normalizer; @@ -116,7 +116,7 @@ public function normalizer(callable $normalizer): self * * @return $this */ - public function disableConstraint(): self + public function disableConstraint(): static { $this->useConstraint = false; @@ -136,7 +136,7 @@ public function disableConstraint(): self * * @see Email for list of options */ - public function useConstraint(?string $message = null, ?string $mode = null, ?callable $normalizer = null): self + public function useConstraint(?string $message = null, ?string $mode = null, ?callable $normalizer = null): static { $this->useConstraint = true; $this->errorMessage = $message; diff --git a/src/Leaf/Helper/UrlElementBuilder.php b/src/Leaf/Helper/UrlElementBuilder.php index 8f25339..ee893e4 100644 --- a/src/Leaf/Helper/UrlElementBuilder.php +++ b/src/Leaf/Helper/UrlElementBuilder.php @@ -2,7 +2,6 @@ namespace Bdf\Form\Leaf\Helper; -use Bdf\Form\ElementInterface; use Bdf\Form\Leaf\StringElementBuilder; use Bdf\Form\Registry\RegistryInterface; use Bdf\Form\Transformer\TransformerInterface; @@ -23,23 +22,19 @@ */ class UrlElementBuilder extends StringElementBuilder { - /** - * @var bool - */ - private $useConstraint = true; - + private bool $useConstraint = true; private ?string $errorMessage = null; /** * @var string[]|null */ - private $protocols = null; + private ?array $protocols = null; private ?bool $relativeProtocol = null; /** * @var (callable(string):string)|null */ - private $normalizer = null; + private mixed $normalizer = null; private ?bool $requireTld = false; private ?string $tldMessage = null; @@ -52,7 +47,7 @@ public function __construct(?RegistryInterface $registry = null) { parent::__construct($registry); - $this->addConstraintsProvider([$this, 'createUrlConstraint']); + $this->addConstraintsProvider($this->createUrlConstraint(...)); } /** @@ -66,7 +61,7 @@ public function __construct(?RegistryInterface $registry = null) * * @return $this */ - public function protocols(string ...$protocols): self + public function protocols(string ...$protocols): static { $this->protocols = $protocols; @@ -81,7 +76,7 @@ public function protocols(string ...$protocols): self * * @return $this */ - public function relativeProtocol(bool $enable = true): self + public function relativeProtocol(bool $enable = true): static { $this->relativeProtocol = $enable; @@ -95,7 +90,7 @@ public function relativeProtocol(bool $enable = true): self * * @return $this */ - public function errorMessage(string $message): self + public function errorMessage(string $message): static { $this->errorMessage = $message; @@ -120,7 +115,7 @@ public function errorMessage(string $message): self * * @return $this */ - public function normalizer(callable $normalizer): self + public function normalizer(callable $normalizer): static { $this->normalizer = $normalizer; @@ -132,7 +127,7 @@ public function normalizer(callable $normalizer): self * * @return $this */ - public function disableConstraint(): self + public function disableConstraint(): static { $this->useConstraint = false; @@ -150,7 +145,7 @@ public function disableConstraint(): self * * @see Url for list of options */ - public function useConstraint(?string $message = null, string|array|null $protocols = null, ?bool $relativeProtocol = null, ?callable $normalizer = null): self + public function useConstraint(?string $message = null, string|array|null $protocols = null, ?bool $relativeProtocol = null, ?callable $normalizer = null): static { $this->useConstraint = true; diff --git a/src/Leaf/IntegerElement.php b/src/Leaf/IntegerElement.php index cae3fcf..4627da5 100644 --- a/src/Leaf/IntegerElement.php +++ b/src/Leaf/IntegerElement.php @@ -5,6 +5,8 @@ use Override; use TypeError; +use function is_numeric; + /** * Element for an integer * @@ -15,19 +17,19 @@ class IntegerElement extends LeafElement { #[Override] - protected function toPhp($httpValue): ?int + protected function toPhp(mixed $httpValue): ?int { return $httpValue === null || $httpValue === '' ? null : (int) $httpValue; } #[Override] - protected function toHttp($phpValue): ?string + protected function toHttp(mixed $phpValue): ?string { return $phpValue === null ? null : (string) $phpValue; } #[Override] - protected function tryCast($value): ?int + protected function tryCast(mixed $value): ?int { if ($value === null) { return null; diff --git a/src/Leaf/IntegerElementBuilder.php b/src/Leaf/IntegerElementBuilder.php index c1da565..304ec8b 100644 --- a/src/Leaf/IntegerElementBuilder.php +++ b/src/Leaf/IntegerElementBuilder.php @@ -28,15 +28,12 @@ */ class IntegerElementBuilder extends NumberElementBuilder { - /** - * @var bool - */ - private $grouping = false; + private bool $grouping = false; /** * @var NumberFormatter::ROUND_* */ - private $roundingMode = NumberFormatter::ROUND_DOWN; + private int $roundingMode = NumberFormatter::ROUND_DOWN; /** diff --git a/src/Leaf/LeafElement.php b/src/Leaf/LeafElement.php index 08acc75..f3388ed 100644 --- a/src/Leaf/LeafElement.php +++ b/src/Leaf/LeafElement.php @@ -16,7 +16,6 @@ use Bdf\Form\Validator\ConstraintValueValidator; use Bdf\Form\Validator\ValueValidatorInterface; use Bdf\Form\View\ConstraintsNormalizer; -use Bdf\Form\View\ElementViewInterface; use Bdf\Form\View\FieldViewInterface; use Exception; use Override; @@ -37,34 +36,24 @@ abstract class LeafElement implements ElementInterface, Choiceable /** * @var ValueValidatorInterface */ - private $validator; + private readonly ValueValidatorInterface $validator; /** * Transformer to view value - * - * @var TransformerInterface */ - private $transformer; + private readonly TransformerInterface $transformer; /** * @var ChoiceInterface|null */ - private $choices; + private ?ChoiceInterface $choices; /** * @var T|null */ - private $value = null; - - /** - * @var FormError - */ - private $error; - - /** - * @var bool - */ - private $submitted = false; + private mixed $value = null; + private FormError $error; + private bool $submitted = false; /** @@ -83,7 +72,7 @@ public function __construct(?ValueValidatorInterface $validator = null, ?Transfo } #[Override] - final public function submit($data): ElementInterface + final public function submit(mixed $data): static { $shouldBeValidated = true; @@ -105,7 +94,7 @@ final public function submit($data): ElementInterface } #[Override] - final public function patch($data): ElementInterface + final public function patch(mixed $data): static { // A data is provided : simply submit the data if ($data !== null) { @@ -138,7 +127,7 @@ final public function error(?HttpFieldPath $field = null): FormError } #[Override] - final public function import($entity): ElementInterface + final public function import(mixed $entity): static { $this->value = $this->tryCast($entity); @@ -146,13 +135,13 @@ final public function import($entity): ElementInterface } #[Override] - final public function value() + final public function value(): mixed { return $this->value; } #[Override] - final public function httpValue() + final public function httpValue(): mixed { try { return $this->transformer->transformToHttp($this->toHttp($this->value), $this); @@ -201,7 +190,7 @@ final public function choices(): ?ChoiceInterface * * @return T|null */ - abstract protected function toPhp($httpValue); + abstract protected function toPhp(mixed $httpValue)/*: mixed*/; /** * Transform the PHP value to the HTTP representation @@ -210,7 +199,7 @@ abstract protected function toPhp($httpValue); * * @return mixed */ - abstract protected function toHttp($phpValue); + abstract protected function toHttp(mixed $phpValue)/*: mixed*/; /** * Try to convert the value into the element type @@ -224,7 +213,7 @@ abstract protected function toHttp($phpValue); * * @see LeafElement::import() */ - protected function tryCast($value) + protected function tryCast(mixed $value)/*: mixed*/ { return $value; } @@ -233,11 +222,9 @@ protected function tryCast($value) * Sanitize the raw HTTP value * * @param mixed $rawValue The raw HTTP value - * - * @return string|null - * @todo return mixed ? + * @return mixed */ - protected function sanitize($rawValue) + protected function sanitize(mixed $rawValue)/*: mixed*/ { if (is_scalar($rawValue)) { return (string) $rawValue; @@ -255,11 +242,7 @@ protected function sanitize($rawValue) */ protected function choiceView(): ?array { - if ($this->choices === null) { - return null; - } - - return $this->choices->view(function (ChoiceView $view) { + return $this->choices?->view(function (ChoiceView $view) { $view->setSelected($view->value() == $this->value()); $view->setValue($this->transformer->transformToHttp($this->toHttp($view->value()), $this)); }); diff --git a/src/Leaf/LeafRootElement.php b/src/Leaf/LeafRootElement.php index 7869383..1a11fb0 100644 --- a/src/Leaf/LeafRootElement.php +++ b/src/Leaf/LeafRootElement.php @@ -27,24 +27,12 @@ final class LeafRootElement implements RootElementInterface { use RootFlagsTrait; - /** - * @var ElementInterface - */ - private $element; - - - /** - * LeafRootElement constructor. - * - * @param ElementInterface $element - */ - public function __construct(ElementInterface $element) - { - $this->element = $element; - } + public function __construct( + private readonly ElementInterface $element, + ) {} #[Override] - public function submit($data): ElementInterface + public function submit(mixed $data): static { $this->element->submit($data); @@ -52,7 +40,7 @@ public function submit($data): ElementInterface } #[Override] - public function patch($data): ElementInterface + public function patch(mixed $data): static { $this->element->patch($data); @@ -60,7 +48,7 @@ public function patch($data): ElementInterface } #[Override] - public function import($entity): ElementInterface + public function import(mixed $entity): static { $this->element->import($entity); @@ -68,13 +56,13 @@ public function import($entity): ElementInterface } #[Override] - public function value() + public function value(): mixed { return $this->element->value(); } #[Override] - public function httpValue() + public function httpValue(): mixed { return $this->element->httpValue(); } @@ -137,7 +125,7 @@ public function button(string $name): ButtonInterface #[Override] public function getValidator(): ValidatorInterface { - return (new ValidatorBuilder())->getValidator(); + return new ValidatorBuilder()->getValidator(); } #[Override] diff --git a/src/Leaf/NumberElementBuilder.php b/src/Leaf/NumberElementBuilder.php index f759902..c10dd50 100644 --- a/src/Leaf/NumberElementBuilder.php +++ b/src/Leaf/NumberElementBuilder.php @@ -22,10 +22,7 @@ abstract class NumberElementBuilder extends AbstractElementBuilder { use ChoiceBuilderTrait; - /** - * @var bool - */ - private $raw = false; + private bool $raw = false; /** @@ -37,7 +34,7 @@ public function __construct(?RegistryInterface $registry = null) { parent::__construct($registry); - $this->addTransformerProvider([$this, 'provideNumberTransformer']); + $this->addTransformerProvider($this->provideNumberTransformer(...)); } /** diff --git a/src/Leaf/StringElement.php b/src/Leaf/StringElement.php index 82d1592..bd76794 100644 --- a/src/Leaf/StringElement.php +++ b/src/Leaf/StringElement.php @@ -5,6 +5,10 @@ use Override; use TypeError; +use function is_object; +use function is_scalar; +use function method_exists; + /** * Element for a simple string field * @@ -15,7 +19,7 @@ class StringElement extends LeafElement { #[Override] - protected function toPhp($httpValue): ?string + protected function toPhp(mixed $httpValue): ?string { if (!is_scalar($httpValue)) { return null; @@ -25,13 +29,13 @@ protected function toPhp($httpValue): ?string } #[Override] - protected function toHttp($phpValue): ?string + protected function toHttp(mixed $phpValue): ?string { return $phpValue; } #[Override] - protected function tryCast($value): ?string + protected function tryCast(mixed $value): ?string { if ($value === null) { return null; diff --git a/src/Leaf/StringElementBuilder.php b/src/Leaf/StringElementBuilder.php index 4fadb76..14f3976 100644 --- a/src/Leaf/StringElementBuilder.php +++ b/src/Leaf/StringElementBuilder.php @@ -40,16 +40,16 @@ class StringElementBuilder extends AbstractElementBuilder * $builder->length(max: 256); * * - * @param positive-int $exactly - * @param non-negative-int $min - * @param positive-int $max + * @param positive-int|null $exactly + * @param non-negative-int|null $min + * @param positive-int|null $max * @param value-of|null $countUnit * * @return $this * * @see Length For options */ - public function length(?int $exactly = null, ?int $min = null, ?int $max = null, ?string $charset = null, ?callable $normalizer = null, ?string $countUnit = null, ?string $exactMessage = null, ?string $minMessage = null, ?string $maxMessage = null, ?string $charsetMessage = null): self + public function length(?int $exactly = null, ?int $min = null, ?int $max = null, ?string $charset = null, ?callable $normalizer = null, ?string $countUnit = null, ?string $exactMessage = null, ?string $minMessage = null, ?string $maxMessage = null, ?string $charsetMessage = null): static { return $this->satisfy( new Length( @@ -81,7 +81,7 @@ public function length(?int $exactly = null, ?int $min = null, ?int $max = null, * * @see Regex */ - public function regex(string $pattern, ?string $message = null, ?string $htmlPattern = null, ?bool $match = null, ?callable $normalizer = null): self + public function regex(string $pattern, ?string $message = null, ?string $htmlPattern = null, ?bool $match = null, ?callable $normalizer = null): static { return $this->satisfy( new Regex( @@ -95,7 +95,7 @@ public function regex(string $pattern, ?string $message = null, ?string $htmlPat } #[Override] - protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): ElementInterface + protected function createElement(ValueValidatorInterface $validator, TransformerInterface $transformer): StringElement { return new StringElement($validator, $transformer, $this->getChoices()); } diff --git a/src/Leaf/Transformer/LocalizedIntegerTransformer.php b/src/Leaf/Transformer/LocalizedIntegerTransformer.php index 3925822..07c4f25 100644 --- a/src/Leaf/Transformer/LocalizedIntegerTransformer.php +++ b/src/Leaf/Transformer/LocalizedIntegerTransformer.php @@ -29,6 +29,6 @@ public function __construct(bool $grouping = false, int $roundingMode = NumberFo #[Override] protected function cast($value): int { - return $value; + return (int) $value; } } diff --git a/src/Leaf/Transformer/LocalizedNumberTransformer.php b/src/Leaf/Transformer/LocalizedNumberTransformer.php index 5c170c4..a1a616b 100644 --- a/src/Leaf/Transformer/LocalizedNumberTransformer.php +++ b/src/Leaf/Transformer/LocalizedNumberTransformer.php @@ -29,20 +29,20 @@ class LocalizedNumberTransformer implements TransformerInterface * * @var int|null */ - private $scale; + private readonly ?int $scale; /** * @var int * @psalm-var NumberFormatter::ROUND_* */ - private $roundingMode; + private readonly int $roundingMode; /** * Group by thousand or not * * @var bool */ - private $grouping; + private readonly bool $grouping; /** * The locale to use @@ -50,7 +50,7 @@ class LocalizedNumberTransformer implements TransformerInterface * * @var string|null */ - private $locale; + private readonly ?string $locale; /** * LocalizedNumberTransformer constructor. diff --git a/src/Leaf/View/BooleanElementView.php b/src/Leaf/View/BooleanElementView.php index 78758b3..413a6d7 100644 --- a/src/Leaf/View/BooleanElementView.php +++ b/src/Leaf/View/BooleanElementView.php @@ -19,15 +19,8 @@ final class BooleanElementView implements FieldViewInterface use ElementViewTrait; use FieldViewTrait; - /** - * @var string - */ - private $httpValue; - - /** - * @var bool - */ - private $checked; + public readonly string $httpValue; + public private(set) bool $checked; /** * BooleanElementView constructor. @@ -39,7 +32,7 @@ final class BooleanElementView implements FieldViewInterface * @param bool $checked * @param string|null $error */ - public function __construct(string $type, string $name, $value, string $httpValue, bool $checked, ?string $error) + public function __construct(string $type, string $name, mixed $value, string $httpValue, bool $checked, ?string $error) { $this->type = $type; $this->name = $name; diff --git a/src/Leaf/View/CheckboxHtmlRenderer.php b/src/Leaf/View/CheckboxHtmlRenderer.php index 079898c..948117a 100644 --- a/src/Leaf/View/CheckboxHtmlRenderer.php +++ b/src/Leaf/View/CheckboxHtmlRenderer.php @@ -14,10 +14,7 @@ */ final class CheckboxHtmlRenderer implements FieldViewRendererInterface { - /** - * @var CheckboxHtmlRenderer|null - */ - private static $instance; + private static ?self $instance = null; #[Override] public function render(FieldViewInterface $view, array $attributes): string @@ -40,10 +37,6 @@ public function render(FieldViewInterface $view, array $attributes): string */ public static function instance(): self { - if (self::$instance) { - return self::$instance; - } - - return self::$instance = new self; + return self::$instance ??= new self; } } diff --git a/src/Leaf/View/SelectHtmlRenderer.php b/src/Leaf/View/SelectHtmlRenderer.php index 07380d4..8e808e7 100644 --- a/src/Leaf/View/SelectHtmlRenderer.php +++ b/src/Leaf/View/SelectHtmlRenderer.php @@ -16,10 +16,7 @@ */ final class SelectHtmlRenderer implements FieldViewRendererInterface { - /** - * @var SelectHtmlRenderer|null - */ - private static $instance; + private static ?self $instance = null; #[Override] public function render(FieldViewInterface $view, array $attributes): string @@ -51,10 +48,6 @@ public function render(FieldViewInterface $view, array $attributes): string */ public static function instance(): self { - if (self::$instance) { - return self::$instance; - } - - return self::$instance = new self; + return self::$instance ??= new self; } } diff --git a/src/Leaf/View/SimpleElementView.php b/src/Leaf/View/SimpleElementView.php index dc8951d..d053e57 100644 --- a/src/Leaf/View/SimpleElementView.php +++ b/src/Leaf/View/SimpleElementView.php @@ -31,7 +31,7 @@ final class SimpleElementView implements FieldViewInterface * @param array $constraints * @param ChoiceView[]|null $choices */ - public function __construct(string $type, string $name, $value, ?string $error, bool $required, array $constraints, ?array $choices = null) + public function __construct(string $type, string $name, mixed $value, ?string $error, bool $required, array $constraints, ?array $choices = null) { $this->type = $type; $this->name = $name; diff --git a/src/Leaf/View/SimpleFieldHtmlRenderer.php b/src/Leaf/View/SimpleFieldHtmlRenderer.php index 3558bac..c33e2c5 100644 --- a/src/Leaf/View/SimpleFieldHtmlRenderer.php +++ b/src/Leaf/View/SimpleFieldHtmlRenderer.php @@ -22,10 +22,7 @@ */ final class SimpleFieldHtmlRenderer implements FieldViewRendererInterface { - /** - * @var SimpleFieldHtmlRenderer|null - */ - private static $instance; + private static ?self $instance = null; /** * Map constraint class name to mapped attributes in form : @@ -33,7 +30,7 @@ final class SimpleFieldHtmlRenderer implements FieldViewRendererInterface * * @var string[][] */ - private $constraintMapping = [ + private array $constraintMapping = [ Length::class => ['min' => 'minlength', 'max' => 'maxlength'], LessThanOrEqual::class => ['value' => 'max'], GreaterThanOrEqual::class => ['value' => 'min'], @@ -45,7 +42,7 @@ final class SimpleFieldHtmlRenderer implements FieldViewRendererInterface * * @var string[] */ - private $typesMapping = [ + private array $typesMapping = [ IntegerElement::class => 'number', PhoneElement::class => 'tel', CsrfElement::class => 'hidden', @@ -97,10 +94,6 @@ private function constraintsToAttributes(array $constraints): array */ public static function instance(): self { - if (self::$instance) { - return self::$instance; - } - - return self::$instance = new self; + return self::$instance ??= new self; } } diff --git a/src/Phone/NotEmptyPhoneNumberValidator.php b/src/Phone/NotEmptyPhoneNumberValidator.php index c9b4225..641e5a5 100644 --- a/src/Phone/NotEmptyPhoneNumberValidator.php +++ b/src/Phone/NotEmptyPhoneNumberValidator.php @@ -11,12 +11,9 @@ /** * NotBlank implementation for PhoneNumber value */ -class NotEmptyPhoneNumberValidator extends NotBlankValidator +final class NotEmptyPhoneNumberValidator extends NotBlankValidator { - /** - * @var PhoneNumberUtil - */ - private $formatter; + private readonly PhoneNumberUtil $formatter; /** diff --git a/src/Phone/PhoneChildBuilder.php b/src/Phone/PhoneChildBuilder.php index d86a2fd..1549d30 100644 --- a/src/Phone/PhoneChildBuilder.php +++ b/src/Phone/PhoneChildBuilder.php @@ -16,12 +16,8 @@ class PhoneChildBuilder extends ChildBuilder /** * @var PhoneNumberFormat::*|null */ - private $saveFormat; - - /** - * @var bool - */ - private $formatIfInvalid = false; + private PhoneNumberFormat|int|null $saveFormat = null; + private bool $formatIfInvalid = false; /** * {@inheritdoc} @@ -32,7 +28,7 @@ public function __construct(string $name, ElementBuilderInterface $elementBuilde { parent::__construct($name, $elementBuilder, $registry); - $this->addTransformerProvider([$this, 'provideModelTransformer']); + $this->addTransformerProvider($this->provideModelTransformer(...)); } /** @@ -47,7 +43,7 @@ public function __construct(string $name, ElementBuilderInterface $elementBuilde * * @see PhoneChildBuilder::saveAsString() To enable string formating when filling the entity */ - public function formatIfInvalid(bool $formatIfInvalid = true): self + public function formatIfInvalid(bool $formatIfInvalid = true): static { $this->formatIfInvalid = $formatIfInvalid; @@ -79,7 +75,7 @@ public function formatIfInvalid(bool $formatIfInvalid = true): self * * @see PhoneNumberToStringTransformer */ - public function saveAsString($format = PhoneNumberFormat::E164): self + public function saveAsString(PhoneNumberFormat|int|null $format = PhoneNumberFormat::E164): static { $this->saveFormat = $format; diff --git a/src/Phone/PhoneElement.php b/src/Phone/PhoneElement.php index 99f44c5..f1b07a8 100644 --- a/src/Phone/PhoneElement.php +++ b/src/Phone/PhoneElement.php @@ -28,12 +28,8 @@ final class PhoneElement extends LeafElement /** * @var callable(PhoneElement):string */ - private $regionResolver; - - /** - * @var PhoneNumberUtil - */ - private $formatter; + private readonly mixed $regionResolver; + private readonly PhoneNumberUtil $formatter; /** @@ -53,7 +49,7 @@ public function __construct(?ValueValidatorInterface $validator = null, ?Transfo } #[Override] - protected function toPhp($httpValue) + protected function toPhp(mixed $httpValue): ?PhoneNumber { if ($httpValue === null || $httpValue === '') { return null; @@ -63,7 +59,7 @@ protected function toPhp($httpValue) } #[Override] - protected function toHttp($phpValue) + protected function toHttp(mixed $phpValue): ?string { if (!$phpValue) { return null; @@ -123,7 +119,7 @@ public function parseValue(string $rawPhoneNumber): PhoneNumber try { return $this->formatter->parse($rawPhoneNumber, $this->resolveRegion(), null, true); } catch (NumberParseException $e) { - return (new PhoneNumber())->setRawInput($rawPhoneNumber); + return new PhoneNumber()->setRawInput($rawPhoneNumber); } } diff --git a/src/Phone/PhoneElementBuilder.php b/src/Phone/PhoneElementBuilder.php index 8de750d..c8693dc 100644 --- a/src/Phone/PhoneElementBuilder.php +++ b/src/Phone/PhoneElementBuilder.php @@ -36,27 +36,19 @@ class PhoneElementBuilder extends AbstractElementBuilder /** * @var callable(ElementInterface):string|null */ - private $regionResolver; - - /** - * @var PhoneNumberUtil|null - */ - private $formatter; + private mixed $regionResolver = null; + private ?PhoneNumberUtil $formatter = null; /** * Invalid phone number are allowed ? * (i.e. number value is not validated) - * - * @var bool */ - private $allowInvalidNumber = false; + private bool $allowInvalidNumber = false; /** * The error message or options for the ValidPhoneNumber constraint if the phone number is invalid - * - * @var string|null */ - private $invalidPhoneErrorMessage = null; + private ?string $invalidPhoneErrorMessage = null; /** @@ -68,11 +60,14 @@ public function __construct(?RegistryInterface $registry = null) { parent::__construct($registry); - $this->addConstraintsProvider([$this, 'providePhoneConstraint']); + $this->addConstraintsProvider($this->providePhoneConstraint(...)); } + /** + * @psalm-suppress MethodSignatureMismatch + */ #[Override] - public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null) + public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null): static { if (!$message instanceof Constraint) { $message = new NotEmptyPhoneNumber( @@ -98,7 +93,7 @@ public function required(string|Constraint|null $message = null, ?bool $allowNul * * @return $this */ - public function regionResolver(callable $regionResolver): self + public function regionResolver(callable $regionResolver): static { $this->regionResolver = $regionResolver; @@ -114,9 +109,9 @@ public function regionResolver(callable $regionResolver): self * * @see RegionCode */ - public function region(string $region): self + public function region(string $region): static { - return $this->regionResolver(function () use($region) { return $region; }); + return $this->regionResolver(static fn() => $region); } /** @@ -141,7 +136,7 @@ public function region(string $region): self * @see FieldPath::parse() For the path syntax * @see ChildBuilderInterface::depends() For declare the dependency to the other field */ - public function regionInput(string $inputPath): self + public function regionInput(string $inputPath): static { return $this->regionResolver(function (ElementInterface $element) use($inputPath) { return FieldPath::parse($inputPath)->value($element); @@ -155,7 +150,7 @@ public function regionInput(string $inputPath): self * * @return $this */ - public function formatter(PhoneNumberUtil $formatter): self + public function formatter(PhoneNumberUtil $formatter): static { $this->formatter = $formatter; @@ -170,7 +165,7 @@ public function formatter(PhoneNumberUtil $formatter): self * * @return $this */ - public function allowInvalidNumber(bool $allowInvalidNumber = true): self + public function allowInvalidNumber(bool $allowInvalidNumber = true): static { $this->allowInvalidNumber = $allowInvalidNumber; @@ -193,7 +188,7 @@ public function allowInvalidNumber(bool $allowInvalidNumber = true): self * @return $this * @see ValidPhoneNumber */ - public function validateNumber(?string $message = null): self + public function validateNumber(?string $message = null): static { $this->allowInvalidNumber = false; $this->invalidPhoneErrorMessage = $message; @@ -209,7 +204,7 @@ public function validateNumber(?string $message = null): self * @return $this * @see ValidPhoneNumber::$message */ - public function errorMessage(string $message): self + public function errorMessage(string $message): static { $this->invalidPhoneErrorMessage = $message; diff --git a/src/Phone/Transformer/PhoneNumberToStringTransformer.php b/src/Phone/Transformer/PhoneNumberToStringTransformer.php index f07a125..bd2442e 100644 --- a/src/Phone/Transformer/PhoneNumberToStringTransformer.php +++ b/src/Phone/Transformer/PhoneNumberToStringTransformer.php @@ -16,22 +16,14 @@ * Transformer PhoneNumber instance to string with a format */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] -final class PhoneNumberToStringTransformer implements TransformerInterface +final readonly class PhoneNumberToStringTransformer implements TransformerInterface { /** * @var PhoneNumberFormat::* */ - private $format; - - /** - * @var bool - */ - private $formatIfInvalid; - - /** - * @var PhoneNumberUtil|null - */ - private $formatter; + private PhoneNumberFormat|int $format; + private bool $formatIfInvalid; + private ?PhoneNumberUtil $formatter; /** * PhoneNumberToStringTransformer constructor. @@ -40,7 +32,7 @@ final class PhoneNumberToStringTransformer implements TransformerInterface * @param bool $formatIfInvalid * @param PhoneNumberUtil|null $formatter */ - public function __construct($format = PhoneNumberFormat::E164, bool $formatIfInvalid = false, ?PhoneNumberUtil $formatter = null) + public function __construct(PhoneNumberFormat|int $format = PhoneNumberFormat::E164, bool $formatIfInvalid = false, ?PhoneNumberUtil $formatter = null) { $this->format = $format; $this->formatIfInvalid = $formatIfInvalid; @@ -48,7 +40,7 @@ public function __construct($format = PhoneNumberFormat::E164, bool $formatIfInv } #[Override] - public function transformToHttp($value, ElementInterface $input): ?PhoneNumber + public function transformToHttp(mixed $value, ElementInterface $input): ?PhoneNumber { if ($value === null) { return null; @@ -64,7 +56,7 @@ public function transformToHttp($value, ElementInterface $input): ?PhoneNumber } #[Override] - public function transformFromHttp($value, ElementInterface $input): ?string + public function transformFromHttp(mixed $value, ElementInterface $input): ?string { if (!$value instanceof PhoneNumber) { return null; diff --git a/src/Phone/ValidPhoneNumber.php b/src/Phone/ValidPhoneNumber.php index 403bc51..041300e 100644 --- a/src/Phone/ValidPhoneNumber.php +++ b/src/Phone/ValidPhoneNumber.php @@ -18,7 +18,7 @@ class ValidPhoneNumber extends Constraint * * @var string */ - public $message = 'The phone number is not valid.'; + public string $message = 'The phone number is not valid.'; public function __construct(?string $message = null) { diff --git a/src/Phone/ValidPhoneNumberValidator.php b/src/Phone/ValidPhoneNumberValidator.php index 4085e3b..9dd8f05 100644 --- a/src/Phone/ValidPhoneNumberValidator.php +++ b/src/Phone/ValidPhoneNumberValidator.php @@ -12,12 +12,9 @@ /** * Validator for @see ValidPhoneNumber */ -class ValidPhoneNumberValidator extends ConstraintValidator +final class ValidPhoneNumberValidator extends ConstraintValidator { - /** - * @var PhoneNumberUtil - */ - private $formatter; + private readonly PhoneNumberUtil $formatter; /** @@ -30,7 +27,7 @@ public function __construct(?PhoneNumberUtil $formatter = null) } #[Override] - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof ValidPhoneNumber) { throw new UnexpectedTypeException($constraint, ValidPhoneNumber::class); diff --git a/src/PropertyAccess/AbstractAccessor.php b/src/PropertyAccess/AbstractAccessor.php index 3acabd3..bfdde65 100644 --- a/src/PropertyAccess/AbstractAccessor.php +++ b/src/PropertyAccess/AbstractAccessor.php @@ -6,47 +6,35 @@ use Override; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +use function is_string; + /** * Base access implementation */ abstract class AbstractAccessor implements AccessorInterface { - /** - * @var string|null - */ - private $propertyName; + private ?string $propertyName = null; /** * @var callable|null */ - protected $transformer; + protected mixed $transformer = null; /** * @var callable|null */ - protected $customAccessor; - - /** - * @var PropertyAccessorInterface - */ - protected $propertyAccessor; + protected mixed $customAccessor = null; + protected ?PropertyAccessorInterface $propertyAccessor = null; + protected ?ChildInterface $input = null; /** - * @var ChildInterface|null - */ - protected $input; - - - /** - * Getter constructor. - * - * @param string|callable $propertyName + * @param string|callable|null $propertyName * @param callable|null $transformer * @param callable|null $customAccessor */ - public function __construct($propertyName = null, ?callable $transformer = null, ?callable $customAccessor = null) + public function __construct(string|callable|null $propertyName = null, ?callable $transformer = null, ?callable $customAccessor = null) { - if (is_callable($propertyName)) { + if ($propertyName !== null && !is_string($propertyName)) { $customAccessor = $transformer; $transformer = $propertyName; $propertyName = null; @@ -75,7 +63,7 @@ final public function setFormElement(?ChildInterface $formElement): void * @param array|object $target * @return string */ - final protected function prepareAccessorPath($target): string + final protected function prepareAccessorPath(array|object $target): string { $propertyName = $this->getPropertyName(); @@ -97,7 +85,7 @@ final protected function prepareAccessorPath($target): string * * @return string */ - final protected function getPropertyName() + final protected function getPropertyName(): string { if ($this->propertyName === null && $this->input) { $this->propertyName = $this->input->name(); diff --git a/src/PropertyAccess/ExtractorInterface.php b/src/PropertyAccess/ExtractorInterface.php index 27f1808..b54087e 100755 --- a/src/PropertyAccess/ExtractorInterface.php +++ b/src/PropertyAccess/ExtractorInterface.php @@ -7,7 +7,7 @@ */ interface ExtractorInterface extends AccessorInterface { - const EXTRACTION = 'extraction'; + public const string EXTRACTION = 'extraction'; /** * Extract the target property value @@ -16,5 +16,5 @@ interface ExtractorInterface extends AccessorInterface * * @return mixed The extracted value */ - public function extract($source); + public function extract(array|object $source)/*: mixed*/; } diff --git a/src/PropertyAccess/Getter.php b/src/PropertyAccess/Getter.php index 2c1eefc..3f2836e 100644 --- a/src/PropertyAccess/Getter.php +++ b/src/PropertyAccess/Getter.php @@ -5,6 +5,8 @@ use Attribute; use Override; +use function assert; + /** * Extract a property value and import it into the form element * @@ -37,15 +39,16 @@ final class Getter extends AbstractAccessor implements ExtractorInterface { #[Override] - public function extract($source) + public function extract(array|object $source): mixed { if ($this->customAccessor !== null) { $value = ($this->customAccessor)($source, null, self::EXTRACTION, $this); } else { + assert($this->propertyAccessor !== null); $value = $this->propertyAccessor->getValue($source, $this->prepareAccessorPath($source)); } - if ($this->transformer) { + if ($this->transformer !== null) { $value = ($this->transformer)($value, $this->input); } diff --git a/src/PropertyAccess/HydratorInterface.php b/src/PropertyAccess/HydratorInterface.php index 3fcb8f1..6a70c07 100755 --- a/src/PropertyAccess/HydratorInterface.php +++ b/src/PropertyAccess/HydratorInterface.php @@ -7,7 +7,7 @@ */ interface HydratorInterface extends AccessorInterface { - const HYDRATION = 'hydration'; + public const string HYDRATION = 'hydration'; /** * Hydrate the target @@ -17,5 +17,5 @@ interface HydratorInterface extends AccessorInterface * * @return void */ - public function hydrate(&$target, $value)/*: void*/; + public function hydrate(array|object &$target, mixed $value)/*: void*/; } diff --git a/src/PropertyAccess/Setter.php b/src/PropertyAccess/Setter.php index d5314f6..772c316 100644 --- a/src/PropertyAccess/Setter.php +++ b/src/PropertyAccess/Setter.php @@ -5,6 +5,8 @@ use Attribute; use Override; +use function assert; + /** * Set the property value using the element value * @@ -37,15 +39,16 @@ final class Setter extends AbstractAccessor implements HydratorInterface { #[Override] - public function hydrate(&$target, $value): void + public function hydrate(array|object &$target, mixed $value): void { - if ($this->transformer) { + if ($this->transformer !== null) { $value = ($this->transformer)($value, $this->input); } if ($this->customAccessor !== null) { ($this->customAccessor)($target, $value, self::HYDRATION, $this); } else { + assert($this->propertyAccessor !== null); $this->propertyAccessor->setValue($target, $this->prepareAccessorPath($target), $value); } } diff --git a/src/Registry/Registry.php b/src/Registry/Registry.php index a57328a..0b7aa04 100755 --- a/src/Registry/Registry.php +++ b/src/Registry/Registry.php @@ -39,15 +39,18 @@ use InvalidArgumentException; use Override; +use function is_string; +use function is_subclass_of; + /** * Base registry interface */ -class Registry implements RegistryInterface +final class Registry implements RegistryInterface { /** * @var class-string[]|callable[] */ - private $elementBuilderFactories = [ + private array $elementBuilderFactories = [ StringElement::class => StringElementBuilder::class, IntegerElement::class => IntegerElementBuilder::class, FloatElement::class => FloatElementBuilder::class, @@ -69,7 +72,7 @@ class Registry implements RegistryInterface /** * @var class-string[]|callable[] */ - private $childBuilderFactories = [ + private array $childBuilderFactories = [ DateTimeElement::class => DateTimeChildBuilder::class, PhoneElement::class => PhoneChildBuilder::class, ArrayElement::class => ArrayChildBuilder::class, @@ -124,7 +127,7 @@ public function elementBuilder(string $element): ElementBuilderInterface } } - if (!$builderFactory) { + if ($builderFactory === null) { throw new InvalidArgumentException('The element '.$element.' is not registered'); } @@ -166,7 +169,7 @@ public function buttonBuilder(string $name): ButtonBuilderInterface * * @see Registry::elementBuilder() */ - public function register(string $elementType, $builderFactory, $childBuilderFactory = null): void + public function register(string $elementType, string|callable $builderFactory, string|callable|null $childBuilderFactory = null): void { $this->elementBuilderFactories[$elementType] = $builderFactory; diff --git a/src/Transformer/ClosureTransformer.php b/src/Transformer/ClosureTransformer.php index 3c25992..7be10a2 100755 --- a/src/Transformer/ClosureTransformer.php +++ b/src/Transformer/ClosureTransformer.php @@ -19,13 +19,12 @@ * @see RegistryInterface::transformer() With callbable should return a ClosureTransformer * @see ElementBuilderInterface::transformer() For register a transformer on an element */ -final class ClosureTransformer implements TransformerInterface +final readonly class ClosureTransformer implements TransformerInterface { /** * @var callable */ - private $callback; - + private mixed $callback; /** * @param callable $callback @@ -36,13 +35,13 @@ public function __construct(callable $callback) } #[Override] - public function transformToHttp($value, ElementInterface $input) + public function transformToHttp(mixed $value, ElementInterface $input): mixed { return ($this->callback)($value, $input, false); } #[Override] - public function transformFromHttp($value, ElementInterface $input) + public function transformFromHttp(mixed $value, ElementInterface $input): mixed { return ($this->callback)($value, $input, true); } diff --git a/src/Transformer/DataTransformerAdapter.php b/src/Transformer/DataTransformerAdapter.php index 2f3090f..6db4f74 100755 --- a/src/Transformer/DataTransformerAdapter.php +++ b/src/Transformer/DataTransformerAdapter.php @@ -9,34 +9,23 @@ /** * Adapter for Symfony data transformer to bdf transformer */ -final class DataTransformerAdapter implements TransformerInterface +final readonly class DataTransformerAdapter implements TransformerInterface { - /** - * The symfony data transformer - * - * @var DataTransformerInterface - */ - private $transformer; - - - /** - * Set the symfony data transformer - * - * @param DataTransformerInterface $transformer - */ - public function __construct(DataTransformerInterface $transformer) - { - $this->transformer = $transformer; - } + public function __construct( + /** + * The symfony data transformer + */ + private DataTransformerInterface $transformer, + ) {} #[Override] - public function transformToHttp($value, ElementInterface $input) + public function transformToHttp(mixed $value, ElementInterface $input): mixed { return $this->transformer->transform($value); } #[Override] - public function transformFromHttp($value, ElementInterface $input) + public function transformFromHttp(mixed $value, ElementInterface $input): mixed { return $this->transformer->reverseTransform($value); } diff --git a/src/Transformer/NullTransformer.php b/src/Transformer/NullTransformer.php index 599d916..9a28635 100644 --- a/src/Transformer/NullTransformer.php +++ b/src/Transformer/NullTransformer.php @@ -8,21 +8,16 @@ /** * Null object for form transformer */ -final class NullTransformer implements TransformerInterface +final readonly class NullTransformer implements TransformerInterface { - /** - * @var NullTransformer|null - */ - private static $instance; - #[Override] - public function transformToHttp($value, ElementInterface $input) + public function transformToHttp(mixed $value, ElementInterface $input): mixed { return $value; } #[Override] - public function transformFromHttp($value, ElementInterface $input) + public function transformFromHttp(mixed $value, ElementInterface $input): mixed { return $value; } @@ -34,10 +29,8 @@ public function transformFromHttp($value, ElementInterface $input) */ public static function instance(): self { - if (self::$instance) { - return self::$instance; - } + static $instance = new self(); - return self::$instance = new self(); + return $instance; } } diff --git a/src/Transformer/TransformerAggregate.php b/src/Transformer/TransformerAggregate.php index 1633b23..559bbe1 100644 --- a/src/Transformer/TransformerAggregate.php +++ b/src/Transformer/TransformerAggregate.php @@ -5,32 +5,28 @@ use Bdf\Form\ElementInterface; use Override; +use function array_unshift; +use function count; +use function sprintf; +use function trigger_error; + /** * Aggregation of transformers * * - The transformers are applied in order for transform from PHP to HTTP value * - For transform from HTTP to PHP, the transformers are applied in reverse order */ -final class TransformerAggregate implements TransformerInterface +final /*readonly*/ class TransformerAggregate implements TransformerInterface { - /** - * @var TransformerInterface[] - */ - private $transformers; - - - /** - * DataTransformerChain constructor. - * - * @param TransformerInterface[] $transformers - */ - public function __construct(array $transformers) - { - $this->transformers = $transformers; - } + public function __construct( + /** + * @var TransformerInterface[] + */ + private array $transformers, + ) {} #[Override] - public function transformToHttp($value, ElementInterface $input) + public function transformToHttp(mixed $value, ElementInterface $input): mixed { foreach ($this->transformers as $transformer) { $value = $transformer->transformToHttp($value, $input); @@ -40,7 +36,7 @@ public function transformToHttp($value, ElementInterface $input) } #[Override] - public function transformFromHttp($value, ElementInterface $input) + public function transformFromHttp(mixed $value, ElementInterface $input): mixed { for ($i = count($this->transformers) - 1; $i >= 0; --$i) { $value = $this->transformers[$i]->transformFromHttp($value, $input); @@ -53,9 +49,11 @@ public function transformFromHttp($value, ElementInterface $input) * Add a transformer at the head of the transformer list * * @param TransformerInterface $transformer + * @deprecated since 2.0, the class will be marked as readonly in 3.0 */ public function prepend(TransformerInterface $transformer): void { + @trigger_error(sprintf('Modifying "%s" is deprecated since 2.0, the class will be marked as readonly in 3.0.', self::class), E_USER_DEPRECATED); array_unshift($this->transformers, $transformer); } @@ -63,9 +61,11 @@ public function prepend(TransformerInterface $transformer): void * Add a transformer at the end of the transformer list * * @param TransformerInterface $transformer + * @deprecated since 2.0, the class will be marked as readonly in 3.0 */ public function append(TransformerInterface $transformer): void { + @trigger_error(sprintf('Modifying "%s" is deprecated since 2.0, the class will be marked as readonly in 3.0.', self::class), E_USER_DEPRECATED); $this->transformers[] = $transformer; } } diff --git a/src/Transformer/TransformerInterface.php b/src/Transformer/TransformerInterface.php index b7fbd90..a7936b9 100755 --- a/src/Transformer/TransformerInterface.php +++ b/src/Transformer/TransformerInterface.php @@ -17,7 +17,7 @@ interface TransformerInterface * * @return mixed The view value */ - public function transformToHttp($value, ElementInterface $input); + public function transformToHttp(mixed $value, ElementInterface $input)/*: mixed*/; /** * Http to model transformation @@ -27,5 +27,5 @@ public function transformToHttp($value, ElementInterface $input); * * @return mixed The model value */ - public function transformFromHttp($value, ElementInterface $input); + public function transformFromHttp(mixed $value, ElementInterface $input)/*: mixed*/; } diff --git a/src/Util/ContainerTrait.php b/src/Util/ContainerTrait.php index 687f2ed..a64b2a7 100644 --- a/src/Util/ContainerTrait.php +++ b/src/Util/ContainerTrait.php @@ -14,7 +14,7 @@ trait ContainerTrait /** * @var WeakReference|null */ - private $container; + private ?WeakReference $container = null; /** diff --git a/src/Util/DelegateElementBuilderTrait.php b/src/Util/DelegateElementBuilderTrait.php index 6da115a..d05b0d3 100644 --- a/src/Util/DelegateElementBuilderTrait.php +++ b/src/Util/DelegateElementBuilderTrait.php @@ -18,7 +18,7 @@ trait DelegateElementBuilderTrait /** * {@inheritdoc} */ - final public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) + final public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true): static { $this->getElementBuilder()->satisfy($constraint, $message, $append); @@ -28,7 +28,7 @@ final public function satisfy(Constraint|callable $constraint, ?string $message /** * {@inheritdoc} */ - final public function transformer(callable|TransformerInterface $transformer, bool $append = true) + final public function transformer(callable|TransformerInterface $transformer, bool $append = true): static { $this->getElementBuilder()->transformer($transformer, $append); @@ -38,7 +38,7 @@ final public function transformer(callable|TransformerInterface $transformer, bo /** * {@inheritdoc} */ - final public function value($value) + final public function value(mixed $value): static { $this->getElementBuilder()->value($value); diff --git a/src/Util/FieldFinderTrait.php b/src/Util/FieldFinderTrait.php index 4a50771..5df08d4 100644 --- a/src/Util/FieldFinderTrait.php +++ b/src/Util/FieldFinderTrait.php @@ -68,7 +68,7 @@ public function findField(string $path): ?ElementInterface * * @see FieldPath::parse() For the path syntax */ - public function findFieldValue(string $path) + public function findFieldValue(string $path): mixed { return $this->fieldPath($path)->value($this); } diff --git a/src/Util/FieldPath.php b/src/Util/FieldPath.php index e545d28..e2cdd29 100644 --- a/src/Util/FieldPath.php +++ b/src/Util/FieldPath.php @@ -14,26 +14,22 @@ */ final class FieldPath { - const SELF_ELEMENT = '.'; - const PARENT_ELEMENT = '..'; - const SEPARATOR = '/'; + public const string SELF_ELEMENT = '.'; + public const string PARENT_ELEMENT = '..'; + public const string SEPARATOR = '/'; /** * Paths cache * * @var FieldPath[] */ - private static $cache = []; + private static array $cache = []; /** * @var string[] */ - private $path; - - /** - * @var bool - */ - private $absolute; + private readonly array $path; + private readonly bool $absolute; /** @@ -57,7 +53,7 @@ public function __construct(array $path, bool $absolute) * * @return ElementInterface|null The resolved element, or null if cannot be found */ - public function resolve($currentElement): ?ElementInterface + public function resolve(ElementInterface|ChildInterface $currentElement): ?ElementInterface { if ($currentElement instanceof ChildInterface) { $currentElement = $currentElement->element(); diff --git a/src/Util/HttpValue.php b/src/Util/HttpValue.php index 9bfe60e..20c4768 100644 --- a/src/Util/HttpValue.php +++ b/src/Util/HttpValue.php @@ -15,7 +15,7 @@ final class HttpValue * * @return bool true if the value is empty */ - public static function isEmpty($value): bool + public static function isEmpty(mixed $value): bool { return $value === null || $value === '' || $value === []; } @@ -29,7 +29,7 @@ public static function isEmpty($value): bool * * @return mixed The value or the default */ - public static function orDefault($value, $default) + public static function orDefault(mixed $value, mixed $default): mixed { if ($default === null || !self::isEmpty($value)) { return $value; diff --git a/src/Util/MagicCallForwarding.php b/src/Util/MagicCallForwarding.php index 938d100..b46cb49 100644 --- a/src/Util/MagicCallForwarding.php +++ b/src/Util/MagicCallForwarding.php @@ -17,7 +17,7 @@ trait MagicCallForwarding * * @return $this|mixed */ - final public function __call(string $name, array $arguments) + final public function __call(string $name, array $arguments): mixed { $builder = $this->getElementBuilder(); $return = $builder->$name(...$arguments); diff --git a/src/Util/RootFlagsTrait.php b/src/Util/RootFlagsTrait.php index 87919df..cf19886 100644 --- a/src/Util/RootFlagsTrait.php +++ b/src/Util/RootFlagsTrait.php @@ -16,7 +16,7 @@ trait RootFlagsTrait * * @var array */ - private $flags = []; + private array $flags = []; /** * {@inheritdoc} diff --git a/src/Util/TransformerBuilderTrait.php b/src/Util/TransformerBuilderTrait.php index 0723c52..8e3f9a1 100644 --- a/src/Util/TransformerBuilderTrait.php +++ b/src/Util/TransformerBuilderTrait.php @@ -9,6 +9,7 @@ use Bdf\Form\Transformer\TransformerAggregate; use Bdf\Form\Transformer\TransformerInterface; +use function array_unshift; use function count; use function is_callable; @@ -18,21 +19,21 @@ trait TransformerBuilderTrait { /** - * @var array + * @var list */ - private $transformers = []; + private array $transformers = []; /** - * @var array + * @var array */ - private $transformerProviders = []; + private array $transformerProviders = []; /** * {@inheritdoc} * * @see ElementBuilderInterface::transformer() */ - final public function transformer(callable|TransformerInterface $transformer, bool $append = true) + final public function transformer(callable|TransformerInterface $transformer, bool $append = true): static { if (is_callable($transformer)) { $transformer = new ClosureTransformer($transformer); @@ -63,7 +64,7 @@ final public function transformer(callable|TransformerInterface $transformer, bo * }); * * - * @param callable(RegistryInterface):TransformerInterface[] $provider + * @param callable(RegistryInterface):(TransformerInterface[]) $provider */ final protected function addTransformerProvider(callable $provider): void { diff --git a/src/Util/ValidatorBuilderTrait.php b/src/Util/ValidatorBuilderTrait.php index 79451a9..412b193 100644 --- a/src/Util/ValidatorBuilderTrait.php +++ b/src/Util/ValidatorBuilderTrait.php @@ -11,6 +11,7 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\NotBlank; +use function array_unshift; use function is_callable; /** @@ -23,17 +24,13 @@ trait ValidatorBuilderTrait /** * @var array */ - private $constraints = []; + private array $constraints = []; + private ?TransformerExceptionConstraint $transformerExceptionConstraint = null; /** - * @var TransformerExceptionConstraint|null + * @var array */ - private $transformerExceptionConstraint; - - /** - * @var array - */ - private $constraintsProviders = []; + private array $constraintsProviders = []; /** * Mark this input as required @@ -57,7 +54,7 @@ trait ValidatorBuilderTrait * * @see NotBlank The used constraint */ - public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null) + public function required(string|Constraint|null $message = null, ?bool $allowNull = null, ?callable $normalizer = null): static { if (!$message instanceof Constraint) { $message = new NotBlank(message: $message, allowNull: $allowNull, normalizer: $normalizer); @@ -71,7 +68,7 @@ public function required(string|Constraint|null $message = null, ?bool $allowNul * * @see ElementBuilderInterface::satisfy() */ - final public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true) + final public function satisfy(Constraint|callable $constraint, ?string $message = null, bool $append = true): static { if (is_callable($constraint)) { $constraint = new Closure($constraint, $message); @@ -96,7 +93,7 @@ final public function satisfy(Constraint|callable $constraint, ?string $message * * @see TransformerExceptionConstraint::$ignoreException */ - final public function ignoreTransformerException(bool $flag = true) + final public function ignoreTransformerException(bool $flag = true): static { $this->getTransformerExceptionConstraint()->ignoreException = $flag; @@ -111,7 +108,7 @@ final public function ignoreTransformerException(bool $flag = true) * * @see TransformerExceptionConstraint::$message */ - final public function transformerErrorMessage(string $message) + final public function transformerErrorMessage(string $message): static { $this->getTransformerExceptionConstraint()->message = $message; @@ -126,7 +123,7 @@ final public function transformerErrorMessage(string $message) * * @see TransformerExceptionConstraint::$code */ - final public function transformerErrorCode(string $code) + final public function transformerErrorCode(string $code): static { $this->getTransformerExceptionConstraint()->code = $code; @@ -164,7 +161,7 @@ final public function transformerErrorCode(string $code) * * @see TransformerExceptionConstraint::$code */ - final public function transformerExceptionValidation(callable $validationCallback) + final public function transformerExceptionValidation(callable $validationCallback): static { $this->getTransformerExceptionConstraint()->validationCallback = $validationCallback; @@ -185,7 +182,7 @@ final public function transformerExceptionValidation(callable $validationCallbac * }); * * - * @param callable(RegistryInterface):Constraint[] $constraintsProvider + * @param callable(RegistryInterface):(Constraint[]) $constraintsProvider */ final protected function addConstraintsProvider(callable $constraintsProvider): void { diff --git a/src/Validator/ConstraintValueValidator.php b/src/Validator/ConstraintValueValidator.php index aafb36c..32b00fa 100644 --- a/src/Validator/ConstraintValueValidator.php +++ b/src/Validator/ConstraintValueValidator.php @@ -15,22 +15,17 @@ * @template T * @implements ValueValidatorInterface */ -final class ConstraintValueValidator implements ValueValidatorInterface +final readonly class ConstraintValueValidator implements ValueValidatorInterface { - /** - * @var self - */ - private static $emptyInstance; - /** * @var Constraint[] */ - private $constraints; + private array $constraints; /** * @var TransformerExceptionConstraint */ - private $transformerExceptionConstraint; + private TransformerExceptionConstraint $transformerExceptionConstraint; /** @@ -101,7 +96,7 @@ public function constraints(): array #[Override] public function hasConstraints(): bool { - return !empty($this->constraints); + return $this->constraints !== []; } /** @@ -111,10 +106,8 @@ public function hasConstraints(): bool */ public static function empty(): self { - if (self::$emptyInstance) { - return self::$emptyInstance; - } + static $instance = new self(); - return self::$emptyInstance = new self(); + return $instance; } } diff --git a/src/Validator/TransformerExceptionConstraint.php b/src/Validator/TransformerExceptionConstraint.php index 330e1ad..9e503e7 100644 --- a/src/Validator/TransformerExceptionConstraint.php +++ b/src/Validator/TransformerExceptionConstraint.php @@ -19,21 +19,21 @@ final class TransformerExceptionConstraint extends Constraint * * @var string|null */ - public $message = null; + public ?string $message = null; /** * The error code * * @var string */ - public $code = self::TRANSFORM_ERROR; + public string $code = self::TRANSFORM_ERROR; /** * The transformer exception * * @var Exception|null */ - public $exception; + public ?Exception $exception = null; /** * Use to validate the exception @@ -43,7 +43,7 @@ final class TransformerExceptionConstraint extends Constraint * * @var callable(mixed,TransformerExceptionConstraint,\Bdf\Form\ElementInterface):bool|null */ - public $validationCallback; + public mixed $validationCallback = null; /** * Does the transformation error should be ignored ? @@ -51,7 +51,7 @@ final class TransformerExceptionConstraint extends Constraint * * @var bool */ - public $ignoreException = false; + public bool $ignoreException = false; public function __construct(?Exception $exception = null, ?string $message = null, ?string $code = null, ?callable $validationCallback = null, ?bool $ignoreException = null) { diff --git a/src/Validator/TransformerExceptionConstraintValidator.php b/src/Validator/TransformerExceptionConstraintValidator.php index f6daf1c..69341b7 100644 --- a/src/Validator/TransformerExceptionConstraintValidator.php +++ b/src/Validator/TransformerExceptionConstraintValidator.php @@ -14,13 +14,13 @@ final class TransformerExceptionConstraintValidator extends ConstraintValidator { #[Override] - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof TransformerExceptionConstraint) { throw new UnexpectedTypeException($constraint, TransformerExceptionConstraint::class); } - if ($constraint->validationCallback) { + if ($constraint->validationCallback !== null) { if (!($constraint->validationCallback)($value, $constraint, $this->context->getRoot())) { return; } diff --git a/src/Validator/ValueValidatorInterface.php b/src/Validator/ValueValidatorInterface.php index 567a9c4..912eb10 100644 --- a/src/Validator/ValueValidatorInterface.php +++ b/src/Validator/ValueValidatorInterface.php @@ -24,7 +24,7 @@ interface ValueValidatorInterface * * @return FormError The error. Return an empty error if the value is valid */ - public function validate($value, ElementInterface $element): FormError; + public function validate(mixed $value, ElementInterface $element): FormError; /** * Handle a transformer exception @@ -35,7 +35,7 @@ public function validate($value, ElementInterface $element): FormError; * * @return FormError The real error */ - public function onTransformerException(Exception $exception, $value, ElementInterface $element): FormError; + public function onTransformerException(Exception $exception, mixed $value, ElementInterface $element): FormError; /** * Get validator constraints diff --git a/src/View/ConstraintsNormalizer.php b/src/View/ConstraintsNormalizer.php index 53b4b53..0037d6b 100644 --- a/src/View/ConstraintsNormalizer.php +++ b/src/View/ConstraintsNormalizer.php @@ -10,6 +10,7 @@ use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; +use function array_intersect_key; use function assert; use function get_object_vars; @@ -22,7 +23,7 @@ final class ConstraintsNormalizer /** * @var array, array> */ - static private $constraints = [ + static private array $constraints = [ NotBlank::class => [], Length::class => ['min' => null, 'max' => null], Count::class => ['min' => null, 'max' => null], @@ -46,7 +47,7 @@ public static function normalize(ValueValidatorInterface $validator): array $normalizedConstraints = []; foreach ($validator->constraints() as $constraint) { - $className = get_class($constraint); + $className = $constraint::class; if (isset(self::$constraints[$className])) { $normalizedConstraints[$className] = array_intersect_key(get_object_vars($constraint), self::$constraints[$className]); @@ -69,7 +70,7 @@ public static function normalize(ValueValidatorInterface $validator): array */ private static function getDefaultOption(Constraint $constraint): ?array { - $ctor = (new ReflectionClass($constraint))->getConstructor(); + $ctor = new ReflectionClass($constraint)->getConstructor(); assert($ctor !== null); $firstParam = $ctor->getParameters()[0] ?? null; @@ -86,7 +87,7 @@ private static function getDefaultOption(Constraint $constraint): ?array } // Cache the option name for the constraint class, to avoid reflection on next calls - self::$constraints[get_class($constraint)][$option] = null; + self::$constraints[$constraint::class][$option] = null; $value = $constraint->{$option} ?? null; diff --git a/src/View/ElementViewInterface.php b/src/View/ElementViewInterface.php index 4033c8f..c131460 100644 --- a/src/View/ElementViewInterface.php +++ b/src/View/ElementViewInterface.php @@ -34,7 +34,7 @@ public function error(): ?string; * @return $this * @since 1.5 */ - public function setError(?string $error): self; + public function setError(?string $error): static; /** * Check if the current element is on error @@ -71,5 +71,5 @@ public function hasError(): bool; * * @see ElementViewInterface::hasError() To check if the element has an error */ - public function onError($action): ?string; + public function onError(string|callable $action): ?string; } diff --git a/src/View/ElementViewTrait.php b/src/View/ElementViewTrait.php index dfa00d3..7278624 100644 --- a/src/View/ElementViewTrait.php +++ b/src/View/ElementViewTrait.php @@ -14,12 +14,12 @@ trait ElementViewTrait /** * @var string */ - private $type; + private string $type; /** * @var string|null */ - private $error; + private ?string $error = null; /** * {@inheritdoc} @@ -58,7 +58,7 @@ public function hasError(): bool /** * {@inheritdoc} */ - public function onError($action): ?string + public function onError(string|callable $action): ?string { if (!$this->hasError()) { return null; diff --git a/src/View/FieldSetViewTrait.php b/src/View/FieldSetViewTrait.php index 03baa30..532d41f 100644 --- a/src/View/FieldSetViewTrait.php +++ b/src/View/FieldSetViewTrait.php @@ -18,12 +18,12 @@ trait FieldSetViewTrait /** * @var array */ - private $elements = []; + private array $elements = []; /** * {@inheritdoc} */ - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return isset($this->elements[$offset]); } @@ -31,7 +31,7 @@ public function offsetExists($offset): bool /** * {@inheritdoc} */ - public function offsetGet($offset): ElementViewInterface + public function offsetGet(mixed $offset): ElementViewInterface { return $this->elements[$offset]; } @@ -39,7 +39,7 @@ public function offsetGet($offset): ElementViewInterface /** * {@inheritdoc} */ - public function offsetSet($offset, $value): void + public function offsetSet(mixed $offset, mixed $value): void { throw new BadMethodCallException('FormView is read only'); } @@ -47,7 +47,7 @@ public function offsetSet($offset, $value): void /** * {@inheritdoc} */ - public function offsetUnset($offset): void + public function offsetUnset(mixed $offset): void { throw new BadMethodCallException('FormView is read only'); } @@ -86,7 +86,7 @@ public function errors(): array if ($element instanceof FieldSetViewInterface) { $errors[$name] = $element->errors(); - } elseif ($error = $element->error()) { + } elseif (($error = $element->error()) !== null) { $errors[$name] = $error; } } diff --git a/src/View/FieldViewInterface.php b/src/View/FieldViewInterface.php index 405ab12..6dedb34 100644 --- a/src/View/FieldViewInterface.php +++ b/src/View/FieldViewInterface.php @@ -25,7 +25,7 @@ public function name(): string; * * @return mixed */ - public function value(); + public function value(): mixed; /** * Override the value @@ -36,7 +36,7 @@ public function value(); * @return $this Return the current instance * @since 1.5 */ - public function setValue($value): self; + public function setValue(mixed $value): static; /** * Does the current field is required (i.e. the value must not be empty) diff --git a/src/View/FieldViewTrait.php b/src/View/FieldViewTrait.php index 937fb13..d267799 100644 --- a/src/View/FieldViewTrait.php +++ b/src/View/FieldViewTrait.php @@ -13,30 +13,19 @@ trait FieldViewTrait { use RenderableTrait; - /** - * @var string - */ - private $name; - - /** - * @var mixed - */ - private $value; - - /** - * @var bool - */ - private $required = false; + public private(set) string $name; + public private(set) mixed $value; + public private(set) bool $required = false; /** * @var array */ - private $constraints = []; + private array $constraints = []; /** * @var ChoiceView[]|null */ - private $choices; + public private(set) ?array $choices = null; /** * {@inheritdoc} @@ -49,7 +38,7 @@ public function name(): string /** * {@inheritdoc} */ - public function value() + public function value(): mixed { return $this->value; } @@ -57,7 +46,7 @@ public function value() /** * {@inheritdoc} */ - public function setValue($value): static + public function setValue(mixed $value): static { $this->value = $value; diff --git a/src/View/Renderable.php b/src/View/Renderable.php index 2fd14ee..51b6b31 100644 --- a/src/View/Renderable.php +++ b/src/View/Renderable.php @@ -18,17 +18,17 @@ interface Renderable extends Stringable * * @return $this */ - public function __call(string $name, array $arguments); + public function __call(string $name, array $arguments): static; /** * Define an attribute value * * @param string $name The attribute name - * @param string|bool $value The attribute value. Use true for a simple flag attribute + * @param scalar|bool $value The attribute value. Use true for a simple flag attribute * * @return $this */ - public function set(string $name, $value); + public function set(string $name, string|int|float|bool $value): static; /** * Define multiple attributes @@ -43,7 +43,7 @@ public function set(string $name, $value); * @return $this * @since 1.5 */ - public function with(array $attributes); + public function with(array $attributes): static; /** * Remove an attribute @@ -52,7 +52,7 @@ public function with(array $attributes); * * @return $this */ - public function unset(string $name); + public function unset(string $name): static; /** * Get all defined attributes diff --git a/src/View/RenderableTrait.php b/src/View/RenderableTrait.php index 1ca124a..96b7dd3 100644 --- a/src/View/RenderableTrait.php +++ b/src/View/RenderableTrait.php @@ -16,14 +16,14 @@ trait RenderableTrait { /** - * @var array + * @var array */ - private $attributes = []; + private array $attributes = []; /** * {@inheritdoc} */ - public function __call(string $name, array $arguments) + public function __call(string $name, array $arguments): static { if (empty($arguments)) { throw new ArgumentCountError('Missing the attribute value.'); @@ -37,12 +37,8 @@ public function __call(string $name, array $arguments) /** * {@inheritdoc} */ - public function set(string $name, $value) + public function set(string $name, int|string|float|bool $value): static { - if (!is_scalar($value)) { - throw new TypeError('The attribute value must be a scalar value.'); - } - $this->attributes[$name] = $value; return $this; @@ -51,7 +47,7 @@ public function set(string $name, $value) /** * {@inheritdoc} */ - public function with(array $attributes) + public function with(array $attributes): static { foreach ($attributes as $name => $value) { if (!is_scalar($value)) { @@ -71,7 +67,7 @@ public function with(array $attributes) /** * {@inheritdoc} */ - public function unset(string $name) + public function unset(string $name): static { unset($this->attributes[$name]); diff --git a/tests/Aggregate/FormTest.php b/tests/Aggregate/FormTest.php index 4fef6b7..b45835b 100644 --- a/tests/Aggregate/FormTest.php +++ b/tests/Aggregate/FormTest.php @@ -540,6 +540,35 @@ public function test_import_with_array() $this->assertSame(42, $form['id']->element()->value()); } + /** + * + */ + public function test_import_null_should_reset_fields() + { + $form = new Form(new ChildrenCollection([ + $this->registry->childBuilder(IntegerElement::class, 'id')->getset()->buildChild(), + $this->registry->childBuilder(StringElement::class, 'firstName')->getset()->buildChild(), + $this->registry->childBuilder(StringElement::class, 'lastName')->getset()->buildChild(), + ])); + + $form->submit($data = [ + 'id' => 42, + 'firstName' => 'Mike', + 'lastName' => 'Smith', + ]); + $this->assertSame($data, $form->value()); + + $this->assertSame([ + 'id' => null, + 'firstName' => null, + 'lastName' => null, + ], $form->import(null)->value()); + + $this->assertNull($form['firstName']->element()->value()); + $this->assertNull($form['lastName']->element()->value()); + $this->assertNull($form['id']->element()->value()); + } + /** * */ diff --git a/tests/Child/ChildBuilderTest.php b/tests/Child/ChildBuilderTest.php index cb8357e..4a6b9fa 100644 --- a/tests/Child/ChildBuilderTest.php +++ b/tests/Child/ChildBuilderTest.php @@ -498,7 +498,7 @@ public function parent(): ChildAggregateInterface { } - public function setParent(ChildAggregateInterface $parent): ChildInterface + public function setParent(ChildAggregateInterface $parent): static { } diff --git a/tests/Child/ChildTest.php b/tests/Child/ChildTest.php index d9525c4..172e049 100644 --- a/tests/Child/ChildTest.php +++ b/tests/Child/ChildTest.php @@ -81,6 +81,18 @@ public function test_import_with_object() $this->assertSame('my value', $child->element()->value()); } + /** + * + */ + public function test_import_null() + { + $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(['message' => 'required error']), null, new Getter()); + $child->setParent($form = new Form(new ChildrenCollection())); + + $child->import(null); + $this->assertNull($child->element()->value()); + } + /** * */ diff --git a/tests/Custom/CustomFormTest.php b/tests/Custom/CustomFormTest.php index 6fe5bb4..e3faf4b 100644 --- a/tests/Custom/CustomFormTest.php +++ b/tests/Custom/CustomFormTest.php @@ -301,7 +301,7 @@ public function child(string $name, FormError $error): void $error->print($this); } - public function print() + public function print(): mixed { if ($this->global || $this->code) { $this->errors[] = [ From 86974489b3273a1ac6480b3b9d80c127080a88dd Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Wed, 11 Mar 2026 17:09:37 +0100 Subject: [PATCH 08/12] chore: Psalm lvl 2 (#FRAM-221) --- psalm.xml | 5 ++++- src/Aggregate/ArrayElementBuilder.php | 3 ++- src/Aggregate/Form.php | 2 +- src/Aggregate/FormBuilder.php | 2 +- src/Aggregate/Value/ValueGenerator.php | 6 ++++-- src/Choice/ArrayChoice.php | 2 +- src/Constraint/ClosureValidator.php | 6 +++--- src/Constraint/FieldComparisonValidatorTrait.php | 2 +- src/Constraint/GreaterThanFieldValidator.php | 2 ++ src/Constraint/GreaterThanOrEqualFieldValidator.php | 2 ++ src/Constraint/LessThanFieldValidator.php | 2 ++ src/Constraint/LessThanOrEqualFieldValidator.php | 2 ++ src/Csrf/CsrfConstraint.php | 4 ++-- src/Csrf/CsrfConstraintValidator.php | 2 +- src/Csrf/CsrfValueValidator.php | 8 ++++---- src/Custom/CustomFormBuilder.php | 1 + src/Error/FormError.php | 12 ++++++------ src/Filter/EmptyArrayValuesFilter.php | 11 ++--------- src/Filter/TrimFilter.php | 11 ++--------- src/Leaf/Date/DateTimeElementBuilder.php | 8 ++++---- .../Transformer/DateTimeToTimestampTransformer.php | 1 + src/Leaf/Transformer/LocalizedIntegerTransformer.php | 2 +- src/Leaf/Transformer/LocalizedNumberTransformer.php | 5 +++-- src/Leaf/View/SelectHtmlRenderer.php | 4 +++- src/Leaf/View/SimpleElementView.php | 2 +- src/Phone/NotEmptyPhoneNumberValidator.php | 4 +++- src/Phone/PhoneElement.php | 2 +- .../Transformer/PhoneNumberToStringTransformer.php | 2 +- src/Phone/ValidPhoneNumber.php | 4 ++-- src/Phone/ValidPhoneNumberValidator.php | 2 ++ tests/StaticAnalysis/MyCustomForm.php | 3 +++ 31 files changed, 68 insertions(+), 56 deletions(-) diff --git a/psalm.xml b/psalm.xml index c6a52c6..8e65e46 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,6 +1,6 @@ + + + diff --git a/src/Aggregate/ArrayElementBuilder.php b/src/Aggregate/ArrayElementBuilder.php index 92217c8..1364707 100644 --- a/src/Aggregate/ArrayElementBuilder.php +++ b/src/Aggregate/ArrayElementBuilder.php @@ -139,7 +139,7 @@ public function element(string $element, ?callable $configurator = null): static /** @psalm-suppress InvalidPropertyAssignmentValue */ $this->element = $this->registry->elementBuilder($element); - if ($configurator) { + if ($configurator !== null) { /** @psalm-suppress InvalidArgument */ $configurator($this->element); } @@ -357,6 +357,7 @@ final public function required(string|Constraint|null $message = null, ?bool $al */ final public function choices(ChoiceInterface|array|callable $choices, ?string $message = null, ?bool $multiple = null, ?bool $strict = null, ?int $min = null, ?int $max = null, ?string $minMessage = null, ?string $maxMessage = null): static { + /** @psalm-suppress MissingConstructor */ $builder = new class { use ChoiceBuilderTrait { getChoices as public; diff --git a/src/Aggregate/Form.php b/src/Aggregate/Form.php index 734b928..3128546 100644 --- a/src/Aggregate/Form.php +++ b/src/Aggregate/Form.php @@ -182,7 +182,7 @@ public function error(?HttpFieldPath $field = null): FormError #[Override] public function import(mixed $entity): static { - if ($entity) { + if ($entity !== null && $entity !== []) { $this->generator->attach($entity); } diff --git a/src/Aggregate/FormBuilder.php b/src/Aggregate/FormBuilder.php index ce9a0fb..5c2a43b 100644 --- a/src/Aggregate/FormBuilder.php +++ b/src/Aggregate/FormBuilder.php @@ -295,7 +295,7 @@ public function embedded(string $name, ?callable $configurator = null): ChildBui { $builder = $this->add($name, Form::class); - if ($configurator) { + if ($configurator !== null) { $configurator($builder); } diff --git a/src/Aggregate/Value/ValueGenerator.php b/src/Aggregate/Value/ValueGenerator.php index 2c78271..1afedcb 100644 --- a/src/Aggregate/Value/ValueGenerator.php +++ b/src/Aggregate/Value/ValueGenerator.php @@ -5,6 +5,7 @@ use Bdf\Form\ElementInterface; use Override; +use function class_exists; use function is_callable; use function is_object; use function is_string; @@ -57,7 +58,7 @@ public function generate(ElementInterface $element): mixed { $value = $this->attachment ?? $this->value; - if (is_string($value)) { + if (is_string($value) && class_exists($value)) { /** @var T */ return new $value; } @@ -67,10 +68,11 @@ public function generate(ElementInterface $element): mixed } // Only clone value if it's not attached - if (!$this->attachment && is_object($value)) { + if ($this->attachment === null && is_object($value)) { return clone $value; } + /** @var T */ return $value; } } diff --git a/src/Choice/ArrayChoice.php b/src/Choice/ArrayChoice.php index 2c3abfa..bd8f760 100644 --- a/src/Choice/ArrayChoice.php +++ b/src/Choice/ArrayChoice.php @@ -38,7 +38,7 @@ public function view(?callable $configuration = null): array foreach ($this->choices as $label => $value) { $view[] = $choice = new ChoiceView($value, $label); - if ($configuration) { + if ($configuration !== null) { $configuration($choice); } } diff --git a/src/Constraint/ClosureValidator.php b/src/Constraint/ClosureValidator.php index f100c57..345b1d2 100755 --- a/src/Constraint/ClosureValidator.php +++ b/src/Constraint/ClosureValidator.php @@ -14,7 +14,7 @@ class ClosureValidator extends ConstraintValidator { #[Override] - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof Closure) { throw new UnexpectedTypeException($constraint, Closure::class); @@ -39,9 +39,9 @@ public function validate($value, Constraint $constraint): void $error = $error['message'] ?? null; } - $this->context->buildViolation($error ?: $constraint->message) + $this->context->buildViolation($error ?? $constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) - ->setCode($code ?: 'CUSTOM_ERROR') + ->setCode($code ?? 'CUSTOM_ERROR') ->addViolation() ; } diff --git a/src/Constraint/FieldComparisonValidatorTrait.php b/src/Constraint/FieldComparisonValidatorTrait.php index 44f3815..a3a388e 100644 --- a/src/Constraint/FieldComparisonValidatorTrait.php +++ b/src/Constraint/FieldComparisonValidatorTrait.php @@ -20,7 +20,7 @@ trait FieldComparisonValidatorTrait * * @return void */ - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { /** @var FieldComparisonTrait $constraint */ /** @var ElementInterface $element */ diff --git a/src/Constraint/GreaterThanFieldValidator.php b/src/Constraint/GreaterThanFieldValidator.php index 72bdc73..e915d34 100644 --- a/src/Constraint/GreaterThanFieldValidator.php +++ b/src/Constraint/GreaterThanFieldValidator.php @@ -6,6 +6,8 @@ /** * Validator for @see GreaterThanField + * + * @psalm-suppress PropertyNotSetInConstructor */ class GreaterThanFieldValidator extends GreaterThanValidator { diff --git a/src/Constraint/GreaterThanOrEqualFieldValidator.php b/src/Constraint/GreaterThanOrEqualFieldValidator.php index f5f6c50..3da246c 100644 --- a/src/Constraint/GreaterThanOrEqualFieldValidator.php +++ b/src/Constraint/GreaterThanOrEqualFieldValidator.php @@ -6,6 +6,8 @@ /** * Validator for @see GreaterThanOrEqualField + * + * @psalm-suppress PropertyNotSetInConstructor */ class GreaterThanOrEqualFieldValidator extends GreaterThanOrEqualValidator { diff --git a/src/Constraint/LessThanFieldValidator.php b/src/Constraint/LessThanFieldValidator.php index 5ac3e97..9c50310 100644 --- a/src/Constraint/LessThanFieldValidator.php +++ b/src/Constraint/LessThanFieldValidator.php @@ -6,6 +6,8 @@ /** * Validator for @see LessThanField + * + * @psalm-suppress PropertyNotSetInConstructor */ class LessThanFieldValidator extends LessThanValidator { diff --git a/src/Constraint/LessThanOrEqualFieldValidator.php b/src/Constraint/LessThanOrEqualFieldValidator.php index 72e66d5..55c90ae 100644 --- a/src/Constraint/LessThanOrEqualFieldValidator.php +++ b/src/Constraint/LessThanOrEqualFieldValidator.php @@ -6,6 +6,8 @@ /** * Validator for @see LessThanOrEqualField + * + * @psalm-suppress PropertyNotSetInConstructor */ class LessThanOrEqualFieldValidator extends LessThanOrEqualValidator { diff --git a/src/Csrf/CsrfConstraint.php b/src/Csrf/CsrfConstraint.php index 88b24cc..751bbaf 100644 --- a/src/Csrf/CsrfConstraint.php +++ b/src/Csrf/CsrfConstraint.php @@ -10,9 +10,9 @@ */ class CsrfConstraint extends Constraint { - const INVALID_TOKEN_ERROR = 'cd108896-d12a-4455-a6cc-ba13708c8e7f'; + public const string INVALID_TOKEN_ERROR = 'cd108896-d12a-4455-a6cc-ba13708c8e7f'; - protected const ERROR_NAMES = [self::INVALID_TOKEN_ERROR => 'INVALID_TOKEN_ERROR']; + protected const array ERROR_NAMES = [self::INVALID_TOKEN_ERROR => 'INVALID_TOKEN_ERROR']; /** * The constraint message diff --git a/src/Csrf/CsrfConstraintValidator.php b/src/Csrf/CsrfConstraintValidator.php index a7c826a..f4406ed 100644 --- a/src/Csrf/CsrfConstraintValidator.php +++ b/src/Csrf/CsrfConstraintValidator.php @@ -14,7 +14,7 @@ class CsrfConstraintValidator extends ConstraintValidator { #[Override] - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof CsrfConstraint) { throw new UnexpectedTypeException($constraint, CsrfConstraint::class); diff --git a/src/Csrf/CsrfValueValidator.php b/src/Csrf/CsrfValueValidator.php index b57b4aa..88726f8 100644 --- a/src/Csrf/CsrfValueValidator.php +++ b/src/Csrf/CsrfValueValidator.php @@ -11,6 +11,7 @@ use Override; +use function assert; use function method_exists; /** @@ -63,13 +64,12 @@ public function __construct(bool $invalidate = false, ?string $message = null, b /** * {@inheritdoc} - * - * @param CsrfElement $element - * @psalm-suppress MoreSpecificImplementedParamType */ #[Override] - public function validate($value, ElementInterface $element): FormError + public function validate(mixed $value, ElementInterface $element): FormError { + assert($element instanceof CsrfElement); + $root = $element->root(); if ($root->is(self::FLAG_DISABLE_CSRF_VALIDATION)) { diff --git a/src/Custom/CustomFormBuilder.php b/src/Custom/CustomFormBuilder.php index f6f7444..9b16422 100644 --- a/src/Custom/CustomFormBuilder.php +++ b/src/Custom/CustomFormBuilder.php @@ -70,6 +70,7 @@ public function buildElement(): CustomForm /** @var class-string $className */ $className = $this->formFactory; + /** @psalm-suppress UnsafeInstantiation */ $form = new $className($this->builder); } else { $form = ($this->formFactory)($this->builder); diff --git a/src/Error/FormError.php b/src/Error/FormError.php index 88237da..7d87408 100644 --- a/src/Error/FormError.php +++ b/src/Error/FormError.php @@ -112,7 +112,7 @@ public function children(): array */ public function empty(): bool { - return empty($this->global) && empty($this->code) && empty($this->children); + return $this->global === null && $this->code === null && $this->children === []; } /** @@ -160,12 +160,12 @@ public function toArray(): array { $errors = []; - if ($this->global) { + if ($this->global !== null) { $errors[0] = $this->global; } foreach ($this->children as $name => $child) { - if ($child->global) { + if ($child->global !== null) { $errors[$name] = $child->global; } else { $errors[$name] = $child->toArray(); @@ -184,15 +184,15 @@ public function toArray(): array */ public function print(FormErrorPrinterInterface $printer): mixed { - if ($this->field) { + if ($this->field !== null) { $printer->field($this->field); } - if ($this->global) { + if ($this->global !== null) { $printer->global($this->global); } - if ($this->code) { + if ($this->code !== null) { $printer->code($this->code); } diff --git a/src/Filter/EmptyArrayValuesFilter.php b/src/Filter/EmptyArrayValuesFilter.php index cdbea52..74bf378 100644 --- a/src/Filter/EmptyArrayValuesFilter.php +++ b/src/Filter/EmptyArrayValuesFilter.php @@ -15,10 +15,7 @@ #[Attribute(Attribute::TARGET_PROPERTY)] final class EmptyArrayValuesFilter implements FilterInterface { - /** - * @var EmptyArrayValuesFilter - */ - private static $instance; + private static ?self $instance = null; #[Override] public function filter(mixed $value, ChildInterface $input, mixed $default): mixed @@ -43,10 +40,6 @@ public function filter(mixed $value, ChildInterface $input, mixed $default): mix */ public static function instance(): self { - if (self::$instance) { - return self::$instance; - } - - return self::$instance = new self; + return self::$instance ??= new self; } } diff --git a/src/Filter/TrimFilter.php b/src/Filter/TrimFilter.php index 9b62960..6d052c2 100644 --- a/src/Filter/TrimFilter.php +++ b/src/Filter/TrimFilter.php @@ -20,10 +20,7 @@ #[Attribute(Attribute::TARGET_PROPERTY)] final class TrimFilter implements FilterInterface { - /** - * @var self - */ - private static $instance; + private static ?self $instance = null; #[Override] public function filter(mixed $value, ChildInterface $input, mixed $default): mixed @@ -47,10 +44,6 @@ public function filter(mixed $value, ChildInterface $input, mixed $default): mix */ public static function instance(): self { - if (self::$instance) { - return self::$instance; - } - - return self::$instance = new self; + return self::$instance ??= new self; } } diff --git a/src/Leaf/Date/DateTimeElementBuilder.php b/src/Leaf/Date/DateTimeElementBuilder.php index 979d1c7..9bc2c72 100644 --- a/src/Leaf/Date/DateTimeElementBuilder.php +++ b/src/Leaf/Date/DateTimeElementBuilder.php @@ -154,7 +154,7 @@ public function before(DateTimeInterface $dateTime, ?string $message = null, boo { $constraint = $orEqual ? new LessThanOrEqual($dateTime) : new LessThan($dateTime); - if ($message) { + if ($message !== null) { $constraint->message = $message; } @@ -186,7 +186,7 @@ public function beforeField(string $field, ?string $message = null, bool $orEqua { $constraint = $orEqual ? new LessThanOrEqualField($field) : new LessThanField($field); - if ($message) { + if ($message !== null) { $constraint->message = $message; } @@ -210,7 +210,7 @@ public function after(DateTimeInterface $dateTime, ?string $message = null, bool { $constraint = $orEqual ? new GreaterThanOrEqual($dateTime) : new GreaterThan($dateTime); - if ($message) { + if ($message !== null) { $constraint->message = $message; } @@ -242,7 +242,7 @@ public function afterField(string $field, ?string $message = null, bool $orEqual { $constraint = $orEqual ? new GreaterThanOrEqualField($field) : new GreaterThanField($field); - if ($message) { + if ($message !== null) { $constraint->message = $message; } diff --git a/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php b/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php index 24493d9..b19ffe8 100644 --- a/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php +++ b/src/Leaf/Date/Transformer/DateTimeToTimestampTransformer.php @@ -58,6 +58,7 @@ public function transformToHttp(mixed $value, ElementInterface $input): ?DateTim $className = $this->className ?? ($input instanceof DateTimeElement ? $input->dateTimeClassName() : DateTime::class); $timezone = $this->timezone ?? ($input instanceof DateTimeElement ? $input->timezone() : null); + /** @psalm-suppress UnsafeInstantiation */ /** @var DateTimeInterface $dateTime */ $dateTime = new $className; diff --git a/src/Leaf/Transformer/LocalizedIntegerTransformer.php b/src/Leaf/Transformer/LocalizedIntegerTransformer.php index 07c4f25..7977a7a 100644 --- a/src/Leaf/Transformer/LocalizedIntegerTransformer.php +++ b/src/Leaf/Transformer/LocalizedIntegerTransformer.php @@ -27,7 +27,7 @@ public function __construct(bool $grouping = false, int $roundingMode = NumberFo } #[Override] - protected function cast($value): int + protected function cast(float|int|string $value): int { return (int) $value; } diff --git a/src/Leaf/Transformer/LocalizedNumberTransformer.php b/src/Leaf/Transformer/LocalizedNumberTransformer.php index a1a616b..2880e74 100644 --- a/src/Leaf/Transformer/LocalizedNumberTransformer.php +++ b/src/Leaf/Transformer/LocalizedNumberTransformer.php @@ -107,7 +107,7 @@ final public function transformToHttp($value, ElementInterface $input): ?string * @throws InvalidArgumentException If the given value is not scalar or cannot be parsed */ #[Override] - final public function transformFromHttp($value, ElementInterface $input) + final public function transformFromHttp(mixed $value, ElementInterface $input): float|int|string|null { if ($value !== null && !is_int($value) && !is_float($value) && !is_string($value)) { throw new InvalidArgumentException('Expected a scalar or null.'); @@ -163,8 +163,9 @@ private function getNumberFormatter(): NumberFormatter * * @return T */ - protected function cast($value): float|int|string + protected function cast(float|int|string $value): float|int|string { + /** @var T */ return $value; } diff --git a/src/Leaf/View/SelectHtmlRenderer.php b/src/Leaf/View/SelectHtmlRenderer.php index 8e808e7..16657fc 100644 --- a/src/Leaf/View/SelectHtmlRenderer.php +++ b/src/Leaf/View/SelectHtmlRenderer.php @@ -21,7 +21,9 @@ final class SelectHtmlRenderer implements FieldViewRendererInterface #[Override] public function render(FieldViewInterface $view, array $attributes): string { - if (!$choices = $view->choices()) { + $choices = $view->choices(); + + if ($choices === null || $choices === []) { throw new InvalidArgumentException('Choices must be provided for render a select element.'); } diff --git a/src/Leaf/View/SimpleElementView.php b/src/Leaf/View/SimpleElementView.php index d053e57..9cae6c4 100644 --- a/src/Leaf/View/SimpleElementView.php +++ b/src/Leaf/View/SimpleElementView.php @@ -45,7 +45,7 @@ public function __construct(string $type, string $name, mixed $value, ?string $e #[Override] protected function defaultRenderer(): FieldViewRendererInterface { - return $this->choices ? SelectHtmlRenderer::instance() : SimpleFieldHtmlRenderer::instance(); + return $this->choices !== null ? SelectHtmlRenderer::instance() : SimpleFieldHtmlRenderer::instance(); } /** diff --git a/src/Phone/NotEmptyPhoneNumberValidator.php b/src/Phone/NotEmptyPhoneNumberValidator.php index 641e5a5..26e132f 100644 --- a/src/Phone/NotEmptyPhoneNumberValidator.php +++ b/src/Phone/NotEmptyPhoneNumberValidator.php @@ -10,6 +10,8 @@ /** * NotBlank implementation for PhoneNumber value + * + * @psalm-suppress PropertyNotSetInConstructor */ final class NotEmptyPhoneNumberValidator extends NotBlankValidator { @@ -26,7 +28,7 @@ public function __construct(?PhoneNumberUtil $formatter = null) } #[Override] - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if ($value instanceof PhoneNumber) { if ($value->hasRawInput()) { diff --git a/src/Phone/PhoneElement.php b/src/Phone/PhoneElement.php index f1b07a8..1318411 100644 --- a/src/Phone/PhoneElement.php +++ b/src/Phone/PhoneElement.php @@ -26,7 +26,7 @@ final class PhoneElement extends LeafElement { /** - * @var callable(PhoneElement):string + * @var callable(PhoneElement):(string|null) */ private readonly mixed $regionResolver; private readonly PhoneNumberUtil $formatter; diff --git a/src/Phone/Transformer/PhoneNumberToStringTransformer.php b/src/Phone/Transformer/PhoneNumberToStringTransformer.php index bd2442e..80ec473 100644 --- a/src/Phone/Transformer/PhoneNumberToStringTransformer.php +++ b/src/Phone/Transformer/PhoneNumberToStringTransformer.php @@ -64,7 +64,7 @@ public function transformFromHttp(mixed $value, ElementInterface $input): ?strin $formatter = $this->formatter ?? ($input instanceof PhoneElement ? $input->getFormatter() : PhoneNumberUtil::getInstance()); - if ((!$this->formatIfInvalid && !$formatter->isValidNumber($value)) || !$value->getNationalNumber()) { + if ((!$this->formatIfInvalid && !$formatter->isValidNumber($value)) || !$value->hasNationalNumber()) { return $value->getRawInput(); } diff --git a/src/Phone/ValidPhoneNumber.php b/src/Phone/ValidPhoneNumber.php index 041300e..d1207da 100644 --- a/src/Phone/ValidPhoneNumber.php +++ b/src/Phone/ValidPhoneNumber.php @@ -9,9 +9,9 @@ */ class ValidPhoneNumber extends Constraint { - const INVALID_PHONE_NUMBER_ERROR = '5169f03c-ec96-4e62-8651-9ee6766e0b5a'; + public const string INVALID_PHONE_NUMBER_ERROR = '5169f03c-ec96-4e62-8651-9ee6766e0b5a'; - protected const ERROR_NAMES = [self::INVALID_PHONE_NUMBER_ERROR => 'INVALID_PHONE_NUMBER_ERROR']; + protected const array ERROR_NAMES = [self::INVALID_PHONE_NUMBER_ERROR => 'INVALID_PHONE_NUMBER_ERROR']; /** * The error message diff --git a/src/Phone/ValidPhoneNumberValidator.php b/src/Phone/ValidPhoneNumberValidator.php index 9dd8f05..9b6b881 100644 --- a/src/Phone/ValidPhoneNumberValidator.php +++ b/src/Phone/ValidPhoneNumberValidator.php @@ -11,6 +11,8 @@ /** * Validator for @see ValidPhoneNumber + * + * @psalm-suppress PropertyNotSetInConstructor */ final class ValidPhoneNumberValidator extends ConstraintValidator { diff --git a/tests/StaticAnalysis/MyCustomForm.php b/tests/StaticAnalysis/MyCustomForm.php index 72253e9..73f8eea 100644 --- a/tests/StaticAnalysis/MyCustomForm.php +++ b/tests/StaticAnalysis/MyCustomForm.php @@ -35,6 +35,9 @@ public static function check(?MyGeneratedEntity $entity): void } } +/** + * @psalm-suppress MissingConstructor + */ class MyGeneratedEntity { /** From 881ad791ccc9ed29f0f50f1d0e22ffb9b1a9657f Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Wed, 11 Mar 2026 17:37:15 +0100 Subject: [PATCH 09/12] chore: Update to phpunit 13 (#FRAM-221) --- composer.json | 2 +- phpunit.xml.dist | 54 +++++++++---------- tests/Aggregate/ArrayElementBuilderTest.php | 2 +- tests/Aggregate/ArrayElementTest.php | 13 +++-- .../View/ArrayElementViewRendererTest.php | 7 ++- tests/Child/ChildTest.php | 21 +++----- .../Child/Http/ArrayOffsetHttpFieldsTest.php | 17 +++--- tests/Child/Http/PrefixedHttpFieldsTest.php | 11 ++-- tests/Custom/CustomFormTest.php | 2 +- tests/CyclicReferenceTest.php | 5 -- tests/Leaf/AnyElementTest.php | 4 +- tests/Leaf/BooleanElementTest.php | 13 ++--- tests/Leaf/BooleanStringElementTest.php | 50 +++++++++-------- tests/Leaf/Date/DateTimeElementTest.php | 7 ++- tests/Leaf/FloatElementTest.php | 15 +++--- tests/Leaf/IntegerElementTest.php | 17 +++--- tests/Leaf/StringElementTest.php | 17 +++--- .../LocalizedIntegerTransformerTest.php | 25 ++++----- .../LocalizedNumberTransformerTest.php | 31 ++++------- .../Leaf/View/SimpleFieldHtmlRendererTest.php | 13 ++--- tests/Phone/PhoneChildBuilderTest.php | 7 ++- tests/Phone/PhoneElementBuilderTest.php | 7 ++- tests/Phone/PhoneElementTest.php | 7 ++- .../PhoneNumberToStringTransformerTest.php | 7 ++- tests/Util/HttpValueTest.php | 13 ++--- 25 files changed, 152 insertions(+), 215 deletions(-) diff --git a/composer.json b/composer.json index 2360e6e..8e8dcb4 100755 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "require-dev": { "symfony/security-csrf": "~6.4|~7.0", "giggsey/libphonenumber-for-php": "~8.0|~9.0", - "phpunit/phpunit": "~9.0", + "phpunit/phpunit": "~13.0", "vimeo/psalm": "~6.15.1", "symfony/http-foundation": "~6.4|~7.0", "symfony/form": "~6.4|~7.0" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9b87c3e..3f3dd10 100755 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,29 +1,29 @@ - - + - - - - - - - - - - - tests - - - - - src - - + + + + + + + + + + tests + + + + + src + + diff --git a/tests/Aggregate/ArrayElementBuilderTest.php b/tests/Aggregate/ArrayElementBuilderTest.php index 73b3d9b..d18c895 100644 --- a/tests/Aggregate/ArrayElementBuilderTest.php +++ b/tests/Aggregate/ArrayElementBuilderTest.php @@ -167,7 +167,7 @@ public function test_phone_with_configurator() $phones = $element->submit(['0451236585', '0241578932'])->value(); - $this->assertContainsOnly(PhoneNumber::class, $phones); + $this->assertContainsOnlyInstancesOf(PhoneNumber::class, $phones); $this->assertCount(2, $phones); $this->assertEquals('+33451236585', PhoneNumberUtil::getInstance()->format($phones[0], PhoneNumberFormat::E164)); $this->assertEquals('+33241578932', PhoneNumberUtil::getInstance()->format($phones[1], PhoneNumberFormat::E164)); diff --git a/tests/Aggregate/ArrayElementTest.php b/tests/Aggregate/ArrayElementTest.php index 03f6b4c..6c387b2 100644 --- a/tests/Aggregate/ArrayElementTest.php +++ b/tests/Aggregate/ArrayElementTest.php @@ -15,6 +15,7 @@ use Bdf\Form\Validator\ConstraintValueValidator; use Bdf\Form\Validator\TransformerExceptionConstraint; use Exception; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\Count; use Symfony\Component\Validator\Constraints\Length; @@ -341,9 +342,7 @@ public function test_import_null() $this->assertSame([], $element->import(null)->value()); } - /** - * @dataProvider provideInvalidValue - */ + #[DataProvider('provideInvalidValue')] public function test_import_invalid_values($value) { $this->expectException(\TypeError::class); @@ -356,7 +355,7 @@ public function test_import_invalid_values($value) /** * */ - public function provideInvalidValue() + public static function provideInvalidValue() { return [ [''], @@ -501,7 +500,7 @@ public function test_view_simple() $this->assertFalse($view->hasError()); $this->assertEquals(['foo', 'bar', 'baz'], $view->value()); $this->assertCount(3, $view); - $this->assertContainsOnly(SimpleElementView::class, $view); + $this->assertContainsOnlyInstancesOf(SimpleElementView::class, $view); $this->assertEquals('foo', $view[0]->value()); $this->assertEquals('arr[0]', $view[0]->name()); $this->assertEquals('bar', $view[1]->value()); @@ -516,7 +515,7 @@ public function test_view_simple() $this->assertFalse($view->hasError()); $this->assertEquals(['foo' => 'bar', 'baz' => 'rab'], $view->value()); $this->assertCount(2, $view); - $this->assertContainsOnly(SimpleElementView::class, $view); + $this->assertContainsOnlyInstancesOf(SimpleElementView::class, $view); $this->assertEquals('bar', $view['foo']->value()); $this->assertEquals('arr[foo]', $view['foo']->name()); $this->assertEquals('rab', $view['baz']->value()); @@ -540,7 +539,7 @@ public function test_view_with_element_transformer_should_be_applied() $this->assertEquals('arr', $view->name()); $this->assertFalse($view->hasError()); $this->assertEquals(['Zm9v', 'YmFy'], $view->value()); - $this->assertContainsOnly(SimpleElementView::class, $view); + $this->assertContainsOnlyInstancesOf(SimpleElementView::class, $view); $this->assertEquals('Zm9v', $view[0]->value()); $this->assertEquals('arr[0]', $view[0]->name()); $this->assertEquals('YmFy', $view[1]->value()); diff --git a/tests/Aggregate/View/ArrayElementViewRendererTest.php b/tests/Aggregate/View/ArrayElementViewRendererTest.php index 10df0d5..19a3d32 100644 --- a/tests/Aggregate/View/ArrayElementViewRendererTest.php +++ b/tests/Aggregate/View/ArrayElementViewRendererTest.php @@ -4,6 +4,7 @@ use Bdf\Form\Aggregate\ArrayElement; use Bdf\Form\Choice\ChoiceView; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\Length; @@ -45,9 +46,7 @@ public function test_render_with_choice() ); } - /** - * @dataProvider provideConstraints - */ + #[DataProvider('provideConstraints')] public function test_render_csv_constraints($constraints, $attributes) { $view = new ArrayElementView(ArrayElement::class, 'foo', 'aaa,bbb,ccc', null, [], false, $constraints); @@ -56,7 +55,7 @@ public function test_render_csv_constraints($constraints, $attributes) $this->assertEquals('', $renderer->render($view, [])); } - public function provideConstraints() + public static function provideConstraints() { return [ [[], ''], diff --git a/tests/Child/ChildTest.php b/tests/Child/ChildTest.php index 172e049..ae38a2d 100644 --- a/tests/Child/ChildTest.php +++ b/tests/Child/ChildTest.php @@ -16,6 +16,7 @@ use Bdf\Form\PropertyAccess\Setter; use Bdf\Form\Transformer\ClosureTransformer; use Bdf\Form\Validator\ConstraintValueValidator; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotEqualTo; @@ -154,9 +155,7 @@ public function test_fill_with_transformer() $this->assertEquals(base64_encode('my value'), $target->child); } - /** - * @dataProvider emptyValues - */ + #[DataProvider('emptyValues')] public function test_submit_empty($value) { $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], null, new Setter()); @@ -166,9 +165,7 @@ public function test_submit_empty($value) $this->assertEmpty($child->element()->value()); } - /** - * @dataProvider emptyValues - */ + #[DataProvider('emptyValues')] public function test_submit_empty_with_default_value($value) { $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], 'default', new Setter()); @@ -178,9 +175,7 @@ public function test_submit_empty_with_default_value($value) $this->assertEquals('default', $child->element()->value()); } - /** - * @dataProvider emptyValues - */ + #[DataProvider('emptyValues')] public function test_submit_empty_with_default_value_on_array_element($value) { $child = new Child('child', new ArrayElement(new StringElement()), new ArrayOffsetHttpFields('child'), [], ['default'], new Setter()); @@ -190,9 +185,7 @@ public function test_submit_empty_with_default_value_on_array_element($value) $this->assertEquals(['default'], $child->element()->value()); } - /** - * @dataProvider notEmptyValues - */ + #[DataProvider('notEmptyValues')] public function test_submit_not_empty($value) { $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], null, new Setter()); @@ -334,7 +327,7 @@ public function test_view() /** * @return array */ - public function emptyValues() + public static function emptyValues() { return [ [null], @@ -348,7 +341,7 @@ public function emptyValues() /** * @return array */ - public function notEmptyValues() + public static function notEmptyValues() { return [ ['0'], diff --git a/tests/Child/Http/ArrayOffsetHttpFieldsTest.php b/tests/Child/Http/ArrayOffsetHttpFieldsTest.php index a5c53c4..5614880 100644 --- a/tests/Child/Http/ArrayOffsetHttpFieldsTest.php +++ b/tests/Child/Http/ArrayOffsetHttpFieldsTest.php @@ -10,6 +10,7 @@ use Bdf\Form\Leaf\StringElement; use Bdf\Form\PropertyAccess\Setter; use Bdf\Form\Validator\ConstraintValueValidator; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\NotEqualTo; @@ -18,9 +19,7 @@ */ class ArrayOffsetHttpFieldsTest extends TestCase { - /** - * @dataProvider emptyValues - */ + #[DataProvider('emptyValues')] public function test_submit_empty($value) { $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], null, new Setter()); @@ -57,9 +56,7 @@ public function test_contains() $this->assertTrue($field->contains(['child' => 'xxx'])); } - /** - * @dataProvider emptyValues - */ + #[DataProvider('emptyValues')] public function test_submit_empty_with_default_value($value) { $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], 'default', new Setter()); @@ -69,9 +66,7 @@ public function test_submit_empty_with_default_value($value) $this->assertEquals('default', $child->element()->value()); } - /** - * @dataProvider notEmptyValues - */ + #[DataProvider('notEmptyValues')] public function test_submit_not_empty($value) { $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], null, new Setter()); @@ -136,7 +131,7 @@ public function test_get() /** * @return array */ - public function emptyValues() + public static function emptyValues() { return [ [null], @@ -150,7 +145,7 @@ public function emptyValues() /** * @return array */ - public function notEmptyValues() + public static function notEmptyValues() { return [ ['0'], diff --git a/tests/Child/Http/PrefixedHttpFieldsTest.php b/tests/Child/Http/PrefixedHttpFieldsTest.php index 594db8b..ab78e1f 100644 --- a/tests/Child/Http/PrefixedHttpFieldsTest.php +++ b/tests/Child/Http/PrefixedHttpFieldsTest.php @@ -11,6 +11,7 @@ use Bdf\Form\Leaf\StringElement; use Bdf\Form\PropertyAccess\Setter; use Bdf\Form\Validator\ConstraintValueValidator; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\Count; @@ -19,9 +20,7 @@ */ class PrefixedHttpFieldsTest extends TestCase { - /** - * @dataProvider emptyValues - */ + #[DataProvider('emptyValues')] public function test_submit_empty($value) { $child = new Child('child', new ArrayElement(new StringElement()), new PrefixedHttpFields('child_'), [], null, new Setter()); @@ -31,9 +30,7 @@ public function test_submit_empty($value) $this->assertSame([], $child->element()->value()); } - /** - * @dataProvider emptyValues - */ + #[DataProvider('emptyValues')] public function test_submit_empty_with_default_value($value) { $child = new Child('child', new ArrayElement(new StringElement()), new PrefixedHttpFields('child_'), [], ['default'], new Setter()); @@ -130,7 +127,7 @@ public function test_get() /** * @return array */ - public function emptyValues() + public static function emptyValues() { return [ [null], diff --git a/tests/Custom/CustomFormTest.php b/tests/Custom/CustomFormTest.php index e3faf4b..82c3bc0 100644 --- a/tests/Custom/CustomFormTest.php +++ b/tests/Custom/CustomFormTest.php @@ -241,7 +241,7 @@ public function test_functional_array_of_custom_form() $this->assertFalse($array->failed()); $this->assertCount(2, $array); - $this->assertContainsOnly(Person::class, $array->value()); + $this->assertContainsOnlyInstancesOf(Person::class, $array->value()); $this->assertSame('Mickey', $array->value()[0]->firstName); $this->assertSame('Mouse', $array->value()[0]->lastName); $this->assertSame('Minnie', $array->value()[1]->firstName); diff --git a/tests/CyclicReferenceTest.php b/tests/CyclicReferenceTest.php index 04b172e..935d94c 100644 --- a/tests/CyclicReferenceTest.php +++ b/tests/CyclicReferenceTest.php @@ -8,11 +8,6 @@ use PHPUnit\Framework\TestCase; use WeakReference; -/** - * Class CyclicReferenceTest - * - * @requires PHP 7.4 - */ class CyclicReferenceTest extends TestCase { /** diff --git a/tests/Leaf/AnyElementTest.php b/tests/Leaf/AnyElementTest.php index 6ba9ee7..837420d 100644 --- a/tests/Leaf/AnyElementTest.php +++ b/tests/Leaf/AnyElementTest.php @@ -313,7 +313,7 @@ public function test_view_with_choice() $view = $element->view(HttpFieldPath::named('val')); - $this->assertContainsOnly(ChoiceView::class, $view->choices()); + $this->assertContainsOnlyInstancesOf(ChoiceView::class, $view->choices()); $this->assertCount(2, $view->choices()); $this->assertSame('foo', $view->choices()[0]->value()); @@ -342,7 +342,7 @@ public function test_view_with_choice_and_transformer() $view = $element->view(HttpFieldPath::named('val')); - $this->assertContainsOnly(ChoiceView::class, $view->choices()); + $this->assertContainsOnlyInstancesOf(ChoiceView::class, $view->choices()); $this->assertCount(2, $view->choices()); $this->assertSame('Zm9v', $view->choices()[0]->value()); diff --git a/tests/Leaf/BooleanElementTest.php b/tests/Leaf/BooleanElementTest.php index 56394cb..8f3cc4a 100644 --- a/tests/Leaf/BooleanElementTest.php +++ b/tests/Leaf/BooleanElementTest.php @@ -12,6 +12,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ConstraintValueValidator; use Bdf\Form\Validator\TransformerExceptionConstraint; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Validator\Constraints\EqualTo; @@ -150,9 +151,7 @@ public function test_transformer() $this->assertSame('-', $element->httpValue()); } - /** - * @dataProvider provideValidValues - */ + #[DataProvider('provideValidValues')] public function test_import($value, $expected) { $element = new BooleanElement(); @@ -160,7 +159,7 @@ public function test_import($value, $expected) $this->assertSame($expected, $element->import($value)->value()); } - public function provideValidValues() + public static function provideValidValues() { return [ ['hello', true], @@ -174,9 +173,7 @@ public function provideValidValues() ]; } - /** - * @dataProvider provideInvalidValue - */ + #[DataProvider('provideInvalidValue')] public function test_import_invalid_type($value) { $this->expectException(\TypeError::class); @@ -189,7 +186,7 @@ public function test_import_invalid_type($value) /** * */ - public function provideInvalidValue() + public static function provideInvalidValue() { return [ [[]], diff --git a/tests/Leaf/BooleanStringElementTest.php b/tests/Leaf/BooleanStringElementTest.php index 7b3409a..601d8e1 100644 --- a/tests/Leaf/BooleanStringElementTest.php +++ b/tests/Leaf/BooleanStringElementTest.php @@ -12,6 +12,8 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ConstraintValueValidator; use Bdf\Form\Validator\TransformerExceptionConstraint; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestWith; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Validator\Constraints\EqualTo; @@ -33,15 +35,15 @@ public function test_default() $this->assertTrue($element->error()->empty()); } - /** - * @testWith [true] - * [1] - * ["1"] - * ["true"] - * ["on"] - * ["yes"] - * [" True "] - */ + #[ + TestWith([true]), + TestWith([1]), + TestWith(["1"]), + TestWith(["true"]), + TestWith(["on"]), + TestWith(["yes"]), + TestWith([" True "]), + ] public function test_submit_true($value) { $element = new BooleanStringElement(); @@ -51,15 +53,15 @@ public function test_submit_true($value) $this->assertTrue($element->error()->empty()); } - /** - * @testWith [false] - * [0] - * ["0"] - * ["false"] - * ["off"] - * ["no"] - * [" False "] - */ + #[ + TestWith([false]), + TestWith([0]), + TestWith(["0"]), + TestWith(["false"]), + TestWith(["off"]), + TestWith(["no"]), + TestWith([" False "]), + ] public function test_submit_false($value) { $element = new BooleanStringElement(); @@ -196,9 +198,7 @@ public function test_transformer() $this->assertSame('-', $element->httpValue()); } - /** - * @dataProvider provideValidValues - */ + #[DataProvider('provideValidValues')] public function test_import($value, $expected) { $element = new BooleanStringElement(); @@ -206,7 +206,7 @@ public function test_import($value, $expected) $this->assertSame($expected, $element->import($value)->value()); } - public function provideValidValues() + public static function provideValidValues() { return [ ['hello', true], @@ -220,9 +220,7 @@ public function provideValidValues() ]; } - /** - * @dataProvider provideInvalidValue - */ + #[DataProvider('provideInvalidValue')] public function test_import_invalid_type($value) { $this->expectException(\TypeError::class); @@ -235,7 +233,7 @@ public function test_import_invalid_type($value) /** * */ - public function provideInvalidValue() + public static function provideInvalidValue() { return [ [[]], diff --git a/tests/Leaf/Date/DateTimeElementTest.php b/tests/Leaf/Date/DateTimeElementTest.php index 230cc99..a95bef9 100644 --- a/tests/Leaf/Date/DateTimeElementTest.php +++ b/tests/Leaf/Date/DateTimeElementTest.php @@ -18,6 +18,7 @@ use DateTime; use DateTimeImmutable; use DateTimeZone; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Validator\Constraints\LessThan; @@ -346,9 +347,7 @@ public function test_import_invalid_class() $element->import(new DateTime('2000-01-05 15:00:00')); } - /** - * @dataProvider provideInvalidValue - */ + #[DataProvider('provideInvalidValue')] public function test_import_invalid($value) { $this->expectException(\TypeError::class); @@ -361,7 +360,7 @@ public function test_import_invalid($value) /** * */ - public function provideInvalidValue() + public static function provideInvalidValue() { return [ [[]], diff --git a/tests/Leaf/FloatElementTest.php b/tests/Leaf/FloatElementTest.php index 57166cc..2e95d68 100644 --- a/tests/Leaf/FloatElementTest.php +++ b/tests/Leaf/FloatElementTest.php @@ -14,6 +14,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ConstraintValueValidator; use Bdf\Form\Validator\TransformerExceptionConstraint; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; @@ -188,9 +189,7 @@ public function test_transformer() $this->assertEqualsWithDelta(1.2, $element->httpValue(), 0.00001); } - /** - * @dataProvider provideValidValues - */ + #[DataProvider('provideValidValues')] public function test_import($value, $expected) { $element = new FloatElement(); @@ -198,7 +197,7 @@ public function test_import($value, $expected) $this->assertSame($expected, $element->import($value)->value()); } - public function provideValidValues() + public static function provideValidValues() { return [ [15, 15.0], @@ -209,9 +208,7 @@ public function provideValidValues() ]; } - /** - * @dataProvider provideInvalidValue - */ + #[DataProvider('provideInvalidValue')] public function test_import_invalid_type($value) { $this->expectException(\TypeError::class); @@ -224,7 +221,7 @@ public function test_import_invalid_type($value) /** * */ - public function provideInvalidValue() + public static function provideInvalidValue() { return [ [[]], @@ -376,7 +373,7 @@ public function test_view_with_choice() $view = $element->view(HttpFieldPath::named('val')); - $this->assertContainsOnly(ChoiceView::class, $view->choices()); + $this->assertContainsOnlyInstancesOf(ChoiceView::class, $view->choices()); $this->assertCount(3, $view->choices()); $this->assertSame('1.2', $view->choices()[0]->value()); diff --git a/tests/Leaf/IntegerElementTest.php b/tests/Leaf/IntegerElementTest.php index 9509a2d..c5d4cd9 100644 --- a/tests/Leaf/IntegerElementTest.php +++ b/tests/Leaf/IntegerElementTest.php @@ -14,6 +14,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ConstraintValueValidator; use Bdf\Form\Validator\TransformerExceptionConstraint; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; @@ -188,9 +189,7 @@ public function test_transformer() $this->assertEquals(1, $element->httpValue()); } - /** - * @dataProvider provideValidValues - */ + #[DataProvider('provideValidValues')] public function test_import($value, $expected) { $element = new IntegerElement(); @@ -198,7 +197,7 @@ public function test_import($value, $expected) $this->assertSame($expected, $element->import($value)->value()); } - public function provideValidValues() + public static function provideValidValues() { return [ [15, 15], @@ -209,9 +208,7 @@ public function provideValidValues() ]; } - /** - * @dataProvider provideInvalidValue - */ + #[DataProvider('provideInvalidValue')] public function test_import_invalid_type($value) { $this->expectException(\TypeError::class); @@ -224,7 +221,7 @@ public function test_import_invalid_type($value) /** * */ - public function provideInvalidValue() + public static function provideInvalidValue() { return [ [[]], @@ -376,7 +373,7 @@ public function test_view_with_choice() $view = $element->view(HttpFieldPath::named('val')); - $this->assertContainsOnly(ChoiceView::class, $view->choices()); + $this->assertContainsOnlyInstancesOf(ChoiceView::class, $view->choices()); $this->assertCount(3, $view->choices()); $this->assertSame('12', $view->choices()[0]->value()); @@ -409,7 +406,7 @@ public function test_view_with_choice_and_transformer() $view = $element->view(HttpFieldPath::named('val')); - $this->assertContainsOnly(ChoiceView::class, $view->choices()); + $this->assertContainsOnlyInstancesOf(ChoiceView::class, $view->choices()); $this->assertCount(3, $view->choices()); $this->assertSame('c', $view->choices()[0]->value()); diff --git a/tests/Leaf/StringElementTest.php b/tests/Leaf/StringElementTest.php index 051e767..f13fcca 100644 --- a/tests/Leaf/StringElementTest.php +++ b/tests/Leaf/StringElementTest.php @@ -13,6 +13,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ConstraintValueValidator; use Bdf\Form\Validator\TransformerExceptionConstraint; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Validator\Constraints\Length; @@ -185,9 +186,7 @@ public function test_transformer() $this->assertEquals('hello', $element->httpValue()); } - /** - * @dataProvider provideValidValues - */ + #[DataProvider('provideValidValues')] public function test_import($value, $expected) { $element = new StringElement(); @@ -195,7 +194,7 @@ public function test_import($value, $expected) $this->assertSame($expected, $element->import($value)->value()); } - public function provideValidValues() + public static function provideValidValues() { return [ ['hello', 'hello'], @@ -208,9 +207,7 @@ public function provideValidValues() ]; } - /** - * @dataProvider provideInvalidValue - */ + #[DataProvider('provideInvalidValue')] public function test_import_invalid_type($value) { $this->expectException(\TypeError::class); @@ -223,7 +220,7 @@ public function test_import_invalid_type($value) /** * */ - public function provideInvalidValue() + public static function provideInvalidValue() { return [ [[]], @@ -370,7 +367,7 @@ public function test_view_with_choice() $view = $element->view(HttpFieldPath::named('val')); - $this->assertContainsOnly(ChoiceView::class, $view->choices()); + $this->assertContainsOnlyInstancesOf(ChoiceView::class, $view->choices()); $this->assertCount(2, $view->choices()); $this->assertSame('foo', $view->choices()[0]->value()); @@ -399,7 +396,7 @@ public function test_view_with_choice_and_transformer() $view = $element->view(HttpFieldPath::named('val')); - $this->assertContainsOnly(ChoiceView::class, $view->choices()); + $this->assertContainsOnlyInstancesOf(ChoiceView::class, $view->choices()); $this->assertCount(2, $view->choices()); $this->assertSame('Zm9v', $view->choices()[0]->value()); diff --git a/tests/Leaf/Transformer/LocalizedIntegerTransformerTest.php b/tests/Leaf/Transformer/LocalizedIntegerTransformerTest.php index 71018b5..c7140bc 100644 --- a/tests/Leaf/Transformer/LocalizedIntegerTransformerTest.php +++ b/tests/Leaf/Transformer/LocalizedIntegerTransformerTest.php @@ -4,13 +4,12 @@ use Bdf\Form\ElementInterface; use Locale; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class LocalizedIntegerTransformerTest extends TestCase { - /** - * @dataProvider provideFromHttpRoundingMode - */ + #[DataProvider('provideFromHttpRoundingMode')] public function test_fromHttp_scale_and_roundingMode($mode, $httpValue, $phpValue) { $transformer = new LocalizedIntegerTransformer(false, $mode); @@ -21,7 +20,7 @@ public function test_fromHttp_scale_and_roundingMode($mode, $httpValue, $phpValu /** * */ - public function provideFromHttpRoundingMode() + public static function provideFromHttpRoundingMode() { return [ [\NumberFormatter::ROUND_CEILING, '12.3456789', 13], @@ -34,9 +33,7 @@ public function provideFromHttpRoundingMode() ]; } - /** - * @dataProvider provideToHttpRoundingMode - */ + #[DataProvider('provideToHttpRoundingMode')] public function test_toHttp_roundingMode($mode, $phpValue, $httpValue) { $transformer = new LocalizedIntegerTransformer(false, $mode); @@ -47,7 +44,7 @@ public function test_toHttp_roundingMode($mode, $phpValue, $httpValue) /** * */ - public function provideToHttpRoundingMode() + public static function provideToHttpRoundingMode() { return [ [\NumberFormatter::ROUND_CEILING, 12.3456789, '13'], @@ -128,9 +125,7 @@ public function test_empty() $this->assertNull($transformer->transformToHttp(null, $element)); } - /** - * @dataProvider invalidValue - */ + #[DataProvider('invalidValue')] public function test_transformFromHttp_invalid_number($value, $error) { $this->expectException(\InvalidArgumentException::class); @@ -142,7 +137,7 @@ public function test_transformFromHttp_invalid_number($value, $error) $transformer->transformFromHttp($value, $element); } - public function invalidValue() + public static function invalidValue() { return [ ['foo', 'Number parsing failed: U_PARSE_ERROR'], @@ -153,9 +148,7 @@ public function invalidValue() ]; } - /** - * @dataProvider invalidPhpValue - */ + #[DataProvider('invalidPhpValue')] public function test_transformToHttp_not_a_number($value) { $this->expectException(\InvalidArgumentException::class); @@ -167,7 +160,7 @@ public function test_transformToHttp_not_a_number($value) $transformer->transformToHttp($value, $element); } - public function invalidPhpValue() + public static function invalidPhpValue() { return [ ['foo'], diff --git a/tests/Leaf/Transformer/LocalizedNumberTransformerTest.php b/tests/Leaf/Transformer/LocalizedNumberTransformerTest.php index 085d79e..652406f 100644 --- a/tests/Leaf/Transformer/LocalizedNumberTransformerTest.php +++ b/tests/Leaf/Transformer/LocalizedNumberTransformerTest.php @@ -4,13 +4,12 @@ use Bdf\Form\ElementInterface; use Locale; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class LocalizedNumberTransformerTest extends TestCase { - /** - * @dataProvider provideFromHttpScaleAndRoundingMode - */ + #[DataProvider('provideFromHttpScaleAndRoundingMode')] public function test_fromHttp_scale_and_roundingMode($scale, $mode, $httpValue, $phpValue) { $transformer = new LocalizedNumberTransformer($scale, false, $mode); @@ -21,7 +20,7 @@ public function test_fromHttp_scale_and_roundingMode($scale, $mode, $httpValue, /** * */ - public function provideFromHttpScaleAndRoundingMode() + public static function provideFromHttpScaleAndRoundingMode() { return [ [null, \NumberFormatter::ROUND_CEILING, '12.3456789', 12.3456789], @@ -51,9 +50,7 @@ public function provideFromHttpScaleAndRoundingMode() [1, \NumberFormatter::ROUND_HALFEVEN, '-3.65', -3.6], ]; } - /** - * @dataProvider provideToHttpScaleAndRoundingMode - */ + #[DataProvider('provideToHttpScaleAndRoundingMode')] public function test_toHttp_scale_and_roundingMode($scale, $mode, $phpValue, $httpValue) { $transformer = new LocalizedNumberTransformer($scale, false, $mode); @@ -64,7 +61,7 @@ public function test_toHttp_scale_and_roundingMode($scale, $mode, $phpValue, $ht /** * */ - public function provideToHttpScaleAndRoundingMode() + public static function provideToHttpScaleAndRoundingMode() { return [ [null, \NumberFormatter::ROUND_CEILING, 12.3456789, '12.346'], @@ -163,9 +160,7 @@ public function test_empty() $this->assertNull($transformer->transformToHttp(null, $element)); } - /** - * @dataProvider invalidValue - */ + #[DataProvider('invalidValue')] public function test_transformFromHttp_invalid_number($value, $error) { $this->expectException(\InvalidArgumentException::class); @@ -177,7 +172,7 @@ public function test_transformFromHttp_invalid_number($value, $error) $transformer->transformFromHttp($value, $element); } - public function invalidValue() + public static function invalidValue() { return [ ['foo', 'Number parsing failed: U_PARSE_ERROR'], @@ -188,9 +183,7 @@ public function invalidValue() ]; } - /** - * @dataProvider invalidPhpValue - */ + #[DataProvider('invalidPhpValue')] public function test_transformToHttp_not_a_number($value) { $this->expectException(\InvalidArgumentException::class); @@ -202,7 +195,7 @@ public function test_transformToHttp_not_a_number($value) $transformer->transformToHttp($value, $element); } - public function invalidPhpValue() + public static function invalidPhpValue() { return [ ['foo'], @@ -212,9 +205,7 @@ public function invalidPhpValue() ]; } - /** - * @dataProvider validPhpValue - */ + #[DataProvider('validPhpValue')] public function test_transformToHttp_valid($httpValue, $expected) { $transformer = new LocalizedNumberTransformer(); @@ -223,7 +214,7 @@ public function test_transformToHttp_valid($httpValue, $expected) $this->assertSame($expected, $transformer->transformToHttp($httpValue, $element)); } - public function validPhpValue() + public static function validPhpValue() { return [ [1.23, '1.23'], diff --git a/tests/Leaf/View/SimpleFieldHtmlRendererTest.php b/tests/Leaf/View/SimpleFieldHtmlRendererTest.php index 9fc8cdf..b150f07 100644 --- a/tests/Leaf/View/SimpleFieldHtmlRendererTest.php +++ b/tests/Leaf/View/SimpleFieldHtmlRendererTest.php @@ -8,6 +8,7 @@ use Bdf\Form\Leaf\StringElement; use Bdf\Form\Phone\PhoneElement; use Bdf\Form\Constraint\Closure; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\Length; @@ -42,9 +43,7 @@ public function test_render_allow_override_required() $this->assertEquals('', $renderer->render($view, ['type' => 'email', 'required' => false])); } - /** - * @dataProvider provideType - */ + #[DataProvider('provideType')] public function test_render_type($elementType, $htmlType) { $view = new SimpleElementView($elementType, 'foo', 'bar', null, false, []); @@ -53,7 +52,7 @@ public function test_render_type($elementType, $htmlType) $this->assertEquals('', $renderer->render($view, [])); } - public function provideType() + public static function provideType() { return [ [StringElement::class, 'text'], @@ -64,9 +63,7 @@ public function provideType() ]; } - /** - * @dataProvider provideConstraints - */ + #[DataProvider('provideConstraints')] public function test_render_constraints($constraints, $attributes) { $view = new SimpleElementView(StringElement::class, 'foo', 'bar', null, false, $constraints); @@ -75,7 +72,7 @@ public function test_render_constraints($constraints, $attributes) $this->assertEquals('', $renderer->render($view, [])); } - public function provideConstraints() + public static function provideConstraints() { return [ [[], ''], diff --git a/tests/Phone/PhoneChildBuilderTest.php b/tests/Phone/PhoneChildBuilderTest.php index 729656e..708c120 100644 --- a/tests/Phone/PhoneChildBuilderTest.php +++ b/tests/Phone/PhoneChildBuilderTest.php @@ -6,13 +6,12 @@ use Bdf\Form\Aggregate\Form; use libphonenumber\PhoneNumber; use libphonenumber\PhoneNumberFormat; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class PhoneChildBuilderTest extends TestCase { - /** - * @dataProvider provideFormats - */ + #[DataProvider('provideFormats')] public function test_saveAsString($format, $formatted) { $builder = new PhoneChildBuilder('child', new PhoneElementBuilder()); @@ -82,7 +81,7 @@ public function test_formatIfInvalid() $this->assertSame(['child' => '+3314554'], $target); } - public function provideFormats() + public static function provideFormats() { return [ [PhoneNumberFormat::E164, '+33142563698'], diff --git a/tests/Phone/PhoneElementBuilderTest.php b/tests/Phone/PhoneElementBuilderTest.php index 8a49267..cdb9c8f 100644 --- a/tests/Phone/PhoneElementBuilderTest.php +++ b/tests/Phone/PhoneElementBuilderTest.php @@ -6,6 +6,7 @@ use Bdf\Form\Child\Child; use libphonenumber\PhoneNumber; use libphonenumber\PhoneNumberUtil; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\NotBlank; @@ -165,9 +166,7 @@ public function test_value() $this->assertSame($phone, $element->value()); } - /** - * @dataProvider emptyValues - */ + #[DataProvider('emptyValues')] public function test_required($value) { $element = $this->builder->required()->allowInvalidNumber()->buildElement(); @@ -179,7 +178,7 @@ public function test_required($value) /** * @return array */ - public function emptyValues() + public static function emptyValues() { return [ [null], diff --git a/tests/Phone/PhoneElementTest.php b/tests/Phone/PhoneElementTest.php index 15a66b6..e2a642a 100644 --- a/tests/Phone/PhoneElementTest.php +++ b/tests/Phone/PhoneElementTest.php @@ -12,6 +12,7 @@ use Bdf\Form\Transformer\TransformerInterface; use Bdf\Form\Validator\ConstraintValueValidator; use libphonenumber\PhoneNumber; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Validator\Constraints\NotBlank; @@ -185,9 +186,7 @@ public function test_import_null() $this->assertNull($element->import(null)->value()); } - /** - * @dataProvider provideInvalidValue - */ + #[DataProvider('provideInvalidValue')] public function test_import_invalid_values($value) { $this->expectException(\TypeError::class); @@ -200,7 +199,7 @@ public function test_import_invalid_values($value) /** * */ - public function provideInvalidValue() + public static function provideInvalidValue() { return [ [[]], diff --git a/tests/Phone/Transformer/PhoneNumberToStringTransformerTest.php b/tests/Phone/Transformer/PhoneNumberToStringTransformerTest.php index 350f328..4e54df3 100644 --- a/tests/Phone/Transformer/PhoneNumberToStringTransformerTest.php +++ b/tests/Phone/Transformer/PhoneNumberToStringTransformerTest.php @@ -6,6 +6,7 @@ use libphonenumber\PhoneNumber; use libphonenumber\PhoneNumberFormat; use libphonenumber\PhoneNumberUtil; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class PhoneNumberToStringTransformerTest extends TestCase @@ -82,9 +83,7 @@ public function test_with_invalid_force_format_the_value() $this->assertInstanceOf(PhoneNumber::class, $form['foo']->element()->value()); } - /** - * @dataProvider provideEmptyValue - */ + #[DataProvider('provideEmptyValue')] public function test_with_empty_value_should_return_null($empty) { $builder = new FormBuilder(); @@ -99,7 +98,7 @@ public function test_with_empty_value_should_return_null($empty) /** * */ - public function provideEmptyValue() + public static function provideEmptyValue() { return [ [null], diff --git a/tests/Util/HttpValueTest.php b/tests/Util/HttpValueTest.php index 1bb7836..527849d 100644 --- a/tests/Util/HttpValueTest.php +++ b/tests/Util/HttpValueTest.php @@ -2,6 +2,7 @@ namespace Bdf\Form\Util; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class HttpValueTest extends TestCase @@ -23,18 +24,14 @@ public function test_isEmpty() $this->assertFalse(HttpValue::isEmpty(false)); } - /** - * @dataProvider emptyValues - */ + #[DataProvider('emptyValues')] public function test_orDefault_with_empty_value($value) { $this->assertSame($value, HttpValue::orDefault($value, null)); $this->assertSame('foo', HttpValue::orDefault($value, 'foo')); } - /** - * @dataProvider notEmptyValues - */ + #[DataProvider('notEmptyValues')] public function test_orDefault_with_not_empty_value($value) { $this->assertSame($value, HttpValue::orDefault($value, null)); @@ -44,7 +41,7 @@ public function test_orDefault_with_not_empty_value($value) /** * @return array */ - public function emptyValues() + public static function emptyValues() { return [ [null], @@ -56,7 +53,7 @@ public function emptyValues() /** * @return array */ - public function notEmptyValues() + public static function notEmptyValues() { return [ ['0'], From d25314b1129eb5eb11d0c87e70a681817193cacf Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Wed, 11 Mar 2026 17:45:33 +0100 Subject: [PATCH 10/12] chore: compatibility with SF 8 (#FRAM-221) --- .github/workflows/php.yml | 33 +++++++++++++++++++++ composer.json | 10 +++---- tests/Aggregate/ArrayElementBuilderTest.php | 2 +- tests/Aggregate/ArrayElementTest.php | 6 ++-- tests/Aggregate/FormBuilderTest.php | 2 +- tests/Child/ChildTest.php | 14 ++++----- tests/Child/Http/PrefixedHttpFieldsTest.php | 2 +- tests/Error/FormErrorTest.php | 2 +- tests/Leaf/AnyElementTest.php | 6 ++-- tests/Leaf/StringElementTest.php | 2 +- tests/Phone/NotEmptyPhoneNumberTest.php | 13 +------- tests/View/ConstraintsNormalizerTest.php | 2 +- 12 files changed, 58 insertions(+), 36 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index c7544ec..92dd39e 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -43,6 +43,39 @@ jobs: - name: Run test suite run: composer run-script tests + sf-compatibility: + runs-on: ubuntu-latest + strategy: + matrix: + sf-versions: ['6.4', '7.4', '8.0'] + name: Symfony ${{ matrix.sf-versions }} + + steps: + - uses: actions/checkout@v2 + + - name: Set Timezone + uses: szenius/set-timezone@v1.0 + with: + timezoneLinux: "Europe/Paris" + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.4 + extensions: json, intl + ini-values: date.timezone=Europe/Paris + - name: Check PHP Version + run: php -v + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: Set Symfony version + run: composer require --dev "symfony/symfony:~${{ matrix.sf-versions }}.0" + + - name: Run test suite + run: composer run-script tests + analysis: name: Analysis runs-on: ubuntu-latest diff --git a/composer.json b/composer.json index 8e8dcb4..2bcae80 100755 --- a/composer.json +++ b/composer.json @@ -20,16 +20,16 @@ }, "require": { "php": "~8.4", - "symfony/property-access": "~6.4|~7.0", - "symfony/validator": "~6.4|~7.0" + "symfony/property-access": "~6.4|~7.0|~8.0", + "symfony/validator": "~6.4|~7.0|~8.0" }, "require-dev": { - "symfony/security-csrf": "~6.4|~7.0", + "symfony/security-csrf": "~6.4|~7.0|~8.0", "giggsey/libphonenumber-for-php": "~8.0|~9.0", "phpunit/phpunit": "~13.0", "vimeo/psalm": "~6.15.1", - "symfony/http-foundation": "~6.4|~7.0", - "symfony/form": "~6.4|~7.0" + "symfony/http-foundation": "~6.4|~7.0|~8.0", + "symfony/form": "~6.4|~7.0|~8.0" }, "suggest": { "symfony/security-csrf": "For enable CSRF element", diff --git a/tests/Aggregate/ArrayElementBuilderTest.php b/tests/Aggregate/ArrayElementBuilderTest.php index d18c895..2593d89 100644 --- a/tests/Aggregate/ArrayElementBuilderTest.php +++ b/tests/Aggregate/ArrayElementBuilderTest.php @@ -315,7 +315,7 @@ public function test_required_with_custom_message() */ public function test_required_with_custom_constraint() { - $element = $this->builder->required(new Count(['min' => 2]))->buildElement(); + $element = $this->builder->required(new Count(min: 2))->buildElement(); $element->submit([]); $this->assertEquals('This collection should contain 2 elements or more.', $element->error()->global()); diff --git a/tests/Aggregate/ArrayElementTest.php b/tests/Aggregate/ArrayElementTest.php index 6c387b2..d511636 100644 --- a/tests/Aggregate/ArrayElementTest.php +++ b/tests/Aggregate/ArrayElementTest.php @@ -183,7 +183,7 @@ public function test_submit_with_transformer_error_ignored_should_apply_other_co */ public function test_submit_with_array_error() { - $element = new ArrayElement(new StringElement(), null, new ConstraintValueValidator([new Count(['min' => 3])])); + $element = new ArrayElement(new StringElement(), null, new ConstraintValueValidator([new Count(min: 3)])); $this->assertFalse($element->submit(['foo', 'bar'])->valid()); $this->assertEquals('This collection should contain 3 elements or more.', $element->error()->global()); @@ -226,7 +226,7 @@ public function test_import_and_patch_null_will_keep_global_error() */ public function test_import_and_patch_null_will_keep_element_error() { - $element = (new ArrayElementBuilder())->satisfy(new Length(['min' => 3]))->buildElement(); + $element = (new ArrayElementBuilder())->satisfy(new Length(min: 3))->buildElement(); $element->submit(['a', 'bar']); @@ -292,7 +292,7 @@ public function test_patch_with_transformer_error() */ public function test_patch_with_array_error() { - $element = new ArrayElement(new StringElement(), null, new ConstraintValueValidator([new Count(['min' => 3])])); + $element = new ArrayElement(new StringElement(), null, new ConstraintValueValidator([new Count(min: 3)])); $this->assertFalse($element->patch(['foo', 'bar'])->valid()); $this->assertEquals('This collection should contain 3 elements or more.', $element->error()->global()); diff --git a/tests/Aggregate/FormBuilderTest.php b/tests/Aggregate/FormBuilderTest.php index fdd9599..51464bc 100644 --- a/tests/Aggregate/FormBuilderTest.php +++ b/tests/Aggregate/FormBuilderTest.php @@ -309,7 +309,7 @@ public function test_required_with_custom_message() */ public function test_required_with_custom_constraint() { - $element = $this->builder->required(new Count(['min' => 2]))->buildElement(); + $element = $this->builder->required(new Count(min: 2))->buildElement(); $element->submit([]); $this->assertEquals('This collection should contain 2 elements or more.', $element->error()->global()); diff --git a/tests/Child/ChildTest.php b/tests/Child/ChildTest.php index ae38a2d..4f4184b 100644 --- a/tests/Child/ChildTest.php +++ b/tests/Child/ChildTest.php @@ -63,7 +63,7 @@ public function test_parent() */ public function test_import_with_array() { - $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(['message' => 'required error']), null, new Getter()); + $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(message: 'required error'), null, new Getter()); $child->setParent($form = new Form(new ChildrenCollection())); $child->import(['child' => 'my value']); @@ -75,7 +75,7 @@ public function test_import_with_array() */ public function test_import_with_object() { - $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(['message' => 'required error']), null, new Getter()); + $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(message: 'required error'), null, new Getter()); $child->setParent($form = new Form(new ChildrenCollection())); $child->import((object) ['child' => 'my value']); @@ -87,7 +87,7 @@ public function test_import_with_object() */ public function test_import_null() { - $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(['message' => 'required error']), null, new Getter()); + $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(message: 'required error'), null, new Getter()); $child->setParent($form = new Form(new ChildrenCollection())); $child->import(null); @@ -99,7 +99,7 @@ public function test_import_null() */ public function test_import_with_transformer() { - $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(['message' => 'required error']), null, new Getter(), [], new ClosureTransformer(function($value) { + $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(message: 'required error'), null, new Getter(), [], new ClosureTransformer(function($value) { return base64_encode($value); })); $child->setParent($form = new Form(new ChildrenCollection())); @@ -113,7 +113,7 @@ public function test_import_with_transformer() */ public function test_fill_with_array() { - $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(['message' => 'required error']), new Setter()); + $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(message: 'required error'), new Setter()); $child->setParent($form = new Form(new ChildrenCollection())); $child->element()->import('my value'); @@ -128,7 +128,7 @@ public function test_fill_with_array() */ public function test_fill_with_object() { - $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(['message' => 'required error']), new Setter()); + $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(message: 'required error'), new Setter()); $child->setParent($form = new Form(new ChildrenCollection())); $child->element()->import('my value'); @@ -143,7 +143,7 @@ public function test_fill_with_object() */ public function test_fill_with_transformer() { - $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(['message' => 'required error']), new Setter(), null, [], new ClosureTransformer(function($value) { + $child = new Child('child', new StringElement(), new ArrayOffsetHttpFields('child'), [], new NotBlank(message: 'required error'), new Setter(), null, [], new ClosureTransformer(function($value) { return base64_encode($value); })); $child->setParent($form = new Form(new ChildrenCollection())); diff --git a/tests/Child/Http/PrefixedHttpFieldsTest.php b/tests/Child/Http/PrefixedHttpFieldsTest.php index ab78e1f..b63d89f 100644 --- a/tests/Child/Http/PrefixedHttpFieldsTest.php +++ b/tests/Child/Http/PrefixedHttpFieldsTest.php @@ -77,7 +77,7 @@ public function test_submit_not_empty_with_default() */ public function test_submit_element_constraint_error() { - $child = new Child('child', new ArrayElement(new StringElement(), null, new ConstraintValueValidator([new Count(['min' => 2])])), new PrefixedHttpFields('child_'), [], null, new Setter()); + $child = new Child('child', new ArrayElement(new StringElement(), null, new ConstraintValueValidator([new Count(min: 2)])), new PrefixedHttpFields('child_'), [], null, new Setter()); $child->setParent($form = new Form(new ChildrenCollection())); $this->assertFalse($child->submit(['child_0' => 'value'])); diff --git a/tests/Error/FormErrorTest.php b/tests/Error/FormErrorTest.php index 9200fd8..8850691 100644 --- a/tests/Error/FormErrorTest.php +++ b/tests/Error/FormErrorTest.php @@ -63,7 +63,7 @@ public function test_message_with_code() public function test_violation() { $validator = (new ValidatorBuilder)->getValidator(); - $violation = $validator->validate('foo', new Length(['min' => 5]))->get(0); + $violation = $validator->validate('foo', new Length(min: 5))->get(0); $error = FormError::violation($violation); $this->assertInstanceOf(FormError::class, $error); diff --git a/tests/Leaf/AnyElementTest.php b/tests/Leaf/AnyElementTest.php index 837420d..472c24c 100644 --- a/tests/Leaf/AnyElementTest.php +++ b/tests/Leaf/AnyElementTest.php @@ -68,7 +68,7 @@ public function test_submit_null() */ public function test_submit_with_constraint() { - $element = new AnyElement(new ConstraintValueValidator([new Length(['max' => 2])])); + $element = new AnyElement(new ConstraintValueValidator([new Length(max: 2)])); $this->assertFalse($element->submit('hello')->valid()); $this->assertSame('hello', $element->value()); @@ -149,7 +149,7 @@ public function test_patch_null() */ public function test_patch_null_with_constraints_should_be_validated() { - $element = (new AnyElementBuilder())->satisfy(new Length(['min' => 5]))->buildElement(); + $element = (new AnyElementBuilder())->satisfy(new Length(min: 5))->buildElement(); $element->import('foo'); $this->assertSame($element, $element->patch(null)); @@ -164,7 +164,7 @@ public function test_patch_null_with_constraints_should_be_validated() */ public function test_patch_with_value() { - $element = (new AnyElementBuilder())->satisfy(new Length(['min' => 3]))->buildElement(); + $element = (new AnyElementBuilder())->satisfy(new Length(min: 3))->buildElement(); $this->assertFalse($element->patch('f')->valid()); $this->assertSame('f', $element->value()); diff --git a/tests/Leaf/StringElementTest.php b/tests/Leaf/StringElementTest.php index f13fcca..20569bc 100644 --- a/tests/Leaf/StringElementTest.php +++ b/tests/Leaf/StringElementTest.php @@ -67,7 +67,7 @@ public function test_submit_null() */ public function test_submit_with_constraint() { - $element = new StringElement(new ConstraintValueValidator([new Length(['max' => 2])])); + $element = new StringElement(new ConstraintValueValidator([new Length(max: 2)])); $this->assertFalse($element->submit('hello')->valid()); $this->assertTrue($element->failed()); diff --git a/tests/Phone/NotEmptyPhoneNumberTest.php b/tests/Phone/NotEmptyPhoneNumberTest.php index 699afd9..bc3f1b0 100644 --- a/tests/Phone/NotEmptyPhoneNumberTest.php +++ b/tests/Phone/NotEmptyPhoneNumberTest.php @@ -35,23 +35,12 @@ public function test_not_empty() $this->assertEquals(FormError::null(), $validator->validate((new PhoneNumber())->setNationalNumber('123456'), $input)); } - /** - * - */ - public function test_custom_message_legacy() - { - $validator = new ConstraintValueValidator([new NotEmptyPhoneNumber(['message' => 'my error'])]); - $input = new PhoneElement(); - - $this->assertEquals(FormError::message('my error', 'IS_BLANK_ERROR'), $validator->validate(null, $input)); - } - /** * */ public function test_custom_message() { - $validator = new ConstraintValueValidator([new NotEmptyPhoneNumber(null, /*message:*/ 'my error')]); + $validator = new ConstraintValueValidator([new NotEmptyPhoneNumber(message: 'my error')]); $input = new PhoneElement(); $this->assertEquals(FormError::message('my error', 'IS_BLANK_ERROR'), $validator->validate(null, $input)); diff --git a/tests/View/ConstraintsNormalizerTest.php b/tests/View/ConstraintsNormalizerTest.php index eea7a97..af8abb4 100644 --- a/tests/View/ConstraintsNormalizerTest.php +++ b/tests/View/ConstraintsNormalizerTest.php @@ -27,6 +27,6 @@ public function test_normalize() Length::class => ['min' => 3, 'max' => 5], LessThanOrEqual::class => ['value' => 42], NotEqualTo::class => ['value' => 666], - ], ConstraintsNormalizer::normalize(new ConstraintValueValidator([new NotBlank(), new Length(['min' => 3, 'max' => 5]), new LessThanOrEqual(42), new NotEqualTo(666)]))); + ], ConstraintsNormalizer::normalize(new ConstraintValueValidator([new NotBlank(), new Length(min: 3, max: 5), new LessThanOrEqual(42), new NotEqualTo(666)]))); } } From 377ae076a62e8a980569411b6b8a21b160d01184 Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Wed, 11 Mar 2026 17:47:47 +0100 Subject: [PATCH 11/12] ci: remove psalm on SF compatibility job --- .github/workflows/php.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 92dd39e..46d82c5 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -70,6 +70,10 @@ jobs: - name: Install dependencies run: composer install --prefer-dist --no-progress + # psalm 6 is not compatible with Symfony 6.4, so remove it + - name: Remove psalm + run: composer remove --dev vimeo/psalm + - name: Set Symfony version run: composer require --dev "symfony/symfony:~${{ matrix.sf-versions }}.0" From f719d681383761fde949039468ecc05f0572966b Mon Sep 17 00:00:00 2001 From: Vincent QUATREVIEUX Date: Wed, 11 Mar 2026 17:54:34 +0100 Subject: [PATCH 12/12] chore: compatibility with SF 6.4 --- src/Leaf/Helper/UrlElementBuilder.php | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Leaf/Helper/UrlElementBuilder.php b/src/Leaf/Helper/UrlElementBuilder.php index ee893e4..52ddbce 100644 --- a/src/Leaf/Helper/UrlElementBuilder.php +++ b/src/Leaf/Helper/UrlElementBuilder.php @@ -10,6 +10,7 @@ use Symfony\Component\Validator\Constraints\Url; use function is_string; +use function property_exists; /** * Provide URL constraint builder for a StringElementBuilder @@ -167,14 +168,22 @@ protected function createUrlConstraint(RegistryInterface $registry): array } return [ - new Url( - message: $this->errorMessage, - protocols: $this->protocols, - relativeProtocol: $this->relativeProtocol, - normalizer: $this->normalizer, - requireTld: $this->requireTld, - tldMessage: $this->tldMessage - ), + property_exists(Url::class, 'requireTld') // SF >= 7.1 + ? new Url( + message: $this->errorMessage, + protocols: $this->protocols, + relativeProtocol: $this->relativeProtocol, + normalizer: $this->normalizer, + requireTld: $this->requireTld, + tldMessage: $this->tldMessage + ) + : new Url( + message: $this->errorMessage, + protocols: $this->protocols, + relativeProtocol: $this->relativeProtocol, + normalizer: $this->normalizer, + ) + , ]; }