Skip to content

Commit dfcda74

Browse files
committed
Some further logic fixes to proxy serialization
1 parent 907d557 commit dfcda74

File tree

3 files changed

+37
-22
lines changed

3 files changed

+37
-22
lines changed

Neos.Flow/Classes/ObjectManagement/DependencyInjection/ProxyClassBuilder.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,6 @@ public function build(): void
123123

124124
$constructor->addPreParentCallCode($constructorInjectionCode);
125125

126-
$sleepMethod = $proxyClass->getMethod('__sleep');
127-
$sleepMethod->setDocBlock(self::AUTOGENERATED_PROXY_METHOD_COMMENT);
128-
129126
$wakeupMethod = $proxyClass->getMethod('__wakeup');
130127
$wakeupMethod->setDocBlock(self::AUTOGENERATED_PROXY_METHOD_COMMENT);
131128

@@ -165,7 +162,13 @@ public function build(): void
165162
$proxyClass->addProperty('Flow_Persistence_RelatedEntitiesContainer', null, 'private readonly \Neos\Flow\ObjectManagement\Proxy\RelatedEntitiesContainer');
166163
$constructor->addPostParentCallCode('$this->Flow_Persistence_RelatedEntitiesContainer = new \Neos\Flow\ObjectManagement\Proxy\RelatedEntitiesContainer();');
167164
}
168-
$sleepMethod->addPostParentCallCode($serializeRelatedEntitiesCode);
165+
166+
$classHasSleepMethod = $this->reflectionService->hasMethod($className, '__sleep');
167+
if (!$classHasSleepMethod) {
168+
$sleepMethod = $proxyClass->getMethod('__sleep');
169+
$sleepMethod->setDocBlock(self::AUTOGENERATED_PROXY_METHOD_COMMENT);
170+
$sleepMethod->addPostParentCallCode($serializeRelatedEntitiesCode);
171+
}
169172
$wakeupMethod->addPreParentCallCode($this->buildSetRelatedEntitiesCode());
170173
}
171174

@@ -224,10 +227,6 @@ protected function buildSerializeRelatedEntitiesCode(Configuration $objectConfig
224227
/** @var class-string $className */
225228
$className = $objectConfiguration->getClassName();
226229
$forceSerializationCode = $forceSerializationCode === false ? ($this->reflectionService->getClassAnnotation($className, Flow\Proxy::class)?->forceSerializationCode ?? false) : true;
227-
if (!$forceSerializationCode && $this->reflectionService->hasMethod($className, '__sleep')) {
228-
return '';
229-
}
230-
231230
$scopeAnnotation = $this->reflectionService->getClassAnnotation($className, Flow\Scope::class);
232231
$transientProperties = $this->reflectionService->getPropertyNamesByAnnotation($className, Flow\Transient::class);
233232
$injectedProperties = $this->reflectionService->getPropertyNamesByAnnotation($className, Flow\Inject::class);

Neos.Flow/Classes/ObjectManagement/Proxy/ObjectSerializationTrait.php

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,12 @@ private function Flow_serializeRelatedEntities(array $transientProperties, array
8484
}
8585
continue;
8686
}
87-
if ($className !== false && (Bootstrap::$staticObjectManager->getScope($className) === Configuration::SCOPE_SINGLETON || $className === DependencyProxy::class)) {
87+
if ($className !== false &&
88+
(
89+
Bootstrap::$staticObjectManager->getScope($className) === Configuration::SCOPE_SINGLETON
90+
|| Bootstrap::$staticObjectManager->getScope($className) === Configuration::SCOPE_SESSION
91+
|| $className === DependencyProxy::class
92+
)) {
8893
continue;
8994
}
9095
}
@@ -114,7 +119,18 @@ private function Flow_searchForEntitiesAndStoreIdentifierArray(string $path, mix
114119
throw new \RuntimeException(sprintf('The class "%s" has an entity reference Flow could not detect, please add a Flow\\Proxy annotation with "forceSerializationCode" set to "true".', 1756936954));
115120
}
116121
$this->Flow_Persistence_RelatedEntitiesContainer->appendRelatedEntity($originalPropertyName, $path, $propertyValue);
117-
$this->$originalPropertyName = Arrays::setValueByPath($this->$originalPropertyName, $path, null);
122+
/**
123+
* The idea of setting to null here is to prevent serialization after we found an entity, BUT this logic
124+
* is heavily flawed in today's PHP world. Type hinting might make null an invalid value. Also
125+
* Arrays::setValueByPath() only works on "Array-like" not on objects, therefore
126+
* we don't handle direct properties of $this (path empty string) at all here.
127+
* They are skipped for serialization in Flow_serializeRelatedEntities so we don't need to unset.
128+
* This still leaves the option of types going awry somewhere, but at the moment there
129+
* isn't really a better solution at hand and the case should be super rare.
130+
*/
131+
if ($path !== '') {
132+
$this->$originalPropertyName = Arrays::setValueByPath($this->$originalPropertyName, $path, null);
133+
}
118134
$foundEntity = true;
119135
}
120136

