Skip to content

Commit 24f32bd

Browse files
authored
Support var-exporter 8 for full symfony 8 support
2 parents 6a66c09 + 550c7bc commit 24f32bd

File tree

11 files changed

+103
-47
lines changed

11 files changed

+103
-47
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"symfony/translation-contracts": "^2.5|^3.0",
3333
"symfony/validator": "^6.4|^7.0|^8.0",
3434
"symfony/form": "^6.4|^7.0|^8.0",
35-
"symfony/var-exporter": "^6.4|^7.0",
35+
"symfony/var-exporter": "^6.4|^7.0|^8.0",
3636
"ergebnis/classy": "^1.6",
3737
"symfony/translation": "^7.0|^6.4|^8.0",
3838
"symfony/deprecation-contracts": "^3.4"

src/Manager/SettingsCloner.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@
3232
use Jbtronics\SettingsBundle\Helper\PropertyAccessHelper;
3333
use Jbtronics\SettingsBundle\Metadata\MetadataManager;
3434
use Jbtronics\SettingsBundle\Metadata\ParameterMetadata;
35+
use Jbtronics\SettingsBundle\Proxy\LegacyProxyHelper;
3536
use Jbtronics\SettingsBundle\Proxy\ProxyFactoryInterface;
3637
use Jbtronics\SettingsBundle\Proxy\SettingsProxyInterface;
3738
use Jbtronics\SettingsBundle\Settings\CloneAndMergeAwareSettingsInterface;
3839
use Jbtronics\SettingsBundle\Settings\ResettableSettingsInterface;
3940
use PhpParser\Node\Param;
40-
use Symfony\Component\VarExporter\LazyObjectInterface;
4141

4242
/**
4343
* @internal
@@ -138,7 +138,7 @@ public function mergeCopyInternal(object $copy, object $into, bool $recursive, a
138138
continue;
139139
}
140140

141-
if ($copyEmbedded instanceof SettingsProxyInterface && $copyEmbedded instanceof LazyObjectInterface && !$copyEmbedded->isLazyObjectInitialized()) { //Fallback for older PHP versions
141+
if ($copyEmbedded instanceof SettingsProxyInterface && LegacyProxyHelper::isLegacyProxyUninitialized($copyEmbedded)) { //Fallback for older PHP versions
142142
continue;
143143
}
144144

@@ -218,4 +218,4 @@ private function cloneDataIfNeeded(mixed $data, ParameterMetadata $parameter): m
218218

219219
return $data;
220220
}
221-
}
221+
}

src/Manager/SettingsManager.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@
3131
use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
3232
use Jbtronics\SettingsBundle\Metadata\MetadataManagerInterface;
3333
use Jbtronics\SettingsBundle\Metadata\ParameterMetadata;
34+
use Jbtronics\SettingsBundle\Proxy\LegacyProxyHelper;
3435
use Jbtronics\SettingsBundle\Proxy\ProxyFactoryInterface;
3536
use Jbtronics\SettingsBundle\Proxy\SettingsProxyInterface;
36-
use Symfony\Component\VarExporter\LazyObjectInterface;
3737
use Symfony\Contracts\Service\ResetInterface;
3838

3939
/**
@@ -210,7 +210,7 @@ public function save(string|object|array|null $settings = null, bool $cascade =
210210
continue;
211211
}
212212

213-
if ($instance instanceof SettingsProxyInterface && $instance instanceof LazyObjectInterface && !$instance->isLazyObjectInitialized()) { //Fallback for older PHP versions
213+
if ($instance instanceof SettingsProxyInterface && LegacyProxyHelper::isLegacyProxyUninitialized($instance)) { //Fallback for older PHP versions
214214
continue;
215215
}
216216

@@ -234,6 +234,7 @@ public function reset(): void
234234
$this->settings_by_class = [];
235235
}
236236

237+
237238
public function isEnvVarOverwritten(
238239
object|string $settings,
239240
ParameterMetadata|string|\ReflectionProperty $property
@@ -311,4 +312,4 @@ public function mergeTemporaryCopy(object|string $copy, bool $cascade = true): v
311312
//Use the cloner service to merge the temporary copy back to the original instance
312313
$this->settingsCloner->mergeCopy($copy, $original, $cascade);
313314
}
314-
}
315+
}

src/Proxy/LegacyProxyHelper.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
6+
namespace Jbtronics\SettingsBundle\Proxy;
7+
8+
/**
9+
* Helper class providing utility methods for working with legacy proxies (pre-PHP 8.4).
10+
* @internal
11+
*/
12+
final class LegacyProxyHelper
13+
{
14+
15+
/**
16+
* Checks if a legacy (pre-PHP 8.4) proxy is still uninitialized.
17+
* If the object is not a legacy proxy, it returns false.
18+
*/
19+
public static function isLegacyProxyUninitialized(object $instance): bool
20+
{
21+
if (!method_exists($instance, 'isLazyObjectInitialized')) {
22+
return false;
23+
}
24+
25+
$method = new \ReflectionMethod($instance, 'isLazyObjectInitialized');
26+
if ($method->getNumberOfParameters() >= 1) {
27+
return !$instance->isLazyObjectInitialized(false);
28+
}
29+
30+
return !$instance->isLazyObjectInitialized();
31+
}
32+
}

src/Proxy/ProxyFactory.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class);
6666
*/
6767
private readonly bool $useNativeGhostObject;
6868

69-
7069
public function __construct(
7170
private readonly string $proxyDir,
7271
private readonly string $proxyNamespace,
@@ -187,7 +186,12 @@ private function generateProxyClassFile(string $className): void
187186
*/
188187
protected function generateUseLazyGhostTrait(\ReflectionClass $reflClass): string
189188
{
190-
$code = ProxyHelper::generateLazyGhost($reflClass);
189+
$proxyHelper = new \ReflectionClass(ProxyHelper::class);
190+
if (!$proxyHelper->hasMethod('generateLazyGhost')) {
191+
throw new \RuntimeException('Lazy ghost proxy generation requires symfony/var-exporter < 8 or PHP 8.4+ native lazy objects.');
192+
}
193+
194+
$code = (string) $proxyHelper->getMethod('generateLazyGhost')->invoke(null, $reflClass);
191195
$code = substr($code, 7 + (int) strpos($code, "\n{"));
192196
$code = substr($code, 0, (int) strpos($code, "\n}"));
193197
/*$code = str_replace('LazyGhostTrait;', str_replace("\n ", "\n", 'LazyGhostTrait {
@@ -221,4 +225,4 @@ public function getProxyClassName(string $class): string
221225
{
222226
return rtrim($this->proxyNamespace, '\\') . '\\' . SettingsProxyInterface::MARKER . '\\' . ltrim($class, '\\');
223227
}
224-
}
228+
}

src/Proxy/SettingsProxyInterface.php

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,24 @@
2828

2929
namespace Jbtronics\SettingsBundle\Proxy;
3030

31-
use \Symfony\Component\VarExporter\LazyObjectInterface;
32-
3331
/**
3432
* This interface is implemented by proxies that lazy load settings.
3533
* @internal
3634
*/
37-
interface SettingsProxyInterface extends LazyObjectInterface
38-
{
39-
/**
40-
* Marker for Proxy class names.
41-
*/
42-
public const MARKER = '__JB__';
43-
}
35+
if (interface_exists(\Symfony\Component\VarExporter\LazyObjectInterface::class)) {
36+
interface SettingsProxyInterface extends \Symfony\Component\VarExporter\LazyObjectInterface
37+
{
38+
/**
39+
* Marker for Proxy class names.
40+
*/
41+
public const MARKER = '__JB__';
42+
}
43+
} else {
44+
interface SettingsProxyInterface
45+
{
46+
/**
47+
* Marker for Proxy class names.
48+
*/
49+
public const MARKER = '__JB__';
50+
}
51+
}

tests/Manager/SettingsManagerTest.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
use Jbtronics\SettingsBundle\Tests\TestApplication\Settings\ValidatableSettings;
3838
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
3939
use Symfony\Component\Validator\DataCollector\ValidatorDataCollector;
40-
use Symfony\Component\VarExporter\LazyObjectInterface;
4140

4241
/**
4342
* The functional/integration test for the SettingsManager
@@ -160,9 +159,7 @@ public function testGetEmbedded(): void
160159
$this->assertEquals('default', $settings->simpleSettings->getValue1());
161160

162161

163-
if ($settings->simpleSettings instanceof LazyObjectInterface) {
164-
$this->assertTrue($settings->simpleSettings->isLazyObjectInitialized());
165-
}
162+
$this->assertTrue(LazyObjectTestHelper::isLazyObjectInitialized($settings->simpleSettings));
166163
}
167164

168165
public function testGetEmbeddedCircular(): void

tests/Migrations/EnvVarToSettingsMigratorTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
use Jbtronics\SettingsBundle\Tests\TestApplication\Settings\ValidatableSettings;
4545
use Jbtronics\SettingsBundle\Tests\TestApplication\Settings\VersionedSettings;
4646
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
47-
use Symfony\Component\VarExporter\LazyObjectInterface;
4847

4948
class EnvVarToSettingsMigratorTest extends KernelTestCase
5049
{

tests/Proxy/LazyObjectTestHelper.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Jbtronics\SettingsBundle\Tests\Proxy;
66

77
use ReflectionClass;
8-
use Symfony\Component\VarExporter\LazyObjectInterface;
98

109
final class LazyObjectTestHelper
1110
{
@@ -16,7 +15,13 @@ final class LazyObjectTestHelper
1615
*/
1716
public static function isLazyObject(object $obj): bool
1817
{
19-
if ($obj instanceof LazyObjectInterface){
18+
if (interface_exists(\Symfony\Component\VarExporter\LazyObjectInterface::class)
19+
&& $obj instanceof \Symfony\Component\VarExporter\LazyObjectInterface
20+
) {
21+
return true;
22+
}
23+
24+
if (method_exists($obj, 'isLazyObjectInitialized')) {
2025
return true;
2126
}
2227

@@ -36,8 +41,13 @@ public static function isLazyObject(object $obj): bool
3641
*/
3742
public static function isLazyObjectInitialized(object $obj, bool $partial = false): bool
3843
{
39-
if ($obj instanceof LazyObjectInterface){
40-
return $obj->isLazyObjectInitialized($partial);
44+
if (method_exists($obj, 'isLazyObjectInitialized')) {
45+
$method = new \ReflectionMethod($obj, 'isLazyObjectInitialized');
46+
if ($method->getNumberOfParameters() >= 1) {
47+
return $obj->isLazyObjectInitialized($partial);
48+
}
49+
50+
return $obj->isLazyObjectInitialized();
4151
}
4252

4353
if (PHP_VERSION_ID >= 80400) {
@@ -47,4 +57,4 @@ public static function isLazyObjectInitialized(object $obj, bool $partial = fals
4757
//If we reach here, the object is not a lazy object, so it is considered initialized
4858
return true;
4959
}
50-
}
60+
}

tests/Proxy/ProxyFactoryTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
use Jbtronics\SettingsBundle\Proxy\SettingsProxyInterface;
3131
use Jbtronics\SettingsBundle\Tests\TestApplication\Settings\SimpleSettings;
3232
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
33-
use Symfony\Component\VarExporter\LazyObjectInterface;
3433

3534
class ProxyFactoryTest extends KernelTestCase
3635
{
@@ -64,7 +63,7 @@ public function testCreateProxy(): void
6463
$instance->setValue1('Initialized');
6564
};
6665

67-
/** @var LazyObjectInterface&SimpleSettings&SettingsProxyInterface $proxy */
66+
/** @var SimpleSettings&SettingsProxyInterface $proxy */
6867
$proxy = $this->proxyFactory->createProxy(SimpleSettings::class, $initializer);
6968
$this->assertInstanceOf(SimpleSettings::class, $proxy);
7069

0 commit comments

Comments
 (0)