Skip to content

Bump to PHP 8.1, improve type safety for Tasks #735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 41 commits into
base: v2
Choose a base branch
from

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() instanceof 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() instanceof 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

    • Introduced a comprehensive Task object with detailed status and type enums and multiple task detail classes for clearer task management.
    • Added a new partial function for partial application of callables.
    • Added extensive tests for the Task object and pagination settings.
  • Breaking Changes

    • Raised minimum PHP version requirement to 8.1.
    • Updated many endpoints to return Task objects instead of arrays for asynchronous operations (documents, indexes, settings, dumps, snapshots, tasks).
    • Enforced stricter and more explicit type declarations across the codebase.
  • Improvements

    • Enhanced type safety with explicit parameter and return types.
    • Streamlined exception classes with clearer type annotations.
    • Simplified and unified method signatures and return types for better consistency.
    • Updated test code to work with Task objects instead of raw arrays, improving clarity and type safety.
    • Simplified asynchronous task handling in tests by directly awaiting Task objects.
    • Improved internal code consistency by removing deprecated or unused methods and variables.
  • Bug Fixes

    • Improved reliability and consistency of method signatures and expected outputs.
  • Tests

    • Expanded and refined test coverage reflecting new Task object usage.
    • Removed redundant assertions and outdated test methods.
    • Updated tests to use method calls on Task objects rather than array access.
    • Corrected test method names for typos and improved test clarity.
  • Chores

    • Updated CI workflows to run tests only on PHP 8.1 and above.
    • Updated coding style configurations and dependency version constraints.
    • Reformatted PHPUnit configuration for detailed error and deprecation reporting.

@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
Copy link

codecov bot commented Apr 10, 2025

Codecov Report

Attention: Patch coverage is 97.15100% with 10 lines in your changes missing coverage. Please review.

Project coverage is 90.40%. Comparing base (368c73f) to head (cfed046).
Report is 73 commits behind head on main.

Files with missing lines Patch % Lines
src/Contracts/TaskDetails/DumpCreationDetails.php 0.00% 6 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   90.74%   90.40%   -0.34%     
==========================================
  Files          52       73      +21     
  Lines        1340     1595     +255     
==========================================
+ Hits         1216     1442     +226     
- Misses        124      153      +29     

☔ 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

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

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

case IndexSwap = 'indexSwap';
case DocumentAdditionOrUpdate = 'documentAdditionOrUpdate';
case DocumentDeletion = 'documentDeletion';
case DocumentEdition = 'documentEdition';
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unless Meilisearch docs are outdated, documentEdition type does not exist: https://www.meilisearch.com/docs/reference/api/tasks#type

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will remove

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh now I see that it was used in tests which broke after I removed it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

I will report it, thanks!

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

Copy link

coderabbitai bot commented May 14, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update introduces strict type safety and replaces array return types for asynchronous task operations with a new immutable Task object, leveraging PHP 8.1+ features such as enums and explicit type declarations. Endpoint methods, contracts, and tests are updated accordingly, and support for older PHP versions is removed. A wait() method is added to the Task class for simplified task awaiting.

Changes

File(s) Change Summary
.github/workflows/*.yml Dropped PHP 7.4/8.0 from test matrices and removed jobs for legacy PHP versions.
composer.json, .php-cs-fixer.dist.php Raised PHP requirement to 8.1+, updated dependencies, and enabled trailing commas in multiline parameters.
src/Contracts/Task.php, src/Contracts/TaskStatus.php, src/Contracts/TaskType.php Introduced immutable Task class with a wait() method and related enums for task status and type.
src/Contracts/TaskDetails/*.php, src/Contracts/TaskError.php, src/Contracts/TaskDetails.php Added task details classes and error class implementing TaskDetails interface with static factory methods.
src/Endpoints/Delegates/HandlesDocuments.php, src/Endpoints/Delegates/HandlesSettings.php, src/Endpoints/Delegates/HandlesIndex.php, src/Endpoints/Delegates/HandlesDumps.php, src/Endpoints/Delegates/HandlesSnapshots.php, src/Endpoints/Delegates/HandlesSystem.php, src/Endpoints/Delegates/HandlesTasks.php, src/Endpoints/Delegates/TasksQueryTrait.php Changed return types from array to Task for all async task-related methods; updated method signatures for stricter typing and PHPDoc annotations.
src/Endpoints/Indexes.php, src/Endpoints/Dumps.php, src/Endpoints/Snapshots.php, src/Endpoints/Tasks.php, src/Endpoints/Batches.php, src/Endpoints/Keys.php, src/Endpoints/TenantToken.php Updated endpoint classes to return Task objects instead of arrays for task operations; improved type safety and parameter typing.
src/Contracts/Data.php, src/Contracts/Http.php, src/Contracts/SimilarDocumentsQuery.php Added/updated type declarations for properties and method parameters.
src/Exceptions/*.php Added type declarations to properties and methods; removed unused static factory method.
src/Http/Serialize/*.php Added explicit type hints and return types to serializer interfaces and implementations.
src/Endpoints/Delegates/HandlesBatches.php, src/Endpoints/Batches.php Enforced stricter typing for batch identifiers.
src/Client.php, src/Http/Client.php Added trailing commas to constructor signatures; refactored JSON response detection.
src/functions.php Added partial function for partial application of callables.
tests/Contracts/TaskTest.php, tests/MockTask.php Added new test class for Task and helper for mocking tasks.
tests/Endpoints/DocumentsTest.php, tests/Endpoints/DumpTest.php, tests/Endpoints/IndexTest.php, tests/Endpoints/SearchTest.php, tests/Endpoints/SnapshotsTest.php, tests/Endpoints/TasksTest.php Updated tests to expect and assert Task objects; removed tests for invalid document IDs and promise assertions; refined exception message checks.
tests/Settings/*Test.php Removed redundant promise assertions and simplified test code by eliminating intermediate variables; updated tests to use wait() method on Task objects.
tests/TestCase.php Removed assertIsValidPromise method; updated teardown and helper methods to handle Task objects with wait().
phpunit.xml.dist Reformatted PHPUnit configuration XML to multi-line with enhanced display settings.
src/Exceptions/LogicException.php Added new final LogicException class extending PHP \LogicException and implementing custom interface.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Endpoint
    participant HTTP
    participant Task

    Client->>Endpoint: Perform async operation (e.g., addDocuments)
    Endpoint->>HTTP: Send HTTP request
    HTTP-->>Endpoint: Receive response (array)
    Endpoint->>Task: Task::fromArray(response)
    Endpoint-->>Client: Return Task object
    Client->>Task: call wait()
    Task->>HTTP: poll task status until finished or timeout
    HTTP-->>Task: return updated task status
    Task-->>Client: resolved Task object
Loading

Assessment against linked issues

Objective (Issue #) Addressed Explanation
Replace array return types from API with an object implementing ArrayAccess (#703) Task class implements ArrayAccess.
Introduce immutable Task class with strict typing and enums for status/type (#703) Added Task class and enums.
Ensure Task object supports array-like access for backward compatibility (#703) ArrayAccess methods implemented.
Update all endpoint methods to return Task objects for async operations (#703) Endpoint methods return Task objects.
Add wait() method to Task class for simplified waiting (#739) wait() method added to Task class.

Poem

Oh, what a joy for a codey hare,
Tasks now are objects, strict and fair!
No more arrays that cause dismay,
Enums and types now lead the way.
With PHP 8.1, we bound and leap—
Our Task class promises are easy to keep!
🐇✨


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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

@Strift can you upmerge to v2, because it requires changes here that are already done on v1.15

@Strift
Copy link
Collaborator

Strift commented Jun 12, 2025

Hi @norkunas, yes! Thanks for updating the target branch to v2.

@brunoocasali
Copy link
Member

brunoocasali commented Jun 19, 2025

So, I think we need to make the tests pass and merge this branch :)

Can you do this @norkunas then ask for my review again, please?

@norkunas
Copy link
Collaborator Author

@brunoocasali that's not up to me. v2 needs to be upmerged, because main has some pushed changes

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 dependencies enhancement New feature or request
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