Problem/Motivation

ModuleHandlerInterface::getImplementations() is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0.

Instead you should use ModuleHandlerInterface::invokeAllWith() for hook invocations, or you should use ModuleHandlerInterface::hasImplementations() to determine if hooks implementations exist.
See https://www.drupal.org/node/3000490

Proposed resolution

Issue fork scheduler-3312069

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

jonathan1055 created an issue. See original summary.

jonathan1055’s picture

This is reported in the Travis tests at 9.5. Drupal Rector may report this on #3289475: Automated Drupal 10 compatibility fixes - Scheduler 2.x at some point. Or we could fix it manually before then.

jonathan1055’s picture

This is a suggestion from DeiterHolvoet on #3289475-11: Automated Drupal 10 compatibility fixes - Scheduler 2.x, to change getHookImplementations() to getHooks(), like this:

public function getHooks(string $hookType, $entity) {
  $entityTypeId = (is_object($entity)) ? $entity->getEntityTypeid() : $entity;
  $hooks = [$hookType, "{$entityTypeId}_{$hookType}"];
  // For backwards compatibility the original node hook is also added.
  if ($entityTypeId == 'node') {
    $legacy_node_hooks = [
      'hide_publish_date' => 'hide_publish_on_field',
      'hide_unpublish_date' => 'hide_unpublish_on_field',
      'list' => 'nid_list',
      'list_alter' => 'nid_list_alter',
      'publish_process' => 'publish_action',
      'unpublish_process' => 'unpublish_action',
      'publishing_allowed' => 'allow_publishing',
      'unpublishing_allowed' => 'allow_unpublishing',
    ];
    $hooks[] = $legacy_node_hooks[$hookType];
  }
  // Append the $hook to the end of the module.
  foreach ($hooks as &$hook) {
    $hook = "scheduler_$hook";
  }
  return $hooks;
}

and invoked like this:

// Allow other modules to add to the list of entities to be published.
$hooks = $this->getHooks('list', $entityTypeId);
foreach ($hooks as $hook) {
  $this->moduleHandler->invokeAllWith($hook, function (callable $hook, string $module) use (&$ids, $process, $entityTypeId) {
    // Cast each hook result as array, to protect from bad implementations.
    $ids = array_merge($ids, (array) $hook($process, $entityTypeId));
  });
}
chandu7929’s picture

Currently I can see 4 warning using upgrade status module,.

modules/contrib/scheduler/tests/src/Functional/SchedulerDevelGenerateTest.php 	59 	Missing explicit access check on entity query.

modules/contrib/scheduler/tests/src/Functional/SchedulerDevelGenerateTest.php 	66 	Missing explicit access check on entity query.

modules/contrib/scheduler/scheduler.module 	966 Call to deprecated method getImplementations() of class Drupal\Core\Extension\ModuleHandlerInterface. Deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Instead you should use ModuleHandlerInterface::invokeAllWith() for hook invocations or you should use ModuleHandlerInterface::hasImplementations() to determine if hooks implementations exist.

modules/contrib/scheduler/src/SchedulerManager.php 738.  Call to deprecated method getImplementations() of class Drupal\Core\Extension\ModuleHandlerInterface. Deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Instead you should use ModuleHandlerInterface::invokeAllWith() for hook invocations or you should use ModuleHandlerInterface::hasImplementations() to determine if hooks implementations exist.
chandu7929’s picture

@jonathan1055 - Shouldn’t we update parent MR with this fix rather than fixing it here?

jonathan1055’s picture

Thanks chandu9729

Shouldn’t we update parent MR with this fix rather than fixing it here?

This issue is all about fixing the getImplementations hooks, so that stays here.
You can create a new issue for the other warning you found - "Missing explicit access check on entity query"

The parent issue will not have any specific deprecation code fixes. It will have a mr for testing at D10, which will just have the version changes and any thing else necessary to allow testing at D10.

vishalkhode made their first commit to this issue’s fork.

jonathan1055’s picture

Hi vishalkhode,
Thanks for working on this, it looks good at first read-through. I'll have to make sure that our test coverage fully checks the changes, but I am fairly sure we are OK on that.

To test at D10 you will need to add the version changes from #3271462: [META] Drupal 10 preparation. Some of the optional modules that we use in testing are not compatible with D10 yet (and may not be) so we might need to customise the test script for D9 vs D10. But in the first instance, just add in the changes from that parent issue and see how the D10 test goes.

chandu7929’s picture

jonathan1055 and vishalkhode
Can we put https://www.drupal.org/node/2857979 changes for 2 failure and get this issue moving?

chandu7929’s picture

Oops! look like the document(https://www.drupal.org/node/2857979) is in draft and that feature(https://www.drupal.org/project/drupal/issues/3261817) is not merged yet, so we can't use that as of now, though its good feature to skip test based on missing modules from codebase.

I think we need some other way around to skip test in D10 in absence of module codebase, while include the same in D9.

jonathan1055’s picture

Thanks for the hint about skipping the tests chandu7929. That would be nice to use, when it becomes available.

#1273478: Implement @requires and @dependencies within TestBase, mark tests as skipped

#3261817: TestRequirementsTrait::checkRequirements() does not work as expected

I think we need some other way around to skip test in D10 in absence of module codebase, while include the same in D9.

Yes that is exactly what I have been thinking about, and I have some ideas. For now, we need to remove your two added commits. I will revert them, then check this actual issue and commit it.

vishalkhode’s picture

Hi jonathan1055
Why not we mark them skipped ? Something like:

 /**
  * {@inheritdoc}
  */
   public function setUp() {
     $modulesList = \Drupal::service('extension.list.module')->getList()
     if (!isset($modulesList['workbench_moderation']) {
       $this->markTestSkipped("Skipping test as module `workbench_moderation` doesn't exist.");
      }
      parent::setUp();
   }
jonathan1055’s picture

Yes that might work. We'll do that on a separate issue, I want to get this one back on focus to the ModuleHandlerInterface::getImplementations() changes.

vishalkhode’s picture

Yes that might work. We'll do that on a separate issue, I want to get this one back on focus to the ModuleHandlerInterface::getImplementations() changes.

jonathan1055: Well in that case, it looks like all tests are passing which is related to issue: ModuleHandlerInterface::getImplementations().

jonathan1055’s picture

it looks like all tests are passing which is related to issue: ModuleHandlerInterface::getImplementations().

Yes they are. With the extra call to moduleHandler()->getImplementations that you found and fixed in 89e7a4c7 I am surprised this was not reported before. Even if there are no impementations of that hook in the test modules, the deprecation should still have been thrown. But the tests against the previous commit did not report it. That is odd, and needs investigation.

Also, the new replacement function ModuleHandler::invokeAllWith() does not exist in Drupal 8 and Scheduler needs to maintain compatibility with Drupal 8.9 to allow sites to convert. Scheduler 2.x does not yet have a release so the first 2.0 should/could remain compatible with 8.9. But then would 2.1 become compatible with D10 and drop 8.9? I don't want to create Scheduler 3.x as that increases the code maintenance burden. More planning needed ...

chandu7929’s picture

vishalkhode & jonathan1055 - I think we should be able to release new module version by adding composer conflict to the modules version from where it becomes incompatible, this way existing user won't be able to get the latest version until they upgrade all the required modules, at the same time drupal 10 users can use the latest release of this module. Hope that make sense.

vipin.mittal18’s picture

I am aligned with @chandu7929 approach.

@jonathan1055: The ideal solution in this case would be having two stable module version releases. You can keep released stable version as is and can release major version with Drupal 10 compatible.

vishalkhode’s picture

Hi @jonathan1055
I liked the idea of @chandu7929 & @vipin.mittal18 and that should solve.
But if this is only major deprecation issue for Drupal 10, then we can update the function getHookImplementations() in such a way that it should work for Drupal 8,9 & 10 as well by making below change:

public function getHookImplementations(string $hookType, $entity) {
    ...
    $all_hook_implementations = [];
    foreach ($hooks as $hook) {
      $hookName = "scheduler_$hook";
      if (version_compare(\Drupal::VERSION, '10', '>=')) {
      // The function getImplementations() is deprecated, use alternate for D10.
        $this->moduleHandler->invokeAllWith($hookName, function (callable $hook, string $module) use ($hookName, &$all_hook_implementations) {
          $all_hook_implementations[] = $module . "_" . $hookName;
        });
      } else {
        // Get all modules that implement these hooks, then use array_walk to append
        // the $hook to the end of the module, thus giving the full function name.
        $implementations = $this->moduleHandler->getImplementations($hook);
        array_walk($implementations, function (&$item) use ($hook) {
          $item = $item . '_' . $hook;
        });
        $all_hook_implementations = array_merge($all_hook_implementations, $implementations);
      }
    }
    return $all_hook_implementations;
  }

I tried above and it's working well. If you want, I can push this change and we can test.

jonathan1055’s picture

@vishalkhode that could be a great solution. I'd not realised that the new replacement can be called to get the names and not actually invoke the functions there and then. It did seem like a massive downgrade in functionality, losing that ability. But if you are right, yes please push this and we'll see.

@chandu7929, @vipin.mittal18 as I said in #16 we really do not want to have another major version branch to maintain if at all possible. We will if that is the only solution, but everything else must be tried before we do that.

ankitv18’s picture

I guess with one issue merged rest 2 issues MR get messed up.
Need to do revert and keep the changes as per this issue only
same is happening with this one https://www.drupal.org/project/scheduler/issues/3271462

vishalkhode’s picture

There was minor typo mistake in the code. Hopefully all tests should pass now (Off course, excluding 2 workbench_moderation tests).

vishalkhode’s picture

Hi @jonathan1055 Looks like all tests are passing now. For 10, we can see 4 other failing tests and this are already fixed as part of #3313848: Specify accessCheck(TRUE/FALSE) in entity queries. So, can we please get this reviewed & merged ?

vishalkhode’s picture

Status: Active » Needs review
chandu7929’s picture

Status: Needs review » Needs work

vishalkhode - I think we should remove commit e628741b807d63129850792ee0efa2bf3d6c45d5 as this has been tested against D10, so that it can be tested with parent MR

jonathan1055’s picture

Assigned: Unassigned » jonathan1055
Status: Needs work » Needs review

Excellent work vishalkhode, this is exactly what we needed.

chandu7929, there is no need to change the MR, as I won't be merging it completely, but will just make a direct commit for the required getImplementations() changes. I will fix the few coding standards faults, then test again. I also want to test the _api change locally as that is not covered by any automated tests.

jonathan1055’s picture

The new function invokeAllWith() only exists from Core 9.4 hence the version check needs to be precise.

  • jonathan1055 committed 1bb684d on 2.x
    Issue #3312069 by vishalkhode, jonathan1055, DieterHolvoet:...

jonathan1055’s picture

Assigned: jonathan1055 » Unassigned
Status: Needs review » Fixed

Committed just the two changes for getImplementations()
Thanks to @DieterHolvoet for the original code and @vishalkhode for the final version, and to all for their interest.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

jonathan1055’s picture

Now that this is fixed, we can reduced the deprecation count in Travis builds - see this commit