Fix Composer Scaffold plugin event listeners

Created on 4 April 2024, 9 months ago
Updated 23 April 2024, 8 months ago

Problem/Motivation

When subscribing to events of the Scaffold plugin from other composer packages, the dispatched events are not received by listeners, because the event dispatcher is initialised as a new instance rather than re-using an existing instance coming from composer. This makes it "forget" all the listeners collected by composer.

Current code:

$dispatcher = new EventDispatcher($this->composer, $this->io);
$dispatcher->dispatch(self::PRE_DRUPAL_SCAFFOLD_CMD);

Fixed code:

$dispatcher = $this->composer->getEventDispatcher();
$dispatcher->dispatch(self::PRE_DRUPAL_SCAFFOLD_CMD);

Steps to reproduce

1. Create a plugin class with the following code

<?php

namespace YourNamespace\Composer\Plugin\YourPlugin;

use Composer\Composer;
use Composer\EventDispatcher\Event;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;

/**
 * Composer plugin for handling drupal scaffold.
 *
 * @internal
 */
class Plugin implements PluginInterface, EventSubscriberInterface {
  
  /**
   * {@inheritdoc}
   */
  public function activate(Composer $composer, IOInterface $io) {
  }

  /**
   * {@inheritdoc}
   */
  public function deactivate(Composer $composer, IOInterface $io) {
  }

  /**
   * {@inheritdoc}
   */
  public function uninstall(Composer $composer, IOInterface $io) {
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      'pre-drupal-scaffold-cmd' => 'preDrupalScaffoldCmd',
      'post-drupal-scaffold-cmd' => 'postDrupalScaffoldCmd',
    ];
  }

  public static function preDrupalScaffoldCmd(Event $event) {
    print 'preDrupalScaffoldCmd' . PHP_EOL;
  }

  public static function postDrupalScaffoldCmd(Event $event) {
    print 'postDrupalScaffoldCmd' . PHP_EOL;
  }

}

2. Create a package with the following `composer.json` and place the file with Plugin class into `src` directory and provide references:


{
    "name": "yournamespace/yourplugin",
    "type": "composer-plugin",
    "require": {
        "php": ">=8.2",
        "composer-plugin-api": "^2"
    },
    "autoload": {
        "psr-4": {
            "YourNamespace\\Composer\\Plugin\\YourPlugin\\": "src"
        }
    },
    "extra": {
        "class": "YourNamespace\\Composer\\Plugin\\YourPlugin\\Plugin"
    }
}

3. Create a consumer website package:
composer create-project drupal-composer/drupal-project:10.x-dev some-dir --no-interaction

4. Add your custom package as a dependency to the newly created project.

5. Run `composer drupal:scaffold`

6. Observe that plugin's listeners were ignored.

Proposed resolution

Use the event dispatcher from provided by composer:

$dispatcher = $this->composer->getEventDispatcher();

Remaining tasks

1.
2.

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

None

🐛 Bug report
Status

Fixed

Version

11.0 🔥

Component
Composer 

Last updated 8 days ago

No maintainer
Created by

🇦🇺Australia alex.skrypnyk Melbourne

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

Merge Requests

Comments & Activities

Production build 0.71.5 2024