Skip to content

refactor: throw typed Elastica exceptions for unsupported features#2303

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

refactor: throw typed Elastica exceptions for unsupported features#2303
ruflin wants to merge 1 commit 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

    • Exception handling enhanced: Client and Task operations now throw specific, typed exceptions instead of generic ones. This improvement allows applications to catch and handle specific error scenarios with greater precision and clarity.
  • Tests

    • Test coverage extended to validate specific exception types are properly thrown in error scenarios, ensuring consistent behavior across the library.

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`.
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
📝 Walkthrough

Walkthrough

The pull request replaces generic exception throws with typed exceptions in Elastica\Client and Elastica\Task methods. Five Client methods now throw NotImplementedException instead of \Exception, and Task::cancel() throws InvalidException instead of a generic exception. Tests are updated to validate these new exception types.

Changes

Cohort / File(s) Summary
Documentation
CHANGELOG.md
Added entries documenting behavioral changes: several Client methods now throw NotImplementedException, and Task::cancel() throws InvalidException.
Exception Type Refinement
src/Client.php
Replaced generic \Exception('Not supported') with NotImplementedException in five methods: setAsync(), getAsync(), setResponseException(), getResponseException(), and setServerless(), with more descriptive error messages.
Exception Type Refinement
src/Task.php
Replaced generic \Exception with InvalidException in cancel() when task id is unset; updated docblock to document InvalidException and propagated response/client exceptions.
Test Validation
tests/ClientTest.php
Added parameterized test with data provider covering five unsupported client methods; added test verifying NotImplementedException is catchable as ExceptionInterface and is a BadMethodCallException.
Test Update
tests/TaskTest.php
Updated testCancelThrowsExceptionWithEmptyTaskId to expect InvalidException instead of generic \Exception.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

A rabbit hops through code so neat,
Where exceptions now are typed complete,
No more generic throws cast about,
NotImplemented, Invalid—no doubt!
Clear error paths, a review so sweet. 🐰✨

🚥 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 and concisely summarizes the main change: replacing generic exceptions with typed Elastica exceptions for unsupported features in Client and Task methods.
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.

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

✨ 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
Review rate limit: 4/8 reviews remaining, refill in 28 minutes and 24 seconds.

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

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
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 on lines +257 to +278

/**
* @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);

$invocation($client);
}

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

Consolidate old unsupported-feature tests to the new typed-exception expectations.

This new provider-based test is good, but the legacy tests at Line 103, Line 120, Line 129, and Line 138 still assert the old message (Not supported). With the new messages from Client, those checks are now inconsistent and can fail CI. Please update/remove those legacy expectations and keep this provider-driven test as the single source of truth.

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

In `@tests/ClientTest.php` around lines 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.

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

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