Skip to content

Validate native array input values#12

Merged
koriym merged 2 commits into1.xfrom
codex/native-array-input-validation
May 2, 2026
Merged

Validate native array input values#12
koriym merged 2 commits into1.xfrom
codex/native-array-input-validation

Conversation

@koriym
Copy link
Copy Markdown
Member

@koriym koriym commented May 2, 2026

Summary

  • validate #[Input] array values before invoking methods or DTO constructors
  • reject scalar container values for plain array inputs and #[Input(item: ...)] array inputs
  • handle array|null input parameters consistently with the same container validation

Why

Native array input DTO fields should be safe to use for request fields such as tagIds. Before this change, scalar values could reach the PHP call boundary and fail as TypeError, or item-array inputs could silently become an empty array.

Validation

  • php vendor/bin/phpunit
  • composer cs
  • vendor/bin/phpstan analyse -c phpstan.neon
  • /opt/homebrew/opt/php@8.4/bin/php vendor/bin/psalm --show-info=false

Note: composer sa under PHP 8.5 currently crashes inside Psalm due PHP 8.5 SplObjectStorage deprecations. Psalm passes with PHP 8.4.

Follow-up

Summary by CodeRabbit

  • New Features

    • Added support for nullable array parameters in input resolution, enabling more flexible parameter handling and type support.
  • Bug Fixes

    • Improved validation and error handling for array inputs with enhanced error messages that provide detailed context about type validation failures.
  • Tests

    • Expanded test coverage for array input validation scenarios, including edge cases for scalar value rejection and comprehensive type mismatch detection.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

Warning

Rate limit exceeded

@koriym has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 37 minutes and 56 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: acddd9fe-6d62-48e7-a891-0ac9b9df870e

📥 Commits

Reviewing files that changed from the base of the PR and between a7ba47c and eee5800.

⛔ Files ignored due to path filters (1)
  • vendor-bin/tools/composer.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .github/workflows/static-analysis.yml
  • composer.json
  • src/Exception/InvalidInputTypeException.php
  • src/InputQuery.php
  • tests/ArrayInputTest.php
📝 Walkthrough

Walkthrough

A new InvalidInputTypeException class and refactored union-type handling enable proper type validation for array|null parameters. Array parameter resolution is extracted into dedicated methods, and all invalid-type errors now throw the structured exception instead of generic InvalidArgumentException.

Changes

Array Input Type Validation & Nullable Union Support

Layer / File(s) Summary
Exception Foundation
src/Exception/InvalidInputTypeException.php
New exception class with properties for paramName, expectedType, actualType, and optional itemKey. Factory methods forParameter() and forItem() simplify construction using get_debug_type().
Union Type & Array Resolution
src/InputQuery.php (lines 19, 194–198, 215–265, 495–513, 527–614)
resolveInputParameter() passes InputAttributes to resolveUnionType(). New getArrayParameterValue() extracts array handling with type-checking. New isNullableArrayUnion() and getNullableArrayParameterValue() add nullable array|null support. createArrayOfInputs() throws InvalidInputTypeException for invalid array and item types instead of InvalidArgumentException.
Test Coverage
tests/ArrayInputTest.php (lines 5–11, 122–217, 268–305, 375–392)
Import updated to use InvalidInputTypeException. Four new test methods validate plain arrays, scalar rejection for both nullable and non-nullable array parameters, and constructor input rejection. Existing tests refactored with new assertInvalidInputTypeContext() helper that validates exception context fields.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Arrays now safely typed, with null and clear exceptions flowing,
Union paths now bloom where nullable arrays grow,
Each scalar caught before it goes astray,
With structured errors lighting up the way! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Validate native array input values' directly and specifically describes the main change in the pull request—adding validation for native array input parameters.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/native-array-input-validation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 37 minutes and 56 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@koriym koriym force-pushed the codex/native-array-input-validation branch 4 times, most recently from 94fc1fc to a7ba47c Compare May 2, 2026 02:23
@koriym
Copy link
Copy Markdown
Member Author

koriym commented May 2, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@koriym koriym marked this pull request as ready for review May 2, 2026 02:48
@koriym
Copy link
Copy Markdown
Member Author

koriym commented May 2, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/Exception/InvalidInputTypeException.php (1)

21-22: 💤 Low value

Consider providing a descriptive exception message.

The exception is constructed with an empty message string. While the structured properties (paramName, expectedType, actualType, itemKey) are useful for programmatic handling, an empty getMessage() can complicate debugging and logging. Consider generating a human-readable message:

💡 Suggested improvement
     ) {
-        parent::__construct('', $code, $previous);
+        $message = $itemKey !== null
+            ? sprintf('Invalid type for item "%s" of parameter "%s": expected %s, got %s', $itemKey, $paramName, $expectedType, $actualType)
+            : sprintf('Invalid type for parameter "%s": expected %s, got %s', $paramName, $expectedType, $actualType);
+        parent::__construct($message, $code, $previous);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Exception/InvalidInputTypeException.php` around lines 21 - 22, The
InvalidInputTypeException constructor currently calls parent::__construct with
an empty message; update the constructor in class InvalidInputTypeException to
build a descriptive human-readable message (including paramName, expectedType,
actualType and itemKey when present) and pass that message into
parent::__construct so getMessage() returns useful debugging info while
preserving $code and $previous; ensure the message is concise and conditionally
includes itemKey if not null.
src/InputQuery.php (1)

572-613: ⚖️ Poor tradeoff

Consider extracting shared logic between getArrayParameterValue and getNullableArrayParameterValue.

Both methods share significant structural overlap: checking for item class, FileUpload type validation, calling createArrayOfInputs, and validating array types. This duplication could be reduced by extracting common logic into a helper, though the null-handling differences may justify keeping them separate for readability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/InputQuery.php` around lines 572 - 613, Both getArrayParameterValue and
getNullableArrayParameterValue duplicate logic for resolving an "item" class,
checking FileUpload types, calling createArrayOfInputs, and validating array
types; extract that shared logic into a single private helper (e.g.,
resolveArrayParameterItems) that accepts the ReflectionParameter $param, the
parameter name, the raw $arrayData (or nullable), and the InputAttributes
instance to: 1) detect and instantiate the input attribute, 2) assert and return
the created array of inputs via createArrayOfInputs when an item class is
present (or signal to the caller that null was explicit), 3) validate non-item
arrays and throw InvalidInputTypeException, and 4) perform the
FileUploadTypeChecker::isFileUploadType check and throw
InvalidFileUploadAttributeException when needed; then simplify
getArrayParameterValue and getNullableArrayParameterValue to call this helper
and handle only the small differences (nullable return vs default value).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/Exception/InvalidInputTypeException.php`:
- Around line 21-22: The InvalidInputTypeException constructor currently calls
parent::__construct with an empty message; update the constructor in class
InvalidInputTypeException to build a descriptive human-readable message
(including paramName, expectedType, actualType and itemKey when present) and
pass that message into parent::__construct so getMessage() returns useful
debugging info while preserving $code and $previous; ensure the message is
concise and conditionally includes itemKey if not null.

In `@src/InputQuery.php`:
- Around line 572-613: Both getArrayParameterValue and
getNullableArrayParameterValue duplicate logic for resolving an "item" class,
checking FileUpload types, calling createArrayOfInputs, and validating array
types; extract that shared logic into a single private helper (e.g.,
resolveArrayParameterItems) that accepts the ReflectionParameter $param, the
parameter name, the raw $arrayData (or nullable), and the InputAttributes
instance to: 1) detect and instantiate the input attribute, 2) assert and return
the created array of inputs via createArrayOfInputs when an item class is
present (or signal to the caller that null was explicit), 3) validate non-item
arrays and throw InvalidInputTypeException, and 4) perform the
FileUploadTypeChecker::isFileUploadType check and throw
InvalidFileUploadAttributeException when needed; then simplify
getArrayParameterValue and getNullableArrayParameterValue to call this helper
and handle only the small differences (nullable return vs default value).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c80585a6-a36f-497a-b71e-d2d318269fca

📥 Commits

Reviewing files that changed from the base of the PR and between 9d29544 and a7ba47c.

📒 Files selected for processing (3)
  • src/Exception/InvalidInputTypeException.php
  • src/InputQuery.php
  • tests/ArrayInputTest.php

@koriym koriym force-pushed the codex/native-array-input-validation branch from a7ba47c to 8314b1e Compare May 2, 2026 02:54
@koriym
Copy link
Copy Markdown
Member Author

koriym commented May 2, 2026

@coderabbitai I reviewed both nitpick comments.

  • Empty exception message: intentionally kept. This package communicates invalid input by exception type plus structured context (paramName, expectedType, actualType, itemKey), and tests assert that contract. Adding a descriptive message would duplicate structured context into text and make the message part of the API surface.
  • Shared array item logic: accepted partially. I extracted getArrayInputItemClass() so #[Input(item: ...)] class resolution and FileUpload misuse validation are shared by native array and nullable array paths. I intentionally kept getArrayParameterValue() and getNullableArrayParameterValue() separate because their missing/default/null behavior differs and should remain explicit.

Validation after the change:

  • /opt/homebrew/opt/php@8.5/bin/php vendor/bin/phpunit
  • PATH=/opt/homebrew/opt/php@8.5/bin:$PATH composer cs
  • /opt/homebrew/opt/php@8.5/bin/php vendor/bin/phpstan analyse -c phpstan.neon
  • /opt/homebrew/opt/php@8.4/bin/php vendor/bin/psalm --show-info=false

Please close the review comments if this addresses your feedback.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

Tip

For best results, initiate chat on the files or code changes.

@koriym: Thank you for the detailed explanation — both decisions are well-reasoned.

  • Empty exception message: Understood. Using structured fields (paramName, expectedType, actualType, itemKey) as the sole API surface (with tests asserting them) is a clean contract. Adding a freeform message on top would create redundancy and ambiguity about which surface consumers should rely on.

  • Shared array item logic: The partial extraction makes sense. getArrayInputItemClass() removes the duplication that mattered (class resolution + FileUpload guard), while keeping getArrayParameterValue() / getNullableArrayParameterValue() separate correctly preserves the divergent missing-value / default / null semantics of each path.

Resolving the two review comments now.

[resolve]


✏️ Learnings added
Learnt from: koriym
URL: https://github.com/ray-di/Ray.InputQuery/pull/12

Timestamp: 2026-05-02T02:55:13.178Z
Learning: In `Ray\InputQuery\Exception\InvalidInputTypeException` (src/Exception/InvalidInputTypeException.php), the exception message is intentionally empty. The package communicates invalid input via exception type plus structured readonly properties (`paramName`, `expectedType`, `actualType`, `itemKey`). Tests assert this structured contract directly; a freeform message would duplicate context and become part of the API surface.

Learnt from: koriym
URL: https://github.com/ray-di/Ray.InputQuery/pull/12

Timestamp: 2026-05-02T02:55:13.178Z
Learning: In `src/InputQuery.php`, `getArrayParameterValue()` and `getNullableArrayParameterValue()` are intentionally kept as separate methods despite similar array-handling logic. Their missing-value, default, and null-handling semantics differ and must remain explicit. The shared sub-logic (`#[Input(item:…)]` class resolution and FileUpload misuse validation) was extracted into `getArrayInputItemClass()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@koriym koriym merged commit b2dd491 into 1.x May 2, 2026
18 checks passed
@koriym koriym deleted the codex/native-array-input-validation branch May 2, 2026 05:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant