Skip to content

Conversation

@norkunas
Copy link
Collaborator

@norkunas norkunas commented Nov 19, 2025

Pull Request

Related issue

Fixes #745

What does this PR do?

  • Returns version object instead of untyped array;
  • Adds mixed return type to Http client/interface

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

  • Breaking Changes

    • Version info now returns an object with accessor methods instead of an associative array — update callers that read version fields.
  • New Features

    • Added a Version value object exposing commit SHA, commit date, and package version accessors.
  • Chores

    • HTTP client and related contracts now declare explicit return types (no behavioral changes).
  • Tests

    • Added tests for the Version value object and updated client tests to use accessors.

✏️ Tip: You can customize this high-level summary in your review settings.

@norkunas norkunas requested a review from Strift November 19, 2025 14:24
@norkunas norkunas added enhancement New feature or request breaking-change The related changes are breaking for the users labels Nov 19, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Walkthrough

Introduces a readonly Version value object with a fromArray factory; changes HandlesSystem::version() to return Version; adds explicit : mixed return types to HTTP contract and client methods; updates tests to use Version getters and adds tests for Version.

Changes

Cohort / File(s) Summary
HTTP return types
src/Contracts/Http.php, src/Http/Client.php
Added explicit : mixed return type declarations to get(), post(), put(), patch(), and delete() in the HTTP interface and its Client implementation.
Version value object
src/Contracts/Version.php
Added final class Version with readonly properties commitSha (non-empty-string), commitDate (\DateTimeImmutable), pkgVersion (non-empty-string); constructor, getters (getCommitSha(), getCommitDate(), getPkgVersion()), and fromArray(array): Version that parses commitDate.
HandlesSystem integration
src/Endpoints/Delegates/HandlesSystem.php
version() now returns Meilisearch\Contracts\Version; validates that show() returned an array and converts it via Version::fromArray(), throwing on invalid data.
Tests
tests/Endpoints/ClientTest.php, tests/Contracts/VersionTest.php
Updated testVersion() to assert Version getters (getCommitSha(), getPkgVersion()); added tests for Version constructor and fromArray() behavior.
Other
manifest/composer metadata (unchanged)
No functional changes described beyond metadata mention.

Sequence Diagram(s)

sequenceDiagram
    participant Test as ClientTest
    participant Client as Meilisearch Client (HandlesSystem)
    participant Delegate as Remote delegate (show())
    participant Version as Meilisearch\Contracts\Version

    Test->>Client: version()
    Client->>Delegate: show()
    Delegate-->>Client: {commitSha, commitDate, pkgVersion} (array)
    Client->>Version: Version::fromArray(array)
    Version->>Version: parse commitDate -> DateTimeImmutable
    Version-->>Client: Version object
    Client-->>Test: Version object
    Note right of Test: Test calls getCommitSha(), getPkgVersion()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review focus:
    • Version::fromArray() date parsing and timezone handling.
    • Validation and exception path in HandlesSystem::version() when show() returns non-array or missing keys.
    • Consistency of added : mixed return types between interface and implementation.
    • Updated tests and any remaining call sites expecting an array.

Poem

🐰 I found a SHA and shaped a date,
Into a Version neat and straight.
HTTP named returns, no more guess,
Tests now peek with getter finesse.
Hop — the patch is done, I celebrate!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% 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 accurately captures the primary change: adding a typed Version object to replace the untyped array return.
Linked Issues check ✅ Passed The PR fulfills issue #745 by adding a typehint to HandlesSystem::version, now returning VersionContract instead of array.
Out of Scope Changes check ✅ Passed All changes align with the core objective: creating a Version object and adding return types to Http methods. No unrelated modifications detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@codecov
Copy link

codecov bot commented Nov 19, 2025

Codecov Report

❌ Patch coverage is 95.45455% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 88.01%. Comparing base (0078a8c) to head (11a7a5b).
⚠️ Report is 87 commits behind head on main.

Files with missing lines Patch % Lines
src/Endpoints/Delegates/HandlesSystem.php 80.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #821      +/-   ##
==========================================
- Coverage   89.78%   88.01%   -1.77%     
==========================================
  Files          59       81      +22     
  Lines        1449     1736     +287     
==========================================
+ Hits         1301     1528     +227     
- Misses        148      208      +60     

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

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

🧹 Nitpick comments (1)
tests/Endpoints/ClientTest.php (1)

202-208: Consider adding test coverage for getCommitDate().

The test validates getCommitSha() and getPkgVersion(), but the getCommitDate() getter is not exercised. Since this is part of the new public API surface, consider adding an assertion to verify that it returns a valid DateTimeImmutable instance.

Apply this diff to add validation for getCommitDate():

     public function testVersion(): void
     {
         $response = $this->client->version();
 
         self::assertMatchesRegularExpression('/^[0-9a-f]{40}$/i', $response->getCommitSha());
         self::assertGreaterThanOrEqual(0, version_compare($response->getPkgVersion(), '1.26.0'));
+        self::assertInstanceOf(\DateTimeImmutable::class, $response->getCommitDate());
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d90618 and 190a568.

📒 Files selected for processing (5)
  • src/Contracts/Http.php (1 hunks)
  • src/Contracts/Version.php (1 hunks)
  • src/Endpoints/Delegates/HandlesSystem.php (1 hunks)
  • src/Http/Client.php (5 hunks)
  • tests/Endpoints/ClientTest.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/Contracts/Http.php (5)
src/Http/Client.php (5)
  • get (69-77)
  • post (87-98)
  • put (108-119)
  • patch (121-129)
  • delete (131-139)
src/Endpoints/Tasks.php (1)
  • get (20-23)
src/Endpoints/Batches.php (1)
  • get (13-16)
src/Endpoints/Keys.php (2)
  • get (156-161)
  • delete (208-211)
src/Endpoints/Indexes.php (1)
  • delete (147-153)
src/Http/Client.php (4)
src/Contracts/Http.php (5)
  • get (16-16)
  • post (24-24)
  • put (32-32)
  • patch (38-38)
  • delete (44-44)
src/Endpoints/Tasks.php (1)
  • get (20-23)
src/Endpoints/Keys.php (2)
  • get (156-161)
  • delete (208-211)
src/Endpoints/Indexes.php (1)
  • delete (147-153)
tests/Endpoints/ClientTest.php (1)
src/Contracts/Version.php (2)
  • getCommitSha (23-26)
  • getPkgVersion (33-36)
src/Endpoints/Delegates/HandlesSystem.php (2)
src/Contracts/Version.php (2)
  • Version (7-53)
  • fromArray (45-52)
src/Contracts/Endpoint.php (1)
  • show (19-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Upload coverage to Codecov
🔇 Additional comments (5)
src/Contracts/Http.php (1)

16-44: LGTM! Return type declarations improve type safety.

The addition of : mixed return types to the HTTP interface methods is appropriate given that different endpoints return different types (arrays, objects, null). This breaking change aligns with the broader refactoring to introduce typed objects like Version.

src/Contracts/Version.php (3)

7-18: LGTM! Well-designed immutable value object.

The use of final class and readonly properties follows best practices for value objects, ensuring immutability and preventing inheritance. The type declarations and PHPDoc annotations provide good static analysis support.


23-36: LGTM! Getters follow standard conventions.

The getter methods provide clean access to the readonly properties with appropriate return types. Using DateTimeImmutable ensures that returned date objects cannot be modified externally.


45-52: Remove validation suggestion—it contradicts established SDK architecture.

The review recommends adding validation to fromArray(), but verification shows the codebase uses a two-layer error handling model:

  1. HTTP layer validation: Client.php handles response validation and throws ApiException or InvalidResponseBodyException before data reaches factory methods
  2. Factory assumption: All 15+ fromArray() implementations assume pre-validated input, including Task.php which also instantiates DateTimeImmutable without try-catch

Version::fromArray is called from HandlesSystem.php with data that has already passed HTTP validation (json_decode with JSON_THROW_ON_ERROR, status checks). Adding local validation would duplicate upstream work and create inconsistency across the SDK. This is deliberate SDK design, not an oversight.

Likely an incorrect or invalid review comment.

src/Http/Client.php (1)

69-131: LGTM! Implementation correctly matches interface contract.

The addition of : mixed return types to the HTTP method implementations is consistent with the updated Http interface. No behavioral changes were made—only type declarations were added.

@norkunas norkunas force-pushed the version branch 6 times, most recently from 1614bd9 to 50c393b Compare November 24, 2025 05:21
@Strift
Copy link
Collaborator

Strift commented Nov 24, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Nov 24, 2025

✅ Actions performed

Review triggered.

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

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

♻️ Duplicate comments (2)
src/Endpoints/Delegates/HandlesSystem.php (2)

38-47: Partial fix: Missing keys and invalid date format still unhandled.

The previous review concern was marked as addressed, but only the null response scenario is now handled (lines 42-44). The Version::fromArray() implementation still lacks protection against:

  1. Missing array keys: Direct access to $data['commitSha'], $data['commitDate'], and $data['pkgVersion'] will cause undefined array key errors
  2. Invalid date format: new \DateTimeImmutable($data['commitDate']) can throw exceptions on malformed dates

The previous review recommended mirroring the error handling pattern in Indexes::parseDate() with try-catch blocks and adding a @throws annotation.

Consider adding comprehensive validation:

 public function version(): VersionContract
 {
     $version = $this->version->show();

     if (!\is_array($version)) {
         throw new LogicException('Version did not respond with valid data.');
     }
+
+    // Validate required keys
+    $requiredKeys = ['commitSha', 'commitDate', 'pkgVersion'];
+    foreach ($requiredKeys as $key) {
+        if (!isset($version[$key]) || $version[$key] === '') {
+            throw new LogicException("Version response missing required key: {$key}");
+        }
+    }
+
+    // Validate date format
+    try {
+        return VersionContract::fromArray($version);
+    } catch (\Exception $e) {
+        throw new LogicException('Failed to parse version data: ' . $e->getMessage(), 0, $e);
+    }
-
-    return VersionContract::fromArray($version);
 }

Alternatively, move this validation logic into Version::fromArray() itself.


38-38: Add @throws documentation for the version() method.

The method can throw LogicException (line 43) and potentially other exceptions from Version::fromArray(). Add a docblock with @throws annotation to document this behavior for API consumers.

+    /**
+     * @throws LogicException If the version endpoint returns invalid data
+     */
     public function version(): VersionContract
🧹 Nitpick comments (1)
tests/Contracts/VersionTest.php (1)

25-36: Consider adding edge case tests for error scenarios.

The current tests only validate the happy path. Consider adding test cases for:

  • Malformed commitDate strings that cannot be parsed by DateTimeImmutable
  • Missing required array keys (commitSha, commitDate, pkgVersion)
  • Empty or invalid values for the non-empty-string typed fields

These tests would ensure that Version::fromArray() handles invalid input appropriately.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 39440bc and 50c393b.

📒 Files selected for processing (6)
  • src/Contracts/Http.php (1 hunks)
  • src/Contracts/Version.php (1 hunks)
  • src/Endpoints/Delegates/HandlesSystem.php (2 hunks)
  • src/Http/Client.php (5 hunks)
  • tests/Contracts/VersionTest.php (1 hunks)
  • tests/Endpoints/ClientTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/Endpoints/ClientTest.php
  • src/Contracts/Version.php
  • src/Http/Client.php
  • src/Contracts/Http.php
🧰 Additional context used
🧬 Code graph analysis (1)
tests/Contracts/VersionTest.php (1)
src/Contracts/Version.php (5)
  • Version (7-53)
  • getCommitSha (23-26)
  • getCommitDate (28-31)
  • getPkgVersion (33-36)
  • fromArray (45-52)
🔇 Additional comments (2)
tests/Contracts/VersionTest.php (1)

12-23: LGTM!

The test correctly validates direct construction of the Version object and all getter methods. The use of assertSame for the date comparison is appropriate since it references the same object instance.

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

8-8: LGTM!

The import statements are appropriate. Aliasing Version as VersionContract avoids naming conflicts with the Version endpoint class, and LogicException is properly used for validation.

Also applies to: 13-13

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

🧹 Nitpick comments (2)
tests/Contracts/VersionTest.php (1)

25-36: Consider adding edge case tests.

The current tests cover happy paths well. Consider adding tests for error scenarios to improve robustness:

  • Invalid date format in fromArray (e.g., 'commitDate' => 'invalid')
  • Missing required keys in fromArray array
  • Empty strings for commitSha and pkgVersion (given the non-empty-string constraint)

Would you like me to generate additional test cases for these scenarios?

src/Contracts/Version.php (1)

33-36: Add @return annotation for consistency.

The getPkgVersion method should include a @return non-empty-string annotation to match the consistency of getCommitSha and align with the constructor's parameter type hint.

Apply this diff:

+    /**
+     * @return non-empty-string
+     */
     public function getPkgVersion(): string
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50c393b and 11a7a5b.

📒 Files selected for processing (6)
  • src/Contracts/Http.php (1 hunks)
  • src/Contracts/Version.php (1 hunks)
  • src/Endpoints/Delegates/HandlesSystem.php (2 hunks)
  • src/Http/Client.php (5 hunks)
  • tests/Contracts/VersionTest.php (1 hunks)
  • tests/Endpoints/ClientTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Endpoints/Delegates/HandlesSystem.php
  • tests/Endpoints/ClientTest.php
🧰 Additional context used
🧬 Code graph analysis (4)
src/Contracts/Version.php (2)
src/Meilisearch.php (1)
  • Meilisearch (7-18)
src/Http/Client.php (1)
  • __construct (43-62)
tests/Contracts/VersionTest.php (1)
src/Contracts/Version.php (5)
  • Version (7-53)
  • getCommitSha (23-26)
  • getCommitDate (28-31)
  • getPkgVersion (33-36)
  • fromArray (45-52)
src/Contracts/Http.php (1)
src/Http/Client.php (5)
  • get (69-77)
  • post (87-98)
  • put (108-119)
  • patch (121-129)
  • delete (131-139)
src/Http/Client.php (3)
src/Endpoints/Tasks.php (1)
  • get (20-23)
src/Endpoints/Keys.php (2)
  • get (156-161)
  • delete (208-211)
src/Endpoints/Indexes.php (1)
  • delete (147-153)
🔇 Additional comments (3)
tests/Contracts/VersionTest.php (1)

5-5: Namespace correctly updated.

The namespace now properly aligns with the PSR-4 file path. This resolves the previous review concern.

src/Contracts/Http.php (1)

16-16: LGTM! Return types properly specified.

The explicit : mixed return types appropriately reflect the varied response types (arrays, null, objects) returned by these HTTP methods and align with the implementation in Client.

Also applies to: 24-24, 32-32, 38-38, 44-44

src/Http/Client.php (1)

69-69: LGTM! Implementation correctly matches interface.

The explicit : mixed return types properly implement the updated Http interface contract and appropriately reflect the varied response types returned by these methods.

Also applies to: 87-87, 108-108, 121-121, 131-131

Comment on lines +45 to +52
public static function fromArray(array $data): Version
{
return new self(
$data['commitSha'],
new \DateTimeImmutable($data['commitDate']),
$data['pkgVersion'],
);
}
Copy link

@coderabbitai coderabbitai bot Nov 24, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add validation and error handling in fromArray.

The fromArray method directly accesses array keys without validating their existence and constructs DateTimeImmutable without error handling. This can lead to runtime errors if:

  • The API response structure changes or keys are missing
  • The commitDate string is in an invalid format

Consider adding validation:

 public static function fromArray(array $data): Version
 {
+    if (!isset($data['commitSha'], $data['commitDate'], $data['pkgVersion'])) {
+        throw new \InvalidArgumentException('Missing required keys in version data');
+    }
+    
+    try {
+        $commitDate = new \DateTimeImmutable($data['commitDate']);
+    } catch (\Exception $e) {
+        throw new \InvalidArgumentException('Invalid commitDate format: ' . $e->getMessage(), 0, $e);
+    }
+    
     return new self(
         $data['commitSha'],
-        new \DateTimeImmutable($data['commitDate']),
+        $commitDate,
         $data['pkgVersion'],
     );
 }
🤖 Prompt for AI Agents
In src/Contracts/Version.php around lines 45 to 52, the fromArray method assumes
keys exist and that commitDate is valid; add explicit validation for required
keys ('commitSha','commitDate','pkgVersion') and their types, throw a clear
InvalidArgumentException when a key is missing or has an unexpected type, and
wrap DateTimeImmutable construction in a try/catch to convert parsing errors
into a descriptive exception (or validate the date format first) so the method
fails fast with a meaningful message instead of producing uncaught runtime
errors.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Static analysis is for that. It's a soft contract

Copy link

Choose a reason for hiding this comment

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

@norkunas, understood! I see this aligns with the project's established approach where docblock type annotations serve as contracts for static analysis tools. The method signature already documents the expected array structure with non-empty-string types, which is sufficient for static analysis to catch issues.

Thank you for the clarification!


🧠 Learnings used
Learnt from: norkunas
Repo: meilisearch/meilisearch-php PR: 735
File: src/Contracts/SimilarDocumentsQuery.php:10-12
Timestamp: 2025-11-17T06:57:43.914Z
Learning: In the meilisearch-php project, docblock type annotations (such as `non-empty-string`, `positive-int`, etc.) are treated as contracts for static analysis tools rather than requiring runtime validation. If users violate these documented constraints, it's their responsibility.

@Strift Strift added this pull request to the merge queue Nov 24, 2025
Merged via the queue into meilisearch:main with commit ec4a626 Nov 24, 2025
10 of 11 checks passed
@norkunas norkunas deleted the version branch November 24, 2025 08:01
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 enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Typehint HandlesSystem::version return type

2 participants