Skip to content

Commit 21860d7

Browse files
committed
fix: review
1 parent c21a618 commit 21860d7

29 files changed

+680
-173
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ jobs:
329329
- name: Setup PHP
330330
uses: shivammathur/setup-php@v2
331331
with:
332-
php-version: 8.4
332+
php-version: 8.3
333333
coverage: none
334334

335335
- name: Install dependencies

composer.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,16 @@
3434
"doctrine/doctrine-migrations-bundle": "^2.2|^3.0",
3535
"doctrine/mongodb-odm": "^2.4",
3636
"doctrine/mongodb-odm-bundle": "^4.6|^5.0",
37-
"doctrine/persistence": "^2.0|^3.0|^4.0",
3837
"doctrine/orm": "^2.16|^3.0",
3938
"doctrine/persistence": "^2.0|^3.0|^4.0",
4039
"phpunit/phpunit": "^9.5.0 || ^10.0 || ^11.0 || ^12.0",
41-
"symfony/browser-kit": "^7.2",
40+
"symfony/browser-kit": "^6.4|^7.0",
4241
"symfony/console": "^6.4|^7.0",
4342
"symfony/dotenv": "^6.4|^7.0",
4443
"symfony/framework-bundle": "^6.4|^7.0",
4544
"symfony/maker-bundle": "^1.55",
4645
"symfony/phpunit-bridge": "^6.4|^7.0",
47-
"symfony/routing": "^7.2",
46+
"symfony/routing": "^6.4|^7.0",
4847
"symfony/runtime": "^6.4|^7.0",
4948
"symfony/translation-contracts": "^3.4",
5049
"symfony/uid": "^6.4|^7.0",

config/persistence.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
44

5+
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
56
use Symfony\Component\HttpKernel\Event\TerminateEvent;
7+
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
68
use Zenstruck\Foundry\Persistence\PersistenceManager;
7-
use Zenstruck\Foundry\Persistence\Proxy\KernelTerminateListener;
9+
use Zenstruck\Foundry\Persistence\Proxy\PersistedObjectsTracker;
810
use Zenstruck\Foundry\Persistence\ResetDatabase\ResetDatabaseManager;
911

1012
return static function (ContainerConfigurator $container): void {
@@ -22,8 +24,11 @@
2224
;
2325

2426
if (PHP_VERSION_ID >= 80400) {
25-
$container->services()->set('.foundry.proxy.kernel_terminate_listener', KernelTerminateListener::class)
26-
->tag('kernel.event_listener', ['event' => TerminateEvent::class, 'method' => '__invoke'])
27+
$container->services()->set('.foundry.persistence.objects_tracker', PersistedObjectsTracker::class)
28+
->tag('kernel.reset', ['method' => 'refresh'])
29+
->tag('kernel.event_listener', ['event' => TerminateEvent::class, 'method' => 'refresh'])
30+
->tag('kernel.event_listener', ['event' => ConsoleTerminateEvent::class, 'method' => 'refresh'])
31+
->tag('kernel.event_listener', ['event' => WorkerMessageHandledEvent::class, 'method' => 'refresh']) // @phpstan-ignore class.notFound
2732
;
2833
}
2934
};

config/services.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
param('zenstruck_foundry.persistence.flush_once'),
3636
'%env(default:zenstruck_foundry.faker.seed:int:FOUNDRY_FAKER_SEED)%',
3737
service('.zenstruck_foundry.in_memory.repository_registry'),
38+
service('.foundry.persistence.objects_tracker')->nullOnInvalid(),
3839
])
3940
->public()
4041
;

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,7 @@ once. To do this, wrap the operations in a ``flush_after()`` callback:
11631163
TagFactory::createMany(200); // instantiated/persisted but not flushed
11641164
}); // single flush
11651165

1166-
The ``flush_after()`` function forwards the callbacks return, in case you need to use the objects in your tests:
1166+
The ``flush_after()`` function forwards the callback's return, in case you need to use the objects in your tests:
11671167

11681168
::
11691169

phpstan.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ parameters:
6969
- identifier: missingType.callable
7070
path: tests/Fixture/Maker/expected/
7171

72+
# we're currently running static analysis with PHP 8.3
73+
- message: '#Call to an undefined method ReflectionClass\<(.*)\>::isUninitializedLazyObject\(\).#'
74+
- message: '#Call to an undefined method ReflectionClass\<(.*)\>::resetAsLazyProxy\(\).#'
75+
- message: '#Call to an undefined method ReflectionClass\<(.*)\>::initializeLazyObject\(\).#'
76+
7277
excludePaths:
7378
- tests/Fixture/Maker/expected/can_create_factory_with_auto_activated_not_persisted_option.php
7479
- tests/Fixture/Maker/expected/can_create_factory_interactively.php

phpunit

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
set -o errexit
44
set -o nounset
55

6+
COMPOSER_BIN="php -d xdebug.mode=off $(which composer)"
7+
68
check_phpunit_version() {
7-
INSTALLED_PHPUNIT_VERSION=$(composer info phpunit/phpunit | grep versions | cut -c 14-)
9+
INSTALLED_PHPUNIT_VERSION=$(${COMPOSER_BIN} info phpunit/phpunit | grep versions | cut -c 14-)
810

911
REQUIRED_PHPUNIT_VERSION="${1?}"
1012

@@ -35,7 +37,7 @@ SHOULD_UPDATE_PHPUNIT=$(check_phpunit_version "${PHPUNIT_VERSION}")
3537

3638
if [ "${SHOULD_UPDATE_PHPUNIT}" = "0" ]; then
3739
echo "ℹ️ Upgrading PHPUnit to ${PHPUNIT_VERSION}"
38-
composer update dama/doctrine-test-bundle brianium/paratest "phpunit/phpunit:^${PHPUNIT_VERSION}" -W
40+
${COMPOSER_BIN} update dama/doctrine-test-bundle brianium/paratest "phpunit/phpunit:^${PHPUNIT_VERSION}" -W
3941
fi
4042
### <<
4143

phpunit-deprecation-baseline.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<file path="vendor/symfony/deprecation-contracts/function.php">
44
<line number="25" hash="c6af5d66288d0667e424978000f29571e4954b81">
55
<issue><![CDATA[Since symfony/framework-bundle 6.4: Not setting the "framework.php_errors.log" config option is deprecated. It will default to "true" in 7.0.]]></issue>
6+
<issue><![CDATA[Since zenstruck/foundry 2.6: Proxy usage is deprecated in PHP 8.4. Use directly PersistentObjectFactory, Foundry now leverages the native PHP lazy system to auto-refresh objects.]]></issue>
67
</line>
78
</file>
89
</files>

src/Configuration.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Zenstruck\Foundry\InMemory\CannotEnableInMemory;
2020
use Zenstruck\Foundry\InMemory\InMemoryRepositoryRegistry;
2121
use Zenstruck\Foundry\Persistence\PersistenceManager;
22+
use Zenstruck\Foundry\Persistence\Proxy\PersistedObjectsTracker;
2223

2324
/**
2425
* @author Kevin Bond <[email protected]>
@@ -60,6 +61,7 @@ public function __construct(
6061
public readonly bool $flushOnce = false,
6162
?int $forcedFakerSeed = null,
6263
public readonly ?InMemoryRepositoryRegistry $inMemoryRepositoryRegistry = null,
64+
public readonly ?PersistedObjectsTracker $persistedObjectsTracker = null,
6365
) {
6466
if (null === self::$instance) {
6567
$this->faker->seed(self::fakerSeed($forcedFakerSeed));

src/Persistence/PersistenceManager.php

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
use Zenstruck\Foundry\Persistence\Relationship\RelationshipMetadata;
2323
use Zenstruck\Foundry\Persistence\ResetDatabase\ResetDatabaseManager;
2424

25+
use function Zenstruck\Foundry\set;
26+
2527
/**
2628
* @author Kevin Bond <[email protected]>
2729
*
@@ -147,7 +149,7 @@ public function flush(ObjectManager $om): void
147149
*
148150
* @return T
149151
*/
150-
public function refresh(object &$object, bool $force = false): object
152+
public function refresh(object &$object, bool $force = false, bool $allowRefreshDeletedObject = false): object
151153
{
152154
if (!$this->flush && !$force) {
153155
return $object;
@@ -157,6 +159,11 @@ public function refresh(object &$object, bool $force = false): object
157159
return $object->_refresh();
158160
}
159161

162+
if (\PHP_VERSION_ID >= 80400 && ($reflector = new \ReflectionClass($object))->isUninitializedLazyObject($object)) {
163+
/** @var T $object */
164+
$object = $reflector->initializeLazyObject($object);
165+
}
166+
160167
$strategy = $this->strategyFor($object::class);
161168

162169
if ($strategy->hasChanges($object)) {
@@ -165,33 +172,48 @@ public function refresh(object &$object, bool $force = false): object
165172

166173
$om = $strategy->objectManagerFor($object::class);
167174

168-
if ($strategy->contains($object)) {
169-
try {
170-
$om->refresh($object);
171-
} catch (\LogicException|\Error) {
172-
// prevent entities/documents with readonly properties to create an error
173-
// LogicException is for ORM / Error is for ODM
174-
// @see https://github.com/doctrine/orm/issues/9505
175-
}
176-
177-
return $object;
178-
}
179-
180175
if ($strategy->isEmbeddable($object)) {
181176
return $object;
182177
}
183178

184-
$id = $om->getClassMetadata($object::class)->getIdentifierValues($object);
179+
if (!$strategy->contains($object)) {
180+
$objectFromDb = null;
185181

186-
if (!$id || !($object = $om->find($object::class, $id))) { // @phpstan-ignore parameterByRef.type
187-
throw RefreshObjectFailed::objectNoLongExists();
182+
$id = $om->getClassMetadata($object::class)->getIdentifierValues($object);
183+
184+
if ($id) {
185+
// "merge" object if it is not managed
186+
$objectFromDb = $om->find($object::class, $id);
187+
}
188+
189+
if ($objectFromDb) {
190+
$object = $objectFromDb;
191+
} else {
192+
if ($allowRefreshDeletedObject) {
193+
return $object;
194+
}
195+
196+
throw RefreshObjectFailed::objectNoLongExists();
197+
}
198+
}
199+
200+
try {
201+
$om->refresh($object);
202+
} catch (\LogicException|\Error) {
203+
// prevent entities/documents with readonly properties to create an error
204+
// LogicException is for ORM / Error is for ODM
205+
// @see https://github.com/doctrine/orm/issues/9505
188206
}
189207

190208
return $object;
191209
}
192210

193211
public function isPersisted(object $object): bool
194212
{
213+
if (\PHP_VERSION_ID >= 80400 && ($reflector = new \ReflectionClass($object))->isUninitializedLazyObject($object)) {
214+
$object = $reflector->initializeLazyObject($object);
215+
}
216+
195217
// prevents doctrine to use its cache and think the object is persisted
196218
if ($this->strategyFor($object::class)->isScheduledForInsert($object)) {
197219
return false;

src/Persistence/PersistentObjectFactory.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
use Zenstruck\Foundry\Persistence\Relationship\OneToManyRelationship;
2828
use Zenstruck\Foundry\Persistence\Relationship\OneToOneRelationship;
2929

30-
use Zenstruck\Foundry\Persistence\Proxy\CreatedObjectsTracker;
31-
3230
use function Zenstruck\Foundry\force;
3331
use function Zenstruck\Foundry\get;
3432
use function Zenstruck\Foundry\set;
@@ -456,14 +454,14 @@ final protected function initializeInternal(): static
456454
return parent::initializeInternal()
457455
->afterInstantiate(
458456
static function(object $object, array $parameters, PersistentObjectFactory $factoryUsed): void {
459-
if (PHP_VERSION_ID >= 80400) {
460-
CreatedObjectsTracker::add($object);
461-
}
462-
463457
if (!$factoryUsed->isPersisting()) {
464458
return;
465459
}
466460

461+
if (\PHP_VERSION_ID >= 80400 && !$factoryUsed instanceof PersistentProxyObjectFactory) {
462+
Configuration::instance()->persistedObjectsTracker?->add($object);
463+
}
464+
467465
$afterPersistCallbacks = [];
468466

469467
foreach ($factoryUsed->afterPersist as $afterPersist) {

src/Persistence/PersistentProxyObjectFactory.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@
2222
*/
2323
abstract class PersistentProxyObjectFactory extends PersistentObjectFactory
2424
{
25+
public function __construct()
26+
{
27+
parent::__construct();
28+
29+
if (\PHP_VERSION_ID >= 80400) {
30+
trigger_deprecation(
31+
'zenstruck/foundry',
32+
'2.6',
33+
'Proxy usage is deprecated in PHP 8.4. Use directly PersistentObjectFactory, Foundry now leverages the native PHP lazy system to auto-refresh objects.',
34+
);
35+
}
36+
}
37+
2538
/**
2639
* @return class-string<T>
2740
*/
@@ -143,6 +156,6 @@ final public static function repository(): ObjectRepository
143156
{
144157
Configuration::instance()->assertPersistenceEnabled();
145158

146-
return new ProxyRepositoryDecorator(static::class(), Configuration::instance()->isInMemoryEnabled()); // @phpstan-ignore argument.type, return.type
159+
return new ProxyRepositoryDecorator(static::class(), Configuration::instance()->isInMemoryEnabled()); // @phpstan-ignore return.type
147160
}
148161
}

src/Persistence/Proxy/CreatedObjectsTracker.php

Lines changed: 0 additions & 51 deletions
This file was deleted.

src/Persistence/Proxy/KernelTerminateListener.php

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)