Skip to content

Conversation

@norkunas
Copy link
Collaborator

@norkunas norkunas commented Apr 9, 2025

Pull Request

Related issue

Fixes #703
Closes #739

What does this PR do?

  • Bumps PHP requirement to 8.1;
  • Adds missing types where there were none at all, or was impossible to use because of unions;
  • Adds Task object for type safety to be returned instead of undocumented array shapes;
  • Fully enables trailing_comma_in_multiline cs fixer rule;
  • Disables php_unit_strict cs fixer rule, because it breaks tests;

This introduces a BC break for someone who is extending meilisearch classes, but not for those who consumes the data, as Task object was added implementing \ArrayAccess, so all raw data can still be accessed.

This introduces a BC break for task data access and for someone who is extending meilisearch classes.

Migration guide

Before

$promise = $this->client->createIndex('new-index', ['primaryKey' => 'objectID']);

$this->index->waitForTask($promise['taskUid']);

After

$task = $this->client->createIndex('new-index', ['primaryKey' => 'objectID']);

$this->index->waitForTask($task->getTaskUid());

Before

$task = $this->client->getTask($taskUid);

if ($task['status'] === 'succeeded') {
    // snip...
}

After

use MeiliSearch\Contracts\TaskStatus;

$task = $this->client->getTask($taskUid);

if ($task->getStatus() === TaskStatus::Succeeded) {
    // snip...
}

Before

$task = $this->client->getTask($taskUid);

if ($task['type'] === 'indexCreation') {
    // snip...
}

After

use MeiliSearch\Contracts\TaskType;

$task = $this->client->getTask($taskUid);

if ($task->getType() === TaskType::IndexCreation) {
    // snip...
}

PR checklist

Please check if your PR fulfills the following requirements:

  • Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)?
  • Have you read the contributing guidelines?
  • Have you made sure that the title is accurate and descriptive of the changes?

Summary by CodeRabbit

  • New Features

    • Mutating operations (documents, indexes, settings, dumps, snapshots, batches, tasks) now return Task objects with a chainable wait() for unified async handling.
  • Bug Fixes

    • JSON serialization now throws on encoding errors for more reliable error reporting.
  • Chores

    • Minimum PHP requirement raised to 8.1.
    • Increased type strictness and clearer return types across the codebase.
  • Tests

    • Test suite updated to use Task-based flows and inline wait() calls.

@norkunas norkunas added enhancement New feature or request breaking-change The related changes are breaking for the users dependencies labels Apr 9, 2025
@norkunas norkunas force-pushed the task-object branch 3 times, most recently from 00a7b98 to 31b5036 Compare April 10, 2025 03:46
@codecov
Copy link

codecov bot commented Apr 10, 2025

Codecov Report

❌ Patch coverage is 96.72619% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.14%. Comparing base (0078a8c) to head (9275679).
⚠️ Report is 80 commits behind head on main.

Files with missing lines Patch % Lines
src/Contracts/TaskDetails/DumpCreationDetails.php 0.00% 4 Missing ⚠️
src/Contracts/TaskDetails/UnknownTaskDetails.php 0.00% 3 Missing ⚠️
src/Endpoints/Tasks.php 80.00% 2 Missing ⚠️
src/Endpoints/Delegates/HandlesTasks.php 66.66% 1 Missing ⚠️
src/Search/FacetSearchResult.php 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #735      +/-   ##
==========================================
- Coverage   89.78%   88.14%   -1.65%     
==========================================
  Files          59       78      +19     
  Lines        1449     1687     +238     
==========================================
+ Hits         1301     1487     +186     
- Misses        148      200      +52     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@tacman
Copy link
Contributor

tacman commented Apr 10, 2025

YAY!

If these are to be deprecated, are they going to be replaced with direct access to the object?

    public function getData(): array
    {
        return $this->data;
    }

    // @todo: deprecate
    public function offsetExists(mixed $offset): bool
    {
        return \array_key_exists($offset, $this->data);
    }

    // @todo: deprecate
    public function offsetGet(mixed $offset): mixed
    {
        return $this->data[$offset] ?? null;
    }

    // @todo: deprecate
    public function offsetSet(mixed $offset, mixed $value): void
    {
        throw new \LogicException(\sprintf('Setting data on "%s::%s" is not supported.', get_debug_type($this), $offset));
    }

    // @todo: deprecate
    public function offsetUnset(mixed $offset): void
    {
        throw new \LogicException(\sprintf('Unsetting data on "%s::%s" is not supported.', get_debug_type($this), $offset));
    }

@norkunas
Copy link
Collaborator Author

@tacman if this PR will get merged, then you'll get access to both ways: $task->getError() or $task['error']
but imho previous way should be deprecated, because it does not provide types

@tacman
Copy link
Contributor

tacman commented Apr 10, 2025

That makes sense. I imagine there will be other things in 2.0 as well.

@Strift
Copy link
Collaborator

Strift commented Apr 14, 2025

Hi, thanks for your PR.

Do we want to release this in a v2.x?

Can you add a "migration guide" to your first comment to highlight the required implementation changes?

@norkunas
Copy link
Collaborator Author

@Strift

Do we want to release this in a v2.x?

Based on semver, it should be in v2.x, but if you want to be in line with meilisearch/meilisearch repository, I think it's reasonable to release this in v1.

Can you add a "migration guide" to your first comment to highlight the required implementation changes?

Can you link to some previous comment where I could see how this looks like?

@Strift
Copy link
Collaborator

Strift commented Apr 14, 2025

Hi @norkunas, no need to follow a specific format. A simple before/after of the relevant parts of the code is enough. Here's an example for meilisearch JS: https://github.com/meilisearch/meilisearch-js/releases/tag/v0.48.0

It's mainly so I have examples to refer to when writing the release changelog. Double-checking with the actual code changes is better, but the code samples are a good resource too for me, especially if I write the changelog a long time after reviewing the PR.

@norkunas
Copy link
Collaborator Author

@Strift I've updated description, is it ok for you?
Also it should be decided if we deprecate the array access or not.

@norkunas
Copy link
Collaborator Author

I also have a side idea for another improvement:
Add wait(int $timeoutInMs, int $intervalInMs) method to task.
So instead of:

$task = $this->client->createIndex('new-index', ['primaryKey' => 'objectID']);
$task = $this->index->waitForTask($task->getTaskUid());

we could write:

$task = $this->client->createIndex('new-index', ['primaryKey' => 'objectID'])->wait();

But not sure, as then we'd need for this method to work at least inject in in the Task object the Meilisearch\Endpoints\Tasks endpoint, or the http client, or the meilisearch client itself..

@curquiza
Copy link
Member

Hello here!
Thank you for your PR @norkunas!
With @brunoocasali and the PHP community, we originally chose to make the PHP SDK follow the same version number as Meilisearch's one
Here, if we merge this branch, we will break this useful convention forever. Is it what we want?

@norkunas
Copy link
Collaborator Author

Hi, I'm for merging to v1 :) I think this is an acceptable BC break to provide type safety

@norkunas
Copy link
Collaborator Author

I also think that it would be good to have typed task details based on https://www.meilisearch.com/docs/reference/api/tasks#details, because now it's always array<mixed>, so static analyzers will always complain.

@Strift Strift requested a review from Copilot May 14, 2025 02:43
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR updates the PHP version to 8.1 and refactors numerous endpoint methods to return the new Task object for improved type safety. Key changes include adding missing type hints with union types, converting array responses into Task objects via Task::fromArray, and updating the code style and CI workflows to support only PHP 8.1+.

Reviewed Changes

Copilot reviewed 66 out of 66 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Endpoints/Delegates/HandlesSystem.php Updated swapIndexes method signature to return Task but without wrapping the response in a Task object.
src/Endpoints/Delegates/HandlesSnapshots.php Changed return type to Task.
src/Endpoints/Delegates/HandlesSettings.php Updated numerous settings methods to wrap responses with Task::fromArray.
src/Endpoints/Delegates/HandlesIndex.php Adjusted index-related methods to return Task and improved type annotations.
src/Endpoints/Delegates/HandlesDumps.php Updated createDump return type to Task.
src/Endpoints/Delegates/HandlesDocuments.php Refactored document-related methods to return Task with appropriate wrapping.
src/Endpoints/Delegates/HandlesBatches.php Refined the parameter type.
Other files (Contracts, Client, composer.json, etc.) Updated types, enums, and CI configurations to support PHP 8.1+ and modern syntax.

Copy link
Collaborator

@Strift Strift left a comment

Choose a reason for hiding this comment

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

This mostly looks good to me. I left a few comments.

I would love to release this with the changes related to Meilisearch v1.15.

Also, Codecov says the following lines are not covered by tests:

  • src/Contracts/Task.php#L114
  • src/Contracts/Task.php#L116

@Strift
Copy link
Collaborator

Strift commented May 14, 2025

Regarding the other topics of discussion in this thread:

I also have a side idea for another improvement:
Add wait(int $timeoutInMs, int $intervalInMs) method to task.

This could be a welcome addition, but I prefer having it in a separate PR to keep this one's scope minimal.

@norkunas
Copy link
Collaborator Author

Thanks @Strift for review, I'm currently preparing for details data to be typed.

@coderabbitai
Copy link

coderabbitai bot commented May 14, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Replaces array-based task responses with a typed Task model and TaskDetails, converts many endpoint mutators to return Task, tightens PHP types (requires ^8.1), adds Task::wait() integration and partial helper, enables JSON_THROW_ON_ERROR for serializers, and updates tests and CI matrices accordingly.

Changes

Cohort / File(s) Summary
Config & Tooling
'.php-cs-fixer.dist.php', composer.json, phpunit.xml.dist, .github/workflows/...
Bumped PHP to ^8.1; updated dependencies and phpunit config; added src/functions.php to autoload files; adjusted php-cs-fixer rules and CI PHP matrices.
Core Task Model & Enums
src/Contracts/Task.php, src/Contracts/TaskStatus.php, src/Contracts/TaskType.php, src/Contracts/TaskError.php
Added Task value object with readonly properties, getters, isFinished(), wait(), fromArray(); added/updated enums TaskType and TaskStatus (Unknown); added TaskError.
Task Details Interface & Implementations
src/Contracts/TaskDetails.php, src/Contracts/TaskDetails/*
New TaskDetails interface and multiple TaskDetails implementations (DocumentAdditionOrUpdateDetails, DocumentDeletionDetails, DocumentEditionDetails, DumpCreationDetails, IndexCreationDetails, IndexDeletionDetails, IndexSwapDetails, IndexUpdateDetails, SettingsUpdateDetails, TaskCancelationDetails, TaskDeletionDetails, UnknownTaskDetails) with static fromArray factories.
Endpoints — Return Types Converted to Task
src/Endpoints/*, src/Endpoints/Delegates/*, src/Endpoints/Indexes.php, src/Endpoints/Tasks.php, src/Endpoints/Dumps.php, src/Endpoints/Snapshots.php, src/Endpoints/Batches.php, src/Endpoints/Keys.php
Many mutators now return Task (or arrays of Task for batch variants); getTask/getBatch tightened to int; endpoints wrap HTTP responses via Task::fromArray(..., partial(Tasks::waitTask(...), $http)); Tasks::waitTask made static/internal.
Documents & Settings Delegates
src/Endpoints/Delegates/HandlesDocuments.php, src/Endpoints/Delegates/HandlesSettings.php
Document mutation and settings mutator methods now return Task (batch variants return arrays of Task); getDocument typed `string
HTTP & Serialization
src/Http/Client.php, src/Http/Serialize/Json.php, src/Http/Serialize/SerializerInterface.php
Added mixed typings on body params/returns, minor constructor/trailing-comma formatting, improved isJSONResponse/buildQueryString logic; JSON serializer now uses JSON_THROW_ON_ERROR.
Exceptions & Utilities
src/Exceptions/*, src/functions.php
Strengthened types on exception properties/methods, removed an InvalidArgumentException factory, added LogicException class, and added Meilisearch\partial() helper function.
Results & Data Classes
src/Contracts/Data.php, src/Contracts/SimilarDocumentsQuery.php, src/Contracts/TasksResults.php
Tightened internal types (e.g., array, mixed), typed SimilarDocumentsQuery properties/params, and TasksResults now maps raw results to Task instances.
Search Serialization Changes
src/Search/SearchResult.php, src/Search/FacetSearchResult.php
toJSON() now encodes with JSON_THROW_ON_ERROR to surface JSON encoding errors as exceptions.
Tests & Test Helpers
tests/**, tests/MockTask.php, tests/Contracts/TaskTest.php, tests/TestCase.php
Tests refactored to use Task objects and ->wait() chaining instead of promise/taskUid flows; added MockTask and TaskTest; updated assertions and TestCase to delete indices with delete()->wait().

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Endpoint
    participant Http
    participant TaskFactory as Task::fromArray
    participant Poll as Tasks::waitTask

    Note over TaskFactory,Poll: partial binds Poll to Http

    Caller->>Endpoint: call mutatingOperation(...)
    Endpoint->>Http: POST/PUT → raw response (array)
    Http-->>Endpoint: response array
    Endpoint->>TaskFactory: Task::fromArray(response, boundPoll)
    TaskFactory-->>Endpoint: Task
    Endpoint-->>Caller: Task

    alt Caller invokes wait()
        Caller->>TaskFactory: task->wait()
        loop poll until finished
            Poll->>Http: GET /tasks/{uid}
            Http-->>Poll: latest task data
            Poll->>TaskFactory: Task::fromArray(...)
            TaskFactory-->>Poll: Task
        end
        Poll-->>Caller: final finished Task
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Areas to focus review on:

  • Task::fromArray mapping and TaskDetails selection (edge-case keys, missing fields).
  • Consistency of Task wrapping across all endpoint mutators and correctness of partial(Tasks::waitTask(...), $http) binding.
  • Tasks::waitTask static refactor (poll loop, timeouts, isFinished checks).
  • Tests updates and MockTask correctness for various TaskStatus/TaskType scenarios.
  • JSON_THROW_ON_ERROR impact on codepaths that relied on previous false return values.

Possibly related PRs

Suggested reviewers

  • brunoocasali

Poem

🐇 I hopped through files both near and far,
Turned loose arrays to Tasks — a shiny star.
wait() now listens while I nibble a treat,
Enums and details make responses neat.
Tests clap their paws — the patch is complete.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.92% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 'Bump to PHP 8.1, improve type safety for Tasks' accurately summarizes the two main changes: PHP version bump and Task object improvements for type safety.
Linked Issues check ✅ Passed The PR implements core requirements from both linked issues: #703 (Task object replaces array returns with typed properties) and #739 (wait() method added for task chaining).
Out of Scope Changes check ✅ Passed All changes align with stated objectives: PHP 8.1 requirement bump, type safety improvements, Task object implementation, code style updates, and supporting infrastructure changes. No unrelated modifications detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7ec932 and 9275679.

📒 Files selected for processing (2)
  • src/Contracts/Task.php (1 hunks)
  • src/Contracts/TaskDetails/UnknownTaskDetails.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/Contracts/TaskDetails/UnknownTaskDetails.php (1)
src/Contracts/Task.php (2)
  • __construct (29-44)
  • fromArray (151-187)
src/Contracts/Task.php (5)
src/Contracts/TaskDetails/DocumentAdditionOrUpdateDetails.php (3)
  • DocumentAdditionOrUpdateDetails (15-34)
  • __construct (21-25)
  • fromArray (27-33)
src/Contracts/TaskDetails/UnknownTaskDetails.php (3)
  • UnknownTaskDetails (12-26)
  • __construct (17-20)
  • fromArray (22-25)
src/Exceptions/LogicException.php (1)
  • LogicException (7-9)
src/Contracts/TaskError.php (3)
  • __construct (15-21)
  • TaskError (7-40)
  • fromArray (31-39)
src/Contracts/TaskDetails.php (1)
  • fromArray (15-15)
🔇 Additional comments (6)
src/Contracts/TaskDetails/UnknownTaskDetails.php (1)

1-26: LGTM! Clean catch-all implementation.

The UnknownTaskDetails class correctly implements the TaskDetails interface with a generic array<mixed> payload, following the same factory pattern as other detail classes. This provides a safe fallback for unknown task types, aligning with the forward-compatibility strategy discussed in the PR (allowing the SDK to handle new engine task types gracefully).

src/Contracts/Task.php (5)

23-44: LGTM! Well-typed immutable constructor.

The constructor leverages PHP 8.1's readonly properties for immutability and provides comprehensive type hints. The await closure signature is well-documented, enabling dependency injection without coupling Task to HTTP clients.


46-113: LGTM! Clean getter implementations.

All getters are straightforward and properly documented with PHPDoc annotations for refined types (e.g., non-negative-int, non-empty-string) that PHP's native type system cannot express.


115-118: LGTM! Correct completion check.

The logic correctly identifies finished tasks (not Enqueued and not Processing). Tasks with Unknown status will also be considered finished, which is appropriate since waiting on an unrecognized state could hang indefinitely.


120-131: LGTM! Solid wait() implementation.

The method correctly short-circuits for finished tasks, delegates to the injected await closure when available, and throws a clear exception otherwise. Default timeouts (5000ms timeout, 50ms interval) are sensible for most use cases.


151-187: LGTM! Robust factory with forward-compatibility.

The fromArray() factory implements several defensive patterns:

  • Legacy support: Line 157 accepts both taskUid and uid keys.
  • Forward-compatibility: Lines 154, 159 use tryFrom() with Unknown fallbacks, allowing the SDK to handle new engine task types gracefully (as discussed in past reviews).
  • Null safety: Lines 158, 162-163 use null coalescing and array_key_exists checks for optional fields.
  • Type-specific details: Lines 167-183 match each TaskType to its corresponding detail class, with UnknownTaskDetails as a safe catch-all.

Note: Line 161 directly accesses enqueuedAt and will throw if missing or malformed. This strict validation is acceptable given the API contract guarantees this field, and aligns with the v2 goal of stronger type safety.


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.

@Strift Strift changed the title Task object Improve type safety for Tasks May 14, 2025
Copy link

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/Contracts/SimilarDocumentsQuery.php (1)

144-148: Align type signatures: both methods should accept ?float for consistency.

The type discrepancy is confirmed and intentional—SimilarDocumentsQuery's test explicitly includes @testWith [123] and [0.123], showing int values are tested. However, since both methods represent the same semantic concept (ranking score threshold), they should use the same type. A ranking score threshold is semantically a float value; accepting int adds unnecessary flexibility. Change SimilarDocumentsQuery::setRankingScoreThreshold() to accept ?float (matching SearchQuery), and update the property type on line 45 from private int|float|null to private ?float. Update the test data provider to use only float values.

tests/Endpoints/DocumentsTest.php (2)

631-632: Migrate to Task-based API for consistency.

This test still uses the deprecated array-based pattern ($promise = ...addDocuments(...); waitForTask($promise['taskUid'])), while the rest of the file has been migrated to the new Task API with ->wait() chaining.

Apply this diff to align with the new pattern:

-        $promise = $index->addDocuments(self::DOCUMENTS);
-        $index->waitForTask($promise['taskUid']);
+        $index->addDocuments(self::DOCUMENTS)->wait();

646-647: Migrate to Task-based API for consistency.

Another instance of the deprecated array-based pattern. This should be updated to match the Task-based approach used elsewhere in the file.

Apply this diff:

-        $promise = $index->addDocuments(self::DOCUMENTS);
-        $index->waitForTask($promise['taskUid']);
+        $index->addDocuments(self::DOCUMENTS)->wait();
tests/Endpoints/SimilarDocumentsTest.php (1)

20-20: Add ->wait() to ensure documents are indexed before tests run.

The updateDocuments() call on line 20 is missing ->wait(), while every other test in the suite that calls updateDocuments() chains .wait() on it. Since embedders are prerequisites that must be configured before document vectors can be indexed, and the test immediately performs a search after updating settings, the document indexing task could still be in progress when the search executes—potentially causing flaky test failures.

This is particularly evident in SearchTest.php line 695, which explicitly waits for both the embedder configuration and the document indexing before proceeding.

-        $this->index->updateDocuments(self::VECTOR_MOVIES);
+        $this->index->updateDocuments(self::VECTOR_MOVIES)->wait();
♻️ Duplicate comments (2)
src/Contracts/TaskDetails/DocumentEditionDetails.php (1)

32-41: Add null coalescing operators for all fields to prevent undefined index warnings.

All fields are accessed directly without guards, which can cause undefined index warnings if Meilisearch omits optional fields. For consistency with DocumentDeletionDetails and other TaskDetails classes, use the null coalescing operator:

     public static function fromArray(array $data): self
     {
         return new self(
-            $data['context'],
-            $data['deletedDocuments'],
-            $data['editedDocuments'],
-            $data['function'],
-            $data['originalFilter'],
+            $data['context'] ?? [],
+            $data['deletedDocuments'] ?? null,
+            $data['editedDocuments'] ?? null,
+            $data['function'] ?? null,
+            $data['originalFilter'] ?? null,
         );
     }

Note: A past review comment indicated this was addressed in commit a1e9277, but the current code doesn't reflect these guards. Please verify whether changes were inadvertently reverted.

tests/Contracts/TaskTest.php (1)

26-28: Date format inconsistencies reduce test clarity.

The constructor parameters (lines 26-28) use varied date formats (space vs T separator, with/without timezone suffix, nanosecond vs microsecond precision), while assertions (lines 45-47) expect different formats. Although tests pass due to timestamp normalization, consistent formats improve maintainability.

As suggested in past reviews, standardize on ISO 8601 format with Z timezone:

         enqueuedAt: new \DateTimeImmutable('2025-04-09 10:28:12.236789123Z'),
-        startedAt: new \DateTimeImmutable('2025-04-09 10:28:12.555566'),
-        finishedAt: new \DateTimeImmutable('2025-04-09 10:28:12.666677'),
+        startedAt: new \DateTimeImmutable('2025-04-09T10:28:12.555566Z'),
+        finishedAt: new \DateTimeImmutable('2025-04-09T10:28:12.666677Z'),

And update assertions to match:

-        self::assertEquals(new \DateTimeImmutable('2025-04-09T10:28:12.236789'), $task->getEnqueuedAt());
-        self::assertEquals(new \DateTimeImmutable('2025-04-09T10:28:12.555566+0000'), $task->getStartedAt());
-        self::assertEquals(new \DateTimeImmutable('2025-04-09T10:28:12.666677+0000'), $task->getFinishedAt());
+        self::assertEquals(new \DateTimeImmutable('2025-04-09T10:28:12.236789Z'), $task->getEnqueuedAt());
+        self::assertEquals(new \DateTimeImmutable('2025-04-09T10:28:12.555566Z'), $task->getStartedAt());
+        self::assertEquals(new \DateTimeImmutable('2025-04-09T10:28:12.666677Z'), $task->getFinishedAt());

Also applies to: 45-47

🧹 Nitpick comments (2)
src/Contracts/TaskDetails/IndexSwapDetails.php (1)

24-29: Consider defensive key access in fromArray.

The fromArray method directly accesses $data['swaps'] without checking if the key exists. While Task::fromArray only calls this when details are present, defensive coding would make this more robust.

Apply this diff for safer access:

 public static function fromArray(array $data): self
 {
     return new self(
-        $data['swaps'],
+        $data['swaps'] ?? [],
     );
 }
src/Endpoints/Tasks.php (1)

25-29: Address TODO: wrap task array results in Task objects.

The all() method currently returns a raw array, but the TODO comment indicates it should return array<Task>. Each task in the results should be wrapped with Task::fromArray() for consistency with other methods.

Would you like me to generate the implementation that maps each result to a Task object?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 28c45ee and db46570.

📒 Files selected for processing (89)
  • .php-cs-fixer.dist.php (1 hunks)
  • composer.json (2 hunks)
  • phpunit.xml.dist (2 hunks)
  • src/Client.php (1 hunks)
  • src/Contracts/Data.php (2 hunks)
  • src/Contracts/Http.php (1 hunks)
  • src/Contracts/SimilarDocumentsQuery.php (4 hunks)
  • src/Contracts/Task.php (1 hunks)
  • src/Contracts/TaskDetails.php (1 hunks)
  • src/Contracts/TaskDetails/DocumentAdditionOrUpdateDetails.php (1 hunks)
  • src/Contracts/TaskDetails/DocumentDeletionDetails.php (1 hunks)
  • src/Contracts/TaskDetails/DocumentEditionDetails.php (1 hunks)
  • src/Contracts/TaskDetails/DumpCreationDetails.php (1 hunks)
  • src/Contracts/TaskDetails/IndexCreationDetails.php (1 hunks)
  • src/Contracts/TaskDetails/IndexDeletionDetails.php (1 hunks)
  • src/Contracts/TaskDetails/IndexSwapDetails.php (1 hunks)
  • src/Contracts/TaskDetails/IndexUpdateDetails.php (1 hunks)
  • src/Contracts/TaskDetails/SettingsUpdateDetails.php (1 hunks)
  • src/Contracts/TaskDetails/TaskCancelationDetails.php (1 hunks)
  • src/Contracts/TaskDetails/TaskDeletionDetails.php (1 hunks)
  • src/Contracts/TaskError.php (1 hunks)
  • src/Contracts/TaskStatus.php (1 hunks)
  • src/Contracts/TaskType.php (1 hunks)
  • src/Contracts/TasksResults.php (2 hunks)
  • src/Endpoints/Batches.php (1 hunks)
  • src/Endpoints/Delegates/HandlesBatches.php (1 hunks)
  • src/Endpoints/Delegates/HandlesDocuments.php (8 hunks)
  • src/Endpoints/Delegates/HandlesDumps.php (1 hunks)
  • src/Endpoints/Delegates/HandlesIndex.php (2 hunks)
  • src/Endpoints/Delegates/HandlesSettings.php (21 hunks)
  • src/Endpoints/Delegates/HandlesSnapshots.php (1 hunks)
  • src/Endpoints/Delegates/HandlesSystem.php (2 hunks)
  • src/Endpoints/Delegates/HandlesTasks.php (2 hunks)
  • src/Endpoints/Delegates/TasksQueryTrait.php (1 hunks)
  • src/Endpoints/Dumps.php (1 hunks)
  • src/Endpoints/Indexes.php (6 hunks)
  • src/Endpoints/Keys.php (4 hunks)
  • src/Endpoints/Snapshots.php (1 hunks)
  • src/Endpoints/Tasks.php (1 hunks)
  • src/Endpoints/TenantToken.php (2 hunks)
  • src/Exceptions/ApiException.php (3 hunks)
  • src/Exceptions/CommunicationException.php (1 hunks)
  • src/Exceptions/InvalidArgumentException.php (0 hunks)
  • src/Exceptions/InvalidResponseBodyException.php (2 hunks)
  • src/Exceptions/LogicException.php (1 hunks)
  • src/Exceptions/TimeOutException.php (1 hunks)
  • src/Http/Client.php (3 hunks)
  • src/Http/Serialize/Json.php (1 hunks)
  • src/Http/Serialize/SerializerInterface.php (2 hunks)
  • src/Search/FacetSearchResult.php (1 hunks)
  • src/Search/SearchResult.php (1 hunks)
  • src/functions.php (1 hunks)
  • tests/Contracts/TaskTest.php (1 hunks)
  • tests/Endpoints/BatchesTest.php (1 hunks)
  • tests/Endpoints/ClientTest.php (3 hunks)
  • tests/Endpoints/DocumentsTest.php (38 hunks)
  • tests/Endpoints/DumpTest.php (1 hunks)
  • tests/Endpoints/FacetSearchTest.php (1 hunks)
  • tests/Endpoints/IndexTest.php (5 hunks)
  • tests/Endpoints/MultiSearchTest.php (1 hunks)
  • tests/Endpoints/SearchNestedFieldsTest.php (4 hunks)
  • tests/Endpoints/SearchTest.php (24 hunks)
  • tests/Endpoints/SimilarDocumentsTest.php (1 hunks)
  • tests/Endpoints/SnapshotsTest.php (1 hunks)
  • tests/Endpoints/TasksTest.php (4 hunks)
  • tests/Endpoints/TenantTokenTest.php (3 hunks)
  • tests/MockTask.php (1 hunks)
  • tests/Settings/DisplayedAttributesTest.php (2 hunks)
  • tests/Settings/DistinctAttributeTest.php (1 hunks)
  • tests/Settings/EmbeddersTest.php (5 hunks)
  • tests/Settings/FacetSearchTest.php (1 hunks)
  • tests/Settings/FacetingAttributesTest.php (1 hunks)
  • tests/Settings/FilterableAttributesTest.php (3 hunks)
  • tests/Settings/LocalizedAttributesTest.php (2 hunks)
  • tests/Settings/NonSeparatorTokensTest.php (1 hunks)
  • tests/Settings/PaginationTest.php (1 hunks)
  • tests/Settings/PrefixSearchTest.php (1 hunks)
  • tests/Settings/ProximityPrecisionTest.php (2 hunks)
  • tests/Settings/RankingRulesTest.php (2 hunks)
  • tests/Settings/SearchCutoffMsTest.php (2 hunks)
  • tests/Settings/SearchableAttributesTest.php (1 hunks)
  • tests/Settings/SeparatorTokensTest.php (1 hunks)
  • tests/Settings/SettingsTest.php (3 hunks)
  • tests/Settings/SortableAttributesTest.php (1 hunks)
  • tests/Settings/StopWordsTest.php (1 hunks)
  • tests/Settings/SynonymsTest.php (1 hunks)
  • tests/Settings/TypoToleranceTest.php (2 hunks)
  • tests/Settings/WordDictionaryTest.php (2 hunks)
  • tests/TestCase.php (2 hunks)
💤 Files with no reviewable changes (1)
  • src/Exceptions/InvalidArgumentException.php
🚧 Files skipped from review as they are similar to previous changes (42)
  • src/Search/FacetSearchResult.php
  • tests/Settings/SynonymsTest.php
  • tests/Endpoints/BatchesTest.php
  • src/Contracts/TaskStatus.php
  • src/Contracts/TasksResults.php
  • src/Exceptions/InvalidResponseBodyException.php
  • src/Contracts/TaskDetails/IndexCreationDetails.php
  • src/Contracts/TaskDetails.php
  • tests/Settings/SearchableAttributesTest.php
  • tests/Settings/DistinctAttributeTest.php
  • tests/TestCase.php
  • src/Contracts/TaskError.php
  • tests/Settings/SettingsTest.php
  • src/Http/Serialize/Json.php
  • src/Endpoints/Dumps.php
  • src/Contracts/TaskDetails/SettingsUpdateDetails.php
  • src/Contracts/TaskDetails/TaskDeletionDetails.php
  • tests/Settings/TypoToleranceTest.php
  • tests/Settings/EmbeddersTest.php
  • src/Exceptions/TimeOutException.php
  • src/Endpoints/Delegates/TasksQueryTrait.php
  • src/Endpoints/Delegates/HandlesSnapshots.php
  • tests/Settings/ProximityPrecisionTest.php
  • src/Exceptions/ApiException.php
  • tests/Settings/NonSeparatorTokensTest.php
  • tests/Settings/SearchCutoffMsTest.php
  • tests/Settings/RankingRulesTest.php
  • src/Endpoints/Delegates/HandlesSystem.php
  • tests/Settings/WordDictionaryTest.php
  • src/Contracts/TaskDetails/IndexUpdateDetails.php
  • src/Contracts/TaskDetails/DumpCreationDetails.php
  • src/Search/SearchResult.php
  • tests/Endpoints/SnapshotsTest.php
  • tests/Settings/DisplayedAttributesTest.php
  • src/Endpoints/Delegates/HandlesDumps.php
  • src/Contracts/TaskDetails/DocumentDeletionDetails.php
  • src/Endpoints/Indexes.php
  • src/Contracts/Data.php
  • tests/Endpoints/TenantTokenTest.php
  • src/Endpoints/Keys.php
  • src/Http/Client.php
  • src/Endpoints/Batches.php
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-20T05:05:22.383Z
Learnt from: bpolaszek
Repo: meilisearch/meilisearch-php PR: 779
File: tests/Endpoints/DocumentsTest.php:669-682
Timestamp: 2025-08-20T05:05:22.383Z
Learning: In Meilisearch, tasks have implicit dependencies where document operations (like addDocuments) won't be processed until prerequisite setting tasks (like updateSortableAttributes, updateFilterableAttributes) have completed. Therefore, waiting for the addDocuments task completion implicitly ensures that all prerequisite setting tasks have also completed.

Applied to files:

  • tests/Endpoints/SimilarDocumentsTest.php
  • tests/Endpoints/DocumentsTest.php
  • tests/Endpoints/MultiSearchTest.php
  • tests/Endpoints/SearchTest.php
  • src/Endpoints/Delegates/HandlesDocuments.php
🧬 Code graph analysis (39)
src/functions.php (1)
src/Meilisearch.php (1)
  • Meilisearch (7-18)
tests/Settings/SeparatorTokensTest.php (2)
src/Endpoints/Delegates/HandlesSettings.php (3)
  • updateSeparatorTokens (352-355)
  • getSeparatorTokens (344-347)
  • resetSeparatorTokens (357-360)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/MockTask.php (2)
src/Contracts/Task.php (1)
  • Task (20-185)
src/Endpoints/Indexes.php (1)
  • create (78-83)
tests/Endpoints/SimilarDocumentsTest.php (2)
src/Endpoints/Indexes.php (1)
  • updateSettings (253-256)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/Settings/FacetSearchTest.php (3)
src/Endpoints/Delegates/HandlesSettings.php (3)
  • updateFacetSearch (470-473)
  • getFacetSearch (462-465)
  • resetFacetSearch (478-481)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/TestCase.php (2)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Endpoints/Snapshots.php (4)
src/Contracts/Task.php (2)
  • Task (20-185)
  • fromArray (150-184)
src/functions.php (1)
  • partial (18-23)
src/Contracts/Endpoint.php (1)
  • Endpoint (7-23)
src/Endpoints/Tasks.php (2)
  • Tasks (16-67)
  • waitTask (50-66)
src/Exceptions/CommunicationException.php (3)
src/Exceptions/ApiException.php (1)
  • __toString (32-53)
src/Exceptions/InvalidResponseBodyException.php (1)
  • __toString (24-33)
src/Exceptions/TimeOutException.php (1)
  • __toString (20-28)
src/Contracts/TaskDetails/IndexSwapDetails.php (2)
src/Contracts/Task.php (1)
  • fromArray (150-184)
src/Contracts/TaskDetails.php (1)
  • fromArray (15-15)
src/Contracts/TaskDetails/DocumentEditionDetails.php (4)
src/Contracts/Task.php (2)
  • __construct (28-43)
  • fromArray (150-184)
src/Contracts/TaskDetails/DocumentAdditionOrUpdateDetails.php (2)
  • __construct (21-25)
  • fromArray (27-33)
src/Contracts/TaskDetails/DocumentDeletionDetails.php (2)
  • __construct (23-28)
  • fromArray (30-37)
src/Contracts/TaskDetails.php (1)
  • fromArray (15-15)
src/Contracts/TaskDetails/TaskCancelationDetails.php (4)
src/Contracts/Task.php (2)
  • __construct (28-43)
  • fromArray (150-184)
src/Contracts/TaskDetails/DocumentDeletionDetails.php (2)
  • __construct (23-28)
  • fromArray (30-37)
src/Contracts/TaskDetails/TaskDeletionDetails.php (2)
  • __construct (23-28)
  • fromArray (30-37)
src/Contracts/TaskDetails.php (1)
  • fromArray (15-15)
src/Http/Serialize/SerializerInterface.php (1)
src/Http/Serialize/Json.php (2)
  • serialize (9-12)
  • unserialize (14-17)
tests/Endpoints/DocumentsTest.php (6)
src/Contracts/Task.php (2)
  • Task (20-185)
  • wait (119-130)
src/Contracts/TaskDetails/DocumentAdditionOrUpdateDetails.php (1)
  • DocumentAdditionOrUpdateDetails (15-34)
src/Endpoints/Indexes.php (2)
  • Indexes (27-282)
  • create (78-83)
tests/MockTask.php (2)
  • MockTask (11-23)
  • create (13-22)
tests/TestCase.php (3)
  • TestCase (16-171)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Endpoints/Delegates/HandlesDocuments.php (16)
  • addDocuments (46-49)
  • getDocuments (28-44)
  • addDocumentsInBatches (69-78)
  • addDocumentsCsv (56-59)
  • addDocumentsJson (51-54)
  • addDocumentsNdjson (61-64)
  • getDocument (21-26)
  • updateDocuments (108-111)
  • updateDocumentsInBatches (131-140)
  • updateDocumentsByFunction (180-183)
  • addDocumentsCsvInBatches (83-92)
  • addDocumentsNdjsonInBatches (97-106)
  • deleteDocument (190-193)
  • deleteDocuments (195-208)
  • deleteAllDocuments (185-188)
  • updateDocumentsJson (113-116)
tests/Endpoints/MultiSearchTest.php (3)
tests/TestCase.php (1)
  • createEmptyIndex (131-136)
src/Endpoints/Delegates/HandlesDocuments.php (2)
  • updateDocuments (108-111)
  • addDocumentsCsv (56-59)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/Settings/SortableAttributesTest.php (3)
src/Endpoints/Delegates/HandlesSettings.php (3)
  • getSortableAttributes (265-268)
  • updateSortableAttributes (273-276)
  • resetSortableAttributes (278-281)
tests/TestCase.php (2)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/Settings/PaginationTest.php (3)
tests/TestCase.php (3)
  • TestCase (16-171)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Endpoints/Delegates/HandlesSettings.php (3)
  • getPagination (161-164)
  • updatePagination (169-172)
  • resetPagination (174-177)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/Settings/LocalizedAttributesTest.php (3)
src/Endpoints/Delegates/HandlesIndex.php (1)
  • index (32-35)
src/Endpoints/Delegates/HandlesSettings.php (2)
  • updateLocalizedAttributes (122-125)
  • resetLocalizedAttributes (127-130)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/Endpoints/FacetSearchTest.php (2)
src/Endpoints/Delegates/HandlesSettings.php (1)
  • updateFilterableAttributes (250-253)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/Settings/FacetingAttributesTest.php (3)
src/Endpoints/Delegates/HandlesSettings.php (3)
  • getFaceting (137-141)
  • updateFaceting (146-149)
  • resetFaceting (151-154)
tests/TestCase.php (2)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Contracts/Task.php (1)
  • wait (119-130)
src/Contracts/Http.php (1)
src/Http/Client.php (3)
  • post (87-98)
  • put (108-119)
  • patch (121-129)
src/Contracts/TaskDetails/IndexDeletionDetails.php (3)
src/Contracts/Task.php (2)
  • __construct (28-43)
  • fromArray (150-184)
src/Contracts/TaskDetails/DocumentDeletionDetails.php (2)
  • __construct (23-28)
  • fromArray (30-37)
src/Contracts/TaskDetails.php (1)
  • fromArray (15-15)
src/Endpoints/Delegates/HandlesIndex.php (2)
src/Contracts/Task.php (1)
  • Task (20-185)
src/Endpoints/Indexes.php (5)
  • fetchRawInfo (130-133)
  • Indexes (27-282)
  • fetchInfo (135-140)
  • delete (147-153)
  • create (78-83)
tests/Endpoints/IndexTest.php (8)
src/Contracts/Task.php (9)
  • Task (20-185)
  • wait (119-130)
  • getIndexUid (56-59)
  • getStatus (61-64)
  • getType (66-69)
  • getDuration (89-92)
  • getStartedAt (76-79)
  • getFinishedAt (81-84)
  • getDetails (104-107)
src/Contracts/TaskDetails/IndexSwapDetails.php (1)
  • IndexSwapDetails (14-30)
src/Contracts/TaskDetails/TaskDeletionDetails.php (1)
  • TaskDeletionDetails (16-38)
src/Contracts/TasksQuery.php (1)
  • TasksQuery (9-96)
src/Endpoints/Indexes.php (4)
  • update (142-145)
  • getTasks (170-183)
  • delete (147-153)
  • swapIndexes (158-161)
src/Contracts/TasksResults.php (1)
  • getResults (42-45)
src/Endpoints/Delegates/HandlesSystem.php (1)
  • swapIndexes (51-56)
src/Endpoints/Tasks.php (1)
  • deleteTasks (38-43)
tests/Endpoints/TasksTest.php (11)
src/Contracts/Task.php (7)
  • Task (20-185)
  • getTaskUid (48-51)
  • getType (66-69)
  • getIndexUid (56-59)
  • getDetails (104-107)
  • getStatus (61-64)
  • wait (119-130)
src/Contracts/TaskDetails/DocumentAdditionOrUpdateDetails.php (1)
  • DocumentAdditionOrUpdateDetails (15-34)
src/Contracts/TaskDetails/TaskCancelationDetails.php (1)
  • TaskCancelationDetails (16-38)
src/Contracts/TasksQuery.php (4)
  • TasksQuery (9-96)
  • setLimit (54-59)
  • setBatchUid (64-69)
  • setReverse (71-76)
src/Endpoints/Indexes.php (2)
  • getTask (165-168)
  • getTasks (170-183)
src/Endpoints/Delegates/HandlesTasks.php (3)
  • getTask (18-21)
  • getTasks (23-30)
  • cancelTasks (37-40)
src/Contracts/TasksResults.php (2)
  • getResults (42-45)
  • getTotal (74-77)
tests/TestCase.php (2)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Endpoints/Delegates/HandlesDocuments.php (1)
  • updateDocuments (108-111)
src/Endpoints/Tasks.php (1)
  • cancelTasks (31-36)
src/Endpoints/Delegates/TasksQueryTrait.php (2)
  • setAfterEnqueuedAt (78-83)
  • setUids (58-63)
tests/Endpoints/SearchNestedFieldsTest.php (5)
tests/TestCase.php (2)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Endpoints/Delegates/HandlesDocuments.php (1)
  • updateDocuments (108-111)
src/Contracts/Task.php (1)
  • wait (119-130)
src/Endpoints/Delegates/HandlesSettings.php (2)
  • updateSearchableAttributes (76-79)
  • updateSortableAttributes (273-276)
src/Endpoints/Indexes.php (1)
  • updateSettings (253-256)
src/Endpoints/Tasks.php (5)
src/Contracts/Task.php (3)
  • Task (20-185)
  • fromArray (150-184)
  • isFinished (114-117)
src/functions.php (1)
  • partial (18-23)
src/Http/Client.php (3)
  • get (69-77)
  • post (87-98)
  • delete (131-139)
src/Contracts/Http.php (3)
  • get (16-16)
  • post (24-24)
  • delete (44-44)
src/Endpoints/Indexes.php (2)
  • all (85-98)
  • delete (147-153)
tests/Settings/PrefixSearchTest.php (3)
src/Endpoints/Delegates/HandlesSettings.php (3)
  • updatePrefixSearch (500-503)
  • getPrefixSearch (490-493)
  • resetPrefixSearch (508-511)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/TestCase.php (2)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Endpoints/Delegates/HandlesTasks.php (3)
src/Contracts/Task.php (1)
  • Task (20-185)
src/Contracts/TasksResults.php (1)
  • TasksResults (7-94)
src/Endpoints/Tasks.php (3)
  • Tasks (16-67)
  • deleteTasks (38-43)
  • cancelTasks (31-36)
src/Contracts/SimilarDocumentsQuery.php (2)
src/Search/SimilarDocumentsSearchResult.php (1)
  • __construct (29-38)
src/Contracts/SearchQuery.php (1)
  • setRankingScoreThreshold (275-280)
tests/Endpoints/SearchTest.php (5)
tests/TestCase.php (2)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Endpoints/Delegates/HandlesDocuments.php (2)
  • updateDocuments (108-111)
  • addDocuments (46-49)
src/Contracts/Task.php (1)
  • wait (119-130)
src/Endpoints/Indexes.php (1)
  • delete (147-153)
src/Endpoints/Delegates/HandlesSettings.php (6)
  • updateSearchableAttributes (76-79)
  • updateFilterableAttributes (250-253)
  • updateRankingRules (30-33)
  • updateSortableAttributes (273-276)
  • updateEmbedders (444-447)
  • updateLocalizedAttributes (122-125)
tests/Settings/StopWordsTest.php (2)
src/Endpoints/Delegates/HandlesSettings.php (3)
  • updateStopWords (192-195)
  • getStopWords (184-187)
  • resetStopWords (197-200)
src/Contracts/Task.php (1)
  • wait (119-130)
tests/Endpoints/DumpTest.php (2)
src/Endpoints/Delegates/HandlesDumps.php (1)
  • createDump (14-17)
src/Contracts/Task.php (1)
  • getType (66-69)
src/Endpoints/TenantToken.php (2)
src/Exceptions/InvalidArgumentException.php (2)
  • InvalidArgumentException (7-26)
  • emptyArgument (9-16)
src/Endpoints/Delegates/HandlesSystem.php (1)
  • generateTenantToken (46-49)
tests/Endpoints/ClientTest.php (3)
tests/TestCase.php (1)
  • safeIndexName (138-141)
src/Endpoints/Delegates/HandlesIndex.php (5)
  • createIndex (56-59)
  • updateIndex (64-67)
  • index (32-35)
  • getIndex (40-43)
  • deleteIndex (48-51)
src/Contracts/Task.php (2)
  • wait (119-130)
  • getIndexUid (56-59)
src/Contracts/Task.php (14)
src/Contracts/TaskDetails/DocumentAdditionOrUpdateDetails.php (3)
  • DocumentAdditionOrUpdateDetails (15-34)
  • __construct (21-25)
  • fromArray (27-33)
src/Contracts/TaskDetails/DocumentDeletionDetails.php (3)
  • DocumentDeletionDetails (16-38)
  • __construct (23-28)
  • fromArray (30-37)
src/Contracts/TaskDetails/DocumentEditionDetails.php (3)
  • DocumentEditionDetails (18-42)
  • __construct (23-30)
  • fromArray (32-41)
src/Contracts/TaskDetails/DumpCreationDetails.php (3)
  • DumpCreationDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/IndexCreationDetails.php (3)
  • IndexCreationDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/IndexDeletionDetails.php (3)
  • IndexDeletionDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/IndexSwapDetails.php (3)
  • IndexSwapDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/IndexUpdateDetails.php (3)
  • IndexUpdateDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/SettingsUpdateDetails.php (3)
  • SettingsUpdateDetails (55-148)
  • __construct (99-121)
  • fromArray (123-147)
src/Contracts/TaskDetails/TaskCancelationDetails.php (3)
  • TaskCancelationDetails (16-38)
  • __construct (23-28)
  • fromArray (30-37)
src/Contracts/TaskDetails/TaskDeletionDetails.php (3)
  • TaskDeletionDetails (16-38)
  • __construct (23-28)
  • fromArray (30-37)
src/Exceptions/LogicException.php (1)
  • LogicException (7-9)
src/Contracts/TaskError.php (3)
  • __construct (15-21)
  • TaskError (7-40)
  • fromArray (31-39)
src/Contracts/TaskDetails.php (1)
  • fromArray (15-15)
src/Contracts/TaskDetails/DocumentAdditionOrUpdateDetails.php (2)
src/Contracts/Task.php (1)
  • fromArray (150-184)
src/Contracts/TaskDetails.php (1)
  • fromArray (15-15)
tests/Contracts/TaskTest.php (8)
src/Contracts/Task.php (14)
  • Task (20-185)
  • getTaskUid (48-51)
  • getIndexUid (56-59)
  • getStatus (61-64)
  • getType (66-69)
  • getEnqueuedAt (71-74)
  • getStartedAt (76-79)
  • getFinishedAt (81-84)
  • getDuration (89-92)
  • getCanceledBy (94-97)
  • getBatchUid (99-102)
  • getDetails (104-107)
  • getError (109-112)
  • wait (119-130)
src/Contracts/TaskDetails/IndexCreationDetails.php (1)
  • IndexCreationDetails (14-30)
src/Contracts/TaskError.php (1)
  • TaskError (7-40)
src/Exceptions/LogicException.php (1)
  • LogicException (7-9)
tests/MockTask.php (2)
  • MockTask (11-23)
  • create (13-22)
src/Endpoints/Indexes.php (1)
  • create (78-83)
src/Endpoints/Dumps.php (1)
  • create (16-19)
src/Endpoints/Snapshots.php (1)
  • create (16-19)
tests/Settings/FilterableAttributesTest.php (3)
src/Endpoints/Delegates/HandlesSettings.php (3)
  • getFilterableAttributes (237-240)
  • updateFilterableAttributes (250-253)
  • resetFilterableAttributes (255-258)
tests/TestCase.php (2)
  • createEmptyIndex (131-136)
  • safeIndexName (138-141)
src/Contracts/Task.php (1)
  • wait (119-130)
src/Endpoints/Delegates/HandlesDocuments.php (6)
src/Contracts/Task.php (2)
  • Task (20-185)
  • fromArray (150-184)
src/Endpoints/Tasks.php (2)
  • Tasks (16-67)
  • waitTask (50-66)
src/functions.php (1)
  • partial (18-23)
src/Http/Client.php (3)
  • post (87-98)
  • put (108-119)
  • delete (131-139)
src/Contracts/Http.php (3)
  • post (24-24)
  • put (32-32)
  • delete (44-44)
src/Endpoints/Indexes.php (1)
  • delete (147-153)
src/Endpoints/Delegates/HandlesSettings.php (6)
src/Contracts/Task.php (2)
  • Task (20-185)
  • fromArray (150-184)
src/Endpoints/Tasks.php (3)
  • Tasks (16-67)
  • waitTask (50-66)
  • get (20-23)
src/functions.php (1)
  • partial (18-23)
src/Http/Client.php (4)
  • put (108-119)
  • delete (131-139)
  • patch (121-129)
  • get (69-77)
src/Contracts/Http.php (4)
  • put (32-32)
  • delete (44-44)
  • patch (38-38)
  • get (16-16)
src/Endpoints/Indexes.php (1)
  • delete (147-153)
🪛 GitHub Actions: Tests
tests/Endpoints/IndexTest.php

[error] 251-251: PHP-CS-Fixer formatting check failed due to indentation issue. Run 'vendor/bin/php-cs-fixer fix' to apply fixes.

🪛 GitHub Check: phpstan-tests
tests/Endpoints/IndexTest.php

[failure] 253-253:
Undefined variable: $response


[failure] 252-252:
Undefined variable: $response


[failure] 251-251:
Undefined variable: $response


[failure] 250-250:
Undefined variable: $response

🪛 PHPMD (2.15.0)
tests/Endpoints/IndexTest.php

248-248: Avoid unused local variables such as '$task'. (undefined)

(UnusedLocalVariable)

🔇 Additional comments (40)
src/Exceptions/CommunicationException.php (1)

9-12: LGTM! Type declaration aligns with PHP 8.1 best practices.

The explicit : string return type improves type safety and is consistent with other exception classes in the codebase (ApiException, InvalidResponseBodyException, TimeOutException).

src/Endpoints/Delegates/HandlesBatches.php (1)

15-15: LGTM! Parameter type addition improves type safety.

The addition of the int type declaration for the $uid parameter aligns with the PR's goal of improving type safety and is consistent with the underlying Batches::get(int $batchUid) method signature.

phpunit.xml.dist (1)

2-37: LGTM! Enhanced test strictness aligns with v2 type safety goals.

The PHPUnit configuration improvements include:

  • Display attributes (lines 10-14) that surface detailed information about deprecations, errors, notices, and warnings during test runs
  • Schema location (line 4) changed to use the local vendor path instead of a remote URL, ensuring consistency with the installed PHPUnit version
  • Suppression-ignoring attributes (lines 26-32) that report issues even when suppressed with the @ operator

These stricter settings are appropriate for a v2 release focused on type safety and will help catch potential issues early.

src/Http/Serialize/SerializerInterface.php (1)

16-16: LGTM! Type safety improvement for serialize.

The explicit mixed $data parameter and : string return type improve type safety and align well with the PR objective. The docblock's more specific union type provides valuable additional information for static analyzers.

src/Contracts/SimilarDocumentsQuery.php (2)

45-45: Good improvement: explicit default and type declaration.

Adding the explicit = null default and int|float|null type declaration improves clarity and type safety. This aligns well with the PR's goal of stronger typing.


51-55: Type safety improvements look good.

Adding explicit type declarations to the constructor parameters aligns well with the PR's PHP 8.1 upgrade and type safety objectives. The constructor now enforces types at runtime, improving robustness.

.php-cs-fixer.dist.php (1)

18-19: LGTM! Configuration changes align with PR objectives.

The php_unit_strict rule is appropriately disabled to prevent test breakage from automatic assertEquals to assertSame conversions. The addition of 'parameters' to trailing_comma_in_multiline is consistent with modern PHP 8.1+ coding standards and improves code maintainability.

tests/Settings/FacetingAttributesTest.php (1)

20-48: LGTM! Clean migration to Task-based API.

The refactoring successfully migrates from promise-based task handling to the new fluent Task API with inline ->wait() chaining. This eliminates intermediate variables and improves readability while maintaining the same test coverage.

tests/Settings/LocalizedAttributesTest.php (1)

28-45: LGTM! Consistent Task-based refactoring.

The test methods properly utilize the new Task API with inline ->wait() calls, eliminating the need for intermediate promise storage and separate task waiting logic.

tests/Settings/StopWordsTest.php (1)

30-41: LGTM! Clean Task-based implementation.

The migration to the Task API is well-executed, with direct ->wait() chaining that simplifies the test logic and improves code clarity.

tests/Settings/SortableAttributesTest.php (1)

15-37: LGTM! Successful Task-based migration.

All test methods correctly implement the new fluent Task API, using ->wait() for synchronous task completion and direct assertions on the resulting state.

src/Client.php (1)

56-56: LGTM! Trailing comma improves maintainability.

Adding a trailing comma after the last parameter is consistent with modern PHP 8.1+ best practices and the trailing_comma_in_multiline rule enabled in this PR. This makes future parameter additions cleaner in version control diffs.

composer.json (4)

34-34: LGTM! PHP 8.1 requirement aligns with PR objectives.

The PHP version bump to 8.1 is intentional and documented in the PR objectives. This enables the use of modern PHP features like mixed types, readonly properties, and other enhancements that support the Task-based API improvements.


44-47: LGTM! Files autoload enables the partial() helper.

Adding src/functions.php to the autoload files is necessary for the new partial() helper function used throughout the codebase for binding wait callbacks in Task-based operations.


60-60: LGTM! PHPUnit 10.5 aligns with PHP 8.1 requirement.

Consolidating to PHPUnit 10.5 only is appropriate given the PHP 8.1 minimum requirement, as PHPUnit 10 requires PHP 8.1+.


36-36: I'll search for more specific information about the php-http/discovery package and its compatibility.

No incompatibility issues found with php-http/discovery 1.19.

The package requires PHP ^7.1 || ^8.0, which includes PHP 8.1. Recent releases include fixes for compatibility with PHP 8.4 and Symfony 7, indicating active maintenance. The version increment from 1.7 to 1.19 remains within the stable 1.x series with no breaking changes documented that would impact this upgrade.

tests/Endpoints/DumpTest.php (1)

7-16: LGTM! Clean migration to Task-based assertion.

The test correctly migrates from array key validation to type-safe Task object assertions using the TaskType enum. This aligns well with the PR's goal of replacing array returns with strongly-typed objects.

tests/Endpoints/FacetSearchTest.php (1)

21-21: LGTM! Cleaner fluent wait pattern.

The test now uses a direct chained wait instead of the two-step promise pattern, making the code more concise and leveraging the new Task-based API effectively.

src/Endpoints/Delegates/HandlesTasks.php (2)

18-21: Breaking change: Task-based return type improves type safety.

The method signature now enforces int $uid and returns a strongly-typed Task object instead of an array, which is a breaking change but aligns with the PR's core objective. This provides better developer experience with IDE autocomplete and static analysis.


32-40: Breaking change: Task-based returns and wait methods moved to Task class.

The deleteTasks and cancelTasks methods now return Task objects instead of arrays. The previous waitForTask() and waitForTasks() methods have been removed in favor of calling ->wait() directly on the returned Task object, enabling fluent chaining like $client->deleteTasks(...)->wait().

src/Exceptions/LogicException.php (1)

1-9: LGTM! Standard domain-specific exception.

This follows the established pattern of wrapping PHP's built-in exceptions with library-specific implementations that implement ExceptionInterface. Used appropriately in Task::wait() when the wait function is not provided.

tests/Settings/FacetSearchTest.php (2)

20-27: LGTM! Simplified test with fluent wait chaining.

The test now uses the new Task-based wait pattern, eliminating intermediate promise variables and making the test flow more readable.


29-37: LGTM! Clean sequential task pattern.

The sequential wait pattern (update->wait(); reset->wait()) clearly expresses the test flow and ensures operations complete before assertions.

src/functions.php (1)

7-23: LGTM! Well-documented partial application helper.

The partial() function provides a clean way to bind arguments (like the HTTP client) to create reusable wait callbacks. The implementation is correct, and the documentation clearly explains its purpose and usage. The @internal annotation appropriately indicates this is for internal SDK use.

tests/Settings/PrefixSearchTest.php (2)

20-26: LGTM! Clean Task-based wait pattern.

The test correctly uses the fluent ->wait() chaining introduced by the Task object, making the test more concise and readable compared to the previous promise-based approach.


28-36: LGTM! Sequential waits properly ensure operation completion.

The sequential pattern with explicit waits ensures each operation completes before the next one begins, which is correct for testing reset functionality.

tests/Endpoints/MultiSearchTest.php (1)

29-29: LGTM! Task-based fluent wait pattern correctly applied.

The changes successfully migrate from the old promise-based pattern to the new Task-based fluent API. Using ->wait() inline simplifies the test setup and aligns with the PR's objective to introduce typed Task objects.

Also applies to: 37-37

src/Endpoints/Snapshots.php (1)

16-18: LGTM! Correctly migrated to Task-based return.

The endpoint properly wraps the HTTP response with Task::fromArray and binds the wait callback using partial(Tasks::waitTask(...), $this->http), consistent with the pattern used across other endpoints in this PR.

tests/Settings/SeparatorTokensTest.php (1)

37-39: LGTM! Tests correctly updated to Task-based pattern.

The tests now use the fluent ->wait() API instead of capturing task UIDs and waiting separately. This simplifies the test flow and is consistent with the Task-based approach adopted throughout the PR.

Also applies to: 44-47

tests/Settings/PaginationTest.php (1)

32-37: LGTM! Pagination tests follow the Task-based pattern correctly.

The tests properly use the fluent ->wait() API for asynchronous operations and assert results directly via getPagination(). The implementation is consistent with other settings tests in the suite.

Also applies to: 39-45

tests/MockTask.php (1)

13-22: LGTM! Useful test helper with sensible defaults.

The MockTask helper provides a convenient way to create Task instances for testing with reasonable defaults. The use of named parameters for the await closure is correct and aligns with the Task constructor signature.

tests/Settings/FilterableAttributesTest.php (1)

23-25: LGTM! FilterableAttributes tests properly migrated to Task pattern.

All test methods correctly use the fluent ->wait() API and assert results directly. The migration is consistent with the Task-based approach used throughout the test suite.

Also applies to: 33-36, 57-59, 66-83

src/Contracts/TaskType.php (1)

7-21: LGTM! Clean enum definition.

The TaskType enum is well-structured with comprehensive coverage of Meilisearch task types. The string-backed values follow consistent camelCase naming.

src/Endpoints/Delegates/HandlesIndex.php (1)

9-67: LGTM! Task-based return types enable fluent API.

The updated method signatures returning Task instead of array align perfectly with the PR's Task-based refactoring. The added PHPDoc non-empty-string annotations improve type safety for static analysis.

tests/Endpoints/ClientTest.php (1)

91-141: LGTM! Tests correctly demonstrate the new Task-based API.

The test updates showcase the fluent chaining pattern (->wait()) and typed accessors (->getIndexUid()). The method rename (line 91) also fixes the capitalization inconsistency.

src/Endpoints/TenantToken.php (1)

21-32: LGTM! Empty object validation fixed.

The cast to array on line 26 correctly addresses the past review concern. Both empty arrays and empty objects are now properly rejected before they can produce invalid tenant tokens.

tests/Contracts/TaskTest.php (1)

84-114: LGTM! Comprehensive Task behavior coverage.

The wait mechanism tests properly exercise both async completion (lines 84-94) and immediate return for finished tasks (lines 96-104). The exception test (lines 106-114) correctly validates the error case when no await function is provided.

tests/Endpoints/DocumentsTest.php (1)

75-79: LGTM! Excellent demonstration of Task-based assertions.

This segment showcases the benefits of the new API: typed status checks via TaskStatus enum and structured details access through DocumentAdditionOrUpdateDetails. This pattern should be used throughout the test suite.

tests/Endpoints/SearchNestedFieldsTest.php (1)

19-111: LGTM! Clean migration and typo fixes.

The file demonstrates consistent adoption of the Task-based API with ->wait() chaining (lines 19, 70, 88, 108-111). The method name corrections (lines 68, 86, 106) fix "Atributes" → "Attributes" typos, improving code quality.

tests/Endpoints/SimilarDocumentsTest.php (1)

25-25: LGTM! Correctly adopts the new Task-based API.

The change properly uses the new fluent chaining pattern with ->wait() on the Task object returned by updateSettings(), ensuring the embedders configuration is applied before the similar documents search is performed.

Comment on lines +24 to +29
public static function fromArray(array $data): self
{
return new self(
$data['deletedDocuments'],
);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add null coalescing operator for nullable field.

The deletedDocuments property is nullable, and the docblock indicates it's null while the task is enqueued or processing. However, the fromArray method doesn't guard against a missing array key, which could trigger an undefined index warning.

For consistency with DocumentDeletionDetails (shown in relevant snippets), use the null coalescing operator:

     public static function fromArray(array $data): self
     {
         return new self(
-            $data['deletedDocuments'],
+            $data['deletedDocuments'] ?? null,
         );
     }
🤖 Prompt for AI Agents
In src/Contracts/TaskDetails/IndexDeletionDetails.php around lines 24 to 29, the
fromArray method accesses $data['deletedDocuments'] directly which can raise an
undefined index warning for the nullable deletedDocuments field; change it to
use the null coalescing operator to default to null (e.g.
$data['deletedDocuments'] ?? null) so the constructor receives null when the key
is absent.

Comment on lines +30 to +37
public static function fromArray(array $data): self
{
return new self(
$data['matchedTasks'],
$data['canceledTasks'],
$data['originalFilter'],
);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Verify array key existence to prevent undefined index warnings.

The fromArray method directly accesses array keys without checking their existence. If the Meilisearch API response omits these keys in certain scenarios, this will trigger undefined array key warnings in PHP 8.

Note that DocumentDeletionDetails uses the null coalescing operator ($data['providedIds'] ?? null) while TaskDeletionDetails uses direct access like this implementation. For consistency and defensive coding, consider using the null coalescing operator.

Apply this diff if keys might be absent:

 public static function fromArray(array $data): self
 {
     return new self(
-        $data['matchedTasks'],
-        $data['canceledTasks'],
-        $data['originalFilter'],
+        $data['matchedTasks'] ?? null,
+        $data['canceledTasks'] ?? null,
+        $data['originalFilter'] ?? null,
     );
 }

Run the following script to verify consistency across TaskDetails implementations and check whether the API guarantees these keys:


🏁 Script executed:

#!/bin/bash
# Check how other TaskDetails implementations handle array access
echo "=== Checking fromArray patterns across TaskDetails implementations ==="
rg -A 10 'public static function fromArray\(array \$data\): self' --type php -g 'src/Contracts/TaskDetails/*.php'

echo ""
echo "=== Looking for usages with potentially missing keys ==="
rg 'TaskCancelationDetails::fromArray' --type php -B 3 -A 3

Length of output: 8156


I need to gather more information about how the API responses are tested and whether keys can be missing.

Let me search for test files and more specific information about task cancelation.

The evidence shows critical findings. Let me check the constructor of TaskCancelationDetails to understand what types it accepts:

Let me search the codebase directly for the TaskCancelationDetails class definition:

You have used 50,500 tokens so far (25% of your available budget). You have 149,500 tokens remaining.

Based on my verification, I found real API responses where canceledTasks can be null while a task is processing. Combined with the codebase evidence showing inconsistent patterns across TaskDetails implementations where some use defensive null coalescing and others don't, the review comment's concern is valid.

The issue is that TaskCancelationDetails and TaskDeletionDetails use direct array access without null coalescing, while DocumentDeletionDetails and SettingsUpdateDetails use the null coalescing operator.

Use the null coalescing operator on all three array keys in TaskCancelationDetails::fromArray().

Apply the suggested diff to add defensive null coalescing to matchedTasks, canceledTasks, and originalFilter keys, ensuring consistency with DocumentDeletionDetails and handling cases where the API response omits these keys or returns null values.

 public static function fromArray(array $data): self
 {
     return new self(
-        $data['matchedTasks'],
-        $data['canceledTasks'],
-        $data['originalFilter'],
+        $data['matchedTasks'] ?? null,
+        $data['canceledTasks'] ?? null,
+        $data['originalFilter'] ?? null,
     );
 }

🏁 Script executed:

#!/bin/bash
# Find TaskCancelationDetails class definition and constructor
echo "=== TaskCancelationDetails class definition ==="
cat src/Contracts/TaskDetails/TaskCancelationDetails.php

echo ""
echo "=== Check if constructor uses nullable types or has defaults ==="
rg -A 20 'class TaskCancelationDetails' src/Contracts/TaskDetails/TaskCancelationDetails.php

Length of output: 2364


Use the null coalescing operator on all three array keys in TaskCancelationDetails::fromArray().

The constructor already declares these parameters as nullable (?int and ?string), and the documentation explicitly states that canceledTasks will be null during enqueued or processing status. The fromArray() method must defensively handle cases where these keys are missing or omitted from the API response, which will cause undefined array key errors in PHP 8.1+.

 public static function fromArray(array $data): self
 {
     return new self(
-        $data['matchedTasks'],
-        $data['canceledTasks'],
-        $data['originalFilter'],
+        $data['matchedTasks'] ?? null,
+        $data['canceledTasks'] ?? null,
+        $data['originalFilter'] ?? null,
     );
 }
🤖 Prompt for AI Agents
In src/Contracts/TaskDetails/TaskCancelationDetails.php around lines 30 to 37,
fromArray() directly indexes $data['matchedTasks'], $data['canceledTasks'], and
$data['originalFilter'] which can throw "undefined index" errors; change each to
use the null coalescing operator (e.g. $data['matchedTasks'] ?? null,
$data['canceledTasks'] ?? null, $data['originalFilter'] ?? null) so the nullable
constructor parameters receive null when keys are missing.

Copy link

@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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db46570 and 288f6c5.

📒 Files selected for processing (6)
  • .github/workflows/meilisearch-beta-tests.yml (1 hunks)
  • .github/workflows/pre-release-tests.yml (1 hunks)
  • .github/workflows/tests.yml (1 hunks)
  • src/Http/Serialize/Json.php (1 hunks)
  • src/Http/Serialize/SerializerInterface.php (2 hunks)
  • tests/Endpoints/IndexTest.php (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Http/Serialize/SerializerInterface.php
  • src/Http/Serialize/Json.php
🧰 Additional context used
🧬 Code graph analysis (1)
tests/Endpoints/IndexTest.php (7)
src/Contracts/Task.php (9)
  • Task (20-185)
  • wait (119-130)
  • getIndexUid (56-59)
  • getStatus (61-64)
  • getType (66-69)
  • getDuration (89-92)
  • getStartedAt (76-79)
  • getFinishedAt (81-84)
  • getDetails (104-107)
src/Contracts/TaskDetails/IndexSwapDetails.php (1)
  • IndexSwapDetails (14-30)
src/Contracts/TaskDetails/TaskDeletionDetails.php (1)
  • TaskDeletionDetails (16-38)
src/Contracts/TasksQuery.php (1)
  • TasksQuery (9-96)
src/Endpoints/Delegates/HandlesIndex.php (3)
  • index (32-35)
  • getIndex (40-43)
  • createIndex (56-59)
src/Endpoints/Indexes.php (4)
  • update (142-145)
  • getTasks (170-183)
  • delete (147-153)
  • swapIndexes (158-161)
src/Endpoints/Delegates/HandlesDocuments.php (1)
  • addDocuments (46-49)
🪛 GitHub Check: phpstan-tests
tests/Endpoints/IndexTest.php

[failure] 254-254:
Offset 'rename' does not exist on array{indexes: array{'indexC', 'indexD'}}.


[failure] 253-253:
Offset 'rename' does not exist on array{indexes: array{'indexA', 'indexB'}}.

🔇 Additional comments (10)
.github/workflows/tests.yml (1)

80-80: PHP test matrix properly narrowed to align with 8.1+ requirement.

The version matrix now tests against PHP 8.1, 8.2, 8.3, and 8.4, correctly reflecting the minimum version bump. This is consistent with the PR objective and aligns with the PHP ^8.1 requirement in composer.json.

Note: The v1.x branch (line 9) will also use this newer matrix. Verify this is intentional or consider branch-specific matrix configuration if v1.x should maintain legacy PHP support separately.

.github/workflows/pre-release-tests.yml (1)

43-43: Pre-release test matrix correctly updated to PHP 8.1–8.4.

Consistent with the version narrowing in the main tests workflow and aligned with the PHP ^8.1 requirement.

.github/workflows/meilisearch-beta-tests.yml (1)

43-43: Beta test matrix correctly updated to PHP 8.1–8.4.

Consistent with the version narrowing across all three test workflows, properly reflecting the PHP ^8.1 requirement.

tests/Endpoints/IndexTest.php (7)

8-13: LGTM!

The new imports align perfectly with the Task-based API migration and are used consistently throughout the test file.


118-129: LGTM!

The refactoring correctly uses the Task API with wait() chaining and typed getIndexUid() accessor.


173-186: LGTM!

The test correctly uses Task->getIndexUid() in the array mapping and properly chains wait() calls.


188-219: LGTM!

The wait tests thoroughly cover different timeout/interval combinations and correctly assert on TaskStatus/TaskType enums and nullable timestamp fields.


221-228: LGTM!

The test correctly validates timeout handling by calling wait(0, 20) to force an immediate timeout and expects TimeOutException.


230-244: LGTM!

The test correctly validates the immediate Task response from delete() without waiting for completion, which is appropriate for verifying task metadata.


257-263: LGTM!

The test correctly validates task deletion by accessing typed details through TaskDeletionDetails and its originalFilter property.

@norkunas
Copy link
Collaborator Author

@Strift enums basically are already value objects, so I don't see a point in wrapping them.
I've added Unknown values to enums itself. Can you please recheck the PR? I've rebased to fix conflicts (oh boy, it took some time.. :D), i hope this will be okay for you

@norkunas
Copy link
Collaborator Author

norkunas commented Nov 17, 2025

Btw integration-tests (PHP 8.4) and integration-tests (PHP 8.0) should be removed from repo settings as required jobs.

Copy link
Collaborator

@Strift Strift left a comment

Choose a reason for hiding this comment

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

Great work! All things LGTM now.

I have a question regarding the parsing of task types/statuses. Should we add a PSR-3 warning?

e.g. "Unknown Meilisearch task status: <status>; mapped to TaskStatus::Unknown. Consider upgrading the SDK for typed support."

@norkunas
Copy link
Collaborator Author

norkunas commented Nov 17, 2025

Great work! All things LGTM now.

I have a question regarding the parsing of task types/statuses. Should we add a PSR-3 warning?

e.g. "Unknown Meilisearch task status: <status>; mapped to TaskStatus::Unknown. Consider upgrading the SDK for typed support."

Well for now this library did not depend on the PSR-3, but sure we can adopt it if you want :) This can be for follow-up PR, with a new issue opened

Copy link

@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: 0

🧹 Nitpick comments (1)
src/Contracts/TaskDetails/UnknownTaskDetails.php (1)

9-20: Consider clarifying PHPDoc type parameter.

The PHPDoc declares @implements TaskDetails<array{}> (empty array shape) but the constructor accepts array<mixed> and can store arbitrary data. Since UnknownTaskDetails is designed to handle any unknown task detail structure, the PHPDoc type parameter should likely be array<mixed> or array<array-key, mixed> for accuracy.

Apply this diff if you want the PHPDoc to match the actual behavior:

 /**
- * @implements TaskDetails<array{}>
+ * @implements TaskDetails<array<mixed>>
  */
 final class UnknownTaskDetails implements TaskDetails
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 288f6c5 and e7ec932.

