-
Notifications
You must be signed in to change notification settings - Fork 9
Document cache attributes and interceptors #167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Document which interceptors are bound to each cache attribute - Add direct links to BEAR.Sunday manual sections with hash fragments - Improve code readability for developers understanding the caching system Attributes updated: - Cacheable: CacheInterceptor, CommandInterceptor - HttpCache/NoHttpCache: HttpCacheInterceptor - Purge/Refresh: RefreshInterceptor, CommandInterceptor - DonutCache: DonutCacheInterceptor - CacheableResponse: DonutCacheableResponseInterceptor, DonutCommandInterceptor - RefreshCache: DonutCacheInterceptor
- Emphasize EDC is for content that is fundamentally static - Changes are predictable via resource methods (onPut, onDelete, etc.) - Add 304 Not Modified benefit for network transfer cost reduction
- Add practical examples to HttpCache, Cacheable, Purge, Refresh - Add class-level examples to DonutCache and CacheableResponse - Show URI template placeholders usage in Purge/Refresh - Demonstrate CDN cache configuration patterns in HttpCache
- Remove example combining noCache and noStore (common misuse) - Keep simple reference to use NoHttpCache for no-caching scenarios - Avoid confusion between no-cache (revalidate) and no-store (don't cache)
- HttpCache is for configuring cache control, not disabling it - NoHttpCache is the dedicated attribute for disabling cache - Keep HttpCache examples focused on actual cache configuration - Better separation of concerns between attributes
- Document which attributes each interceptor binds to - Clarify CQRS query (onGet) vs command (onPut/onPatch/onDelete) distinction - Add links to attribute classes and manual sections - Explain cache behavior and ETag generation differences Interceptors documented: - CacheInterceptor: TTL-based caching for queries - CommandInterceptor: Cache invalidation for commands - HttpCacheInterceptor: HTTP Cache-Control header - DonutCacheInterceptor: Donut caching for queries - DonutCacheableResponseInterceptor: Full response caching for queries - DonutCommandInterceptor: Donut cache invalidation for commands - RefreshInterceptor: Cache refresh for non-Cacheable classes
Reviewer's GuideThis PR enriches the caching system with detailed docblocks across all cache annotations and interceptor classes, embedding usage examples, bound-interceptor listings, manual links, and clarifications between TTL-based and event-driven (ETag/304) caching. Class diagram for updated cache attribute annotations and interceptorsclassDiagram
class Cacheable {
<<Attribute>>
+expirySecond: int
+expiry: string
+expiryAt: string
"TTL-based caching"
"Bound Interceptors: CacheInterceptor (onGet), CommandInterceptor (onPut/onPatch/onDelete)"
}
class CacheableResponse {
<<Attribute>>
"Event-driven full response caching"
"Bound Interceptors: DonutCacheableResponseInterceptor (onGet), DonutCommandInterceptor (onPut/onPatch/onDelete), DonutCacheInterceptor (method)"
}
class DonutCache {
<<Attribute>>
"Event-driven donut caching for resources with non-cacheable embedded content"
"Bound Interceptors: DonutCacheInterceptor (onGet or method)"
}
class HttpCache {
<<Attribute>>
+maxAge: int
+mustRevalidate: bool
+isPrivate: bool
+sMaxAge: int
"HTTP Cache-Control header"
"Bound Interceptors: HttpCacheInterceptor (onGet)"
}
class NoHttpCache {
<<Attribute>>
"Disable HTTP caching"
"Bound Interceptors: HttpCacheInterceptor (onGet)"
}
class Purge {
<<Attribute>>
+uri: string
"Cache invalidation after command execution"
"Bound Interceptors: RefreshInterceptor (non-Cacheable), CommandInterceptor (Cacheable)"
}
class Refresh {
<<Attribute>>
+uri: string
"Cache refresh after command execution"
"Bound Interceptors: RefreshInterceptor (non-Cacheable), CommandInterceptor (Cacheable)"
}
class RefreshCache {
<<Attribute>>
"Donut cache refresh after command execution"
"Bound Interceptors: DonutCacheInterceptor"
}
class CacheInterceptor {
<<Interceptor>>
"TTL-based caching on CQRS queries"
"Binds to: Cacheable"
}
class CommandInterceptor {
<<Interceptor>>
"Cache invalidation on CQRS commands"
"Binds to: Purge, Refresh (Cacheable)"
}
class HttpCacheInterceptor {
<<Interceptor>>
"HTTP Cache-Control header"
"Binds to: HttpCache, NoHttpCache"
}
class DonutCacheInterceptor {
<<Interceptor>>
"Donut caching on CQRS queries"
"Binds to: DonutCache, RefreshCache"
}
class DonutCacheableResponseInterceptor {
<<Interceptor>>
"Full response caching on CQRS queries"
"Binds to: CacheableResponse"
}
class DonutCommandInterceptor {
<<Interceptor>>
"Donut cache invalidation on CQRS commands"
"Binds to: CacheableResponse, DonutCache"
}
class RefreshInterceptor {
<<Interceptor>>
"Cache refresh for non-Cacheable classes"
"Binds to: Purge, Refresh (non-Cacheable)"
}
Cacheable <|.. CacheInterceptor
Cacheable <|.. CommandInterceptor
CacheableResponse <|.. DonutCacheableResponseInterceptor
CacheableResponse <|.. DonutCommandInterceptor
DonutCache <|.. DonutCacheInterceptor
DonutCache <|.. DonutCommandInterceptor
HttpCache <|.. HttpCacheInterceptor
NoHttpCache <|.. HttpCacheInterceptor
Purge <|.. RefreshInterceptor
Purge <|.. CommandInterceptor
Refresh <|.. RefreshInterceptor
Refresh <|.. CommandInterceptor
RefreshCache <|.. DonutCacheInterceptor
Flow diagram of attribute to interceptor bindingflowchart TD
A["#[Cacheable]"] --> B["CacheInterceptor (onGet)"]
A --> C["CommandInterceptor (onPut/onPatch/onDelete)"]
D["#[CacheableResponse]"] --> E["DonutCacheableResponseInterceptor (onGet)"]
D --> F["DonutCommandInterceptor (onPut/onPatch/onDelete)"]
D --> G["DonutCacheInterceptor (method)"]
H["#[DonutCache]"] --> I["DonutCacheInterceptor (onGet or method)"]
J["#[HttpCache]"] --> K["HttpCacheInterceptor (onGet)"]
L["#[NoHttpCache]"] --> K
M["#[Purge]"] --> N["RefreshInterceptor (non-Cacheable)"]
M --> O["CommandInterceptor (Cacheable)"]
P["#[Refresh]"] --> N
P --> O
Q["#[RefreshCache]"] --> I
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughThis PR enhances documentation across cache annotation and interceptor classes through comprehensive PHPDoc blocks, removes unused imports from interceptor references, and introduces property promotion with #[Commands] attribute in CommandInterceptor. No functional logic changes to core behaviors. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes
Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes - here's some feedback:
- Consider centralizing the interceptor binding lists into a shared doc template or trait to reduce duplication across annotations and interceptors.
- Use a constant or config for the manual’s base URL to ensure consistency and simplify updates when the docs path changes.
- Standardize the indentation and formatting of the code examples in the docblocks for consistency across all annotations.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider centralizing the interceptor binding lists into a shared doc template or trait to reduce duplication across annotations and interceptors.
- Use a constant or config for the manual’s base URL to ensure consistency and simplify updates when the docs path changes.
- Standardize the indentation and formatting of the code examples in the docblocks for consistency across all annotations.
## Individual Comments
### Comment 1
<location> `src-annotation/Cacheable.php:21-22` </location>
<code_context>
+ * #[Cacheable(expirySecond: 3600)]
+ *
+ * // Cache with predefined expiry preset
+ * #[Cacheable(expiry: 'short')] // short, medium, long, never
+ *
+ * // Cache until specific time from body field
</code_context>
<issue_to_address>
**suggestion:** The list of expiry presets could be referenced to a source or defined.
If these presets are defined or configurable elsewhere, please reference their source or clarify their definitions for better maintainability.
```suggestion
* // Cache with predefined expiry preset
* #[Cacheable(expiry: 'short')] // short, medium, long, never
* // See preset definitions in CacheInterceptor::$expiryPresets or config/cache.php
```
</issue_to_address>
### Comment 2
<location> `src-annotation/DonutCache.php:13-22` </location>
<code_context>
/**
+ * Enables event-driven cache invalidation for fully cacheable responses
+ *
+ * For content that is fundamentally static but changes predictably via resource
+ * methods (onPut, onDelete, etc.). Unlike #[Cacheable] which uses TTL-based
+ * expiration, this enables tag-based invalidation driven by resource dependencies.
</code_context>
<issue_to_address>
**suggestion:** Clarify the behavior when applied to method versus class.
Please clarify how DonutCacheInterceptor behaves when applied at the class level versus the method level, so users understand the scope and effect of the attribute in each case.
</issue_to_address>
### Comment 3
<location> `src-annotation/Purge.php:19-21` </location>
<code_context>
+ * #[Cacheable(expiryAt: 'expires_at')]
+ * ```
+ *
+ * Interceptors bound:
+ * - CacheInterceptor (onGet methods)
+ * - CommandInterceptor (onPut/onPatch/onDelete methods)
</code_context>
<issue_to_address>
**suggestion:** Clarify the difference in behavior for Cacheable vs non-Cacheable classes.
Expand the documentation to explain how the bound interceptors differ for Cacheable and non-Cacheable classes, clarifying the impact of using the Cacheable attribute.
</issue_to_address>
### Comment 4
<location> `src-annotation/Refresh.php:18-20` </location>
<code_context>
+ * #[Cacheable(expiryAt: 'expires_at')]
+ * ```
+ *
+ * Interceptors bound:
+ * - CacheInterceptor (onGet methods)
+ * - CommandInterceptor (onPut/onPatch/onDelete methods)
</code_context>
<issue_to_address>
**suggestion:** Clarify the distinction between interceptor behavior for Cacheable and non-Cacheable classes.
Add a short note explaining how refresh logic operates differently for Cacheable versus non-Cacheable classes to improve maintainability.
</issue_to_address>
### Comment 5
<location> `src-annotation/NoHttpCache.php:15-16` </location>
<code_context>
+ * #[Cacheable(expiryAt: 'expires_at')]
+ * ```
+ *
+ * Interceptors bound:
+ * - CacheInterceptor (onGet methods)
+ * - CommandInterceptor (onPut/onPatch/onDelete methods)
</code_context>
<issue_to_address>
**suggestion:** Consider clarifying the effect of NoHttpCache on HTTP headers.
Briefly note how NoHttpCache modifies HTTP headers to clarify its practical impact for users.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| * // Cache with predefined expiry preset | ||
| * #[Cacheable(expiry: 'short')] // short, medium, long, never |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: The list of expiry presets could be referenced to a source or defined.
If these presets are defined or configurable elsewhere, please reference their source or clarify their definitions for better maintainability.
| * // Cache with predefined expiry preset | |
| * #[Cacheable(expiry: 'short')] // short, medium, long, never | |
| * // Cache with predefined expiry preset | |
| * #[Cacheable(expiry: 'short')] // short, medium, long, never | |
| * // See preset definitions in CacheInterceptor::$expiryPresets or config/cache.php |
| * Interceptors bound: | ||
| * - HttpCacheInterceptor (onGet methods) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Consider clarifying the effect of NoHttpCache on HTTP headers.
Briefly note how NoHttpCache modifies HTTP headers to clarify its practical impact for users.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 1.x #167 +/- ##
===========================================
Coverage 100.00% 100.00%
Complexity 243 243
===========================================
Files 52 52
Lines 734 734
===========================================
Hits 734 734 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src-annotation/CacheableResponse.php (1)
19-29: Consider completing the method signatures in the example.The example code shows method signatures without bodies or continuation indicators. While the intent is clear, adding
{ ... }or a comment would make the example more syntactically complete and easier to understand.Apply this diff to improve the example clarity:
* Example: * ```php * #[CacheableResponse] * class Article extends ResourceObject * { - * public function onGet(int $id): static + * public function onGet(int $id): static + * { + * // ... + * } * * #[RefreshCache] - * public function onDelete(int $id): static + * public function onDelete(int $id): static + * { + * // ... + * } * } * ```
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
src-annotation/Cacheable.php(1 hunks)src-annotation/CacheableResponse.php(1 hunks)src-annotation/DonutCache.php(1 hunks)src-annotation/HttpCache.php(1 hunks)src-annotation/NoHttpCache.php(1 hunks)src-annotation/Purge.php(1 hunks)src-annotation/Refresh.php(1 hunks)src-annotation/RefreshCache.php(1 hunks)src/CacheInterceptor.php(1 hunks)src/CommandInterceptor.php(1 hunks)src/DonutCacheInterceptor.php(1 hunks)src/DonutCacheableResponseInterceptor.php(1 hunks)src/DonutCommandInterceptor.php(1 hunks)src/HttpCacheInterceptor.php(1 hunks)src/RefreshInterceptor.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Adhere to PSR-12 coding standards using PHP_CodeSniffer for all PHP source files
Files:
src/DonutCacheableResponseInterceptor.phpsrc-annotation/DonutCache.phpsrc-annotation/Purge.phpsrc/HttpCacheInterceptor.phpsrc/DonutCacheInterceptor.phpsrc/RefreshInterceptor.phpsrc/CommandInterceptor.phpsrc-annotation/Refresh.phpsrc-annotation/CacheableResponse.phpsrc/CacheInterceptor.phpsrc/DonutCommandInterceptor.phpsrc-annotation/NoHttpCache.phpsrc-annotation/Cacheable.phpsrc-annotation/HttpCache.phpsrc-annotation/RefreshCache.php
{src,tests}/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
{src,tests}/**/*.php: Ensure code passes PHPStan at max level as configured by phpstan.neon
Ensure code passes Psalm at error level 1 as configured by psalm.xml
Files:
src/DonutCacheableResponseInterceptor.phpsrc/HttpCacheInterceptor.phpsrc/DonutCacheInterceptor.phpsrc/RefreshInterceptor.phpsrc/CommandInterceptor.phpsrc/CacheInterceptor.phpsrc/DonutCommandInterceptor.php
src-annotation/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Define and maintain cache-related attributes #[Cacheable], #[HttpCache], #[Refresh], #[Purge] in src-annotation/
Files:
src-annotation/DonutCache.phpsrc-annotation/Purge.phpsrc-annotation/Refresh.phpsrc-annotation/CacheableResponse.phpsrc-annotation/NoHttpCache.phpsrc-annotation/Cacheable.phpsrc-annotation/HttpCache.phpsrc-annotation/RefreshCache.php
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: bearsunday/BEAR.QueryRepository PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-21T05:23:58.622Z
Learning: Applies to src-annotation/**/*.php : Define and maintain cache-related attributes #[Cacheable], #[HttpCache], #[Refresh], #[Purge] in src-annotation/
📚 Learning: 2025-10-21T05:23:58.622Z
Learnt from: CR
Repo: bearsunday/BEAR.QueryRepository PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-21T05:23:58.622Z
Learning: Applies to src-annotation/**/*.php : Define and maintain cache-related attributes #[Cacheable], #[HttpCache], #[Refresh], #[Purge] in src-annotation/
Applied to files:
src/DonutCacheableResponseInterceptor.phpsrc-annotation/DonutCache.phpsrc-annotation/Purge.phpsrc/HttpCacheInterceptor.phpsrc/DonutCacheInterceptor.phpsrc/RefreshInterceptor.phpsrc-annotation/Refresh.phpsrc-annotation/CacheableResponse.phpsrc/CacheInterceptor.phpsrc/DonutCommandInterceptor.phpsrc-annotation/NoHttpCache.phpsrc-annotation/Cacheable.phpsrc-annotation/HttpCache.phpsrc-annotation/RefreshCache.php
📚 Learning: 2024-11-01T14:52:06.297Z
Learnt from: koriym
Repo: bearsunday/BEAR.QueryRepository PR: 144
File: src-deprecated/ResourceStorageCacheableTrait.php:24-24
Timestamp: 2024-11-01T14:52:06.297Z
Learning: When deprecating the `ResourceStorageCacheableTrait` in `src-deprecated/ResourceStorageCacheableTrait.php`, it is acceptable to only add the `deprecated` annotation without adding a runtime deprecation notice using `trigger_deprecation()`.
Applied to files:
src-annotation/Cacheable.php
⏰ 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: Sourcery review
🔇 Additional comments (10)
src/CommandInterceptor.php (2)
15-24: Excellent documentation!The docblock provides clear, comprehensive information about the interceptor's purpose, binding, and execution context. This aligns perfectly with the PR's goal of making it easier to understand interceptor bindings without reading module code.
28-30: No changes required — the #[Commands] attribute usage is properly implemented.The attribute is correctly defined as a
#[Qualifier]insrc-annotation/Commands.phpand properly bound inCacheableModule.phpto inject an array of command implementations viaCommandsProvider. The constructor property promotion syntax is PSR-12 compliant and follows standard Ray\DI patterns. Static analysis configurations are in place.src-annotation/Purge.php (1)
9-24: Excellent documentation improvements!The comprehensive PHPDoc block clearly explains the cache purging behavior, provides practical examples with URI templates, and documents the interceptor binding logic for both Cacheable and non-Cacheable classes. This directly addresses the previous review feedback about clarifying interceptor behavior differences.
src/DonutCacheInterceptor.php (1)
7-20: Well-documented new interceptor class.The PHPDoc block clearly explains the donut caching strategy for CQRS queries, binding behavior, and the key distinction that no ETag is generated for the entire response. The
IS_ENTIRE_CONTENT_CACHEABLE = falseconstant appropriately differentiates this fromDonutCacheableResponseInterceptor.src/DonutCacheableResponseInterceptor.php (1)
7-16: Clear documentation of full response caching.The PHPDoc block effectively explains the interceptor's role in caching entire responses with ETag generation and 304 Not Modified support. The documentation clearly contrasts with
DonutCacheInterceptorby emphasizing full response caching.src-annotation/Refresh.php (1)
9-23: Comprehensive documentation addressing previous feedback.The enhanced PHPDoc block clearly documents cache refresh behavior, provides a practical example, and explicitly addresses the previous review comment by clarifying how interceptor binding differs between Cacheable and non-Cacheable classes.
src/RefreshInterceptor.php (1)
14-23: Well-documented interceptor binding behavior.The PHPDoc block clearly explains the interceptor's role in cache invalidation for non-Cacheable classes, its binding to Purge/Refresh attributes, and the execution flow. This complements the documentation in the corresponding attribute classes.
src-annotation/DonutCache.php (1)
10-33: Comprehensive documentation addressing previous feedback.The extensive PHPDoc block clearly explains donut caching use cases, provides a practical example with embedded resources, and explicitly addresses the previous review comment by clarifying interceptor binding behavior when applied at class versus method level (line 29). The contrast with TTL-based
#[Cacheable]is particularly helpful.src/DonutCommandInterceptor.php (1)
22-31: Clear documentation of command-side cache invalidation.The PHPDoc block effectively explains the interceptor's role in CQRS command handling, its binding to write operations (onPut/onPatch/onDelete) on CacheableResponse classes, and the cache refresh behavior after successful writes.
src-annotation/RefreshCache.php (1)
9-16: Concise and clear documentation.The PHPDoc block effectively documents the donut cache refresh behavior and its binding to
DonutCacheInterceptor, with an appropriate manual reference for cache invalidation.
… classes - Explain automatic binding for Cacheable classes (CommandInterceptor) - Explain explicit attribute requirement for non-Cacheable classes (RefreshInterceptor) - Cross-reference related interceptors in documentation - Address review comment: #167 (comment) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Add method bodies ({ ... }) to all example method signatures to make
the code syntactically complete and easier to understand.
Address CodeRabbit review comment.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
Summary
Changes
Cache Attributes Documentation
#[Cacheable] - TTL-based caching
#[HttpCache] - HTTP Cache-Control header
#[NoHttpCache] - Disable HTTP caching
#[CacheableResponse] - Event-driven full response caching
#[DonutCache] - Event-driven donut caching
#[Purge] / #[Refresh] - Cache invalidation
#[RefreshCache] - Donut cache refresh
Interceptor Classes Documentation
CacheInterceptor - TTL-based caching on CQRS queries
CommandInterceptor - Cache invalidation on CQRS commands
HttpCacheInterceptor - HTTP Cache-Control header
DonutCacheInterceptor - Donut caching on CQRS queries
DonutCacheableResponseInterceptor - Full response caching on CQRS queries
DonutCommandInterceptor - Donut cache invalidation on CQRS commands
RefreshInterceptor - Cache refresh for non-Cacheable classes
All interceptors now include:
Benefits
Summary by Sourcery
Document cache annotations and interceptor classes with detailed docblocks, usage examples, binding information, and links to the manual
Enhancements:
Documentation: