From 79c37ea59953298d96c6127c2daaa7d5ec1625c4 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Thu, 6 Nov 2025 18:24:05 +0900 Subject: [PATCH 01/20] refactor: Migrate from doctrine/annotations to PHP 8 Attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove doctrine/annotations and doctrine/cache dependencies from composer.json and replace annotation reader usage with native PHP 8 Attributes API. Changes: - QueryRepository: Replace Reader::getClassAnnotation() with ReflectionClass::getAttributes() - HttpCacheInterceptor: Replace getAnnotation() with getAttributes() for HttpCache and NoHttpCache attributes - Remove Reader dependency from QueryRepository constructor - Update test code to match new constructor signature All tests pass successfully (103 tests, 200 assertions). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- composer.json | 2 -- src/HttpCacheInterceptor.php | 10 +++++++++- src/QueryRepository.php | 10 ++++++---- tests/ResourceRepositoryTest.php | 3 --- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index c61d45ca..9d04276a 100644 --- a/composer.json +++ b/composer.json @@ -18,8 +18,6 @@ "php": "^8.1", "bear/resource": "^1.16.1", "bear/sunday": "^1.5", - "doctrine/annotations": "^1.8 || ^2.0", - "doctrine/cache": "^1.12 || ^2.0", "psr/cache": "^1.0 || ^2.0 || ^3.0", "ray/aop": "^2.16", "ray/di": "^2.17.2", diff --git a/src/HttpCacheInterceptor.php b/src/HttpCacheInterceptor.php index f740761b..26c94c08 100644 --- a/src/HttpCacheInterceptor.php +++ b/src/HttpCacheInterceptor.php @@ -5,6 +5,8 @@ namespace BEAR\QueryRepository; use BEAR\RepositoryModule\Annotation\AbstractCacheControl; +use BEAR\RepositoryModule\Annotation\HttpCache; +use BEAR\RepositoryModule\Annotation\NoHttpCache; use BEAR\Resource\ResourceObject; use Override; use Ray\Aop\MethodInterceptor; @@ -20,7 +22,13 @@ final class HttpCacheInterceptor implements MethodInterceptor #[Override] public function invoke(MethodInvocation $invocation) { - $cacheControl = $invocation->getMethod()->getDeclaringClass()->getAnnotation(AbstractCacheControl::class); + $class = $invocation->getMethod()->getDeclaringClass(); + $attributes = $class->getAttributes(HttpCache::class); + if (empty($attributes)) { + $attributes = $class->getAttributes(NoHttpCache::class); + } + + $cacheControl = isset($attributes[0]) ? $attributes[0]->newInstance() : null; $ro = $invocation->proceed(); assert($ro instanceof ResourceObject); if ($ro->code === 200 && $cacheControl instanceof AbstractCacheControl) { diff --git a/src/QueryRepository.php b/src/QueryRepository.php index c4d9500d..f6e0e15e 100644 --- a/src/QueryRepository.php +++ b/src/QueryRepository.php @@ -9,7 +9,6 @@ use BEAR\RepositoryModule\Annotation\HttpCache; use BEAR\Resource\AbstractUri; use BEAR\Resource\ResourceObject; -use Doctrine\Common\Annotations\Reader; use Override; use ReflectionClass; @@ -24,7 +23,6 @@ public function __construct( private readonly RepositoryLoggerInterface $logger, private readonly HeaderSetter $headerSetter, private readonly ResourceStorageInterface $storage, - private readonly Reader $reader, private readonly Expiry $expiry, ) { } @@ -85,12 +83,16 @@ public function purge(AbstractUri $uri) private function getHttpCacheAnnotation(ResourceObject $ro): HttpCache|null { - return $this->reader->getClassAnnotation(new ReflectionClass($ro), HttpCache::class); + $attributes = (new ReflectionClass($ro))->getAttributes(HttpCache::class); + + return isset($attributes[0]) ? $attributes[0]->newInstance() : null; } private function getCacheableAnnotation(ResourceObject $ro): Cacheable|null { - return $this->reader->getClassAnnotation(new ReflectionClass($ro), Cacheable::class); + $attributes = (new ReflectionClass($ro))->getAttributes(Cacheable::class); + + return isset($attributes[0]) ? $attributes[0]->newInstance() : null; } private function getExpiryTime(ResourceObject $ro, Cacheable|null $cacheable = null): int diff --git a/tests/ResourceRepositoryTest.php b/tests/ResourceRepositoryTest.php index 4d3160b2..bb2a40a6 100644 --- a/tests/ResourceRepositoryTest.php +++ b/tests/ResourceRepositoryTest.php @@ -6,7 +6,6 @@ use BEAR\QueryRepository\QueryRepository as Repository; use BEAR\Resource\Uri; -use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Cache\CacheProvider; use FakeVendor\HelloWorld\Resource\Page\Index; use PHPUnit\Framework\TestCase; @@ -49,7 +48,6 @@ public function get() $tagAwareAdapterProvider, $tagAwareAdapterProvider, ), - new AnnotationReader(), new Expiry(0, 0, 0), ); $this->ro = new Index(); @@ -138,7 +136,6 @@ public function get() $tagAwareAdapterProvider, $tagAwareAdapterProvider, ), - new AnnotationReader(), new Expiry(0, 0, 0), ); $this->assertInstanceOf(Repository::class, $repository); From b52a80489cae944f582960bb56f8989042df29a1 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 9 Nov 2025 07:43:50 +0900 Subject: [PATCH 02/20] Add annotation to attribute migration support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide tooling and documentation to help users migrate from Doctrine annotations to PHP 8 attributes: - Add rector-migrate.php: Rector configuration for automated migration of BEAR.QueryRepository annotations - Add ANNOTATION_TO_ATTRIBUTE.md: Comprehensive migration guide with: - Explanation of why migration is necessary (doctrine/annotations is abandoned) - Step-by-step migration instructions - Before/after code examples - Troubleshooting guide - List of all supported annotations - Update CHANGELOG.md: Update release date to 2025-11-09 and add migration tool entries This supports users in migrating their applications away from the abandoned doctrine/annotations package to native PHP 8 attributes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ANNOTATION_TO_ATTRIBUTE.md | 319 +++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 5 +- rector-migrate.php | 37 +++++ 3 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 ANNOTATION_TO_ATTRIBUTE.md create mode 100644 rector-migrate.php diff --git a/ANNOTATION_TO_ATTRIBUTE.md b/ANNOTATION_TO_ATTRIBUTE.md new file mode 100644 index 00000000..5e199cd9 --- /dev/null +++ b/ANNOTATION_TO_ATTRIBUTE.md @@ -0,0 +1,319 @@ +# Migrating from Doctrine Annotations to PHP 8 Attributes + +## Overview + +BEAR.QueryRepository 1.13.0 has removed the dependency on `doctrine/annotations` and now exclusively uses native PHP 8 attributes. This guide will help you migrate your application code from Doctrine annotations to PHP 8 attributes. + +## Why Migrate? + +- **doctrine/annotations is Abandoned**: The `doctrine/annotations` package has been officially abandoned by its maintainers. Continuing to use it poses security and compatibility risks as it will no longer receive updates or security patches. +- **Native PHP Support**: PHP 8 attributes are a built-in language feature, providing first-class support without external dependencies +- **Better Performance**: No runtime annotation parsing overhead - attributes are compiled and cached by PHP itself +- **Modern Syntax**: Cleaner, more readable code that follows PHP 8+ best practices +- **No Extra Dependencies**: Eliminates the need for the abandoned doctrine/annotations package +- **Future-Proof**: Attributes are the official PHP standard for metadata, ensuring long-term compatibility + +## Migration Steps + +### Step 1: Update BEAR.QueryRepository + +First, ensure you're using BEAR.QueryRepository v1.13.0 or later: + +```bash +composer require bear/query-repository:^1.13 +``` + +### Step 2: Install Rector (if not already installed) + +Rector is an automated refactoring tool that can convert annotations to attributes: + +```bash +composer require --dev rector/rector +``` + +### Step 3: Run Automated Migration + +BEAR.QueryRepository provides a Rector configuration file for automated migration: + +```bash +# Dry-run to preview changes +vendor/bin/rector process src --config=vendor/bear/query-repository/rector-migrate.php --dry-run + +# Apply the changes +vendor/bin/rector process src --config=vendor/bear/query-repository/rector-migrate.php +``` + +If you have tests that use annotations: + +```bash +vendor/bin/rector process tests --config=vendor/bear/query-repository/rector-migrate.php +``` + +### Step 4: Manual Review + +Review the changes made by Rector and adjust if necessary. Pay special attention to: + +- Multi-line annotations with complex values +- Annotations with custom parameters +- Import statements (Rector should handle these automatically) + +### Step 5: Remove doctrine/annotations + +After migration, you can safely remove the doctrine/annotations dependency: + +```bash +composer remove doctrine/annotations +``` + +## Before and After Examples + +### Cacheable Resource + +**Before (Doctrine Annotation):** +```php +use BEAR\RepositoryModule\Annotation\Cacheable; + +/** + * @Cacheable(expiry="short", type="value") + */ +class User extends ResourceObject +{ + public function onGet($id) + { + // ... + } +} +``` + +**After (PHP 8 Attribute):** +```php +use BEAR\RepositoryModule\Annotation\Cacheable; + +#[Cacheable(expiry: "short", type: "value")] +class User extends ResourceObject +{ + public function onGet($id) + { + // ... + } +} +``` + +### HTTP Cache Headers + +**Before (Doctrine Annotation):** +```php +use BEAR\RepositoryModule\Annotation\HttpCache; + +/** + * @HttpCache(maxAge=60, sMaxAge=600) + */ +class News extends ResourceObject +{ + public function onGet() + { + // ... + } +} +``` + +**After (PHP 8 Attribute):** +```php +use BEAR\RepositoryModule\Annotation\HttpCache; + +#[HttpCache(maxAge: 60, sMaxAge: 600)] +class News extends ResourceObject +{ + public function onGet() + { + // ... + } +} +``` + +### Cache Invalidation + +**Before (Doctrine Annotation):** +```php +use BEAR\RepositoryModule\Annotation\Refresh; +use BEAR\RepositoryModule\Annotation\Purge; + +class User extends ResourceObject +{ + /** + * @Refresh(uri="app://self/users") + * @Purge(uri="app://self/user/{id}") + */ + public function onPut($id, $name) + { + // ... + } +} +``` + +**After (PHP 8 Attribute):** +```php +use BEAR\RepositoryModule\Annotation\Refresh; +use BEAR\RepositoryModule\Annotation\Purge; + +class User extends ResourceObject +{ + #[Refresh(uri: "app://self/users")] + #[Purge(uri: "app://self/user/{id}")] + public function onPut($id, $name) + { + // ... + } +} +``` + +### Complex Cache Configuration + +**Before (Doctrine Annotation):** +```php +use BEAR\RepositoryModule\Annotation\Cacheable; +use BEAR\RepositoryModule\Annotation\HttpCache; + +/** + * @Cacheable(expiry="medium", expirySecond=3600, type="view", update=true) + * @HttpCache(maxAge=60, sMaxAge=600, isPrivate=false, mustRevalidate=true) + */ +class Article extends ResourceObject +{ + // ... +} +``` + +**After (PHP 8 Attribute):** +```php +use BEAR\RepositoryModule\Annotation\Cacheable; +use BEAR\RepositoryModule\Annotation\HttpCache; + +#[Cacheable(expiry: "medium", expirySecond: 3600, type: "view", update: true)] +#[HttpCache(maxAge: 60, sMaxAge: 600, isPrivate: false, mustRevalidate: true)] +class Article extends ResourceObject +{ + // ... +} +``` + +### Donut Caching + +**Before (Doctrine Annotation):** +```php +use BEAR\RepositoryModule\Annotation\DonutCache; + +class Page extends ResourceObject +{ + /** + * @DonutCache + */ + public function onGet() + { + // ... + } +} +``` + +**After (PHP 8 Attribute):** +```php +use BEAR\RepositoryModule\Annotation\DonutCache; + +class Page extends ResourceObject +{ + #[DonutCache] + public function onGet() + { + // ... + } +} +``` + +## Supported Annotations + +The following BEAR.QueryRepository annotations are automatically converted: + +- `@Cacheable` → `#[Cacheable]` - Resource caching configuration +- `@HttpCache` → `#[HttpCache]` - HTTP cache control headers +- `@NoHttpCache` → `#[NoHttpCache]` - Disable HTTP caching +- `@Refresh` → `#[Refresh]` - Invalidate dependent caches +- `@Purge` → `#[Purge]` - Purge specific cache entries +- `@DonutCache` → `#[DonutCache]` - Donut caching pattern + +## Key Differences + +1. **Syntax Change**: Use `#[AttributeName]` instead of `@AttributeName` in docblocks +2. **Named Parameters**: Use colons for parameters (e.g., `expiry: "short"` instead of `expiry="short"`) +3. **Placement**: Attributes go before the class/method declaration, not in docblocks +4. **Import Statements**: Add proper `use` statements for all attributes +5. **Multiple Attributes**: Stack multiple attributes on separate lines or combine with commas + +## Troubleshooting + +### Rector doesn't find annotations + +Make sure your code is using fully qualified class names in `use` statements: + +```php +// Correct +use BEAR\RepositoryModule\Annotation\Cacheable; + +// Incorrect - Rector won't recognize this +use BEAR\RepositoryModule\Annotation as Cache; +``` + +### Import statements not updated + +Rector should automatically update import statements, but if it doesn't: + +1. Manually verify `use` statements are present +2. Run your IDE's "Optimize Imports" feature +3. Use tools like PHP-CS-Fixer to clean up unused imports + +### Complex annotation values + +For annotations with complex array values, you may need to manually adjust the syntax: + +**Before:** +```php +/** + * @HttpCache(etag={"id", "updated_at"}) + */ +``` + +**After:** +```php +#[HttpCache(etag: ["id", "updated_at"])] +``` + +### Testing the migration + +After migration, ensure all tests pass: + +```bash +composer test +``` + +## Manual Migration + +If you prefer not to use Rector, you can manually convert annotations: + +1. Replace `/** @AnnotationName */` with `#[AnnotationName]` +2. Move attributes from docblocks to the line before the method/property/class +3. Convert parameter syntax from `key="value"` to `key: "value"` +4. Ensure all necessary `use` statements are present +5. For multiple attributes, place each on a new line or combine: `#[Attr1, Attr2]` + +## Need Help? + +If you encounter issues during migration: + +1. Check the [BEAR.QueryRepository documentation](https://github.com/bearsunday/BEAR.QueryRepository) +2. Review the [PHP 8 Attributes documentation](https://www.php.net/manual/en/language.attributes.php) +3. [Open an issue](https://github.com/bearsunday/BEAR.QueryRepository/issues) on GitHub + +## References + +- [PHP 8 Attributes RFC](https://wiki.php.net/rfc/attributes_v2) +- [Rector Documentation](https://github.com/rectorphp/rector) +- [BEAR.Sunday Documentation](https://bearsunday.github.io/) \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5523fca5..794dfbfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [1.13.0] - 2025-10-21 +## [1.13.0] - 2025-11-09 ### Added +- **Migration Tools**: Added `rector-migrate.php` for automated annotation-to-attribute migration +- **Migration Guide**: Added `ANNOTATION_TO_ATTRIBUTE.md` with comprehensive migration instructions - Add CLAUDE.md with comprehensive codebase architecture and development guide - Add marshaller configuration support for Redis with compression options (deflate) - Add `MarshallerType` enum for type-safe marshaller selection @@ -25,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add PHP 8.5 support to CI workflow ### Changed +- **PHP 8 Attributes Migration**: Removed `doctrine/annotations` and `doctrine/cache` dependencies, migrated to native PHP 8 attributes - Improve marshaller provider error handling with better exception messages - Enhance Memcached module with TagAwareAdapter support - Update Symfony Cache to support version ^7.3 diff --git a/rector-migrate.php b/rector-migrate.php new file mode 100644 index 00000000..4121a69d --- /dev/null +++ b/rector-migrate.php @@ -0,0 +1,37 @@ +withPaths([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + ->withConfiguredRule( + AnnotationToAttributeRector::class, + [ + // BEAR.QueryRepository Annotations + new AnnotationToAttribute('BEAR\RepositoryModule\Annotation\Cacheable'), + new AnnotationToAttribute('BEAR\RepositoryModule\Annotation\HttpCache'), + new AnnotationToAttribute('BEAR\RepositoryModule\Annotation\NoHttpCache'), + new AnnotationToAttribute('BEAR\RepositoryModule\Annotation\Refresh'), + new AnnotationToAttribute('BEAR\RepositoryModule\Annotation\Purge'), + new AnnotationToAttribute('BEAR\RepositoryModule\Annotation\DonutCache'), + new AnnotationToAttribute('BEAR\RepositoryModule\Annotation\RefreshCache'), + new AnnotationToAttribute('BEAR\RepositoryModule\Annotation\Commands'), + ] + ); \ No newline at end of file From 34a5ef36e5c5980830e3afc87f8138968d541d33 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 9 Nov 2025 11:55:03 +0900 Subject: [PATCH 03/20] refactor: Remove doctrine/annotations remnants from attribute classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove all Doctrine annotation-related imports and docblock annotations from attribute classes in src-annotation/: - Remove `use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor` - Remove `@Annotation`, `@Target`, `@NamedArgumentConstructor` docblock annotations - Keep only PHP 8 Attribute declarations and `@see` documentation Affected files: - Cacheable.php - HttpCache.php - Refresh.php - Purge.php - KnownTagTtl.php - Redis.php - CacheEngine.php - Memcache.php 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src-annotation/CacheEngine.php | 7 ------- src-annotation/Cacheable.php | 8 -------- src-annotation/HttpCache.php | 6 ------ src-annotation/KnownTagTtl.php | 6 ------ src-annotation/Memcache.php | 7 ------- src-annotation/Purge.php | 8 +------- src-annotation/Redis.php | 7 ------- src-annotation/Refresh.php | 8 +------- 8 files changed, 2 insertions(+), 55 deletions(-) diff --git a/src-annotation/CacheEngine.php b/src-annotation/CacheEngine.php index de6b18cf..c25200d8 100644 --- a/src-annotation/CacheEngine.php +++ b/src-annotation/CacheEngine.php @@ -5,15 +5,8 @@ namespace BEAR\RepositoryModule\Annotation; use Attribute; -use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; use Ray\Di\Di\Qualifier; -/** - * @Annotation - * @Target("METHOD") - * @Qualifier() - * @NamedArgumentConstructor() - */ #[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PROPERTY)] #[Qualifier] final class CacheEngine diff --git a/src-annotation/Cacheable.php b/src-annotation/Cacheable.php index c74e3f71..27790af0 100644 --- a/src-annotation/Cacheable.php +++ b/src-annotation/Cacheable.php @@ -5,15 +5,7 @@ namespace BEAR\RepositoryModule\Annotation; use Attribute; -use BEAR\QueryRepository\CacheInterceptor; -use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; -/** - * @Annotation - * @Target("CLASS") - * @see CacheInterceptor - * @NamedArgumentConstructor() - */ #[Attribute(Attribute::TARGET_CLASS)] final class Cacheable { diff --git a/src-annotation/HttpCache.php b/src-annotation/HttpCache.php index 449b0353..47e66684 100644 --- a/src-annotation/HttpCache.php +++ b/src-annotation/HttpCache.php @@ -6,7 +6,6 @@ use Attribute; use BEAR\QueryRepository\HttpCacheInterceptor; -use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; use function implode; use function sprintf; @@ -16,11 +15,6 @@ * * Builds a complex Cache-Control header * - * @Annotation - * @Target("CLASS") - * @NamedArgumentConstructor() - * - * {@inheritDoc} * @see HttpCacheInterceptor */ #[Attribute(Attribute::TARGET_CLASS)] diff --git a/src-annotation/KnownTagTtl.php b/src-annotation/KnownTagTtl.php index 4c279758..cd70d519 100644 --- a/src-annotation/KnownTagTtl.php +++ b/src-annotation/KnownTagTtl.php @@ -5,14 +5,8 @@ namespace BEAR\RepositoryModule\Annotation; use Attribute; -use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; use Ray\Di\Di\Qualifier; -/** - * @Annotation - * @Qualifier - * @NamedArgumentConstructor - */ #[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_METHOD)] #[Qualifier] final class KnownTagTtl diff --git a/src-annotation/Memcache.php b/src-annotation/Memcache.php index edf7187f..6a7d67d6 100644 --- a/src-annotation/Memcache.php +++ b/src-annotation/Memcache.php @@ -5,15 +5,8 @@ namespace BEAR\RepositoryModule\Annotation; use Attribute; -use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; use Ray\Di\Di\Qualifier; -/** - * @Annotation - * @Target("METHOD") - * @Qualifier() - * @NamedArgumentConstructor() - */ #[Attribute(Attribute::TARGET_METHOD)] #[Qualifier] final class Memcache diff --git a/src-annotation/Purge.php b/src-annotation/Purge.php index 2dae7d7b..147caa55 100644 --- a/src-annotation/Purge.php +++ b/src-annotation/Purge.php @@ -5,14 +5,8 @@ namespace BEAR\RepositoryModule\Annotation; use Attribute; -use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; -/** - * @Annotation - * @Target("METHOD") - * @NamedArgumentConstructor() - * @see RefreshInterceptor - */ +/** @see RefreshInterceptor */ #[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] final class Purge extends AbstractCommand { diff --git a/src-annotation/Redis.php b/src-annotation/Redis.php index 47a27e40..b0dd3136 100644 --- a/src-annotation/Redis.php +++ b/src-annotation/Redis.php @@ -5,15 +5,8 @@ namespace BEAR\RepositoryModule\Annotation; use Attribute; -use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; use Ray\Di\Di\Qualifier; -/** - * @Annotation - * @Target("METHOD") - * @Qualifier() - * @NamedArgumentConstructor() - */ #[Attribute(Attribute::TARGET_METHOD)] #[Qualifier] final class Redis diff --git a/src-annotation/Refresh.php b/src-annotation/Refresh.php index 4a1500ef..1f096d2a 100644 --- a/src-annotation/Refresh.php +++ b/src-annotation/Refresh.php @@ -6,14 +6,8 @@ use Attribute; use BEAR\QueryRepository\RefreshInterceptor; -use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; -/** - * @Annotation - * @Target("METHOD") - * @NamedArgumentConstructor() - * @see RefreshInterceptor - */ +/** @see RefreshInterceptor */ #[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] final class Refresh extends AbstractCommand { From 8891cd7506a03ee9d9c0911d748c455fd24d8176 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 9 Nov 2025 13:50:38 +0900 Subject: [PATCH 04/20] refactor: Remove koriym/attributes dependency and migrate to native PHP Reflection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Complete migration from annotation readers to native PHP 8 Reflection API: - Remove koriym/attributes from composer.json dev dependencies - Update AttributeTest to use native getAttributes() instead of annotation readers - Remove AttributeReader and ServiceLocator setup from tests/bootstrap.php - Remove all docblock annotations from test fixture files - Clean up empty docblocks left after annotation removal Test fixtures updated (32 files): - Remove @Cacheable, @Refresh, @Purge, @HttpCache docblock annotations - Keep only PHP 8 #[Attribute] syntax - All tests pass (102 tests, 198 assertions) This completes the transition to native PHP 8 Attributes, eliminating all dependencies on the abandoned doctrine/annotations package and its wrappers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- composer.json | 1 - tests-php8/AttributeTest.php | 45 ++++++++----------- tests/Fake/fake-app/src/Resource/App/Code.php | 3 -- .../src/Resource/App/ControlExpiry.php | 3 -- .../src/Resource/App/ControlExpiryError.php | 3 -- .../fake-app/src/Resource/App/ControlNone.php | 3 -- .../src/Resource/App/ControlPublic.php | 3 -- .../src/Resource/App/Dep/LevelOne.php | 3 -- .../Fake/fake-app/src/Resource/App/Entry.php | 5 --- tests/Fake/fake-app/src/Resource/App/Etag.php | 4 -- .../src/Resource/App/HttpCacheControl.php | 3 -- .../App/HttpCacheControlOverrideMaxAge.php | 4 -- .../App/HttpCacheControlWithCacheable.php | 4 -- .../fake-app/src/Resource/App/Invalid.php | 3 -- .../fake-app/src/Resource/App/NullView.php | 3 -- .../Resource/App/SometimesSameResponse.php | 3 -- .../fake-app/src/Resource/App/TypedParam.php | 4 -- .../fake-app/src/Resource/App/Unmatch.php | 4 -- tests/Fake/fake-app/src/Resource/App/User.php | 5 --- .../src/Resource/App/User/Profile.php | 3 -- .../Fake/fake-app/src/Resource/App/Value.php | 3 -- tests/Fake/fake-app/src/Resource/App/View.php | 3 -- .../src/Resource/Page/Dep/LevelOne.php | 3 -- .../src/Resource/Page/Dep/LevelThree.php | 3 -- .../src/Resource/Page/Dep/LevelTwo.php | 3 -- .../fake-app/src/Resource/Page/EmbVal.php | 3 -- .../fake-app/src/Resource/Page/EmbView.php | 3 -- .../src/Resource/Page/Html/BlogPosting.php | 3 -- .../Resource/Page/Html/BlogPostingCache.php | 2 - .../Page/Html/BlogPostingCacheControl.php | 3 -- .../src/Resource/Page/Html/Comment.php | 3 -- .../fake-app/src/Resource/Page/Html/Like.php | 3 -- .../Resource/Page/Html/PageSurrogateKey.php | 3 -- .../Fake/fake-app/src/Resource/Page/Index.php | 3 -- tests/bootstrap.php | 5 --- 35 files changed, 18 insertions(+), 137 deletions(-) diff --git a/composer.json b/composer.json index 9d04276a..592ce275 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,6 @@ "ext-redis": "*", "bamarni/composer-bin-plugin": "^1.8", "bear/fastly-module": "^1.0", - "koriym/attributes": "^1.0.1", "madapaja/twig-module": "^2.6", "mobiledetect/mobiledetectlib": "^3.74 || ^4.8", "phpunit/phpunit": "^9.6.23", diff --git a/tests-php8/AttributeTest.php b/tests-php8/AttributeTest.php index e0fc0b9f..2e7a3ac4 100644 --- a/tests-php8/AttributeTest.php +++ b/tests-php8/AttributeTest.php @@ -8,45 +8,36 @@ use BEAR\RepositoryModule\Annotation\NoHttpCache; use BEAR\RepositoryModule\Annotation\Purge; use BEAR\RepositoryModule\Annotation\Refresh; -use Doctrine\Common\Annotations\AnnotationReader; -use Doctrine\Common\Annotations\Reader; -use Koriym\Attributes\AttributeReader; use PHPUnit\Framework\TestCase; use ReflectionClass; use ReflectionMethod; class AttributeTest extends TestCase { - /** @var Reader */ - protected $reader; - - /** - * @return array - */ - public function readerProvider() : array - { - return [ - [new AttributeReader()], - [new AnnotationReader()] - ]; - } - - /** - * @dataProvider readerProvider - */ - public function testReadAttributes(Reader $reader) : void + public function testReadAttributes() : void { $class = new ReflectionClass(FakeAttributes::class); - $cacheable = $reader->getClassAnnotation($class, Cacheable::class); + + $cacheableAttrs = $class->getAttributes(Cacheable::class); + $this->assertNotEmpty($cacheableAttrs); + $cacheable = $cacheableAttrs[0]->newInstance(); $this->assertInstanceOf(Cacheable::class, $cacheable); - $noHttpCache = $reader->getClassAnnotation($class, NoHttpCache::class); - $this->assertInstanceOf(NoHttpCache::class, $noHttpCache); - $noHttpCache = $reader->getClassAnnotation($class, NoHttpCache::class); + + $noHttpCacheAttrs = $class->getAttributes(NoHttpCache::class); + $this->assertNotEmpty($noHttpCacheAttrs); + $noHttpCache = $noHttpCacheAttrs[0]->newInstance(); $this->assertInstanceOf(NoHttpCache::class, $noHttpCache); + $method = new ReflectionMethod(FakeAttributes::class, 'onGet'); - $purge = $reader->getMethodAnnotation($method, Purge::class); + + $purgeAttrs = $method->getAttributes(Purge::class); + $this->assertNotEmpty($purgeAttrs); + $purge = $purgeAttrs[0]->newInstance(); $this->assertInstanceOf(Purge::class, $purge); - $refresh = $reader->getMethodAnnotation($method, Refresh::class); + + $refreshAttrs = $method->getAttributes(Refresh::class); + $this->assertNotEmpty($refreshAttrs); + $refresh = $refreshAttrs[0]->newInstance(); $this->assertInstanceOf(Refresh::class, $refresh); } } diff --git a/tests/Fake/fake-app/src/Resource/App/Code.php b/tests/Fake/fake-app/src/Resource/App/Code.php index c6a0e26f..a45f5ebc 100644 --- a/tests/Fake/fake-app/src/Resource/App/Code.php +++ b/tests/Fake/fake-app/src/Resource/App/Code.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class Code extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/ControlExpiry.php b/tests/Fake/fake-app/src/Resource/App/ControlExpiry.php index b90bd5b4..cf8d6647 100644 --- a/tests/Fake/fake-app/src/Resource/App/ControlExpiry.php +++ b/tests/Fake/fake-app/src/Resource/App/ControlExpiry.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(expiryAt="expiry_at") - */ #[Cacheable(expiryAt: "expiry_at")] class ControlExpiry extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/ControlExpiryError.php b/tests/Fake/fake-app/src/Resource/App/ControlExpiryError.php index 35643a1a..fa8cdb95 100644 --- a/tests/Fake/fake-app/src/Resource/App/ControlExpiryError.php +++ b/tests/Fake/fake-app/src/Resource/App/ControlExpiryError.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(expiryAt="expiry_at") - */ #[Cacheable(expiryAt: "expiry_at")] class ControlExpiryError extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/ControlNone.php b/tests/Fake/fake-app/src/Resource/App/ControlNone.php index 3837ffd7..2aea2eea 100644 --- a/tests/Fake/fake-app/src/Resource/App/ControlNone.php +++ b/tests/Fake/fake-app/src/Resource/App/ControlNone.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(expirySecond=60) - */ #[Cacheable(expirySecond: 60)] class ControlNone extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/ControlPublic.php b/tests/Fake/fake-app/src/Resource/App/ControlPublic.php index 2dd74d48..ceb7e84c 100644 --- a/tests/Fake/fake-app/src/Resource/App/ControlPublic.php +++ b/tests/Fake/fake-app/src/Resource/App/ControlPublic.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(expirySecond=60) - */ #[Cacheable(expirySecond: 60)] class ControlPublic extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/Dep/LevelOne.php b/tests/Fake/fake-app/src/Resource/App/Dep/LevelOne.php index 2a00e2e7..b287e34f 100644 --- a/tests/Fake/fake-app/src/Resource/App/Dep/LevelOne.php +++ b/tests/Fake/fake-app/src/Resource/App/Dep/LevelOne.php @@ -6,9 +6,6 @@ use BEAR\Resource\Annotation\Embed; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class LevelOne extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/Entry.php b/tests/Fake/fake-app/src/Resource/App/Entry.php index 7ca0c516..c25d1be0 100644 --- a/tests/Fake/fake-app/src/Resource/App/Entry.php +++ b/tests/Fake/fake-app/src/Resource/App/Entry.php @@ -12,9 +12,6 @@ use BEAR\Resource\Code; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(expiry="never", update=true) - */ #[Cacheable(expiry: "never", update: true)] class Entry extends ResourceObject { @@ -42,8 +39,6 @@ public function onPatch($id, $name) } /** - * @Purge(uri="app://self/user/friend?user_id={id}") - * @Refresh(uri="app://self/user/profile?user_id={id}") */ public function onPut(mixed $id, mixed $name, mixed $age) { diff --git a/tests/Fake/fake-app/src/Resource/App/Etag.php b/tests/Fake/fake-app/src/Resource/App/Etag.php index a52b90ff..f156b09b 100644 --- a/tests/Fake/fake-app/src/Resource/App/Etag.php +++ b/tests/Fake/fake-app/src/Resource/App/Etag.php @@ -10,10 +10,6 @@ use BEAR\RepositoryModule\Annotation\HttpCache; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - * @HttpCache(etag={"updated_at"}) - */ #[Cacheable, HttpCache(etag: ["updated_at"])] class Etag extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/HttpCacheControl.php b/tests/Fake/fake-app/src/Resource/App/HttpCacheControl.php index 588e2639..1bd550f5 100644 --- a/tests/Fake/fake-app/src/Resource/App/HttpCacheControl.php +++ b/tests/Fake/fake-app/src/Resource/App/HttpCacheControl.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\HttpCache; use BEAR\Resource\ResourceObject; -/** - * @HttpCache(isPrivate=true, maxAge=0, sMaxAge=0, mustRevalidate=true, noStore=true, noCache=true) - */ #[HttpCache(isPrivate: true, maxAge: 0, sMaxAge: 0, mustRevalidate: true, noStore: true, noCache: true)] class HttpCacheControl extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/HttpCacheControlOverrideMaxAge.php b/tests/Fake/fake-app/src/Resource/App/HttpCacheControlOverrideMaxAge.php index 656ab5ca..399be00d 100644 --- a/tests/Fake/fake-app/src/Resource/App/HttpCacheControlOverrideMaxAge.php +++ b/tests/Fake/fake-app/src/Resource/App/HttpCacheControlOverrideMaxAge.php @@ -10,10 +10,6 @@ use BEAR\RepositoryModule\Annotation\HttpCache; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(expirySecond=10) - * @HttpCache(maxAge=5) - */ #[Cacheable(expirySecond: 10), HttpCache(maxAge: 5)] class HttpCacheControlOverrideMaxAge extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/HttpCacheControlWithCacheable.php b/tests/Fake/fake-app/src/Resource/App/HttpCacheControlWithCacheable.php index 23eb1a81..10ee4e0e 100644 --- a/tests/Fake/fake-app/src/Resource/App/HttpCacheControlWithCacheable.php +++ b/tests/Fake/fake-app/src/Resource/App/HttpCacheControlWithCacheable.php @@ -10,10 +10,6 @@ use BEAR\RepositoryModule\Annotation\HttpCache; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(expirySecond=10) - * @HttpCache(isPrivate=true) - */ #[Cacheable(expirySecond: 10), HttpCache(isPrivate: true)] class HttpCacheControlWithCacheable extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/Invalid.php b/tests/Fake/fake-app/src/Resource/App/Invalid.php index a4661579..8bc22407 100644 --- a/tests/Fake/fake-app/src/Resource/App/Invalid.php +++ b/tests/Fake/fake-app/src/Resource/App/Invalid.php @@ -10,9 +10,6 @@ use BEAR\RepositoryModule\Annotation\Purge; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class Invalid extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/NullView.php b/tests/Fake/fake-app/src/Resource/App/NullView.php index 74484dd6..279dd063 100644 --- a/tests/Fake/fake-app/src/Resource/App/NullView.php +++ b/tests/Fake/fake-app/src/Resource/App/NullView.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(type="view") - */ #[Cacheable(type: "view")] class NullView extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/SometimesSameResponse.php b/tests/Fake/fake-app/src/Resource/App/SometimesSameResponse.php index 7d836ecb..8165461c 100644 --- a/tests/Fake/fake-app/src/Resource/App/SometimesSameResponse.php +++ b/tests/Fake/fake-app/src/Resource/App/SometimesSameResponse.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class SometimesSameResponse extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/TypedParam.php b/tests/Fake/fake-app/src/Resource/App/TypedParam.php index 177f346a..063647c3 100644 --- a/tests/Fake/fake-app/src/Resource/App/TypedParam.php +++ b/tests/Fake/fake-app/src/Resource/App/TypedParam.php @@ -10,9 +10,6 @@ use BEAR\RepositoryModule\Annotation\Refresh; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class TypedParam extends ResourceObject { @@ -26,7 +23,6 @@ public function onGet(int $id) : ResourceObject } /** - * @Refresh(uri="app://self/typed-param{?id}") */ public function onPut(int $id) : ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/Unmatch.php b/tests/Fake/fake-app/src/Resource/App/Unmatch.php index 2de53e09..cb564fee 100644 --- a/tests/Fake/fake-app/src/Resource/App/Unmatch.php +++ b/tests/Fake/fake-app/src/Resource/App/Unmatch.php @@ -11,9 +11,6 @@ use BEAR\RepositoryModule\Annotation\Purge; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class Unmatch extends ResourceObject { @@ -28,7 +25,6 @@ public function onGet($id, $unused) } /** - * @Purge(uri="app://self/user/friend?user_id={id}") */ #[Purge(uri: 'app://self/user/friend?user_id={id}')] public function onPut(mixed $id, mixed $name, mixed $age) diff --git a/tests/Fake/fake-app/src/Resource/App/User.php b/tests/Fake/fake-app/src/Resource/App/User.php index db8c8245..1cc2673b 100644 --- a/tests/Fake/fake-app/src/Resource/App/User.php +++ b/tests/Fake/fake-app/src/Resource/App/User.php @@ -13,9 +13,6 @@ use BEAR\Resource\Code; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class User extends ResourceObject { @@ -50,8 +47,6 @@ public function onPatch($id, $name) } /** - * @Purge(uri="app://self/user/friend?user_id={id}") - * @Refresh(uri="app://self/user/profile?user_id={id}") * * @FakeAnnotation // ignored in RefreshAnnotatedCommand::request. This was put for the test coverage. */ diff --git a/tests/Fake/fake-app/src/Resource/App/User/Profile.php b/tests/Fake/fake-app/src/Resource/App/User/Profile.php index c3751412..df35eedb 100644 --- a/tests/Fake/fake-app/src/Resource/App/User/Profile.php +++ b/tests/Fake/fake-app/src/Resource/App/User/Profile.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class Profile extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/Value.php b/tests/Fake/fake-app/src/Resource/App/Value.php index b0184d47..f6b29c7f 100644 --- a/tests/Fake/fake-app/src/Resource/App/Value.php +++ b/tests/Fake/fake-app/src/Resource/App/Value.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(type="value") - */ #[Cacheable(type: "value")] class Value extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/App/View.php b/tests/Fake/fake-app/src/Resource/App/View.php index a2c3835e..1485a6bc 100644 --- a/tests/Fake/fake-app/src/Resource/App/View.php +++ b/tests/Fake/fake-app/src/Resource/App/View.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(type="view") - */ #[Cacheable(type: 'view')] class View extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelOne.php b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelOne.php index 5a158d34..810606c3 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelOne.php +++ b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelOne.php @@ -6,9 +6,6 @@ use BEAR\Resource\Annotation\Embed; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class LevelOne extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelThree.php b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelThree.php index df409b7b..3bf5b7cf 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelThree.php +++ b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelThree.php @@ -6,9 +6,6 @@ use BEAR\Resource\Annotation\Embed; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class LevelThree extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelTwo.php b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelTwo.php index 83466272..aa682124 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelTwo.php +++ b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelTwo.php @@ -6,9 +6,6 @@ use BEAR\Resource\Annotation\Embed; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class LevelTwo extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/EmbVal.php b/tests/Fake/fake-app/src/Resource/Page/EmbVal.php index 19d47038..8e805e43 100644 --- a/tests/Fake/fake-app/src/Resource/Page/EmbVal.php +++ b/tests/Fake/fake-app/src/Resource/Page/EmbVal.php @@ -10,9 +10,6 @@ use BEAR\Resource\Annotation\Embed; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class EmbVal extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/EmbView.php b/tests/Fake/fake-app/src/Resource/Page/EmbView.php index 78c9e4b9..e9419414 100644 --- a/tests/Fake/fake-app/src/Resource/Page/EmbView.php +++ b/tests/Fake/fake-app/src/Resource/Page/EmbView.php @@ -10,9 +10,6 @@ use BEAR\Resource\Annotation\Embed; use BEAR\Resource\ResourceObject; -/** - * @Cacheable(type="view") - */ #[Cacheable(type: "view")] class EmbView extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPosting.php b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPosting.php index 73d6d6ec..7371d1ff 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPosting.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPosting.php @@ -10,9 +10,6 @@ use Koriym\HttpConstants\CacheControl; use Koriym\HttpConstants\ResponseHeader; -/** - * @CacheableResponse - */ #[CacheableResponse] class BlogPosting extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCache.php b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCache.php index d371f850..2902fc6c 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCache.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCache.php @@ -18,7 +18,6 @@ class BlogPostingCache extends ResourceObject /** * @Embed(rel="comment", src="page://self/html/comment") - * @CacheableResponse */ #[CacheableResponse] #[Embed(rel: "comment", src: "page://self/html/comment")] @@ -30,7 +29,6 @@ public function onGet(int $id = 0) } /** - * @RefreshCache() */ #[RefreshCache] public function onDelete(int $id = 0) diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php index 13b53ecd..7fb3541b 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php @@ -9,9 +9,6 @@ use Koriym\HttpConstants\CacheControl; use Koriym\HttpConstants\RequestHeader; -/** - * @CacheableResponse - */ #[CacheableResponse] class BlogPostingCacheControl extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/Comment.php b/tests/Fake/fake-app/src/Resource/Page/Html/Comment.php index 11620da7..63c0cb83 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/Comment.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/Comment.php @@ -8,9 +8,6 @@ use BEAR\Resource\Code; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class Comment extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/Like.php b/tests/Fake/fake-app/src/Resource/Page/Html/Like.php index bb9687a2..726a9a81 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/Like.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/Like.php @@ -6,9 +6,6 @@ use BEAR\Resource\Annotation\Embed; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable(type: 'view')] class Like extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/PageSurrogateKey.php b/tests/Fake/fake-app/src/Resource/Page/Html/PageSurrogateKey.php index cd158f6b..7042e2a0 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/PageSurrogateKey.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/PageSurrogateKey.php @@ -11,9 +11,6 @@ use BEAR\Resource\Annotation\Embed; use BEAR\Resource\ResourceObject; -/** - * @CacheableResponse - */ #[CacheableResponse] class PageSurrogateKey extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Index.php b/tests/Fake/fake-app/src/Resource/Page/Index.php index ff497cf7..f1a2783f 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Index.php +++ b/tests/Fake/fake-app/src/Resource/Page/Index.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\ResourceObject; -/** - * @Cacheable - */ #[Cacheable] class Index extends ResourceObject { diff --git a/tests/bootstrap.php b/tests/bootstrap.php index b64d04d2..53b2de3a 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -2,9 +2,4 @@ declare(strict_types=1); -use Koriym\Attributes\AttributeReader; -use Ray\ServiceLocator\ServiceLocator; - array_map('unlink', glob(__DIR__ . '/tests/tmp/*.php')); // @phpstan-ignore-line - -ServiceLocator::setReader(new AttributeReader()); From c4817436ad12544877141ca9503c8d3a5691538b Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 9 Nov 2025 13:56:04 +0900 Subject: [PATCH 05/20] Add post-install-cmd command to prevent PHP version conflict --- composer.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/composer.json b/composer.json index 592ce275..8eaf384e 100644 --- a/composer.json +++ b/composer.json @@ -71,6 +71,8 @@ } }, "scripts" :{ + "post-install-cmd": ["@composer bin all install --ansi --ignore-platform-req=php"], + "post-update-cmd": ["@composer bin all update --ansi --ignore-platform-req=php"], "test": ["./vendor/bin/phpunit"], "tests": ["@cs", "@sa", "@test"], "coverage": ["php -dzend_extension=xdebug.so -dxdebug.mode=coverage ./vendor/bin/phpunit --coverage-text --coverage-html=build/coverage"], From 7e7a055ea60f9e4eeab44b24cac1660ad750f77e Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 9 Nov 2025 15:29:59 +0900 Subject: [PATCH 06/20] refactor: Complete removal of doctrine/annotations and doctrine/cache dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up all remaining references to abandoned Doctrine packages: - Update composer-require-checker.json whitelist to use CacheProvider instead of ArrayCache - Remove Doctrine\Common\Cache bindings from demo/AppModule.php - Remove NamedArgumentConstructorAnnotation from CacheVersion (deprecated) - Simplify BcModule to only emit deprecation warning, remove all Doctrine bindings - Remove unused AnnotationReader imports from tests - Remove Doctrine CacheProvider test case from ResourceRepositoryTest All code now uses native PHP 8 Attributes and Symfony Cache components only. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- composer-require-checker.json | 4 +++- demo/AppModule.php | 4 ---- src-annotation-deprecated/CacheVersion.php | 7 +----- src-deprecated/BcModule.php | 17 +++----------- tests/QueryRepositoryTest.php | 3 --- tests/ResourceRepositoryTest.php | 27 ---------------------- 6 files changed, 7 insertions(+), 55 deletions(-) diff --git a/composer-require-checker.json b/composer-require-checker.json index fcb00648..8e3a40e5 100644 --- a/composer-require-checker.json +++ b/composer-require-checker.json @@ -4,7 +4,9 @@ "static", "self", "parent", "array", "string", "int", "float", "bool", "iterable", "callable", "void", "object", "Attribute", "Memcached", "Redis", "RedisException", - "Doctrine\\Common\\Cache\\ArrayCache", "Doctrine\\Common\\Cache\\MemcachedCache", "Doctrine\\Common\\Cache\\RedisCache", + "Doctrine\\Common\\Cache\\CacheProvider", + "Doctrine\\Common\\Cache\\MemcachedCache", + "Doctrine\\Common\\Cache\\RedisCache", "BEAR\\FastlyModule\\FastlyCachePurgerInterface", "BEAR\\FastlyModule\\FastlyPurgeModule", "Detection\\MobileDetect" ] diff --git a/demo/AppModule.php b/demo/AppModule.php index a511f9f0..be6c7845 100644 --- a/demo/AppModule.php +++ b/demo/AppModule.php @@ -5,10 +5,7 @@ namespace FakeVendor\DemoApp; use BEAR\QueryRepository\QueryRepositoryModule; -use BEAR\RepositoryModule\Annotation\Storage; use BEAR\Resource\Module\ResourceModule; -use Doctrine\Common\Cache\ArrayCache; -use Doctrine\Common\Cache\CacheProvider; use Ray\Di\AbstractModule; use Ray\Di\Scope; @@ -21,7 +18,6 @@ protected function configure() { $this->bind()->annotatedWith('storage_dir')->toInstance(__DIR__ . '/tmp')->in(Scope::SINGLETON); // $this->bind(CacheProvider::class)->annotatedWith(Storage::class)->toConstructor(FilesystemCache::class, 'directory=storage_dir')->in(Scope::SINGLETON); - $this->bind(CacheProvider::class)->annotatedWith(Storage::class)->to(ArrayCache::class)->in(Scope::SINGLETON); $this->install(new ResourceModule(__NAMESPACE__)); $this->install(new QueryRepositoryModule); } diff --git a/src-annotation-deprecated/CacheVersion.php b/src-annotation-deprecated/CacheVersion.php index e98a1529..0abf788c 100644 --- a/src-annotation-deprecated/CacheVersion.php +++ b/src-annotation-deprecated/CacheVersion.php @@ -5,20 +5,15 @@ namespace BEAR\RepositoryModule\Annotation; use Attribute; -use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; use Ray\Di\Di\Qualifier; /** * @deprecated * * Use \Ray\PsrCacheModule\Annotation\CacheNamespace - * - * @Annotation - * @Target("METHOD") - * @Qualifier() */ #[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER), Qualifier] -final class CacheVersion implements NamedArgumentConstructorAnnotation +final class CacheVersion { /** * @var string diff --git a/src-deprecated/BcModule.php b/src-deprecated/BcModule.php index ce581f0e..8be7c525 100644 --- a/src-deprecated/BcModule.php +++ b/src-deprecated/BcModule.php @@ -4,21 +4,15 @@ namespace BEAR\QueryRepository; -use BEAR\QueryRepository\HttpCacheInterface as DeprecatedHttpCacheInterface; -use BEAR\RepositoryModule\Annotation\CacheVersion; -use BEAR\RepositoryModule\Annotation\Storage; -use Doctrine\Common\Cache\ArrayCache; -use Doctrine\Common\Cache\Cache; -use Doctrine\Common\Cache\CacheProvider; use Ray\Di\AbstractModule; -use Ray\Di\Scope; +use function trigger_error; /** * @deprecated * * Backward Compatibility module * - * Install this when you need deprecated interface. + * Install this when you need a deprecated interface. * (I don't think it' ever going to be needed, but just in case.) */ class BcModule extends AbstractModule @@ -28,11 +22,6 @@ class BcModule extends AbstractModule */ protected function configure() { - $this->bind(DeprecatedHttpCacheInterface::class)->to(HttpCache::class); - /** @psalm-suppress DeprecatedClass */ - $this->bind(Cache::class)->annotatedWith(Storage::class)->toProvider(StorageProvider::class)->in(Scope::SINGLETON); - /** @psalm-suppress DeprecatedClass */ - $this->bind(CacheProvider::class)->annotatedWith(Storage::class)->to(ArrayCache::class)->in(Scope::SINGLETON); - $this->bind()->annotatedWith(CacheVersion::class)->toInstance(''); + trigger_error('BEAR\QueryRepository\BcModule is deprecated.', E_USER_DEPRECATED); } } diff --git a/tests/QueryRepositoryTest.php b/tests/QueryRepositoryTest.php index e422edd6..3b13d7df 100644 --- a/tests/QueryRepositoryTest.php +++ b/tests/QueryRepositoryTest.php @@ -11,8 +11,6 @@ use BEAR\Resource\ResourceInterface; use BEAR\Resource\Uri; use BEAR\Sunday\Extension\Transfer\HttpCacheInterface; -use Doctrine\Common\Annotations\AnnotationReader; -use Doctrine\Common\Annotations\Reader; use FakeVendor\HelloWorld\Resource\App\NullView; use FakeVendor\HelloWorld\Resource\App\User\Profile; use FakeVendor\HelloWorld\Resource\Page\None; @@ -222,7 +220,6 @@ protected function configure(): void { $this->bind(CacheItemPoolInterface::class)->annotatedWith(Shared::class)->to(FilesystemAdapter::class); $this->bind(CacheItemPoolInterface::class)->annotatedWith(EtagPool::class)->to(FilesystemAdapter::class); - $this->bind(Reader::class)->to(AnnotationReader::class); } }); $injector = new Injector($module); diff --git a/tests/ResourceRepositoryTest.php b/tests/ResourceRepositoryTest.php index bb2a40a6..673376b8 100644 --- a/tests/ResourceRepositoryTest.php +++ b/tests/ResourceRepositoryTest.php @@ -6,7 +6,6 @@ use BEAR\QueryRepository\QueryRepository as Repository; use BEAR\Resource\Uri; -use Doctrine\Common\Cache\CacheProvider; use FakeVendor\HelloWorld\Resource\Page\Index; use PHPUnit\Framework\TestCase; use Ray\Di\ProviderInterface; @@ -87,32 +86,6 @@ public function testDelete(): void public function testCreateFromDoctrineAnnotation(): void { - // phpcs:disable SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint - $doctrineCache = new class extends CacheProvider{ - protected function doFetch($id) - { - } - - protected function doContains($id) - { - } - - protected function doSave($id, $data, $lifeTime = 0) - { - } - - protected function doDelete($id) - { - } - - protected function doFlush() - { - } - - protected function doGetStats() - { - } - }; // phpcs:enable $tagAwareAdapter = new TagAwareAdapter(new NullAdapter()); $tagAwareAdapterProvider = new class ($tagAwareAdapter) implements ProviderInterface{ From c0898ac5349508fd233f46bb91ebaeee72a9eca1 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 9 Nov 2025 15:48:55 +0900 Subject: [PATCH 07/20] refactor: Make ext-redis optional with @requires annotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove ext-redis from require-dev and add @requires extension redis to test classes that need it: - Remove ext-redis from composer.json require-dev - Add suggest section for ext-redis and ext-memcached - Add @requires extension redis to DonutCommandRedisCacheTest - Add @requires extension redis to StorageRedisDsnModuleMarshallerTest - Add @requires extension redis to StorageRedisDsnModuleTest This allows developers to run composer install without Redis extension installed. Tests requiring Redis will be automatically skipped by PHPUnit when the extension is not available. Composer will suggest installing the extensions when they are needed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- composer.json | 7 +- tests-pecl-ext/StorageRedisDsnModuleTest.php | 3 + tests/DonutCommandRedisCacheTest.php | 1 + tests/StorageRedisDsnModuleMarshallerTest.php | 1 + vendor-bin/tool/composer.json | 1 - vendor-bin/tool/composer.lock | 18 - vendor-bin/tools/composer.json | 5 +- vendor-bin/tools/composer.lock | 431 ++++++++++-------- 8 files changed, 256 insertions(+), 211 deletions(-) delete mode 100644 vendor-bin/tool/composer.json delete mode 100644 vendor-bin/tool/composer.lock diff --git a/composer.json b/composer.json index 8eaf384e..b296317b 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,6 @@ "symfony/polyfill-php83": "^v1.32.0" }, "require-dev": { - "ext-redis": "*", "bamarni/composer-bin-plugin": "^1.8", "bear/fastly-module": "^1.0", "madapaja/twig-module": "^2.6", @@ -37,6 +36,10 @@ "symfony/process": "^6.1 || ^7.1", "twig/twig": "^3.4.3" }, + "suggest": { + "ext-redis": "Required for Redis cache storage backend", + "ext-memcached": "Required for Memcached cache storage backend" + }, "autoload": { "psr-4": { "BEAR\\QueryRepository\\": ["src/", "src-deprecated/"], @@ -71,8 +74,6 @@ } }, "scripts" :{ - "post-install-cmd": ["@composer bin all install --ansi --ignore-platform-req=php"], - "post-update-cmd": ["@composer bin all update --ansi --ignore-platform-req=php"], "test": ["./vendor/bin/phpunit"], "tests": ["@cs", "@sa", "@test"], "coverage": ["php -dzend_extension=xdebug.so -dxdebug.mode=coverage ./vendor/bin/phpunit --coverage-text --coverage-html=build/coverage"], diff --git a/tests-pecl-ext/StorageRedisDsnModuleTest.php b/tests-pecl-ext/StorageRedisDsnModuleTest.php index 5abc929f..b127cce3 100644 --- a/tests-pecl-ext/StorageRedisDsnModuleTest.php +++ b/tests-pecl-ext/StorageRedisDsnModuleTest.php @@ -20,6 +20,9 @@ use function getenv; use function usleep; +/** + * @requires extension redis + */ class StorageRedisDsnModuleTest extends TestCase { /** @var Process */ diff --git a/tests/DonutCommandRedisCacheTest.php b/tests/DonutCommandRedisCacheTest.php index 5a8d347f..3ce976e6 100644 --- a/tests/DonutCommandRedisCacheTest.php +++ b/tests/DonutCommandRedisCacheTest.php @@ -14,6 +14,7 @@ use function serialize; use function unserialize; +/** @requires extension redis */ class DonutCommandRedisCacheTest extends DonutCommandInterceptorTest { protected function setUp(): void diff --git a/tests/StorageRedisDsnModuleMarshallerTest.php b/tests/StorageRedisDsnModuleMarshallerTest.php index c8d1a4b6..d8ce64ca 100644 --- a/tests/StorageRedisDsnModuleMarshallerTest.php +++ b/tests/StorageRedisDsnModuleMarshallerTest.php @@ -9,6 +9,7 @@ use Ray\Di\Injector; use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface; +/** @requires extension redis */ final class StorageRedisDsnModuleMarshallerTest extends TestCase { public function testModuleBindings(): void diff --git a/vendor-bin/tool/composer.json b/vendor-bin/tool/composer.json deleted file mode 100644 index 9e26dfee..00000000 --- a/vendor-bin/tool/composer.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/vendor-bin/tool/composer.lock b/vendor-bin/tool/composer.lock deleted file mode 100644 index b383d88a..00000000 --- a/vendor-bin/tool/composer.lock +++ /dev/null @@ -1,18 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "d751713988987e9331980363e24189ce", - "packages": [], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": {}, - "prefer-stable": false, - "prefer-lowest": false, - "platform": {}, - "platform-dev": {}, - "plugin-api-version": "2.6.0" -} diff --git a/vendor-bin/tools/composer.json b/vendor-bin/tools/composer.json index f8efd849..ba0760e9 100644 --- a/vendor-bin/tools/composer.json +++ b/vendor-bin/tools/composer.json @@ -11,6 +11,9 @@ "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true }, - "sort-packages": true + "sort-packages": true, + "platform": { + "php": "8.4.99" + } } } diff --git a/vendor-bin/tools/composer.lock b/vendor-bin/tools/composer.lock index 703390b9..9c741c3e 100644 --- a/vendor-bin/tools/composer.lock +++ b/vendor-bin/tools/composer.lock @@ -4,21 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0f42766d36d7379bb2634d8f8565e169", + "content-hash": "47b44077ff0b2feaad0b5161f9f64bfc", "packages": [], "packages-dev": [ { "name": "amphp/amp", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9" + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", - "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", + "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f", + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f", "shasum": "" }, "require": { @@ -78,7 +78,7 @@ ], "support": { "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v3.1.0" + "source": "https://github.com/amphp/amp/tree/v3.1.1" }, "funding": [ { @@ -86,7 +86,7 @@ "type": "github" } ], - "time": "2025-01-26T16:07:39+00:00" + "time": "2025-08-27T21:42:00+00:00" }, { "name": "amphp/byte-stream", @@ -319,16 +319,16 @@ }, { "name": "amphp/parallel", - "version": "v2.3.1", + "version": "v2.3.2", "source": { "type": "git", "url": "https://github.com/amphp/parallel.git", - "reference": "5113111de02796a782f5d90767455e7391cca190" + "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parallel/zipball/5113111de02796a782f5d90767455e7391cca190", - "reference": "5113111de02796a782f5d90767455e7391cca190", + "url": "https://api.github.com/repos/amphp/parallel/zipball/321b45ae771d9c33a068186b24117e3cd1c48dce", + "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce", "shasum": "" }, "require": { @@ -391,7 +391,7 @@ ], "support": { "issues": "https://github.com/amphp/parallel/issues", - "source": "https://github.com/amphp/parallel/tree/v2.3.1" + "source": "https://github.com/amphp/parallel/tree/v2.3.2" }, "funding": [ { @@ -399,7 +399,7 @@ "type": "github" } ], - "time": "2024-12-21T01:56:09+00:00" + "time": "2025-08-27T21:55:40+00:00" }, { "name": "amphp/parser", @@ -896,16 +896,16 @@ }, { "name": "composer/semver", - "version": "3.4.3", + "version": "3.4.4", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", "shasum": "" }, "require": { @@ -957,7 +957,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.3" + "source": "https://github.com/composer/semver/tree/3.4.4" }, "funding": [ { @@ -967,13 +967,9 @@ { "url": "https://github.com/composer", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" } ], - "time": "2024-09-19T14:15:21+00:00" + "time": "2025-08-20T19:15:30+00:00" }, { "name": "composer/xdebug-handler", @@ -1139,28 +1135,28 @@ }, { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.0.0", + "version": "v1.1.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "4be43904336affa5c2f70744a348312336afd0da" + "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", - "reference": "4be43904336affa5c2f70744a348312336afd0da", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", + "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0 || ^2.0", + "composer-plugin-api": "^2.2", "php": ">=5.4", "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { - "composer/composer": "*", + "composer/composer": "^2.2", "ext-json": "*", "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.3.1", + "php-parallel-lint/php-parallel-lint": "^1.4.0", "phpcompatibility/php-compatibility": "^9.0", "yoast/phpunit-polyfills": "^1.0" }, @@ -1180,9 +1176,9 @@ "authors": [ { "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" }, { "name": "Contributors", @@ -1190,7 +1186,6 @@ } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", "keywords": [ "PHPCodeSniffer", "PHP_CodeSniffer", @@ -1211,9 +1206,28 @@ ], "support": { "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", "source": "https://github.com/PHPCSStandards/composer-installer" }, - "time": "2023-01-05T11:28:13+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-07-17T20:45:56+00:00" }, { "name": "dnoegel/php-xdg-base-dir", @@ -1414,16 +1428,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "8520451a140d3f46ac33042715115e290cf5785f" + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", - "reference": "8520451a140d3f46ac33042715115e290cf5785f", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", "shasum": "" }, "require": { @@ -1433,10 +1447,10 @@ "fidry/makefile": "^0.2.0", "fidry/php-cs-fixer-config": "^1.1.2", "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.9.2", - "phpstan/phpstan-deprecation-rules": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.2.2", - "phpstan/phpstan-strict-rules": "^1.4.4", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^8.5.31 || ^9.5.26", "webmozarts/strict-phpunit": "^7.5" }, @@ -1463,7 +1477,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" }, "funding": [ { @@ -1471,7 +1485,7 @@ "type": "github" } ], - "time": "2024-08-06T10:04:20+00:00" + "time": "2025-08-14T07:29:31+00:00" }, { "name": "kelunik/certificate", @@ -1758,16 +1772,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.5.0", + "version": "v5.6.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + "reference": "3a454ca033b9e06b63282ce19562e892747449bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb", "shasum": "" }, "require": { @@ -1786,7 +1800,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -1810,9 +1824,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" }, - "time": "2025-05-31T08:24:38+00:00" + "time": "2025-10-21T19:32:17+00:00" }, { "name": "pdepend/pdepend", @@ -1932,16 +1946,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.6.2", + "version": "5.6.3", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62" + "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62", - "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9", + "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9", "shasum": "" }, "require": { @@ -1990,9 +2004,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3" }, - "time": "2025-04-13T19:20:35+00:00" + "time": "2025-08-01T19:43:32+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -2137,16 +2151,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.1.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68" + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", - "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", "shasum": "" }, "require": { @@ -2178,22 +2192,17 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.1.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" }, - "time": "2025-02-19T13:28:12+00:00" + "time": "2025-08-30T15:50:23+00:00" }, { "name": "phpstan/phpstan", - "version": "2.1.17", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053" - }, + "version": "2.1.31", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053", - "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ead89849d879fe203ce9292c6ef5e7e76f867b96", + "reference": "ead89849d879fe203ce9292c6ef5e7e76f867b96", "shasum": "" }, "require": { @@ -2238,7 +2247,7 @@ "type": "github" } ], - "time": "2025-05-21T20:55:28+00:00" + "time": "2025-10-10T14:14:11+00:00" }, { "name": "psr/container", @@ -2453,21 +2462,21 @@ }, { "name": "rector/rector", - "version": "2.0.18", + "version": "2.2.7", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "be3a452085b524a04056e3dfe72d861948711062" + "reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/be3a452085b524a04056e3dfe72d861948711062", - "reference": "be3a452085b524a04056e3dfe72d861948711062", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/022038537838bc8a4e526af86c2d6e38eaeff7ef", + "reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef", "shasum": "" }, "require": { "php": "^7.4|^8.0", - "phpstan/phpstan": "^2.1.17" + "phpstan/phpstan": "^2.1.26" }, "conflict": { "rector/rector-doctrine": "*", @@ -2492,6 +2501,7 @@ "MIT" ], "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "homepage": "https://getrector.com/", "keywords": [ "automation", "dev", @@ -2500,7 +2510,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/2.0.18" + "source": "https://github.com/rectorphp/rector/tree/2.2.7" }, "funding": [ { @@ -2508,20 +2518,20 @@ "type": "github" } ], - "time": "2025-06-11T11:19:37+00:00" + "time": "2025-10-29T15:46:12+00:00" }, { "name": "rector/swiss-knife", - "version": "2.3.0", + "version": "2.3.3", "source": { "type": "git", "url": "https://github.com/rectorphp/swiss-knife.git", - "reference": "d681109ef62d0657cca6610fdf4488837e5e9522" + "reference": "4e19741422511b7b26d64dcf272fab6dc155f873" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/swiss-knife/zipball/d681109ef62d0657cca6610fdf4488837e5e9522", - "reference": "d681109ef62d0657cca6610fdf4488837e5e9522", + "url": "https://api.github.com/repos/rectorphp/swiss-knife/zipball/4e19741422511b7b26d64dcf272fab6dc155f873", + "reference": "4e19741422511b7b26d64dcf272fab6dc155f873", "shasum": "" }, "require": { @@ -2543,7 +2553,7 @@ "description": "Swiss knife in pocket of every upgrade architect", "support": { "issues": "https://github.com/rectorphp/swiss-knife/issues", - "source": "https://github.com/rectorphp/swiss-knife/tree/2.3.0" + "source": "https://github.com/rectorphp/swiss-knife/tree/2.3.3" }, "funding": [ { @@ -2555,7 +2565,7 @@ "type": "github" } ], - "time": "2025-06-16T07:59:07+00:00" + "time": "2025-08-15T14:49:18+00:00" }, { "name": "revolt/event-loop", @@ -2698,32 +2708,32 @@ }, { "name": "slevomat/coding-standard", - "version": "8.19.1", + "version": "8.22.1", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "458d665acd49009efebd7e0cb385d71ae9ac3220" + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/458d665acd49009efebd7e0cb385d71ae9ac3220", - "reference": "458d665acd49009efebd7e0cb385d71ae9ac3220", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/1dd80bf3b93692bedb21a6623c496887fad05fec", + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", "php": "^7.4 || ^8.0", - "phpstan/phpdoc-parser": "^2.1.0", - "squizlabs/php_codesniffer": "^3.13.0" + "phpstan/phpdoc-parser": "^2.3.0", + "squizlabs/php_codesniffer": "^3.13.4" }, "require-dev": { - "phing/phing": "3.0.1", + "phing/phing": "3.0.1|3.1.0", "php-parallel-lint/php-parallel-lint": "1.4.0", - "phpstan/phpstan": "2.1.17", + "phpstan/phpstan": "2.1.24", "phpstan/phpstan-deprecation-rules": "2.0.3", - "phpstan/phpstan-phpunit": "2.0.6", - "phpstan/phpstan-strict-rules": "2.0.4", - "phpunit/phpunit": "9.6.8|10.5.45|11.4.4|11.5.21|12.1.3" + "phpstan/phpstan-phpunit": "2.0.7", + "phpstan/phpstan-strict-rules": "2.0.6", + "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.36|12.3.10" }, "type": "phpcodesniffer-standard", "extra": { @@ -2747,7 +2757,7 @@ ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.19.1" + "source": "https://github.com/slevomat/coding-standard/tree/8.22.1" }, "funding": [ { @@ -2759,7 +2769,7 @@ "type": "tidelift" } ], - "time": "2025-06-09T17:53:57+00:00" + "time": "2025-09-13T08:53:30+00:00" }, { "name": "spatie/array-to-xml", @@ -2831,16 +2841,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.2", + "version": "3.13.5", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", "shasum": "" }, "require": { @@ -2857,11 +2867,6 @@ "bin/phpcs" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -2911,20 +2916,20 @@ "type": "thanks_dev" } ], - "time": "2025-06-17T22:17:01+00:00" + "time": "2025-11-04T16:30:35+00:00" }, { "name": "symfony/config", - "version": "v7.3.0", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "ba62ae565f1327c2f6366726312ed828c85853bc" + "reference": "9d18eba95655a3152ae4c1d53c6cc34eb4d4a0b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/ba62ae565f1327c2f6366726312ed828c85853bc", - "reference": "ba62ae565f1327c2f6366726312ed828c85853bc", + "url": "https://api.github.com/repos/symfony/config/zipball/9d18eba95655a3152ae4c1d53c6cc34eb4d4a0b7", + "reference": "9d18eba95655a3152ae4c1d53c6cc34eb4d4a0b7", "shasum": "" }, "require": { @@ -2970,7 +2975,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.3.0" + "source": "https://github.com/symfony/config/tree/v7.3.6" }, "funding": [ { @@ -2981,25 +2986,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-15T09:04:05+00:00" + "time": "2025-11-02T08:04:43+00:00" }, { "name": "symfony/console", - "version": "v7.3.0", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44" + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44", - "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44", + "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", "shasum": "" }, "require": { @@ -3064,7 +3073,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.0" + "source": "https://github.com/symfony/console/tree/v7.3.6" }, "funding": [ { @@ -3075,25 +3084,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-24T10:34:04+00:00" + "time": "2025-11-04T01:21:42+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.3.0", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "f64a8f3fa7d4ad5e85de1b128a0e03faed02b732" + "reference": "98af8bb46c56aedd9dd5a7f0414fc72bf2dcfe69" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f64a8f3fa7d4ad5e85de1b128a0e03faed02b732", - "reference": "f64a8f3fa7d4ad5e85de1b128a0e03faed02b732", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/98af8bb46c56aedd9dd5a7f0414fc72bf2dcfe69", + "reference": "98af8bb46c56aedd9dd5a7f0414fc72bf2dcfe69", "shasum": "" }, "require": { @@ -3144,7 +3157,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.3.0" + "source": "https://github.com/symfony/dependency-injection/tree/v7.3.6" }, "funding": [ { @@ -3155,12 +3168,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-19T13:28:56+00:00" + "time": "2025-10-31T10:11:11+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3231,16 +3248,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.3.0", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a", + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a", "shasum": "" }, "require": { @@ -3277,7 +3294,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.0" + "source": "https://github.com/symfony/filesystem/tree/v7.3.6" }, "funding": [ { @@ -3288,16 +3305,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2025-11-05T09:52:27+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -3356,7 +3377,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -3367,6 +3388,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -3376,16 +3401,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -3434,7 +3459,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -3445,16 +3470,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -3515,7 +3544,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -3526,6 +3555,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -3535,7 +3568,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -3596,7 +3629,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -3607,6 +3640,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -3616,16 +3653,16 @@ }, { "name": "symfony/polyfill-php84", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "000df7860439609837bbe28670b0be15783b7fbf" + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/000df7860439609837bbe28670b0be15783b7fbf", - "reference": "000df7860439609837bbe28670b0be15783b7fbf", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", "shasum": "" }, "require": { @@ -3672,7 +3709,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" }, "funding": [ { @@ -3683,25 +3720,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-20T12:04:08+00:00" + "time": "2025-06-24T13:30:11+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -3755,7 +3796,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -3766,25 +3807,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "symfony/string", - "version": "v7.3.0", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125" + "reference": "f96476035142921000338bad71e5247fbc138872" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125", + "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", + "reference": "f96476035142921000338bad71e5247fbc138872", "shasum": "" }, "require": { @@ -3799,7 +3844,6 @@ }, "require-dev": { "symfony/emoji": "^7.1", - "symfony/error-handler": "^6.4|^7.0", "symfony/http-client": "^6.4|^7.0", "symfony/intl": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", @@ -3842,7 +3886,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.0" + "source": "https://github.com/symfony/string/tree/v7.3.4" }, "funding": [ { @@ -3853,25 +3897,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-20T20:19:01+00:00" + "time": "2025-09-11T14:36:48+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.3.0", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "c9a1168891b5aaadfd6332ef44393330b3498c4c" + "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/c9a1168891b5aaadfd6332ef44393330b3498c4c", - "reference": "c9a1168891b5aaadfd6332ef44393330b3498c4c", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0f020b544a30a7fe8ba972e53ee48a74c0bc87f4", + "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4", "shasum": "" }, "require": { @@ -3919,7 +3967,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.3.0" + "source": "https://github.com/symfony/var-exporter/tree/v7.3.4" }, "funding": [ { @@ -3930,25 +3978,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-15T09:04:05+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { "name": "vimeo/psalm", - "version": "6.12.0", + "version": "6.13.1", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "cf420941d061a57050b6c468ef2c778faf40aee2" + "reference": "1e3b7f0a8ab32b23197b91107adc0a7ed8a05b51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/cf420941d061a57050b6c468ef2c778faf40aee2", - "reference": "cf420941d061a57050b6c468ef2c778faf40aee2", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/1e3b7f0a8ab32b23197b91107adc0a7ed8a05b51", + "reference": "1e3b7f0a8ab32b23197b91107adc0a7ed8a05b51", "shasum": "" }, "require": { @@ -4053,32 +4105,32 @@ "issues": "https://github.com/vimeo/psalm/issues", "source": "https://github.com/vimeo/psalm" }, - "time": "2025-05-28T12:52:06+00:00" + "time": "2025-08-06T10:10:28+00:00" }, { "name": "webmozart/assert", - "version": "1.11.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", "shasum": "" }, "require": { "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", "php": "^7.2 || ^8.0" }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" }, "type": "library", "extra": { @@ -4109,9 +4161,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" + "source": "https://github.com/webmozarts/assert/tree/1.12.1" }, - "time": "2022-06-03T18:03:27+00:00" + "time": "2025-10-29T15:56:20+00:00" } ], "aliases": [], @@ -4121,5 +4173,8 @@ "prefer-lowest": false, "platform": {}, "platform-dev": {}, + "platform-overrides": { + "php": "8.4.99" + }, "plugin-api-version": "2.6.0" } From 12188d60f2a5925663f5364e8de4a037a88d214a Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 9 Nov 2025 15:57:27 +0900 Subject: [PATCH 08/20] fix: Remove obsolete PHPStan ignoreErrors for deleted test code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove ignoreErrors pattern for CacheProvider test code that was deleted in commit 7e7a055. The 'but return statement is missing' error no longer occurs since the Doctrine CacheProvider test case was removed from ResourceRepositoryTest.php. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- phpstan.neon | 4 ---- 1 file changed, 4 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 8529a8f3..f91ed7ed 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -18,9 +18,5 @@ parameters: - */tests/tmp/* - */tests/Fake/* - */src/StorageRedisCacheProvider.php* - ignoreErrors: - - - message: '#but return statement is missing#' - path: tests/ResourceRepositoryTest.php stubFiles: - tests/stubs/Injector.phpstub From 66182f99957debe3535b012aaf967bd7fa79c189 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 9 Nov 2025 16:13:22 +0900 Subject: [PATCH 09/20] refactor: Clean up demo files from doctrine/annotations remnants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove leftover Doctrine annotation references from demo application: - Remove commented-out CacheProvider binding from demo/AppModule.php - Remove @Cacheable docblock annotation from demo/Resource/App/User.php (keep #[Cacheable] attribute) Demo application now uses only native PHP 8 Attributes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- demo/AppModule.php | 1 - demo/Resource/App/User.php | 3 --- 2 files changed, 4 deletions(-) diff --git a/demo/AppModule.php b/demo/AppModule.php index be6c7845..7c382315 100644 --- a/demo/AppModule.php +++ b/demo/AppModule.php @@ -17,7 +17,6 @@ class AppModule extends AbstractModule protected function configure() { $this->bind()->annotatedWith('storage_dir')->toInstance(__DIR__ . '/tmp')->in(Scope::SINGLETON); - // $this->bind(CacheProvider::class)->annotatedWith(Storage::class)->toConstructor(FilesystemCache::class, 'directory=storage_dir')->in(Scope::SINGLETON); $this->install(new ResourceModule(__NAMESPACE__)); $this->install(new QueryRepositoryModule); } diff --git a/demo/Resource/App/User.php b/demo/Resource/App/User.php index 8c0934e8..510e9064 100644 --- a/demo/Resource/App/User.php +++ b/demo/Resource/App/User.php @@ -8,9 +8,6 @@ use BEAR\Resource\ResourceObject; use function error_log; -/** - * @Cacheable(expirySecond=300) - */ #[Cacheable] class User extends ResourceObject { From 2be656d9d874dd4519423730f6cee7b4bfe4ad50 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 9 Nov 2025 16:19:07 +0900 Subject: [PATCH 10/20] update .scrutinizer.yml php 8.4 --- .scrutinizer.yml | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 163a238b..c485693c 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,20 +1,15 @@ -filter: - paths: ["src/*"] - -tools: - php_sim: true - php_pdepend: true - php_analyzer: true build: - image: default-bionic - nodes: - analysis: - tests: - override: - - php-scrutinizer-run --enable-security-analysis + image: default-jammy environment: - redis: true php: - version: 8.2 + version: 8.4 pecl_extensions: - redis + nodes: + analysis: + tests: + override: + - php-scrutinizer-run + +filter: + paths: ["src/*"] From fc18dae97219aed8f6615218e5fed484e2e89f1a Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 10:26:59 +0900 Subject: [PATCH 11/20] refactor: Improve rector-migrate.php and migration guide for vendor installation Remove hardcoded paths from rector-migrate.php to support vendor installation. Users now specify paths via command-line arguments, following Ray.AuraSqlModule pattern. - Remove `withPaths()` from rector-migrate.php - Add usage examples for single and multiple directory processing - Simplify migration guide steps (remove version update step) - Add Ray.Di annotation migration note - Update test command to vendor/bin/phpunit - Add missing annotations to supported list --- ANNOTATION_TO_ATTRIBUTE.md | 22 +++++++++------------- rector-migrate.php | 8 ++++---- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/ANNOTATION_TO_ATTRIBUTE.md b/ANNOTATION_TO_ATTRIBUTE.md index 5e199cd9..a6527415 100644 --- a/ANNOTATION_TO_ATTRIBUTE.md +++ b/ANNOTATION_TO_ATTRIBUTE.md @@ -15,15 +15,7 @@ BEAR.QueryRepository 1.13.0 has removed the dependency on `doctrine/annotations` ## Migration Steps -### Step 1: Update BEAR.QueryRepository - -First, ensure you're using BEAR.QueryRepository v1.13.0 or later: - -```bash -composer require bear/query-repository:^1.13 -``` - -### Step 2: Install Rector (if not already installed) +### Step 1: Install Rector (if not already installed) Rector is an automated refactoring tool that can convert annotations to attributes: @@ -31,7 +23,7 @@ Rector is an automated refactoring tool that can convert annotations to attribut composer require --dev rector/rector ``` -### Step 3: Run Automated Migration +### Step 2: Run Automated Migration BEAR.QueryRepository provides a Rector configuration file for automated migration: @@ -49,7 +41,7 @@ If you have tests that use annotations: vendor/bin/rector process tests --config=vendor/bear/query-repository/rector-migrate.php ``` -### Step 4: Manual Review +### Step 3: Manual Review Review the changes made by Rector and adjust if necessary. Pay special attention to: @@ -57,7 +49,7 @@ Review the changes made by Rector and adjust if necessary. Pay special attention - Annotations with custom parameters - Import statements (Rector should handle these automatically) -### Step 5: Remove doctrine/annotations +### Step 4: Remove doctrine/annotations After migration, you can safely remove the doctrine/annotations dependency: @@ -239,6 +231,10 @@ The following BEAR.QueryRepository annotations are automatically converted: - `@Refresh` → `#[Refresh]` - Invalidate dependent caches - `@Purge` → `#[Purge]` - Purge specific cache entries - `@DonutCache` → `#[DonutCache]` - Donut caching pattern +- `@RefreshCache` → `#[RefreshCache]` - Refresh cache after command +- `@Commands` → `#[Commands]` - Cache invalidation commands + +**Note**: This migration tool only handles BEAR.QueryRepository annotations. For Ray.Di annotations (such as `@Inject`, `@Named`, etc.), please refer to the [Ray.Di migration guide](https://github.com/ray-di/Ray.Di). ## Key Differences @@ -291,7 +287,7 @@ For annotations with complex array values, you may need to manually adjust the s After migration, ensure all tests pass: ```bash -composer test +vendor/bin/phpunit ``` ## Manual Migration diff --git a/rector-migrate.php b/rector-migrate.php index 4121a69d..23ebb114 100644 --- a/rector-migrate.php +++ b/rector-migrate.php @@ -13,14 +13,14 @@ * to native PHP 8 attributes for BEAR.QueryRepository annotations. * * Usage: + * # Process a single directory * vendor/bin/rector process src --config=vendor/bear/query-repository/rector-migrate.php --dry-run * vendor/bin/rector process src --config=vendor/bear/query-repository/rector-migrate.php + * + * # Process multiple directories + * vendor/bin/rector process src tests --config=vendor/bear/query-repository/rector-migrate.php */ return RectorConfig::configure() - ->withPaths([ - __DIR__ . '/src', - __DIR__ . '/tests', - ]) ->withConfiguredRule( AnnotationToAttributeRector::class, [ From 683b2af4694a80e44b9057e249150adbdbb4534e Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 10:51:36 +0900 Subject: [PATCH 12/20] docs: Update CHANGELOG for rector-migrate.php improvements --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 794dfbfb..beb177c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [1.13.0] - 2025-11-09 - ### Added - **Migration Tools**: Added `rector-migrate.php` for automated annotation-to-attribute migration - **Migration Guide**: Added `ANNOTATION_TO_ATTRIBUTE.md` with comprehensive migration instructions @@ -28,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **PHP 8 Attributes Migration**: Removed `doctrine/annotations` and `doctrine/cache` dependencies, migrated to native PHP 8 attributes +- Improve `rector-migrate.php` to support vendor installation by removing hardcoded paths +- Update `ANNOTATION_TO_ATTRIBUTE.md` migration guide following Ray.AuraSqlModule pattern - Improve marshaller provider error handling with better exception messages - Enhance Memcached module with TagAwareAdapter support - Update Symfony Cache to support version ^7.3 From 60da77e5e0c08961507db916b8583845351875d8 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 11:07:20 +0900 Subject: [PATCH 13/20] chore: Use dev-fix-legacy-annotations branch for ray/psr-cache-module Temporarily use the dev-fix-legacy-annotations branch to fix AnnotationException caused by legacy doctrine annotation comments in provider classes. Related: ray-di/Ray.PsrCacheModule#33 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b296317b..51d98472 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "psr/cache": "^1.0 || ^2.0 || ^3.0", "ray/aop": "^2.16", "ray/di": "^2.17.2", - "ray/psr-cache-module": "^1.3.4", + "ray/psr-cache-module": "dev-fix-legacy-annotations as 1.5.0", "symfony/cache": "^5.3 || ^6.0 || ^7.3", "symfony/cache-contracts": "^2.4 || ^3.0", "symfony/polyfill-php83": "^v1.32.0" From 5339b165cf5603247e8412699e15022eb1923ae0 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 11:56:59 +0900 Subject: [PATCH 14/20] chore: Update ray/psr-cache-module to ^1.5.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 51d98472..d93f2f8e 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "psr/cache": "^1.0 || ^2.0 || ^3.0", "ray/aop": "^2.16", "ray/di": "^2.17.2", - "ray/psr-cache-module": "dev-fix-legacy-annotations as 1.5.0", + "ray/psr-cache-module": "^1.5.1", "symfony/cache": "^5.3 || ^6.0 || ^7.3", "symfony/cache-contracts": "^2.4 || ^3.0", "symfony/polyfill-php83": "^v1.32.0" From b1b246ab20125560cced42cf34ba5408098587c4 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 12:19:03 +0900 Subject: [PATCH 15/20] refactor: Remove legacy doctrine annotation docblock tags Remove @Annotation, @Target, and @Qualifier docblock tags from attribute classes. These legacy doctrine annotation markers are no longer needed with PHP 8 attributes and could cause conflicts with packages still using DualReader. --- src-annotation/CacheableResponse.php | 2 -- src-annotation/Commands.php | 3 --- src-annotation/DonutCache.php | 2 -- src-annotation/NoHttpCache.php | 2 -- src-annotation/RefreshCache.php | 2 -- 5 files changed, 11 deletions(-) diff --git a/src-annotation/CacheableResponse.php b/src-annotation/CacheableResponse.php index 39055a02..c1e9e822 100644 --- a/src-annotation/CacheableResponse.php +++ b/src-annotation/CacheableResponse.php @@ -10,8 +10,6 @@ use BEAR\QueryRepository\DonutCommandInterceptor; /** - * @Annotation - * @Target({"METHOD","CLASS"}) * @see DonutCacheModule * @see DonutCacheableResponseInterceptor * @see DonutCommandInterceptor diff --git a/src-annotation/Commands.php b/src-annotation/Commands.php index 7dabad70..1d8ed536 100644 --- a/src-annotation/Commands.php +++ b/src-annotation/Commands.php @@ -8,9 +8,6 @@ use Ray\Di\Di\Qualifier; /** - * @Annotation - * @Target("METHOD") - * @Qualifier */ #[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)] #[Qualifier] diff --git a/src-annotation/DonutCache.php b/src-annotation/DonutCache.php index 2571e0a2..0a0331bb 100644 --- a/src-annotation/DonutCache.php +++ b/src-annotation/DonutCache.php @@ -9,8 +9,6 @@ use BEAR\QueryRepository\DonutCommandInterceptor; /** - * @Annotation - * @Target({"METHOD","CLASS"}) * @see DonutCacheModule * @see DonutCacheInterceptor * @see DonutCommandInterceptor diff --git a/src-annotation/NoHttpCache.php b/src-annotation/NoHttpCache.php index dde82d56..4298621f 100644 --- a/src-annotation/NoHttpCache.php +++ b/src-annotation/NoHttpCache.php @@ -12,8 +12,6 @@ * * Simplified notation to say that you don't want anything cached * - * @Annotation - * @Target("CLASS") * @see HttpCacheInterceptor */ #[Attribute(Attribute::TARGET_CLASS)] diff --git a/src-annotation/RefreshCache.php b/src-annotation/RefreshCache.php index d9a6a756..cee83590 100644 --- a/src-annotation/RefreshCache.php +++ b/src-annotation/RefreshCache.php @@ -8,8 +8,6 @@ use BEAR\QueryRepository\DonutCommandInterceptor; /** - * @Annotation - * @Target("METHOD") * @see DonutCommandInterceptor */ #[Attribute(Attribute::TARGET_METHOD)] From df51c586008f18f5dba46d20460cc1be37118b13 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 12:31:07 +0900 Subject: [PATCH 16/20] refactor: Remove all docblock annotations from test fixtures Remove remaining doctrine-style docblock annotations from test fixture files: - Remove @DonutCache, @NoHttpCache, @Embed annotations from docblocks - Keep only PHP 8 Attributes (#[...]) - Convert @FakeAnnotation docblock to inline comment for test coverage documentation This fixes CI errors where doctrine/annotations parser was failing on classes without @Annotation marker in their docblocks. --- tests/Fake/fake-app/src/Resource/App/Dep/LevelOne.php | 1 - tests/Fake/fake-app/src/Resource/App/NoHttpCacheControl.php | 3 --- tests/Fake/fake-app/src/Resource/Page/Dep/LevelOne.php | 1 - tests/Fake/fake-app/src/Resource/Page/Dep/LevelTwo.php | 1 - tests/Fake/fake-app/src/Resource/Page/EmbVal.php | 1 - tests/Fake/fake-app/src/Resource/Page/EmbView.php | 1 - tests/Fake/fake-app/src/Resource/Page/Html/BlogPosting.php | 1 - .../fake-app/src/Resource/Page/Html/BlogPostingCache.php | 1 - .../src/Resource/Page/Html/BlogPostingCacheControl.php | 1 - .../fake-app/src/Resource/Page/Html/BlogPostingDonut.php | 6 ------ tests/Fake/fake-app/src/Resource/Page/Html/Comment.php | 1 - .../fake-app/src/Resource/Page/Html/PageSurrogateKey.php | 1 - 12 files changed, 19 deletions(-) diff --git a/tests/Fake/fake-app/src/Resource/App/Dep/LevelOne.php b/tests/Fake/fake-app/src/Resource/App/Dep/LevelOne.php index b287e34f..27c22172 100644 --- a/tests/Fake/fake-app/src/Resource/App/Dep/LevelOne.php +++ b/tests/Fake/fake-app/src/Resource/App/Dep/LevelOne.php @@ -12,7 +12,6 @@ class LevelOne extends ResourceObject public $body = ['level-one' => 1]; /** - * @Embed(rel="level-two", src="/dep/level-two") */ #[Embed(src: '/dep/level-two', rel: 'two')] public function onGet() diff --git a/tests/Fake/fake-app/src/Resource/App/NoHttpCacheControl.php b/tests/Fake/fake-app/src/Resource/App/NoHttpCacheControl.php index 57bcc521..607f3a9b 100644 --- a/tests/Fake/fake-app/src/Resource/App/NoHttpCacheControl.php +++ b/tests/Fake/fake-app/src/Resource/App/NoHttpCacheControl.php @@ -9,9 +9,6 @@ use BEAR\RepositoryModule\Annotation\NoHttpCache; use BEAR\Resource\ResourceObject; -/** - * @NoHttpCache - */ #[NoHttpCache] class NoHttpCacheControl extends ResourceObject { diff --git a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelOne.php b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelOne.php index 810606c3..d7e8cbf5 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelOne.php +++ b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelOne.php @@ -12,7 +12,6 @@ class LevelOne extends ResourceObject public $body = ['level-one' => 1]; /** - * @Embed(rel="level-two", src="/dep/level-two") */ #[Embed(rel: 'level-two', src: '/dep/level-two')] public function onGet() diff --git a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelTwo.php b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelTwo.php index aa682124..f9caa915 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Dep/LevelTwo.php +++ b/tests/Fake/fake-app/src/Resource/Page/Dep/LevelTwo.php @@ -12,7 +12,6 @@ class LevelTwo extends ResourceObject public $body = ['level-two' => 1]; /** - * @Embed(rel="level-three", src="/dep/level-three") */ #[Embed(rel: 'level-three', src: '/dep/level-three')] public function onGet() diff --git a/tests/Fake/fake-app/src/Resource/Page/EmbVal.php b/tests/Fake/fake-app/src/Resource/Page/EmbVal.php index 8e805e43..51f3f1a2 100644 --- a/tests/Fake/fake-app/src/Resource/Page/EmbVal.php +++ b/tests/Fake/fake-app/src/Resource/Page/EmbVal.php @@ -14,7 +14,6 @@ class EmbVal extends ResourceObject { /** - * @Embed(rel="time", src="page://self/none"); */ #[Embed(rel: "time", src: "page://self/none")] public function onGet() : ResourceObject diff --git a/tests/Fake/fake-app/src/Resource/Page/EmbView.php b/tests/Fake/fake-app/src/Resource/Page/EmbView.php index e9419414..7aa52cdb 100644 --- a/tests/Fake/fake-app/src/Resource/Page/EmbView.php +++ b/tests/Fake/fake-app/src/Resource/Page/EmbView.php @@ -14,7 +14,6 @@ class EmbView extends ResourceObject { /** - * @Embed(rel="time", src="page://self/none") */ #[Embed(rel: "time", src: "page://self/none")] public function onGet() : ResourceObject diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPosting.php b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPosting.php index 7371d1ff..d4dfad12 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPosting.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPosting.php @@ -14,7 +14,6 @@ class BlogPosting extends ResourceObject { /** - * @Embed(rel="comment", src="page://self/html/comment") */ #[Embed(rel: "comment", src: "page://self/html/comment")] public function onGet(int $id = 0) diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCache.php b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCache.php index 2902fc6c..150d8189 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCache.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCache.php @@ -17,7 +17,6 @@ class BlogPostingCache extends ResourceObject ]; /** - * @Embed(rel="comment", src="page://self/html/comment") */ #[CacheableResponse] #[Embed(rel: "comment", src: "page://self/html/comment")] diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php index 7fb3541b..a43dae33 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php @@ -22,7 +22,6 @@ public function __construct( } /** - * @Embed(rel="comment", src="page://self/html/comment") */ #[Embed(rel: "comment", src: "page://self/html/comment")] public function onGet() diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingDonut.php b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingDonut.php index 59b55785..436686dc 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingDonut.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingDonut.php @@ -6,15 +6,9 @@ use BEAR\Resource\Annotation\Embed; use BEAR\Resource\ResourceObject; -/** - * @DonutCache - */ #[DonutCache] class BlogPostingDonut extends ResourceObject { - /** - * @Embed(rel="comment", src="page://self/html/comment") - */ #[Embed(rel: "comment", src: "page://self/html/comment")] public function onGet(int $id = 0) { diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/Comment.php b/tests/Fake/fake-app/src/Resource/Page/Html/Comment.php index 63c0cb83..9db2953d 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/Comment.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/Comment.php @@ -12,7 +12,6 @@ class Comment extends ResourceObject { /** - * @Embed(rel="like", src="page://self/html/like") */ #[Embed(rel: "like", src: "page://self/html/like")] public function onGet() diff --git a/tests/Fake/fake-app/src/Resource/Page/Html/PageSurrogateKey.php b/tests/Fake/fake-app/src/Resource/Page/Html/PageSurrogateKey.php index 7042e2a0..9d8bed7b 100644 --- a/tests/Fake/fake-app/src/Resource/Page/Html/PageSurrogateKey.php +++ b/tests/Fake/fake-app/src/Resource/Page/Html/PageSurrogateKey.php @@ -15,7 +15,6 @@ class PageSurrogateKey extends ResourceObject { /** - * @Embed(rel="comment", src="page://self/html/comment") */ #[Embed(rel: "comment", src: "page://self/html/comment")] public function onGet() : ResourceObject From 28bc37e3120ff3d7a18e103cc6dfbfc46debc8d0 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 12:34:13 +0900 Subject: [PATCH 17/20] refactor: Require PHP 8.2+ and clean up test fixtures - Update minimum PHP version from 8.1 to 8.2 - Remove unnecessary comment from User.php test fixture --- composer.json | 2 +- tests/Fake/fake-app/src/Resource/App/User.php | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/composer.json b/composer.json index d93f2f8e..ce9fa1cb 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^8.1", + "php": "^8.2", "bear/resource": "^1.16.1", "bear/sunday": "^1.5", "psr/cache": "^1.0 || ^2.0 || ^3.0", diff --git a/tests/Fake/fake-app/src/Resource/App/User.php b/tests/Fake/fake-app/src/Resource/App/User.php index 1cc2673b..6df24d37 100644 --- a/tests/Fake/fake-app/src/Resource/App/User.php +++ b/tests/Fake/fake-app/src/Resource/App/User.php @@ -46,10 +46,6 @@ public function onPatch($id, $name) return $this; } - /** - * - * @FakeAnnotation // ignored in RefreshAnnotatedCommand::request. This was put for the test coverage. - */ #[Purge(uri: "app://self/user/friend?user_id={id}")] #[Refresh(uri: "app://self/user/profile?user_id={id}")] #[FakeAnnotation] From f50ef0c8f09736f31715fabdad24db41d4da8462 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 12:35:10 +0900 Subject: [PATCH 18/20] docs: Update CHANGELOG with PHP 8.2 requirement --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index beb177c0..aba75c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **PHP 8 Attributes Migration**: Removed `doctrine/annotations` and `doctrine/cache` dependencies, migrated to native PHP 8 attributes +- **Minimum PHP Version**: Updated requirement from PHP 8.1 to PHP 8.2 - Improve `rector-migrate.php` to support vendor installation by removing hardcoded paths - Update `ANNOTATION_TO_ATTRIBUTE.md` migration guide following Ray.AuraSqlModule pattern - Improve marshaller provider error handling with better exception messages From c8d977fc72929e46a1ecf77f788872a52f959a20 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 12:49:45 +0900 Subject: [PATCH 19/20] ci: Remove PHP 8.1 from test matrix --- .github/workflows/continuous-integration.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index aa632e5f..1cb260ff 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -27,9 +27,6 @@ jobs: matrix: include: # Ubuntu: Test all PHP versions - - os: ubuntu-latest - php-version: "8.1" - dependencies: highest - os: ubuntu-latest php-version: "8.2" dependencies: lowest From b9e1584e0221aded4bd4fad79945d89fb4256b4f Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 10 Nov 2025 12:50:57 +0900 Subject: [PATCH 20/20] chore: Update PHPCS target PHP version to 8.2 --- phpcs.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpcs.xml b/phpcs.xml index 2a16700c..e1b79edf 100755 --- a/phpcs.xml +++ b/phpcs.xml @@ -8,8 +8,8 @@ - - + +