refactor: throw typed Elastica exceptions for unsupported features - #2303
refactor: throw typed Elastica exceptions for unsupported features#2303ruflin wants to merge 2 commits into
Conversation
📝 WalkthroughWalkthroughThe pull request replaces generic exceptions with typed Elastica exceptions. Five ChangesTyped exception behavior
Estimated code review effort: 2 (Simple) | ~12 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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\Clientunsupported feature methods now throwElastica\Exception\NotImplementedException.Elastica\Task::cancel()now throwsElastica\Exception\InvalidExceptionwhen 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.
| * @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); |
|
|
||
| /** | ||
| * @throws \Exception | ||
| * @throws InvalidException if no task id is set |
There was a problem hiding this comment.
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
📒 Files selected for processing (5)
CHANGELOG.mdsrc/Client.phpsrc/Task.phptests/ClientTest.phptests/TaskTest.php
| } catch (ExceptionInterface $e) { | ||
| $this->assertInstanceOf(NotImplementedException::class, $e); | ||
| $this->assertInstanceOf(\BadMethodCallException::class, $e); | ||
| } |
There was a problem hiding this comment.
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.
| } 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).
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.
9044934 to
acdfc9a
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/Client.php (1)
84-89: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocument the typed exception contract.
These public methods now always throw
NotImplementedException, but their declarations do not expose that contract via PHPDoc. Add@throws NotImplementedExceptiondocumentation here or inClientInterface.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
📒 Files selected for processing (5)
CHANGELOG.mdsrc/Client.phpsrc/Task.phptests/ClientTest.phptests/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
Summary
Replace
throw new \Exception('Not supported')calls inElastica\Clientand
Elastica\Taskwith the existing typed Elastica exceptions:Elastica\Client::setAsync(),getAsync(),setResponseException(),getResponseException()andsetServerless()now throwElastica\Exception\NotImplementedException(already extends\BadMethodCallExceptionand implementsElastica\Exception\ExceptionInterface).Elastica\Task::cancel()'s missing-id guard now throwsElastica\Exception\InvalidException.This lets callers catch a typed exception (or the
Elastica\Exception\ExceptionInterfaceumbrella) instead of relying onthe SPL root.
Identified during a P0/P1 code-review pass.
Test plan
DataProvidercovers all five Client methods.ExceptionInterfaceand\BadMethodCallException.TaskTest::testCancelThrowsExceptionWithEmptyTaskIdtightened to expect
InvalidException.Summary by CodeRabbit
Clientfeatures to throwNotImplementedException(with method-specific messages).Task::cancel()to throwInvalidExceptionwhen no task id is provided, instead of a generic exception.Clienttests to assert the newNotImplementedExceptiontype and verify it’s catchable via Elastica’s exception interface.Tasktests to expectInvalidExceptionwhen cancelling with an empty task id.