📒 Files selected for processing (11)
  • src/Contracts/Http.php (2 hunks)
  • src/Contracts/Task.php (1 hunks)
  • src/Contracts/TaskDetails/IndexSwapDetails.php (1 hunks)
  • src/Contracts/TaskDetails/UnknownTaskDetails.php (1 hunks)
  • src/Contracts/TaskStatus.php (1 hunks)
  • src/Contracts/TaskType.php (1 hunks)
  • src/Endpoints/Delegates/HandlesSettings.php (21 hunks)
  • src/Http/Client.php (7 hunks)
  • tests/Endpoints/DocumentsTest.php (40 hunks)
  • tests/Endpoints/MultiModalSearchTest.php (1 hunks)
  • tests/Settings/ChatTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Contracts/TaskDetails/IndexSwapDetails.php
  • src/Contracts/Http.php
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-20T05:05:22.383Z
Learnt from: bpolaszek
Repo: meilisearch/meilisearch-php PR: 779
File: tests/Endpoints/DocumentsTest.php:669-682
Timestamp: 2025-08-20T05:05:22.383Z
Learning: In Meilisearch, tasks have implicit dependencies where document operations (like addDocuments) won't be processed until prerequisite setting tasks (like updateSortableAttributes, updateFilterableAttributes) have completed. Therefore, waiting for the addDocuments task completion implicitly ensures that all prerequisite setting tasks have also completed.

Applied to files:

  • tests/Endpoints/DocumentsTest.php
🧬 Code graph analysis (7)
tests/Endpoints/MultiModalSearchTest.php (2)
src/Contracts/Task.php (1)
  • wait (120-131)
src/Endpoints/Delegates/HandlesDocuments.php (1)
  • addDocuments (46-49)
tests/Settings/ChatTest.php (2)
src/Endpoints/Delegates/HandlesSettings.php (1)
  • updateChat (596-599)
src/Contracts/Task.php (1)
  • wait (120-131)
src/Contracts/TaskDetails/UnknownTaskDetails.php (1)
src/Contracts/Task.php (2)
  • __construct (29-44)
  • fromArray (151-187)
tests/Endpoints/DocumentsTest.php (5)
src/Contracts/Task.php (4)
  • Task (21-188)
  • wait (120-131)
  • getStatus (62-65)
  • getDetails (105-108)
src/Contracts/TaskDetails/DocumentAdditionOrUpdateDetails.php (1)
  • DocumentAdditionOrUpdateDetails (15-34)
tests/MockTask.php (2)
  • MockTask (11-23)
  • create (13-22)
src/Endpoints/Delegates/HandlesDocuments.php (18)
  • addDocuments (46-49)
  • addDocumentsInBatches (69-78)
  • addDocumentsCsv (56-59)
  • addDocumentsJson (51-54)
  • addDocumentsNdjson (61-64)
  • getDocument (21-26)
  • updateDocuments (108-111)
  • updateDocumentsInBatches (131-140)
  • addDocumentsCsvInBatches (83-92)
  • addDocumentsNdjsonInBatches (97-106)
  • deleteDocument (190-193)
  • deleteDocuments (195-208)
  • deleteAllDocuments (185-188)
  • updateDocumentsJson (113-116)
  • updateDocumentsCsv (118-121)
  • updateDocumentsNdjson (123-126)
  • updateDocumentsCsvInBatches (145-154)
  • updateDocumentsNdjsonInBatches (159-168)
src/Endpoints/Delegates/HandlesSettings.php (1)
  • updateEmbedders (444-447)
src/Http/Client.php (1)
src/Contracts/Http.php (4)
  • post (24-24)
  • put (32-32)
  • patch (38-38)
  • postStream (50-50)
src/Contracts/Task.php (15)
src/Contracts/TaskDetails/DocumentAdditionOrUpdateDetails.php (3)
  • DocumentAdditionOrUpdateDetails (15-34)
  • __construct (21-25)
  • fromArray (27-33)
src/Contracts/TaskDetails/DocumentDeletionDetails.php (3)
  • DocumentDeletionDetails (16-38)
  • __construct (23-28)
  • fromArray (30-37)
src/Contracts/TaskDetails/DocumentEditionDetails.php (3)
  • DocumentEditionDetails (18-42)
  • __construct (23-30)
  • fromArray (32-41)
src/Contracts/TaskDetails/DumpCreationDetails.php (3)
  • DumpCreationDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/IndexCreationDetails.php (3)
  • IndexCreationDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/IndexDeletionDetails.php (3)
  • IndexDeletionDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/IndexSwapDetails.php (3)
  • IndexSwapDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/IndexUpdateDetails.php (3)
  • IndexUpdateDetails (14-30)
  • __construct (19-22)
  • fromArray (24-29)
src/Contracts/TaskDetails/SettingsUpdateDetails.php (3)
  • SettingsUpdateDetails (55-148)
  • __construct (99-121)
  • fromArray (123-147)
src/Contracts/TaskDetails/TaskCancelationDetails.php (3)
  • TaskCancelationDetails (16-38)
  • __construct (23-28)
  • fromArray (30-37)
src/Contracts/TaskDetails/TaskDeletionDetails.php (3)
  • TaskDeletionDetails (16-38)
  • __construct (23-28)
  • fromArray (30-37)
src/Contracts/TaskDetails/UnknownTaskDetails.php (3)
  • UnknownTaskDetails (12-26)
  • __construct (17-20)
  • fromArray (22-25)
src/Exceptions/LogicException.php (1)
  • LogicException (7-9)
src/Contracts/TaskError.php (3)
  • __construct (15-21)
  • TaskError (7-40)
  • fromArray (31-39)
src/Contracts/TaskDetails.php (1)
  • fromArray (15-15)
src/Endpoints/Delegates/HandlesSettings.php (6)
src/Contracts/Task.php (2)
  • Task (21-188)
  • fromArray (151-187)
src/Endpoints/Tasks.php (3)
  • Tasks (16-67)
  • waitTask (50-66)
  • get (20-23)
src/functions.php (1)
  • partial (18-23)
src/Http/Client.php (4)
  • put (108-119)
  • delete (131-139)
  • patch (121-129)
  • get (69-77)
src/Contracts/Http.php (4)
  • put (32-32)
  • delete (44-44)
  • patch (38-38)
  • get (16-16)
src/Endpoints/Indexes.php (1)
  • delete (147-153)
🔇 Additional comments (24)
src/Http/Client.php (4)

43-50: LGTM: Trailing comma improves maintainability.

The trailing comma in the constructor parameter list aligns with the enabled trailing_comma_in_multiline coding style rule and makes future parameter additions cleaner in diffs.


87-87: LGTM: Explicit mixed type aligns with interface contract.

The explicit mixed type declaration for the $body parameter across post(), put(), patch(), and postStream() methods correctly aligns with the updated interface signatures in src/Contracts/Http.php. The implementations properly handle serialization and document \JsonException in their throws clauses.

Also applies to: 108-108, 121-121, 147-147


216-228: LGTM: Explicit empty-array check improves URL formatting.

The explicit [] !== $queryParams guard prevents appending a trailing ? when no query parameters are present, resulting in cleaner URLs. This is a functional improvement over relying on implicit behavior.


261-264: LGTM: Cleaner implementation with modern PHP syntax.

