flow-development-collection
flow-development-collection copied to clipboard
BUG: Dto with Dto in constructor creates proxy
Given the following code, i would expect no proxy class to be generated for either Dto or OtherDto
// no proxy class?
final readonly class Dto
{
private function __construct(public string $bar) {}
public static function fromString(string $bar) { return new self($bar); }
}
// no proxy class? -> or maybe yes because of a non straight value?
final readonly class OtherDto
{
private function __construct(public Dto $dto) {}
public static function fromString(Dto $dto) { return new self($dto); }
}
For Dto this is true, but there will be a proxy class for OtherDto, which causes problems like not being able to use named arguments: https://github.com/neos/flow-development-collection/issues/3076
<?php
declare(strict_types=1);
namespace Neos\Neos;
readonly class OtherDto_Original
{
public function __construct(public Dto $dto) {}
public static function fromString(Dto $dto) { return new static($dto); }
}
#
# Start of Flow generated Proxy code
#
final readonly class OtherDto extends OtherDto_Original implements \Neos\Flow\ObjectManagement\Proxy\ProxyInterface {
/**
* Autogenerated Proxy Method
*/
public function __construct()
{
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
if (isset($backtrace[1]) &&
!is_subclass_of($backtrace[1]['class'], \Neos\Neos\OtherDto::class) &&
!is_subclass_of(\Neos\Neos\OtherDto::class, $backtrace[1]['class']) &&
$backtrace[1]['class'] !== 'Neos\Neos\OtherDto' &&
$backtrace[1]['class'] !== 'Neos\Neos\OtherDto_Original'
) {
throw new \Error('Call to private Neos\Neos\OtherDto::__construct() from invalid context', 1686153840);
}
$arguments = func_get_args();
if (!array_key_exists(0, $arguments)) $arguments[0] = \Neos\Flow\Core\Bootstrap::$staticObjectManager->get('Neos\Neos\Dto');
if (!array_key_exists(0, $arguments)) throw new \Neos\Flow\ObjectManagement\Exception\UnresolvedDependenciesException('Missing required constructor argument $dto in class ' . __CLASS__ . '. Note that constructor injection is only support for objects of scope singleton (and this is not a singleton) – for other scopes you must pass each required argument to the constructor yourself.', 1296143788);
parent::__construct(...$arguments);
}
}
Since this issue is already part of the Flow Proxy Refactoring board, I just wanted to mention, that this causes an Exception with current Neos 9 implementation during node creation.
What I've done
- Delete all tables in the DB
composer updaterm -rf Data/Temporary./flow flow:cache:flush --force# just in case./flow flow:package:rescan./flow doctrine:migrate./flow cr:setup./flow site:create neosdemo Neos.Demo Neos.Demo:Document.Homepage./flow user:create --roles Neos.Neos:Administrator --username user --first-name us --last-name er- Open Neos in Browser - you see the Demo page
- Login to Neos
- In
neosdemo(=Home) >Teaser areacreate a new Text Elementinside
A red alert is shown Unknown named parameter $elementValues - Check the logs for details
Error details
From System_Development.log:
24-04-26 11:49:42 53 CRITICAL Exception in line 167 of /application/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/Neos_Neos_Ui_Domain_Model_Changes_AbstractCreate.php: Unknown named parameter $elementValues - See also: 202404261149424c0ba0.txt
The exception:
Exception in line 167 of /application/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/Neos_Neos_Ui_Domain_Model_Changes_AbstractCreate.php: Unknown named parameter $elementValues
56 Neos\Neos\Ui\Domain\Service\NodePropertyConversionService_Original::convertNodeCreationElements()
55 Neos\Neos\Ui\Domain\Model\Changes\AbstractCreate_Original::createNode()
54 Neos\Neos\Ui\Domain\Model\Changes\Create_Original::apply()
53 Neos\Neos\Ui\Domain\Model\ChangeCollection_Original::apply()
52 Neos\Neos\Ui\Controller\BackendServiceController_Original::changeAction()
51 Neos\Neos\Ui\Controller\BackendServiceController::changeAction()
50 Neos\Neos\Ui\Controller\BackendServiceController::Flow_Aop_Proxy_invokeJoinPoint()
49 Neos\Flow\Aop\Advice\AdviceChain::proceed()
48 Neos\Flow\Security\Aspect\PolicyEnforcementAspect_Original::enforcePolicy()
47 Neos\Flow\Aop\Advice\AroundAdvice::invoke()
46 Neos\Flow\Aop\Advice\AdviceChain::proceed()
45 Neos\Neos\Ui\Controller\BackendServiceController::changeAction()
44 Neos\Flow\Mvc\Controller\ActionController_Original::callActionMethod()
43 Neos\Neos\Ui\Controller\BackendServiceController::callActionMethod()
42 Neos\Neos\Ui\Controller\BackendServiceController::Flow_Aop_Proxy_invokeJoinPoint()
41 Neos\Flow\Aop\Advice\AdviceChain::proceed()
40 Neos\Flow\Security\Aspect\PolicyEnforcementAspect_Original::enforcePolicy()
39 Neos\Flow\Aop\Advice\AroundAdvice::invoke()
38 Neos\Flow\Aop\Advice\AdviceChain::proceed()
37 Neos\Neos\Ui\Controller\BackendServiceController::callActionMethod()
36 Neos\Flow\Mvc\Controller\ActionController_Original::processRequest()
35 Neos\Neos\Ui\Controller\BackendServiceController::processRequest()
34 Neos\Neos\Ui\Controller\BackendServiceController::Flow_Aop_Proxy_invokeJoinPoint()
33 Neos\Flow\Aop\Advice\AdviceChain::proceed()
32 Neos\Flow\Security\Aspect\PolicyEnforcementAspect_Original::enforcePolicy()
31 Neos\Flow\Aop\Advice\AroundAdvice::invoke()
30 Neos\Flow\Aop\Advice\AdviceChain::proceed()
29 Neos\Neos\Ui\Controller\BackendServiceController::processRequest()
28 Neos\Flow\Mvc\Dispatcher_Original::initiateDispatchLoop()
27 Neos\Flow\Mvc\Dispatcher_Original::dispatch()
26 Neos\Flow\Mvc\DispatchMiddleware_Original::process()
25 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
24 Neos\Flow\Http\Middleware\SecurityEntryPointMiddleware_Original::process()
23 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
22 Neos\Flow\Http\Middleware\RequestBodyParsingMiddleware_Original::process()
21 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
20 Neos\Flow\Mvc\FlashMessage\FlashMessageMiddleware_Original::process()
19 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
18 Neos\Flow\Http\Middleware\PoweredByMiddleware_Original::process()
17 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
16 Neos\Flow\Mvc\Routing\RoutingMiddleware_Original::process()
15 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
14 Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionMiddleware_Original::process()
13 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
12 Neos\FluidAdaptor\Core\Widget\AjaxWidgetMiddleware_Original::process()
11 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
10 Neos\Flow\Http\Middleware\SessionMiddleware_Original::process()
9 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
8 Neos\Flow\Http\Middleware\MethodOverrideMiddleware_Original::process()
7 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
6 Neos\Flow\Http\Middleware\TrustedProxiesMiddleware_Original::process()
5 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
4 Neos\Flow\Http\Middleware\StandardsComplianceMiddleware_Original::process()
3 Neos\Flow\Http\Middleware\MiddlewaresChain_Original::handle()
2 Neos\Flow\Http\RequestHandler::handleRequest()
1 Neos\Flow\Core\Bootstrap::run()
HTTP REQUEST:
target: /neos/ui-services/change
Host: playground001.webco.pw
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0
Content-Length: 544
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
Content-Type: application/json
Cookie: Neos_Session=yvDQyeLHq17k77CNPmOSXHHv4dML4usA
Origin: http://playground001.webco.pw
Referer: http://playground001.webco.pw/neos/content?node=user-gj__eyJsYW5ndWFnZSI6ImVuX1VTIn0%3D__6244183f-5027-4efa-9f0d-a06dd97a6d58
X-Flow-Csrftoken: 144f8ba50bf406550c282933651944bd
X-Forwarded-For: 172.17.21.1
X-Forwarded-Host: playground001.webco.pw
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 7a183e19853d
X-Real-Ip: 172.17.21.1
PHP PROCESS:
Inode: 5241236
PID: 53
UID: 1000
GID: 1000
User: www-data
Environment
I'm using php 8.2.4 in a docker container, Mariadb 11.0.2 and current up to date Neos 9 packages:
neos/neos-development-collection 9.0.x-dev dab3d0b Neos packages in a joined repository for pull requests.
neos/neos-ui 9.0.x-dev 2485e9e Neos CMS UI written in React
neos/neos-ui-compiled 9.0.x-dev e016abd
neos/flow-development-collection 9.0.x-dev 00fa8ff Flow packages in a joined repository for pull requests.
Further details
The reason, as correctly identified by @mhsdesign here, is, that Flow creates a proxy class for NodeCreationElements. The proxy class does not have named constructor arguments. Thus NodePropertyConversionService::convertNodeCreationElements fails with the shown php fatal.
Slightly unrelated, there is also a proxy class for NodeCreationCommands. Not sure if this information is of any value.
Just wanted to mention, that my specific problem above seems to be gone with neos 9-beta19.
THanks, i fixed the neos ui problem via https://github.com/neos/neos-ui/commit/d9721fd069b1e9b6745b26fb7006ea1a41912a06
I started implementing fix but then realized: we did discuss that a lot already in 2023 which lead to #3049:
Flow cannot reliably detect weather a prototype class depends on autowiring for constructor arguments or not. Use this option to optimize your application to avoid the small but measurable overhead of proxy generation for those kinds of classes.
You are right that this is related to #3076 - but to be exact, that's a different issue which need to be solved separately.
Therefore, I suggest we close this issue.
This won't be possible to implement without breaking changes. A good solution would be to not proxy readonly or final classes or private constructors. We can look into that for Flow 10.0.