Fatal error from Twig when creating default target module in Drupal 10

Created on 18 May 2023, over 1 year ago
Updated 19 May 2023, over 1 year ago

Problem/Motivation

This module fails spectacularly on Drupal 10:

ArgumentCountError: Too few arguments to function Twig\Environment::loadTemplate(), 1 passed in /var/www/html/web/modules/contrib/config_enforce_devel/src/TargetModuleBuilder.php on line 342 and at least 2 expected in Twig\Environment->loadTemplate() (line 330 of /var/www/html/vendor/twig/twig/src/Environment.php).

Drupal\config_enforce_devel\TargetModuleBuilder->getInfoFileContents() (Line: 287)
Drupal\config_enforce_devel\TargetModuleBuilder->writeInfoFile() (Line: 149)
Drupal\config_enforce_devel\TargetModuleBuilder->createModule() (Line: 93)
Drupal\config_enforce_devel\TargetModuleCollection->ensureDefaultTargetModuleIsSet() (Line: 50)
Drupal\config_enforce_devel\TargetModuleCollection->getDefaultTargetModule() (Line: 534)
Drupal\config_enforce_devel\Form\EnforcedConfigs->getTargetModuleField() (Line: 185)
Drupal\config_enforce_devel\Form\EnforcedConfigs->addUpdateTargetModule() (Line: 170)
Drupal\config_enforce_devel\Form\EnforcedConfigs->addUpdateEnforcedConfigs() (Line: 32)
Drupal\config_enforce_devel\Form\EnforcedConfigs->buildForm(Array, Object)
call_user_func_array(Array, Array) (Line: 536)
Drupal\Core\Form\FormBuilder->retrieveForm('config_enforce_enforced_configs_form', Object) (Line: 283)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 73)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 163)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 74)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 686)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Steps to reproduce

Install "Config Enforce - Devel" on a Drupal 10 site; navigate to the "Enforced configs" overview page; get the above fatal error.

Proposed resolution

It looks like this is due to Drupal 10 upgrading the Twig major version from 2.x to 3.4.3 ; the method that we call to render the template now expects two parameters rather than the one we're passing it.

Compare v2.15.3 (in Drupal 9.5) and v3.5.1 (in Drupal 10.0).

Given that the function is marked as @internal, that it specifically states that it should never be called externally, and that we can do the same thing by rendering a render array of '#type' => 'inline_template', we should refactor this so doesn't need to call Twig directly but use the Drupal renderer and let it handle all this for us.

So instead of

    return (string) \Drupal::service('twig')
      ->loadTemplate($template)
      ->render([
        'name' => $this->getName(),
        'description' => $this->getDescription(),
        // Needed to prevent notices when Twig debugging is enabled.
        'theme_hook_original' => 'not-applicable',
      ]);

we do

    /** @var array Render array for the extension .info.yml contents. */
    $renderArray = [
      '#type'     => 'inline_template',
      '#template' => \file_get_contents($template),
      '#context'  => [
        'name'        => $this->getName(),
        'description' => $this->getDescription(),
      ],
    ];

    return (string) $this->renderer->renderPlain($renderArray);

Remaining tasks

Make the above changes.

User interface changes

None, well, other than not throwing a fatal error.

API changes

None.

Data model changes

None.

🐛 Bug report
Status

Fixed

Version

1.0

Component

Code

Created by

🇨🇦Canada ambient.impact Toronto

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024