Skip to content

refactor: throw typed Elastica exceptions for unsupported features - #2303

Open
ruflin wants to merge 2 commits into
9.xfrom
fix/use-not-implemented-exception
Open

refactor: throw typed Elastica exceptions for unsupported features#2303
ruflin wants to merge 2 commits into
9.xfrom
fix/use-not-implemented-exception

Conversation

@ruflin

@ruflin ruflin commented Apr 30, 2026

Copy link
Copy Markdown
Owner

Summary

Replace throw new \Exception('Not supported') calls in Elastica\Client
and Elastica\Task with the existing typed Elastica exceptions:

  • Elastica\Client::setAsync(), getAsync(), setResponseException(),
    getResponseException() and setServerless() now throw
    Elastica\Exception\NotImplementedException (already extends
    \BadMethodCallException and implements
    Elastica\Exception\ExceptionInterface).
  • Elastica\Task::cancel()'s missing-id guard now throws
    Elastica\Exception\InvalidException.

This lets callers catch a typed exception (or the
Elastica\Exception\ExceptionInterface umbrella) instead of relying on
the SPL root.

Identified during a P0/P1 code-review pass.

Test plan

  • Unit test using a DataProvider covers all five Client methods.
  • Additional test asserts the exception is catchable via
    ExceptionInterface and \BadMethodCallException.
  • Existing TaskTest::testCancelThrowsExceptionWithEmptyTaskId
    tightened to expect InvalidException.
  • CI matrix (PHP 8.1–8.5)
  • PHPStan + php-cs-fixer

Summary by CodeRabbit

  • Refactor
    • Updated exception behavior for unsupported Client features to throw NotImplementedException (with method-specific messages).
    • Updated Task::cancel() to throw InvalidException when no task id is provided, instead of a generic exception.
  • Tests
    • Revised and consolidated Client tests to assert the new NotImplementedException type and verify it’s catchable via Elastica’s exception interface.
    • Updated Task tests to expect InvalidException when cancelling with an empty task id.

Copilot AI review requested due to automatic review settings April 30, 2026 20:28
@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request replaces generic exceptions with typed Elastica exceptions. Five Client methods now throw NotImplementedException, while Task::cancel() throws InvalidException when no task id is set. Tests and changelog entries are updated accordingly.

Changes

Typed exception behavior

Layer / File(s) Summary
Client unsupported-feature exceptions
src/Client.php, tests/ClientTest.php
Unsupported client methods now throw NotImplementedException with specific messages. Parameterized tests verify each method, exception interfaces, and BadMethodCallException inheritance.
Task cancellation exception contract
src/Task.php, tests/TaskTest.php, CHANGELOG.md
Task::cancel() throws and documents InvalidException for missing task ids; the corresponding test and changelog entry are updated.

Estimated code review effort: 2 (Simple) | ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main client exception-typing change, though it omits the Task::cancel update.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/use-not-implemented-exception

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.

Copilot AI left a comment

Copy link
Copy Markdown

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 refactors unsupported-feature code paths in Elastica\Client and Elastica\Task to throw existing typed Elastica exceptions instead of generic \Exception, improving catchability via Elastica\Exception\ExceptionInterface.

Changes:

  • Elastica\Client unsupported feature methods now throw Elastica\Exception\NotImplementedException.
  • Elastica\Task::cancel() now throws Elastica\Exception\InvalidException when called without a task id.
  • Tests and changelog updated to reflect the new typed exceptions.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Client.php Replace generic exceptions with NotImplementedException for unsupported client features.
src/Task.php Replace generic exception with InvalidException for missing task id; update @throws docs.
tests/ClientTest.php Add data-provider coverage and interface-catchability assertions for NotImplementedException.
tests/TaskTest.php Tighten expectation to InvalidException for empty task id cancel.
CHANGELOG.md Document the exception type changes under Unreleased.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/ClientTest.php Outdated
Comment on lines +259 to +275
* @return iterable<string, array{0: callable(Client): mixed}>
*/
public static function unsupportedClientFeaturesProvider(): iterable
{
yield 'setAsync' => [static fn (Client $client) => $client->setAsync(true)];
yield 'getAsync' => [static fn (Client $client) => $client->getAsync()];
yield 'setResponseException' => [static fn (Client $client) => $client->setResponseException(true)];
yield 'getResponseException' => [static fn (Client $client) => $client->getResponseException()];
yield 'setServerless' => [static fn (Client $client) => $client->setServerless(true)];
}

#[DataProvider('unsupportedClientFeaturesProvider')]
public function testUnsupportedFeaturesThrowNotImplementedException(callable $invocation): void
{
$client = new Client();

$this->expectException(NotImplementedException::class);
Comment thread src/Task.php

/**
* @throws \Exception
* @throws InvalidException if no task id is set

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@tests/ClientTest.php`:
- Around line 257-278: The legacy single-case tests that still assert the old
message "Not supported" must be removed or updated to match the new
provider-based expectation: replace the message-based assertions with a typed
exception check (expectException(NotImplementedException::class)) or delete
those legacy tests so the provider-driven test
(unsupportedClientFeaturesProvider +
testUnsupportedFeaturesThrowNotImplementedException) is the single source of
truth; ensure references to Client methods (setAsync, getAsync,
setResponseException, getResponseException, setServerless) remain covered by the
provider test and that no remaining tests assert the exact "Not supported"
message.
- Around line 287-290: The test currently catches ExceptionInterface and asserts
it's a NotImplementedException then redundantly asserts \BadMethodCallException
(which PHPStan flags as always-true). Fix by making the catch specific (catch
NotImplementedException $e) or keep the generic catch but remove the redundant
$this->assertInstanceOf(\BadMethodCallException, $e);—ensure only a single
meaningful assertion remains referencing NotImplementedException (and retain
ExceptionInterface only if you need to assert the interface explicitly).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2a050cc3-02d4-4748-bd07-326f98bab7b4

📥 Commits

Reviewing files that changed from the base of the PR and between d0c0d60 and 9044934.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • src/Client.php
  • src/Task.php
  • tests/ClientTest.php
  • tests/TaskTest.php

Comment thread tests/ClientTest.php
Comment thread tests/ClientTest.php
Comment on lines +287 to +290
} catch (ExceptionInterface $e) {
$this->assertInstanceOf(NotImplementedException::class, $e);
$this->assertInstanceOf(\BadMethodCallException::class, $e);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove the always-true assertion flagged by PHPStan.

After asserting NotImplementedException, the \BadMethodCallException assertion is redundant and reported as always true. Rework the catch/assert pattern to avoid tautological checks.

Suggested adjustment
-        } catch (ExceptionInterface $e) {
-            $this->assertInstanceOf(NotImplementedException::class, $e);
-            $this->assertInstanceOf(\BadMethodCallException::class, $e);
+        } catch (\BadMethodCallException $e) {
+            $this->assertInstanceOf(ExceptionInterface::class, $e);
+            $this->assertInstanceOf(NotImplementedException::class, $e);
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (ExceptionInterface $e) {
$this->assertInstanceOf(NotImplementedException::class, $e);
$this->assertInstanceOf(\BadMethodCallException::class, $e);
}
} catch (\BadMethodCallException $e) {
$this->assertInstanceOf(ExceptionInterface::class, $e);
$this->assertInstanceOf(NotImplementedException::class, $e);
}
🧰 Tools
🪛 GitHub Check: PHPStan

[failure] 289-289:
Call to method PHPUnit\Framework\Assert::assertInstanceOf() with 'BadMethodCallException' and Elastica\Exception\NotImplementedException will always evaluate to true.

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

In `@tests/ClientTest.php` around lines 287 - 290, The test currently catches
ExceptionInterface and asserts it's a NotImplementedException then redundantly
asserts \BadMethodCallException (which PHPStan flags as always-true). Fix by
making the catch specific (catch NotImplementedException $e) or keep the generic
catch but remove the redundant $this->assertInstanceOf(\BadMethodCallException,
$e);—ensure only a single meaningful assertion remains referencing
NotImplementedException (and retain ExceptionInterface only if you need to
assert the interface explicitly).

ruflin added 2 commits July 28, 2026 22:53
Replace `throw new \Exception('Not supported')` calls in
`Elastica\Client` (setAsync/getAsync/setResponseException/
getResponseException/setServerless) and the bare `\Exception` in
`Elastica\Task::cancel()` with the existing typed exceptions:

- `Elastica\Exception\NotImplementedException` for unsupported features
  on the Client. It already extends `\BadMethodCallException` and
  implements `Elastica\Exception\ExceptionInterface`.
- `Elastica\Exception\InvalidException` for the missing-id guard in
  `Task::cancel()`.

Callers can now `catch (Elastica\Exception\ExceptionInterface)` instead
of relying on the SPL root.

Update unit tests accordingly and add coverage that asserts the
NotImplementedException is catchable as both `BadMethodCallException`
and `ExceptionInterface`.
The four standalone tests still asserted the old 'Not supported' message
and failed once Client threw NotImplementedException with a descriptive
message. Fold them into the existing data provider, which now carries the
expected message per method, and drop the tautological BadMethodCallException
assertion that PHPStan flagged as always true (reaching the catch block via
ExceptionInterface already proves the umbrella; the SPL parent is what needs
pinning). Also reorder the provider after its test method to satisfy
php-cs-fixer.
@ruflin
ruflin force-pushed the fix/use-not-implemented-exception branch from 9044934 to acdfc9a Compare July 28, 2026 20:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/Client.php (1)

84-89: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the typed exception contract.

These public methods now always throw NotImplementedException, but their declarations do not expose that contract via PHPDoc. Add @throws NotImplementedException documentation here or in ClientInterface.

As per coding guidelines, “Use PHPDoc where it adds additional information.”

Also applies to: 106-116

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Client.php` around lines 84 - 89, Document the typed exception contract
for the public async-mode methods shown, including getAsync() and the
corresponding method around the preceding throw. Add PHPDoc with `@throws`
NotImplementedException either directly above both methods in Client or
centrally in ClientInterface, preserving the existing method behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/Client.php`:
- Around line 84-89: Document the typed exception contract for the public
async-mode methods shown, including getAsync() and the corresponding method
around the preceding throw. Add PHPDoc with `@throws` NotImplementedException
either directly above both methods in Client or centrally in ClientInterface,
preserving the existing method behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5de31ff1-cb9d-4158-a024-d080255e9e7d

📥 Commits

Reviewing files that changed from the base of the PR and between 9044934 and acdfc9a.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • src/Client.php
  • src/Task.php
  • tests/ClientTest.php
  • tests/TaskTest.php
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/TaskTest.php
  • src/Task.php
  • CHANGELOG.md
  • tests/ClientTest.php

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants