Skip to content

Commit 59ec930

Browse files
authored
Merge pull request #943 from zenstruck/feat/proxy-php84
feat: auto refresh using PHP 8.4 ghost objects
2 parents 17817e9 + 39fd073 commit 59ec930

File tree

151 files changed

+5632
-300
lines changed

Some content is hidden

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

151 files changed

+5632
-300
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ MONGO_URL="mongodb://127.0.0.1:27018/dbName?compressors=disabled&gssapiServi
99

1010
USE_DAMA_DOCTRINE_TEST_BUNDLE="0"
1111
USE_FOUNDRY_PHPUNIT_EXTENSION="0"
12+
USE_PHP_84_LAZY_OBJECTS="0"
1213
PHPUNIT_VERSION="12" # allowed values: 9, 10, 11, 12

.github/workflows/ci.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88

99
jobs:
1010
tests:
11-
name: P:${{ matrix.php }}, S:${{ matrix.symfony }}, D:${{ matrix.database }}, PU:${{ matrix.phpunit }}${{ matrix.deps == 'lowest' && ' (lowest)' || '' }}${{ matrix.use-phpunit-extension == 1 && ' (phpunit extension)' || '' }}
11+
name: P:${{ matrix.php }}, S:${{ matrix.symfony }}, D:${{ matrix.database }}, PU:${{ matrix.phpunit }}${{ matrix.deps == 'lowest' && ' (lowest)' || '' }}${{ matrix.use-phpunit-extension == 1 && ' (phpunit extension)' || '' }}${{ (matrix.use-php-84-lazy-objects != 1 || matrix.php != '8.4') && ' (legacy proxy)' || '' }}
1212
runs-on: ubuntu-latest
1313
strategy:
1414
fail-fast: false
@@ -17,6 +17,7 @@ jobs:
1717
symfony: [ 6.4.*, 7.3.*, 8.0.*-dev ]
1818
database: [ mysql|mongo ]
1919
phpunit: [ 11, 12 ]
20+
use-php-84-lazy-objects: [ 1 ]
2021

2122
# default values:
2223
# deps: [ highest ]
@@ -55,11 +56,15 @@ jobs:
5556

5657
# using Foundry's PHPUnit extension
5758
- {php: 8.4, symfony: '*', phpunit: 12, database: mysql|mongo, use-phpunit-extension: 1}
59+
60+
# disable lazy objects in PHP 8.4
61+
- {php: 8.4, symfony: '*', phpunit: 12, database: mysql|mongo, use-php-84-lazy-objects: 0}
5862
env:
5963
DATABASE_URL: ${{ contains(matrix.database, 'mysql') && 'mysql://root:root@localhost:3306/foundry?serverVersion=5.7.42' || contains(matrix.database, 'pgsql') && 'postgresql://root:root@localhost:5432/foundry?serverVersion=15' || contains(matrix.database, 'sqlite') && 'sqlite:///%kernel.project_dir%/var/data.db' || '' }}
6064
MONGO_URL: ${{ contains(matrix.database, 'mongo') && 'mongodb://127.0.0.1:27017/dbName?compressors=disabled&gssapiServiceName=mongodb' || '' }}
6165
USE_DAMA_DOCTRINE_TEST_BUNDLE: ${{ contains(matrix.database, 'sql') && 1 || 0 }}
6266
USE_FOUNDRY_PHPUNIT_EXTENSION: ${{ matrix.use-phpunit-extension || 0 }}
67+
USE_PHP_84_LAZY_OBJECTS: ${{ matrix.use-php-84-lazy-objects }}
6368
PHPUNIT_VERSION: ${{ matrix.phpunit }}
6469
services:
6570
postgres:
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
paths:
6+
- 'utils/rector/**'
7+
pull_request:
8+
paths:
9+
- 'utils/rector/**'
10+
schedule:
11+
- cron: '0 0 1,16 * *'
12+
13+
jobs:
14+
test-rector-rules:
15+
name: Test rector rules
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v3
20+
21+
- name: Setup PHP
22+
uses: shivammathur/setup-php@v2
23+
with:
24+
php-version: 8.4
25+
coverage: none
26+
27+
- name: Install dependencies
28+
uses: ramsey/composer-install@v2
29+
with:
30+
composer-options: --prefer-dist
31+
32+
- name: Install Rector & PHPStan
33+
run: |
34+
composer update phpunit/phpunit:^11 brianium/paratest -W
35+
36+
composer bin phpstan install
37+
composer bin rector install
38+
39+
- name: Test
40+
run: vendor/bin/phpunit -c phpunit-rector.xml.dist
41+
shell: bash
42+
43+
- name: Static analysis
44+
run: bin/tools/rector/vendor/phpstan/phpstan/phpstan analyse -c utils/rector/phpstan.neon
45+
shell: bash

UPGRADE-2.7.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Migration guide from Foundry 2.6 to 2.7
2+
3+
Foundry 2.7 provides a new way to auto-refresh entities, which leverages new [PHP 8.4 lazy objects](https://www.php.net/manual/en/language.oop5.lazy-objects.php)!
4+
5+
This means that the [`Proxy` mechanism](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#object-proxy)
6+
and all related classes and functions are deprecated. This change was made to fix a lot of quirks involved by the proxy mechanism,
7+
and to reduce the maintenance burden of this feature.
8+
9+
## How to
10+
11+
> [!IMPORTANT]
12+
> The new auto-refresh mechanism only applies for PHP 8.4,
13+
> if you're still not using PHP 8.4, there is nothing to do (yet!)
14+
15+
First, you need to configure whether you want to use the new auto-refresh mechanism:
16+
17+
```yaml
18+
zenstruck_foundry:
19+
# from Foundry 2.7, with PHP >=8.4, not setting this configuration is deprecated
20+
enable_auto_refresh_with_lazy_objects: true
21+
```
22+
23+
In both cases, you'll need to migrate your factories and code to remove all the `Proxy`-related code:
24+
- remove all `_real()` calls
25+
- more generally, replace all proxy methods, by their [function equivalent](https://github.com/zenstruck/foundry/blob/2.x/src/Persistence/functions.php)
26+
- replace `PersistentProxyObjectFactory` to `PersistentObjectFactory`
27+
- remove all types and PHPDoc related to proxies
28+
29+
Every modification needed for the migration is covered by a deprecation.
30+
You'll need to upgrade to the 2.7 version, run the tests, and fix all the deprecations reported.
31+
32+
## Rector rules
33+
34+
This could be a lot of work in big projects, so we provide a [Rector rule set](https://getrector.org/) to help you with this migration.
35+
36+
First, you'll need to install `rector/rector`:
37+
```shell
38+
composer require --dev rector/rector
39+
```
40+
41+
Then, create a `rector.php` file:
42+
43+
```php
44+
<?php
45+
46+
use Rector\Config\RectorConfig;
47+
use Zenstruck\Foundry\Utils\Rector\FoundrySetList;
48+
49+
return RectorConfig::configure()
50+
->withPaths([
51+
// add all paths where your factories are defined and where Foundry is used
52+
'src',
53+
'tests'
54+
])
55+
->withSets([FoundrySetList::REMOVE_PROXIES])
56+
;
57+
```
58+
59+
And finally, run Rector:
60+
```shell
61+
# you can run Rector in "dry run" mode, in order to see which files will be modified
62+
vendor/bin/rector process --dry-run
63+
64+
# actually modify files
65+
vendor/bin/rector process
66+
```
67+
68+
> [!IMPORTANT]
69+
> Rector rules may not totally cover all deprecations (some complex cases may not be handled)
70+
> You'd still need to run the tests to ensure everything is fixed and no more deprecation are reported.
71+
72+
> [!TIP]
73+
> You can try to run these rules twice with `--clear-cache` option. Sometimes, the second run will find differences
74+
> that it could not spot on the first run.
75+
76+
> [!NOTE]
77+
> Once you've finished the migration to 2.7, it is not necessary to keep the Foundry rule set in your Rector
78+
> config.
79+
80+
## Deprecations list
81+
82+
Here is the full list of modifications needed:
83+
84+
- Change the base class of your factories from `PersistentProxyObjectFactory` to `PersistentObjectFactory`
85+
You'll also need to update the PHPDoc `@extends` annotation to use the new class (covered by `ChangeFactoryBaseClassRector`).
86+
- Remove all `_real()`, `_enableAutoRefresh()` and `_disableAutoRefresh()` calls (covered by `RemoveMethodCallRector`).
87+
- Remove all `\Zenstruck\Foundry\Persistence\proxy()` and `\Zenstruck\Foundry\Persistence\proxy()` calls (covered by `RemoveFunctionCallRector`).
88+
- Remove all `_withoutAutoRefresh()` calls (covered by `RemoveWithoutAutorefreshCallRector`).
89+
- Replace some method calls on `Proxy` class with their function equivalent (covered by `MethodCallToFuncCallWIthObjectAsFirstParameterRector`):
90+
- `_get()` => `\Zenstruck\Foundry\Persistence\get()`
91+
- `_set()` => `\Zenstruck\Foundry\Persistence\set()`
92+
- `_save()` => `\Zenstruck\Foundry\Persistence\save()`
93+
- `_refresh()` => `\Zenstruck\Foundry\Persistence\refresh()`
94+
- `_delete()` => `\Zenstruck\Foundry\Persistence\delete()`
95+
- `_assertPersisted()` => `\Zenstruck\Foundry\Persistence\assert_persisted()`
96+
- `_assertNotPersisted()` => `\Zenstruck\Foundry\Persistence\assert_not_persisted()`
97+
98+
- Remove `Proxy` type for parameters in the prototype in methods and functions (covered by `ChangeProxyParamTypesRector`).
99+
- Remove `Proxy` return type in methods and functions (covered by `ChangeProxyReturnTypesRector`).
100+
- Remove all `Proxy` type hints in PHPDoc (covered by `RemovePhpDocProxyTypeHintRector`).
101+
102+
## Troubleshooting
103+
104+
After enabling the new auto-refresh mechanism and removing all proxy-related code, you may encounter some issues.
105+
Most of the time, these can be resolved by calling the `\Zenstruck\Foundry\Persistence\refresh()` function on the affected entity,
106+
which mimics the behavior of the former proxy mechanism.

bin/tools/rector/composer.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"require": {
3+
"rector/rector": "^2.0",
4+
"phpstan/phpstan-doctrine": "^2.0"
5+
}
6+
}

0 commit comments

Comments
 (0)