neos / flow-development-collection

The unified repository containing the Flow core packages, used for Flow development.
https://flow.neos.io/
MIT License
134 stars 187 forks source link

BUG: Dto with Dto in constructor creates proxy #3212

Open mhsdesign opened 8 months ago

mhsdesign commented 8 months ago

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);
    }
}
gjwnc commented 2 months ago

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

  1. Delete all tables in the DB
  2. composer update
  3. rm -rf Data/Temporary
  4. ./flow flow:cache:flush --force # just in case
  5. ./flow flow:package:rescan
  6. ./flow doctrine:migrate
  7. ./flow cr:setup
  8. ./flow site:create neosdemo Neos.Demo Neos.Demo:Document.Homepage
  9. ./flow user:create --roles Neos.Neos:Administrator --username user --first-name us --last-name er
  10. Open Neos in Browser - you see the Demo page
  11. Login to Neos
  12. In neosdemo (=Home) > Teaser area create a new Text Element inside

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.