-
-
Notifications
You must be signed in to change notification settings - Fork 190
BUGFIX: ProxyBuilding minor refactor and fixes #3494
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 9.0
Are you sure you want to change the base?
Conversation
Props to @lorenzulrich for this correct fix, which always gets the parent in relation to the method being called and not the parent of the instance at hand. Fixes: neos#3406
This allows classes without constructor injection to have a proper constructor signature.
This is an overhaul of how object serialization is prepared in proxies. Proxies can skip object serialization code if there is nothing to serialize, that is, if there are no entity properties, no injected, or transient properties. We were too eager prior to this patch with not using the serialization code, the checks are now way more detailed. Additionally the "Proxy" Annotation now allows to force serialization code for a class if the checks still fail to detect correctly, this should be rarely needed. This fix however broke some code in Neos that should have gotten the serialization code previously but didn't. Since the class in question is readonly, injecting a mutable property via trait resulted in PHP errors. Therefore we now use a mutable object to hold related entities for serialization purposes which is declared readonly in the proxy to avoid errors with readonly classes should they need serialization code. Other mutable properties were removed as they are not strictly needed. We should do the same refactoring for AOP as well. Proxies can use the original constructor argument signature if no constructor injection is used. Finally prototype autowiring is now a choice via setting, currently default enabled to not change behavior, in the future we should plan a breaking change to disable it and then remove the option altogether. Fixes: neos#3493 Related: neos#3212 Related: neos#3076
This removes occurances of constructor injection with prototypes, the modified classes are all injected via constructor and should therefore be singletons. Related: neos/flow-development-collection#3494
|
Interesting test failures... because that did work fine... Investigating... |
|
Thanks @kitsunet. This is "above my pay grade", so thanks for taking care and finding the reason why my code works ;-). |
|
Ok funny, now this PR shows one of the errors I wanted to fix in the functional tests. Why? Well because I broke something (that is if an object already has a sleep method we do not proxy anything) but intererstingly this scenario is AFAIK not happening in Flow nor Neos, nor have I seen it in any of the projects I checked. Anyways, will fix, seems like a good idea. |
This removes occurances of constructor injection with prototypes, the modified classes are all injected via constructor and should therefore be singletons. Related: neos/flow-development-collection#3494
|
Some documentation for the new flag - I don't know where to put it, maybe into this PR's description? Or the manual? When Flow generates proxy classes, it automatically detects if your class contains entity properties
This detection is automatic and works in most cases. However, in rare edge cases where the automatic use Neos\Flow\Annotations as Flow;
/**
* @Flow\Proxy(forceSerializationCode=true)
*/
class ComplexObjectWithEntities {
/**
* @var ComplexGenericType<SomeEntity>
*/
protected $complexProperty;
}You should rarely need to use |
robertlemke
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. I tested this locally based on the functional tests and verified the difference of the generated proxy classes. Fine to merge, I guess?
53be99c to
14c41f0
Compare
14c41f0 to
024bd10
Compare
| * see references to it in serialized object strings. | ||
| * @internal | ||
| */ | ||
| #[Flow\Proxy(false)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? Or an optimization / safeguard?
| private function Flow_searchForEntitiesAndStoreIdentifierArray(string $path, mixed $propertyValue, string $originalPropertyName): void | ||
| private function Flow_searchForEntitiesAndStoreIdentifierArray(string $path, mixed $propertyValue, string $originalPropertyName): bool | ||
| { | ||
| $foundEntity = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| $foundEntity = false; | |
| $entityWasFound = false; |
like in the code above – and $foundEntity sounds as if it contains the entity that was found.
| if (is_array($propertyValue) || ($propertyValue instanceof \ArrayObject || $propertyValue instanceof \SplObjectStorage)) { | ||
| foreach ($propertyValue as $key => $value) { | ||
| $this->Flow_searchForEntitiesAndStoreIdentifierArray($path . '.' . $key, $value, $originalPropertyName); | ||
| $foundEntity = $foundEntity || $this->Flow_searchForEntitiesAndStoreIdentifierArray($path . '.' . $key, $value, $originalPropertyName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| $foundEntity = $foundEntity || $this->Flow_searchForEntitiesAndStoreIdentifierArray($path . '.' . $key, $value, $originalPropertyName); | |
| $entityWasFound = $entityWasFound || $this->Flow_searchForEntitiesAndStoreIdentifierArray($path . '.' . $key, $value, $originalPropertyName); |
| 'entityPath' => $path | ||
| ]; | ||
| $this->$originalPropertyName = Arrays::setValueByPath($this->$originalPropertyName, $path, null); | ||
| $foundEntity = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| $foundEntity = true; | |
| $entityWasFound = true; |
| $foundEntity = true; | ||
| } | ||
|
|
||
| return $foundEntity; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| return $foundEntity; | |
| return $entityWasFound; |
| protected function couldHaveEntityRelations(Configuration $objectConfiguration): bool | ||
| { | ||
| $result = false; | ||
| /** @var class-string $className */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is class-string on a plain @var something useful?
| # | ||
| # In the future autowiring of prototypes should no longer be an option as it makes no sense. | ||
| # Use a factory class if you need this otherwise. | ||
| prototypeAutowiring: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name is not as clear to me, as it should be. Does this prevent the autowiring of constructor arguments to prototypes or does it prevent the use of prototypes as constructor arguments?
Props to @lorenzulrich for this correct fix, which always gets the
parent in relation to the method being called and not the parent of
the instance at hand.
Fixes: #3406
This is an overhaul of how object serialization
is prepared in proxies.
Proxies can skip object serialization code if there is nothing to
serialize, that is, if there are no entity properties, no injected, or
transient properties. We were too eager prior to this patch with
not using the serialization code, the checks are now way more detailed.
Additionally the "Proxy" Annotation now allows to force serialization
code for a class if the checks still fail to detect correctly, this
should be rarely needed.
This fix however broke some code in Neos that should have gotten the
serialization code previously but didn't. Since the class in question
is readonly, injecting a mutable property via trait resulted in
PHP errors.
Therefore we now use a mutable object to hold related entities for
serialization purposes which is declared readonly in the proxy to
avoid errors with readonly classes should they need serialization
code. Other mutable properties were removed as they are not strictly
needed. We should do the same refactoring for AOP as well.
Proxies can use the original constructor argument signature if no
constructor injection is used.
Finally prototype autowiring is now a choice via setting, currently
default enabled to not change behavior, in the future we should plan
a breaking change to disable it and then remove the option altogether.
Fixes: #3493
Related: #3212
Related: #3076