@@ -132,11 +148,11 @@ private function Flow_setRelatedEntities(): void
132148
if (isset($this->Flow_Persistence_RelatedEntitiesContainer)) {
133149
$persistenceManager = Bootstrap::$staticObjectManager->get(PersistenceManagerInterface::class);
134150
foreach ($this->Flow_Persistence_RelatedEntitiesContainer as $entityInformation) {
135-
$entity = $persistenceManager->getObjectByIdentifier($entityInformation['identifier'], $entityInformation['entityType'], true);
136-
if (isset($entityInformation['entityPath'])) {
137-
$this->{$entityInformation['propertyName']} = Arrays::setValueByPath($this->{$entityInformation['propertyName']}, $entityInformation['entityPath'], $entity);
151+
$entity = $persistenceManager->getObjectByIdentifier($entityInformation['i'], $entityInformation['c'], true);
152+
if (isset($entityInformation['p'])) {
153+
$this->{$entityInformation['n']} = Arrays::setValueByPath($this->{$entityInformation['n']}, $entityInformation['p'], $entity);
138154
} else {
139-
$this->{$entityInformation['propertyName']} = $entity;
155+
$this->{$entityInformation['n']} = $entity;
140156
}
141157
}
142158

Neos.Flow/Classes/ObjectManagement/Proxy/RelatedEntitiesContainer.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@
1616
#[Flow\Proxy(false)]
1717
final class RelatedEntitiesContainer implements \IteratorAggregate
1818
{
19-
protected array $relatedEntities = [];
19+
protected array $e = [];
2020

2121
public function getIterator(): \Generator
2222
{
23-
foreach ($this->relatedEntities as $entityInformation) {
23+
foreach ($this->e as $entityInformation) {
2424
yield $entityInformation;
2525
}
2626
}
2727

2828
public function reset(): void
2929
{
30-
$this->relatedEntities = [];
30+
$this->e = [];
3131
}
3232

3333
public function appendRelatedEntity(string $originalPropertyName, string $path, object $propertyValue): void
@@ -42,11 +42,11 @@ public function appendRelatedEntity(string $originalPropertyName, string $path,
4242
$identifier = current(ObjectAccess::getProperty($propertyValue, '_identifier', true));
4343
}
4444

45-
$this->relatedEntities[$originalPropertyName . '.' . $path] = [
46-
'propertyName' => $originalPropertyName,
47-
'entityType' => $className,
48-
'identifier' => $identifier,
49-
'entityPath' => $path
45+
$this->e[$originalPropertyName . '.' . $path] = [
46+
'n' => $originalPropertyName,
47+
'c' => $className,
48+
'i' => $identifier,
49+
'p' => $path
5050
];
5151
}
5252
}

0 commit comments

Comments
 (0)