Verified Commit f6f705f8 authored by Dave Long's avatar Dave Long
Browse files

Issue #3478621 by catch, longwave, nicxvan: Add filecache to OOP hook attribute parsing

(cherry picked from commit 6aca2acf)
parent 024ed06c
Loading
Loading
Loading
Loading
Loading
+39 −11
Original line number Diff line number Diff line
@@ -6,9 +6,11 @@

use Drupal\Component\Annotation\Doctrine\StaticReflectionParser;
use Drupal\Component\Annotation\Reflection\MockFileFinder;
use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Core\Extension\ProceduralCall;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Hook\Attribute\LegacyHook;
use Drupal\Core\Site\Settings;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

@@ -156,6 +158,11 @@ public static function collectAllHookImplementations(array $module_filenames): s
   * @return void
   */
  protected function collectModuleHookImplementations($dir, $module, $module_preg): void {
    // Add the deployment identifier to the cache namespace so that changes in
    // the implementation of attribute parsing will not result in a stale
    // cache.
    $file_cache = FileCacheFactory::get('hook_implementations' . ':' . Settings::get('deployment_identifier'));

    $iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::FOLLOW_SYMLINKS);
    $iterator = new \RecursiveCallbackFilterIterator($iterator, static::filterIterator(...));
    $iterator = new \RecursiveIteratorIterator($iterator);
@@ -163,32 +170,53 @@ protected function collectModuleHookImplementations($dir, $module, $module_preg)
    foreach ($iterator as $fileinfo) {
      assert($fileinfo instanceof \SplFileInfo);
      $extension = $fileinfo->getExtension();
      $filename = $fileinfo->getPathname();
      $cached = $file_cache->get($filename);

      if ($extension === 'module' && !$iterator->getDepth()) {
        // There is an expectation for all modules to be loaded. However,
        // .module files are not supposed to be in subdirectories.
        include_once $fileinfo->getPathname();
        include_once $filename;
      }
      if ($extension === 'php') {
        if ($cached) {
          $class = $cached['class'];
          $attributes = $cached['attributes'];
        }
        else {
          $namespace = preg_replace('#^src/#', "Drupal/$module/", $iterator->getSubPath());
          $class = $namespace . '/' . $fileinfo->getBasename('.php');
          $class = str_replace('/', '\\', $class);
        foreach (static::getHookAttributesInClass($class) as $attribute) {
          $attributes = static::getHookAttributesInClass($class);
          $file_cache->set($filename, ['class' => $class, 'attributes' => $attributes]);
        }
        foreach ($attributes as $attribute) {
          $this->addFromAttribute($attribute, $class, $module);
        }
      }
      else {
        $finder = MockFileFinder::create($fileinfo->getPathName());
        if ($cached) {
          $implementations = $cached;
        }
        else {
          $finder = MockFileFinder::create($filename);
          $parser = new StaticReflectionParser('', $finder);
          $implementations = [];
          foreach ($parser->getMethodAttributes() as $function => $attributes) {
            if (!StaticReflectionParser::hasAttribute($attributes, LegacyHook::class) && preg_match($module_preg, $function, $matches)) {
            $this->addProceduralImplementation($fileinfo, $matches['hook'], $matches['module'], $matches['function']);
              $implementations[] = ['function' => $function, 'module' => $matches['module'], 'hook' => $matches['hook']];
            }
          }
          $file_cache->set($filename, $implementations);
        }
        foreach ($implementations as $implementation) {
          $this->addProceduralImplementation($fileinfo, $implementation['hook'], $implementation['module'], $implementation['function']);
        }
      }
      if ($extension === 'inc') {
        $parts = explode('.', $fileinfo->getFilename());
        if (count($parts) === 3 && $parts[0] === $module) {
          $this->groupIncludes[$parts[1]][] = $fileinfo->getPathname();
          $this->groupIncludes[$parts[1]][] = $filename;
        }
      }
    }