Skip to content
Snippets Groups Projects
Unverified Commit 6d78e0cf authored by Alex Pott's avatar Alex Pott
Browse files

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

(cherry picked from commit 59598e57)
parent c58b5d48
No related branches found
No related tags found
23 merge requests!11887Issue #3520065: The migrate Row class API is incomplete,!11636Draft: Issue #3515643 by macsim: fieldNameExists method is inconsistent,!11515Issue #3480419 by mondrake, smustgrave, catch: Method...,!11380Issue #3490698 by catch, spokje: Bump MINIMUM_STABILITY back to 'stable' when...,!11281Use Drupal Core Leadership terminology in MAINTAINERS.txt,!11239Issue #3507548: Allow workspace changes listing to show all items, without a pager,!11238Fix issue #3051797,!11213Issue #3506743 by tomislav.matokovic: Increasing the color contrast for the navigation block title against the background of the navigation sidebar to at least 4.5:1,!11147Draft: Try to avoid manually setting required cache contexts,!11108Issue #3490298 by nicxvan: Profiles can be missed in OOP hooks,!11093Drupal on MongoDB 11.1.x,!11017Issue #3502540: Add date filter for moderated content.,!11009Issue #3486972 migrate feed icon,!10999Cleaning up Taxonomy hooks and updating baseline.,!10977Issue #3501457: Fix path used in a A11y Test Admin,!10881Issue #3489329 by mfb, casey: symfony/http-foundation commit 32310ff breaks PathValidator,!10570Issue #3494197: Convert Twig engine hooks,!10567Issue #3494154: Index is not added if entity doesn't support revisions,!10548Revert "Issue #3478621 by catch, longwave, nicxvan: Add filecache to OOP hook attribute parsing",!10404Margin has been added,!10391Issue #3485117 by nexusnovaz, godotislate, nicxvan: Fix return type on...,!10388Issue #3485117 by nexusnovaz, godotislate, nicxvan: Fix return type on...,!10376Issue #3485117 by nexusnovaz, godotislate, nicxvan: Fix return type on...
Pipeline #351700 canceled
Pipeline: drupal

#351701

    ...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
    use Drupal\Component\Annotation\Doctrine\StaticReflectionParser; use Drupal\Component\Annotation\Doctrine\StaticReflectionParser;
    use Drupal\Component\Annotation\Reflection\MockFileFinder; use Drupal\Component\Annotation\Reflection\MockFileFinder;
    use Drupal\Component\FileCache\FileCacheFactory;
    use Drupal\Core\Extension\ProceduralCall; use Drupal\Core\Extension\ProceduralCall;
    use Drupal\Core\Hook\Attribute\Hook; use Drupal\Core\Hook\Attribute\Hook;
    use Drupal\Core\Hook\Attribute\LegacyHook; use Drupal\Core\Hook\Attribute\LegacyHook;
    ...@@ -156,6 +157,9 @@ public static function collectAllHookImplementations(array $module_filenames): s ...@@ -156,6 +157,9 @@ public static function collectAllHookImplementations(array $module_filenames): s
    * @return void * @return void
    */ */
    protected function collectModuleHookImplementations($dir, $module, $module_preg): void { protected function collectModuleHookImplementations($dir, $module, $module_preg): void {
    $hook_file_cache = FileCacheFactory::get('hook_implementations');
    $procedural_hook_file_cache = FileCacheFactory::get('procedural_hook_implementations:' . $module_preg);
    $iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::FOLLOW_SYMLINKS); $iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::FOLLOW_SYMLINKS);
    $iterator = new \RecursiveCallbackFilterIterator($iterator, static::filterIterator(...)); $iterator = new \RecursiveCallbackFilterIterator($iterator, static::filterIterator(...));
    $iterator = new \RecursiveIteratorIterator($iterator); $iterator = new \RecursiveIteratorIterator($iterator);
    ...@@ -163,32 +167,51 @@ protected function collectModuleHookImplementations($dir, $module, $module_preg) ...@@ -163,32 +167,51 @@ protected function collectModuleHookImplementations($dir, $module, $module_preg)
    foreach ($iterator as $fileinfo) { foreach ($iterator as $fileinfo) {
    assert($fileinfo instanceof \SplFileInfo); assert($fileinfo instanceof \SplFileInfo);
    $extension = $fileinfo->getExtension(); $extension = $fileinfo->getExtension();
    $filename = $fileinfo->getPathname();
    if ($extension === 'module' && !$iterator->getDepth()) { if ($extension === 'module' && !$iterator->getDepth()) {
    // There is an expectation for all modules to be loaded. However, // There is an expectation for all modules to be loaded. However,
    // .module files are not supposed to be in subdirectories. // .module files are not supposed to be in subdirectories.
    include_once $fileinfo->getPathname(); include_once $filename;
    } }
    if ($extension === 'php') { if ($extension === 'php') {
    $namespace = preg_replace('#^src/#', "Drupal/$module/", $iterator->getSubPath()); $cached = $hook_file_cache->get($filename);
    $class = $namespace . '/' . $fileinfo->getBasename('.php'); if ($cached) {
    $class = str_replace('/', '\\', $class); $class = $cached['class'];
    foreach (static::getHookAttributesInClass($class) as $attribute) { $attributes = $cached['attributes'];
    }
    else {
    $namespace = preg_replace('#^src/#', "Drupal/$module/", $iterator->getSubPath());
    $class = $namespace . '/' . $fileinfo->getBasename('.php');
    $class = str_replace('/', '\\', $class);
    $attributes = static::getHookAttributesInClass($class);
    $hook_file_cache->set($filename, ['class' => $class, 'attributes' => $attributes]);
    }
    foreach ($attributes as $attribute) {
    $this->addFromAttribute($attribute, $class, $module); $this->addFromAttribute($attribute, $class, $module);
    } }
    } }
    else { else {
    $finder = MockFileFinder::create($fileinfo->getPathName()); $implementations = $procedural_hook_file_cache->get($filename);
    $parser = new StaticReflectionParser('', $finder); if ($implementations === NULL) {
    foreach ($parser->getMethodAttributes() as $function => $attributes) { $finder = MockFileFinder::create($filename);
    if (!StaticReflectionParser::hasAttribute($attributes, LegacyHook::class) && preg_match($module_preg, $function, $matches)) { $parser = new StaticReflectionParser('', $finder);
    $this->addProceduralImplementation($fileinfo, $matches['hook'], $matches['module'], $matches['function']); $implementations = [];
    foreach ($parser->getMethodAttributes() as $function => $attributes) {
    if (!StaticReflectionParser::hasAttribute($attributes, LegacyHook::class) && preg_match($module_preg, $function, $matches)) {
    $implementations[] = ['function' => $function, 'module' => $matches['module'], 'hook' => $matches['hook']];
    }
    } }
    $procedural_hook_file_cache->set($filename, $implementations);
    }
    foreach ($implementations as $implementation) {
    $this->addProceduralImplementation($fileinfo, $implementation['hook'], $implementation['module'], $implementation['function']);
    } }
    } }
    if ($extension === 'inc') { if ($extension === 'inc') {
    $parts = explode('.', $fileinfo->getFilename()); $parts = explode('.', $fileinfo->getFilename());
    if (count($parts) === 3 && $parts[0] === $module) { if (count($parts) === 3 && $parts[0] === $module) {
    $this->groupIncludes[$parts[1]][] = $fileinfo->getPathname(); $this->groupIncludes[$parts[1]][] = $filename;
    } }
    } }
    } }
    ......
    name: 'Test Hooks on behalf of other modules'
    type: module
    description: 'Test hooks invoked on behalf of other modules when installed later.'
    package: Testing
    version: VERSION
    <?php
    declare(strict_types=1);
    namespace Drupal\hook_collector_on_behalf\Hook;
    use Drupal\Core\Hook\Attribute\Hook;
    /**
    * Hook implementation on behalf of another module.
    */
    class OnBehalfOfOtherModuleHook {
    /**
    * Implements hook_module_preinstall().
    */
    #[Hook('cache_flush', module: 'respond_install_uninstall_hook_test')]
    public function flush(): void {
    // Set a global value we can check in test code.
    $GLOBALS['on_behalf_oop'] = 'on_behalf_oop';
    }
    }
    name: 'Test Hooks on behalf of other modules'
    type: module
    description: 'Test hooks invoked on behalf of other modules when installed later.'
    package: Testing
    version: VERSION
    <?php
    /**
    * @file
    * Implement hooks.
    */
    declare(strict_types=1);
    /**
    * This implements a hook on behalf of another module.
    *
    * We do not have implements so this does not get converted.
    */
    function respond_install_uninstall_hook_test_cache_flush(): void {
    // Set a global value we can check in test code.
    $GLOBALS['on_behalf_procedural'] = 'on_behalf_procedural';
    }
    ...@@ -82,4 +82,23 @@ public function testOrdering(): void { ...@@ -82,4 +82,23 @@ public function testOrdering(): void {
    $this->assertLessThan($priorities['drupal_hook.order2']['order'], $priorities['drupal_hook.order2']['module_handler_test_all2_order2']); $this->assertLessThan($priorities['drupal_hook.order2']['order'], $priorities['drupal_hook.order2']['module_handler_test_all2_order2']);
    } }
    /**
    * Test hooks implemented on behalf of an uninstalled module.
    *
    * They should be picked up but only executed when the other
    * module is installed.
    */
    public function testHooksImplementedOnBehalfFileCache(): void {
    $module_installer = $this->container->get('module_installer');
    $this->assertTrue($module_installer->install(['hook_collector_on_behalf']));
    $this->assertTrue($module_installer->install(['hook_collector_on_behalf_procedural']));
    drupal_flush_all_caches();
    $this->assertFalse(isset($GLOBALS['on_behalf_oop']));
    $this->assertFalse(isset($GLOBALS['on_behalf_procedural']));
    $this->assertTrue($module_installer->install(['respond_install_uninstall_hook_test']));
    drupal_flush_all_caches();
    $this->assertTrue(isset($GLOBALS['on_behalf_oop']));
    $this->assertTrue(isset($GLOBALS['on_behalf_procedural']));
    }
    } }
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment