function Recipe::parseRecipeContents

Same name and namespace in other branches
  1. 11.x core/lib/Drupal/Core/Recipe/Recipe.php \Drupal\Core\Recipe\Recipe::parseRecipeContents()

Parses recipe files.

If the recipe contains constants or enums from uninstalled extensions, a classloader will be registered to autoload them.

Parameters

string $contents: The recipe file contents.

string[] $already_loaded: The list of extensions that have been added to the autoloader. Used by recursive calls to this method.

Return value

array The parsed recipe contents.

File

core/lib/Drupal/Core/Recipe/Recipe.php, line 353

Class

Recipe
@internal This API is experimental.

Namespace

Drupal\Core\Recipe

Code

private static function parseRecipeContents(string $contents, array $already_loaded = []) : array {
  try {
    return Yaml::decode($contents);
  } catch (InvalidDataTypeException $e) {
    // Extract the possibly uninstalled Drupal extension from the exception
    // message, see \Symfony\Component\Yaml\Inline::evaluateScalar().
    if (preg_match('/^The (enum|constant) "Drupal\\\\([^\\\\]*)\\\\[^"]*" is not defined/', $e->getMessage(), $matches)) {
      $extension = $matches[2];
      foreach ([
        'module',
        'profile',
        'theme',
      ] as $list_service_name) {
        /** @var \Drupal\Core\Extension\ExtensionList $list_service */
        $list_service = \Drupal::service('extension.list.' . $list_service_name);
        // Does the extension exist on the file system.
        if ($list_service->exists($extension)) {
          // Is the extension installed already.
          $installed = match ($list_service_name) {  'module', 'profile' => \Drupal::moduleHandler()->moduleExists($extension),
            'theme' => \Drupal::service('theme_handler')->themeExists($extension),
          
          };
          if ($installed || in_array($extension, $already_loaded, TRUE)) {
            // The extension is installed, the missing enum or constant will
            // not be fixed by altering the classloader.
            throw $e;
          }
          // Register the extension with the classloader and try parsing the
          // recipe contents again.
          $dir = $list_service->getPath($extension);
          $classloader = new ClassLoader();
          $classloader->addPsr4("Drupal\\{$extension}\\", $dir . '/src');
          $already_loaded[] = $extension;
          $classloader->register();
          try {
            return static::parseRecipeContents($contents, $already_loaded);
          } finally {
            $classloader->unregister();
          }
        }
      }
    }
    throw $e;
  }
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.