Skip to content

Forward calls via ForwardsCalls trait instead of method_exists - #9

Merged
trm42 merged 1 commit into
masterfrom
review-cache-decorator
Jun 12, 2026
Merged

trm42 merged 1 commit into
masterfrom
review-cache-decorator

Conversation

@trm42

@trm42 trm42 commented Jun 11, 2026

Copy link
Copy Markdown
Owner

What

Replaces the method_exists($this->decorated, $method) gate in CacheDecorator::callMethod() with Laravel's Illuminate\Support\Traits\ForwardsCalls trait, delegating through forwardDecoratedCallTo().

Why

The old gate meant calls were not forwarded to methods the decorated object exposes via its own __call()/__callStatic() magic — they wrongly threw BadMethodCallException. ForwardsCalls (the same trait Eloquent's Builder/Model use) invokes the method and only converts a genuine "undefined method" failure into a clean BadMethodCallException. This removes the limitation, aligns with idiomatic Laravel, and adds no new dependency (the trait ships in illuminate/support, already required).

Changes

  • src/CacheDecorator.php
    • Add use ForwardsCalls; and rewrite callMethod() to return $this->forwardDecoratedCallTo($this->decorated, $method, $arguments);.
    • Append the trait's __call-reachable surface (forwardCallTo, forwardDecoratedCallTo, throwBadMethodCallException) to initExcludes() defaults.
    • Missing-method calls now throw BadMethodCallException reading Call to undefined method {Decorator}::{method}().
  • Fluent behavior: when the inner method does return $this;, forwardDecoratedCallTo() returns the decorator instead, so chaining stays on the cached surface. Fluent/self-returning methods should be listed in $excludes (they aren't cache candidates and excluding them avoids caching a decorator instance on a miss).
  • README.md: documents transparent forwarding to the inner's __call(), the new exception message, the "exclude fluent methods" caveat, and the shared-static-returning-interface type-coherence convention (per the repo's README-sync rule).
  • Tests / stubs: add StubMagicService + CachedMagicService (regression: a magic-only method is forwarded and cached) and StubFluentService + CachedFluentService + FluentServiceContract (a fluent return $this; call returns the decorator, not the inner object).

Verification

  • composer test → 31 tests, 48 assertions, OK
  • vendor/bin/phpstan analyse → no errors (level 8)
  • vendor/bin/pint --test → passed

🤖 Generated with Claude Code

Replace the method_exists() gate in CacheDecorator::callMethod() with
Laravel's ForwardsCalls trait. Calls now reach methods the decorated
object exposes via its own __call() magic, and self-returning fluent
methods return the decorator so chaining stays on the cached surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@trm42
trm42 merged commit 63465a8 into master Jun 12, 2026
19 checks passed
@trm42
trm42 deleted the review-cache-decorator branch June 12, 2026 07:31
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.

1 participant