Skip to content

Commit 5ef5a69

Browse files
authored
Merge pull request #165 from bearsunday/php82
Migrate from doctrine/annotations to PHP 8 Attributes
2 parents a1c16a2 + b9e1584 commit 5ef5a69

73 files changed

Lines changed: 670 additions & 532 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/continuous-integration.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ jobs:
2727
matrix:
2828
include:
2929
# Ubuntu: Test all PHP versions
30-
- os: ubuntu-latest
31-
php-version: "8.1"
32-
dependencies: highest
3330
- os: ubuntu-latest
3431
php-version: "8.2"
3532
dependencies: lowest

.scrutinizer.yml

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
1-
filter:
2-
paths: ["src/*"]
3-
4-
tools:
5-
php_sim: true
6-
php_pdepend: true
7-
php_analyzer: true
81
build:
9-
image: default-bionic
10-
nodes:
11-
analysis:
12-
tests:
13-
override:
14-
- php-scrutinizer-run --enable-security-analysis
2+
image: default-jammy
153
environment:
16-
redis: true
174
php:
18-
version: 8.2
5+
version: 8.4
196
pecl_extensions:
207
- redis
8+
nodes:
9+
analysis:
10+
tests:
11+
override:
12+
- php-scrutinizer-run
13+
14+
filter:
15+
paths: ["src/*"]

ANNOTATION_TO_ATTRIBUTE.md

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
# Migrating from Doctrine Annotations to PHP 8 Attributes
2+
3+
## Overview
4+
5+
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.
6+
7+
## Why Migrate?
8+
9+
- **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.
10+
- **Native PHP Support**: PHP 8 attributes are a built-in language feature, providing first-class support without external dependencies
11+
- **Better Performance**: No runtime annotation parsing overhead - attributes are compiled and cached by PHP itself
12+
- **Modern Syntax**: Cleaner, more readable code that follows PHP 8+ best practices
13+
- **No Extra Dependencies**: Eliminates the need for the abandoned doctrine/annotations package
14+
- **Future-Proof**: Attributes are the official PHP standard for metadata, ensuring long-term compatibility
15+
16+
## Migration Steps
17+
18+
### Step 1: Install Rector (if not already installed)
19+
20+
Rector is an automated refactoring tool that can convert annotations to attributes:
21+
22+
```bash
23+
composer require --dev rector/rector
24+
```
25+
26+
### Step 2: Run Automated Migration
27+
28+
BEAR.QueryRepository provides a Rector configuration file for automated migration:
29+
30+
```bash
31+
# Dry-run to preview changes
32+
vendor/bin/rector process src --config=vendor/bear/query-repository/rector-migrate.php --dry-run
33+
34+
# Apply the changes
35+
vendor/bin/rector process src --config=vendor/bear/query-repository/rector-migrate.php
36+
```
37+
38+
If you have tests that use annotations:
39+
40+
```bash
41+
vendor/bin/rector process tests --config=vendor/bear/query-repository/rector-migrate.php
42+
```
43+
44+
### Step 3: Manual Review
45+
46+
Review the changes made by Rector and adjust if necessary. Pay special attention to:
47+
48+
- Multi-line annotations with complex values
49+
- Annotations with custom parameters
50+
- Import statements (Rector should handle these automatically)
51+
52+
### Step 4: Remove doctrine/annotations
53+
54+
After migration, you can safely remove the doctrine/annotations dependency:
55+
56+
```bash
57+
composer remove doctrine/annotations
58+
```
59+
60+
## Before and After Examples
61+
62+
### Cacheable Resource
63+
64+
**Before (Doctrine Annotation):**
65+
```php
66+
use BEAR\RepositoryModule\Annotation\Cacheable;
67+
68+
/**
69+
* @Cacheable(expiry="short", type="value")
70+
*/
71+
class User extends ResourceObject
72+
{
73+
public function onGet($id)
74+
{
75+
// ...
76+
}
77+
}
78+
```
79+
80+
**After (PHP 8 Attribute):**
81+
```php
82+
use BEAR\RepositoryModule\Annotation\Cacheable;
83+
84+
#[Cacheable(expiry: "short", type: "value")]
85+
class User extends ResourceObject
86+
{
87+
public function onGet($id)
88+
{
89+
// ...
90+
}
91+
}
92+
```
93+
94+
### HTTP Cache Headers
95+
96+
**Before (Doctrine Annotation):**
97+
```php
98+
use BEAR\RepositoryModule\Annotation\HttpCache;
99+
100+
/**
101+
* @HttpCache(maxAge=60, sMaxAge=600)
102+
*/
103+
class News extends ResourceObject
104+
{
105+
public function onGet()
106+
{
107+
// ...
108+
}
109+
}
110+
```
111+
112+
**After (PHP 8 Attribute):**
113+
```php
114+
use BEAR\RepositoryModule\Annotation\HttpCache;
115+
116+
#[HttpCache(maxAge: 60, sMaxAge: 600)]
117+
class News extends ResourceObject
118+
{
119+
public function onGet()
120+
{
121+
// ...
122+
}
123+
}
124+
```
125+
126+
### Cache Invalidation
127+
128+
**Before (Doctrine Annotation):**
129+
```php
130+
use BEAR\RepositoryModule\Annotation\Refresh;
131+
use BEAR\RepositoryModule\Annotation\Purge;
132+
133+
class User extends ResourceObject
134+
{
135+
/**
136+
* @Refresh(uri="app://self/users")
137+
* @Purge(uri="app://self/user/{id}")
138+
*/
139+
public function onPut($id, $name)
140+
{
141+
// ...
142+
}
143+
}
144+
```
145+
146+
**After (PHP 8 Attribute):**
147+
```php
148+
use BEAR\RepositoryModule\Annotation\Refresh;
149+
use BEAR\RepositoryModule\Annotation\Purge;
150+
151+
class User extends ResourceObject
152+
{
153+
#[Refresh(uri: "app://self/users")]
154+
#[Purge(uri: "app://self/user/{id}")]
155+
public function onPut($id, $name)
156+
{
157+
// ...
158+
}
159+
}
160+
```
161+
162+
### Complex Cache Configuration
163+
164+
**Before (Doctrine Annotation):**
165+
```php
166+
use BEAR\RepositoryModule\Annotation\Cacheable;
167+
use BEAR\RepositoryModule\Annotation\HttpCache;
168+
169+
/**
170+
* @Cacheable(expiry="medium", expirySecond=3600, type="view", update=true)
171+
* @HttpCache(maxAge=60, sMaxAge=600, isPrivate=false, mustRevalidate=true)
172+
*/
173+
class Article extends ResourceObject
174+
{
175+
// ...
176+
}
177+
```
178+
179+
**After (PHP 8 Attribute):**
180+
```php
181+
use BEAR\RepositoryModule\Annotation\Cacheable;
182+
use BEAR\RepositoryModule\Annotation\HttpCache;
183+
184+
#[Cacheable(expiry: "medium", expirySecond: 3600, type: "view", update: true)]
185+
#[HttpCache(maxAge: 60, sMaxAge: 600, isPrivate: false, mustRevalidate: true)]
186+
class Article extends ResourceObject
187+
{
188+
// ...
189+
}
190+
```
191+
192+
### Donut Caching
193+
194+
**Before (Doctrine Annotation):**
195+
```php
196+
use BEAR\RepositoryModule\Annotation\DonutCache;
197+
198+
class Page extends ResourceObject
199+
{
200+
/**
201+
* @DonutCache
202+
*/
203+
public function onGet()
204+
{
205+
// ...
206+
}
207+
}
208+
```
209+
210+
**After (PHP 8 Attribute):**
211+
```php
212+
use BEAR\RepositoryModule\Annotation\DonutCache;
213+
214+
class Page extends ResourceObject
215+
{
216+
#[DonutCache]
217+
public function onGet()
218+
{
219+
// ...
220+
}
221+
}
222+
```
223+
224+
## Supported Annotations
225+
226+
The following BEAR.QueryRepository annotations are automatically converted:
227+
228+
- `@Cacheable``#[Cacheable]` - Resource caching configuration
229+
- `@HttpCache``#[HttpCache]` - HTTP cache control headers
230+
- `@NoHttpCache``#[NoHttpCache]` - Disable HTTP caching
231+
- `@Refresh``#[Refresh]` - Invalidate dependent caches
232+
- `@Purge``#[Purge]` - Purge specific cache entries
233+
- `@DonutCache``#[DonutCache]` - Donut caching pattern
234+
- `@RefreshCache``#[RefreshCache]` - Refresh cache after command
235+
- `@Commands``#[Commands]` - Cache invalidation commands
236+
237+
**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).
238+
239+
## Key Differences
240+
241+
1. **Syntax Change**: Use `#[AttributeName]` instead of `@AttributeName` in docblocks
242+
2. **Named Parameters**: Use colons for parameters (e.g., `expiry: "short"` instead of `expiry="short"`)
243+
3. **Placement**: Attributes go before the class/method declaration, not in docblocks
244+
4. **Import Statements**: Add proper `use` statements for all attributes
245+
5. **Multiple Attributes**: Stack multiple attributes on separate lines or combine with commas
246+
247+
## Troubleshooting
248+
249+
### Rector doesn't find annotations
250+
251+
Make sure your code is using fully qualified class names in `use` statements:
252+
253+
```php
254+
// Correct
255+
use BEAR\RepositoryModule\Annotation\Cacheable;
256+
257+
// Incorrect - Rector won't recognize this
258+
use BEAR\RepositoryModule\Annotation as Cache;
259+
```
260+
261+
### Import statements not updated
262+
263+
Rector should automatically update import statements, but if it doesn't:
264+
265+
1. Manually verify `use` statements are present
266+
2. Run your IDE's "Optimize Imports" feature
267+
3. Use tools like PHP-CS-Fixer to clean up unused imports
268+
269+
### Complex annotation values
270+
271+
For annotations with complex array values, you may need to manually adjust the syntax:
272+
273+
**Before:**
274+
```php
275+
/**
276+
* @HttpCache(etag={"id", "updated_at"})
277+
*/
278+
```
279+
280+
**After:**
281+
```php
282+
#[HttpCache(etag: ["id", "updated_at"])]
283+
```
284+
285+
### Testing the migration
286+
287+
After migration, ensure all tests pass:
288+
289+
```bash
290+
vendor/bin/phpunit
291+
```
292+
293+
## Manual Migration
294+
295+
If you prefer not to use Rector, you can manually convert annotations:
296+
297+
1. Replace `/** @AnnotationName */` with `#[AnnotationName]`
298+
2. Move attributes from docblocks to the line before the method/property/class
299+
3. Convert parameter syntax from `key="value"` to `key: "value"`
300+
4. Ensure all necessary `use` statements are present
301+
5. For multiple attributes, place each on a new line or combine: `#[Attr1, Attr2]`
302+
303+
## Need Help?
304+
305+
If you encounter issues during migration:
306+
307+
1. Check the [BEAR.QueryRepository documentation](https://github.com/bearsunday/BEAR.QueryRepository)
308+
2. Review the [PHP 8 Attributes documentation](https://www.php.net/manual/en/language.attributes.php)
309+
3. [Open an issue](https://github.com/bearsunday/BEAR.QueryRepository/issues) on GitHub
310+
311+
## References
312+
313+
- [PHP 8 Attributes RFC](https://wiki.php.net/rfc/attributes_v2)
314+
- [Rector Documentation](https://github.com/rectorphp/rector)
315+
- [BEAR.Sunday Documentation](https://bearsunday.github.io/)

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
## [1.13.0] - 2025-10-21
11-
1210
### Added
11+
- **Migration Tools**: Added `rector-migrate.php` for automated annotation-to-attribute migration
12+
- **Migration Guide**: Added `ANNOTATION_TO_ATTRIBUTE.md` with comprehensive migration instructions
1313
- Add CLAUDE.md with comprehensive codebase architecture and development guide
1414
- Add marshaller configuration support for Redis with compression options (deflate)
1515
- Add `MarshallerType` enum for type-safe marshaller selection
@@ -25,6 +25,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2525
- Add PHP 8.5 support to CI workflow
2626

2727
### Changed
28+
- **PHP 8 Attributes Migration**: Removed `doctrine/annotations` and `doctrine/cache` dependencies, migrated to native PHP 8 attributes
29+
- **Minimum PHP Version**: Updated requirement from PHP 8.1 to PHP 8.2
30+
- Improve `rector-migrate.php` to support vendor installation by removing hardcoded paths
31+
- Update `ANNOTATION_TO_ATTRIBUTE.md` migration guide following Ray.AuraSqlModule pattern
2832
- Improve marshaller provider error handling with better exception messages
2933
- Enhance Memcached module with TagAwareAdapter support
3034
- Update Symfony Cache to support version ^7.3

composer-require-checker.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
"static", "self", "parent",
55
"array", "string", "int", "float", "bool", "iterable", "callable", "void", "object",
66
"Attribute", "Memcached", "Redis", "RedisException",
7-
"Doctrine\\Common\\Cache\\ArrayCache", "Doctrine\\Common\\Cache\\MemcachedCache", "Doctrine\\Common\\Cache\\RedisCache",
7+
"Doctrine\\Common\\Cache\\CacheProvider",
8+
"Doctrine\\Common\\Cache\\MemcachedCache",
9+
"Doctrine\\Common\\Cache\\RedisCache",
810
"BEAR\\FastlyModule\\FastlyCachePurgerInterface", "BEAR\\FastlyModule\\FastlyPurgeModule",
911
"Detection\\MobileDetect"
1012
]

0 commit comments

Comments
 (0)