Skip to content

fix: return empty paginator when scout text value is empty#216

Open
AlzUrt wants to merge 2 commits into
Lomkit:mainfrom
AlzUrt:fix/scout-empty-text-value
Open

fix: return empty paginator when scout text value is empty#216
AlzUrt wants to merge 2 commits into
Lomkit:mainfrom
AlzUrt:fix/scout-empty-text-value

Conversation

@AlzUrt
Copy link
Copy Markdown
Contributor

@AlzUrt AlzUrt commented Apr 16, 2026

Problem

When {"search": {"text": {"value": ""}}} or {"value": null} is sent to the search endpoint, Elasticsearch returns a 400 error:

[match] unknown token [VALUE_NULL] after [query]

This happens because $request->has('search.text') returns true even with an empty value, causing ScoutBuilder to be selected and an invalid match: { query: "" } to be sent to Elasticsearch.

Root cause

The dispatcher in PerformsRestOperations::search() was only checking for the presence of search.text, not whether its value was actually usable:

// Before
$builder = $request->has('search.text') ? ScoutBuilder::class : QueryBuilder::class;

Fix

When search.text is provided but its value is empty/null, we return an empty paginated result immediately without hitting Elasticsearch or the database:

$textProvided = $request->has('search.text');

if ($textProvided && !filled($request->input('search.text.value'))) {
$this->afterSearch($request);
return $this->buildResponse(
$resource,
new LengthAwarePaginator([], 0, $request->input('search.limit', $resource->defaultLimit))
);
}

$builder = $textProvided ? ScoutBuilder::class : QueryBuilder::class;

A buildResponse() private method was also extracted to avoid duplicating the response structure.

Behaviour

Input Before After
text not provided All results via Eloquent ✅ All results via Eloquent
value: "" or value: null 400 from Elasticsearch ✅ Empty paginated result []
value: "foo" Scout results ✅ Scout results

Summary by CodeRabbit

  • Bug Fixes

    • Search now correctly handles provided-but-empty search text by returning an immediate empty result set with proper pagination, avoiding unnecessary processing.
  • Refactor

    • Response construction was centralized to streamline how search results (including empty responses) are packaged and returned.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c8c36237-16b2-47a2-9fd2-e9c24a97d93d

📥 Commits

Reviewing files that changed from the base of the PR and between ea49112 and 1984fc2.

📒 Files selected for processing (1)
  • src/Concerns/PerformsRestOperations.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Concerns/PerformsRestOperations.php

Walkthrough

The search() method in src/Concerns/PerformsRestOperations.php now early-returns an empty LengthAwarePaginator when search.text is present but its value is not filled. Builder selection uses a $textProvided flag, and response construction is moved into a new private buildResponse() helper.

Changes

Cohort / File(s) Summary
Search Control Flow & Response Helper
src/Concerns/PerformsRestOperations.php
Added early-return branch for provided-but-empty search.text that returns an empty LengthAwarePaginator. Introduced $textProvided to choose between ScoutBuilder and QueryBuilder. Extracted response construction into a new private buildResponse(Resource $resource, mixed $responsable): mixed helper and updated search() to use it.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main fix: returning an empty paginator when the scout text value is empty, which directly addresses the core problem solved in this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 PHPStan (2.1.46)

PHP Parse error: syntax error, unexpected token "->" in /vendor/phpunit/phpunit/src/Runner/Version.php on line 38
Parse error: syntax error, unexpected token "->" in /vendor/phpunit/phpunit/src/Runner/Version.php on line 38


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

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

Copy link
Copy Markdown
Contributor

@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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Concerns/PerformsRestOperations.php`:
- Around line 56-65: The LengthAwarePaginator instantiation uses
$resource->defaultLimit directly which can be null; change it to use a fallback
consistent with Paginable::paginate() (e.g., $resource->defaultLimit ?? 50) so
per-page is never null. Update the block in PerformsRestOperations (the code
that calls $this->afterSearch($request) and returns $this->buildResponse(...,
new LengthAwarePaginator(...))) to replace $resource->defaultLimit with the
fallback expression and ensure the paginator receives an integer perPage.
- Around line 42-43: Docblock in the PerformsRestOperations trait currently ends
mid-sentence ("Returns an empty paginated result if search text is provided but
empty,") — complete or rephrase it to a full sentence in the
PerformsRestOperations.php docblock (e.g., "Returns an empty paginated result if
search text is provided but empty.") or reformat to remove the trailing comma;
update the docblock surrounding the trait/method that describes returning an
empty paginated result so it is grammatically complete and clear.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7ebf219b-4f9e-42f8-94d5-7d5433a9fc2d

📥 Commits

Reviewing files that changed from the base of the PR and between e397dca and ea49112.

📒 Files selected for processing (1)
  • src/Concerns/PerformsRestOperations.php

Comment thread src/Concerns/PerformsRestOperations.php Outdated
Comment on lines +56 to +65
if ($textProvided && !filled($request->input('search.text.value'))) {
$this->afterSearch($request);
return $this->buildResponse(
$resource,
new LengthAwarePaginator(
[],
0,
$request->input('search.limit', $resource->defaultLimit)
)
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing fallback for defaultLimit — potential null perPage value.

In Paginable::paginate() (context snippet 3), the default limit is computed as $this->defaultLimit ?? 50, ensuring a fallback when the property is unset. Here, $resource->defaultLimit is used directly without the ?? 50 fallback.

If neither search.limit is provided nor $resource->defaultLimit is set, perPage could be null, which may cause unexpected behavior in the paginator.

🔧 Suggested fix to align with Paginable pattern
         if ($textProvided && !filled($request->input('search.text.value'))) {
             $this->afterSearch($request);
             return $this->buildResponse(
                 $resource, 
                 new LengthAwarePaginator(
                     [],
                     0,
-                    $request->input('search.limit', $resource->defaultLimit)
+                    $request->input('search.limit', $resource->defaultLimit ?? 50)
                 )
             );
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Concerns/PerformsRestOperations.php` around lines 56 - 65, The
LengthAwarePaginator instantiation uses $resource->defaultLimit directly which
can be null; change it to use a fallback consistent with Paginable::paginate()
(e.g., $resource->defaultLimit ?? 50) so per-page is never null. Update the
block in PerformsRestOperations (the code that calls
$this->afterSearch($request) and returns $this->buildResponse(..., new
LengthAwarePaginator(...))) to replace $resource->defaultLimit with the fallback
expression and ensure the paginator receives an integer perPage.

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