skip to Main Content

I’m upgrading from TYPO3 v10 to v11.

In TYPO3 v10 this worked:

<?php
use TYPO3CMSFormDomainModelFormElementsGenericFormElement;
class ServiceSelectFormElement extends GenericFormElement
{
    public function __construct(string $identifier, string $type, ApiService $apiClient)
    {
        $this->apiClient = $apiClient;
        parent::__construct($identifier, $type);
    }
}

In TYPO3 v11 it does not work anymore, and I get an error:

Uncaught TYPO3 Exception: Too few arguments to function VendorExampleFormElementServiceSelectFormElement::__construct(), 2 passed in /var/www/typo3/public/typo3/sysext/core/Classes/Utility/GeneralUtility.php on line 3215 and exactly 3 expected

So I have to go back from constructor injection to inject*() method injection:

<?php
use TYPO3CMSFormDomainModelFormElementsGenericFormElement;
class ServiceSelectFormElement extends GenericFormElement
{
    public function injectApiClient(ApiService $apiClient): void
    {
        $this->apiClient = $apiClient;
    }

.. but this inject method is not called automatically, unless we mark the class public and enable autowiring in Configuration/Services.yaml:

services:
  VendorExampleFormElementServiceSelectFormElement:
    public: true
    autowire: true
    calls:
      - method: injectApiClient
        arguments:
          $apiClient: '@VendorExampleServiceApiService'

but this leads to another error, because it tries to inject the constructor parameters:

[ SymfonyComponentDependencyInjectionExceptionRuntimeException ] Cannot autowire service "VendorExampleFormElementServiceSelectFormElement": argument "$identifier" of method "TYPO3CMSFormDomainModelFormElementsAbstractFormElement::__construct()" is type-hinted "string", you should configure its value explicitly.


Now my question: How can I prevent TYPO3/Symfony from injecting constructor parameters while still calling my inject*() method?

2

Answers


  1. Chosen as BEST ANSWER

    Dependency Injection in TYPO3 11, 12 and 13 only works when no constructor parameters are given to GeneralUtility::makeInstance - even though method injection could work if it were implemented.

    The solution is to manually load dependencies in the constructor or when the services are used.

    The docs need to be updated.


  2. You need to configure the constructor arguments ($identifier, $type) in your Services.yaml to avoid Symfony trying to autowire them. Then, you separately define the call for injectApiClient.

    YAML

        services:
          VendorExampleFormElementServiceSelectFormElement:
            public: true
            autowire: false # Disable autowiring for constructor
            arguments:
              $identifier: '' # Default value or a placeholder
              $type: ''       # Default value or a placeholder
            calls:
              - method: injectApiClient
                arguments:
                  $apiClient: '@VendorExampleServiceApiService'
    

    autowire => false: prevent Symfony from attempting to autowire the constructor arguments automatically.

    arguments => sets default values for $identifier and $type in the constructor.

    calls => configure injectApiClient() to be called with the ApiService dependency.

    TYPO3 v11 gives importance to the use of inject*() over constructor injection, you should change your class to use setter injection.

    PHP

        <?php
        use TYPO3CMSFormDomainModelFormElementsGenericFormElement;
        use VendorExampleServiceApiService;
        
        class ServiceSelectFormElement extends GenericFormElement
        {
            protected ApiService $apiClient;
        
            public function injectApiClient(ApiService $apiClient): void
            {
                $this->apiClient = $apiClient;
            }
        
            public function initialize(): void
            {
                // your code to set make sure $apiClient is set
            }
        }
    ?>
    

    This should do it!!!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search