The refactored isJSONResponse() using array_filter() with a static arrow function and str_contains() is more readable and idiomatic for PHP 8.1+. The string type hint on the parameter correctly matches PSR-7's getHeader() return type.

src/Contracts/TaskType.php (1)

7-22: LGTM! Well-structured enum with forward compatibility.

The string-backed enum correctly defines all known Meilisearch task types with the Unknown case providing graceful fallback for future task types. The DocumentEdition case has been validated against Meilisearch documentation per past discussions.

src/Contracts/TaskStatus.php (1)

14-14: LGTM! Unknown case enables forward compatibility.

The addition of the Unknown status case follows the same graceful fallback pattern as TaskType, allowing the SDK to handle new task statuses introduced in future Meilisearch versions without breaking.

tests/Endpoints/MultiModalSearchTest.php (2)

29-34: LGTM! Clean migration to fluent Task-based waiting.

The change from promise-based handling to fluent ->wait() chaining simplifies the test setup while maintaining the same synchronous behavior.


39-39: LGTM! Consistent with fluent wait pattern.

The addDocuments call now uses the same fluent ->wait() pattern as updateSettings above, creating a consistent and readable test setup.

tests/Settings/ChatTest.php (1)

57-57: LGTM! Consistent fluent wait pattern.

The migration from promise-based handling to fluent ->wait() simplifies the test code while maintaining identical behavior.

tests/Endpoints/DocumentsTest.php (6)

9-18: LGTM! Import changes align with Task-based refactor.

The imports correctly add the new Task-related types and remove the now-unused InvalidArgumentException, reflecting the shift to Task-based async handling throughout the test suite.


26-26: LGTM! Clean fluent wait pattern.

The direct ->wait() call eliminates the unused variable noted in past reviews while maintaining the same synchronous test behavior.


35-41: LGTM! Correct batch Task handling.

The code properly captures the Task array returned by addDocumentsInBatches and waits for each task in a loop, correctly handling the batch operation semantics.


75-79: LGTM! Proper Task status and details validation.

The test correctly validates the Task status and asserts on the typed DocumentAdditionOrUpdateDetails, demonstrating proper use of the new Task object model.


369-384: LGTM! Correct MockTask usage in test expectations.

The test properly uses MockTask::create(TaskType::DocumentEdition) to create stub Task objects in the mocked method callback, correctly modeling the new Task-based return type.


896-896: LGTM! Improved type signature.

The explicit ?array return type improves type safety and makes the nullable return clearer compared to the previous implicit mixed return type.

src/Contracts/Task.php (5)

29-44: LGTM! Well-typed immutable constructor.

The constructor properly defines all Task properties as readonly with appropriate types, including the optional $await closure for wait functionality. The PHPDoc accurately describes the closure signature.


49-113: LGTM! Complete getter coverage with correct types.

All readonly properties have corresponding getter methods with accurate return types and PHPDoc annotations, providing a clean public API for Task inspection.


115-118: LGTM! Correct finished state logic.

The isFinished() method correctly identifies a task as finished when it's neither Enqueued nor Processing, matching Meilisearch task lifecycle semantics.


120-131: LGTM! Well-implemented wait method with proper error handling.

The wait method correctly short-circuits for already-finished tasks, invokes the await closure when provided, and throws a clear LogicException when wait functionality is unavailable. The default timeout and interval values are reasonable.


151-187: LGTM! Comprehensive factory with proper type mapping.

The fromArray factory correctly:

  • Handles legacy uid fallback for taskUid
  • Uses ?? null for optional indexUid as resolved in past reviews
  • Gracefully handles unknown types/statuses with tryFrom and Unknown fallback
  • Maps task types to appropriate TaskDetails implementations
  • Includes explanatory comment for SnapshotCreation's null details
  • Properly handles optional error and await closure

This implementation provides excellent forward compatibility with future Meilisearch versions.

src/Endpoints/Delegates/HandlesSettings.php (4)

10-13: LGTM! Correct imports for Task-based pattern.

The imports properly add Task, Tasks endpoint, and the partial function needed for binding wait callbacks to all mutating operations.


30-37: LGTM! Consistent Task-based mutator pattern.

Both updateRankingRules and resetRankingRules correctly return Task objects with the wait callback bound via partial(Tasks::waitTask(...), $this->http), establishing the pattern followed throughout this file.


410-424: LGTM! Proper PHPDoc and Task return for searchCutoffMs.

The PHPDoc correctly specifies non-negative-int for both getter and update method, and updateSearchCutoffMs follows the consistent Task-based pattern with proper wait callback binding.


596-599: LGTM! Chat settings correctly returns Task with wait support.

The updateChat method correctly returns a Task with the wait callback bound, matching the pattern used by all other mutating methods in this file. This resolves the issue noted in past reviews.

@Strift
Copy link
Collaborator

Strift commented Nov 18, 2025

Thanks for this gigantic PR!

I'm thrilled to merge it finally 🙌 congrats!

@Strift Strift added this pull request to the merge queue Nov 18, 2025
Merged via the queue into meilisearch:main with commit e402d00 Nov 18, 2025
10 of 11 checks passed
@tacman
Copy link
Contributor

tacman commented Nov 18, 2025

Wahoo! Congrats and thanks.

@Strift Strift removed enhancement New feature or request dependencies labels Nov 18, 2025
@norkunas norkunas deleted the task-object branch November 19, 2025 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change The related changes are breaking for the users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add wait() method to Task class Replace array return types from api to object Typehint HandleSettings methods return types

5 participants