2121 */
2222class Plugin implements PluginInterface, EventSubscriberInterface, Capable {
2323
24+ /**
25+ * The Composer service.
26+ *
27+ * @var \Composer\Composer
28+ */
29+ protected $ composer ;
30+
31+ /**
32+ * Composer's I/O service.
33+ *
34+ * @var \Composer\IO\IOInterface
35+ */
36+ protected $ io ;
37+
2438 /**
2539 * The Composer Scaffold handler.
2640 *
2741 * @var \Drupal\Composer\Plugin\Scaffold\Handler
2842 */
2943 protected $ handler ;
3044
45+ /**
46+ * Record whether the 'require' command was called.
47+ *
48+ * @param bool
49+ */
50+ protected $ requireWasCalled ;
51+
3152 /**
3253 * {@inheritdoc}
3354 */
3455 public function activate (Composer $ composer , IOInterface $ io ) {
35- // We use a Handler object to separate the main functionality
36- // of this plugin from the Composer API. This also avoids some
37- // debug issues with the plugin being copied on initialisation.
38- // @see \Composer\Plugin\PluginManager::registerPackage()
39- $ this ->handler = new Handler ($ composer , $ io );
56+ $ this ->composer = $ composer ;
57+ $ this ->io = $ io ;
58+ $ this ->requireWasCalled = FALSE ;
4059 }
4160
4261 /**
@@ -50,6 +69,7 @@ public function getCapabilities() {
5069 * {@inheritdoc}
5170 */
5271 public static function getSubscribedEvents () {
72+ // Important note: We only instantiate our handler on "post" events.
5373 return [
5474 ScriptEvents::POST_UPDATE_CMD => 'postCmd ' ,
5575 ScriptEvents::POST_INSTALL_CMD => 'postCmd ' ,
@@ -65,7 +85,7 @@ public static function getSubscribedEvents() {
6585 * The Composer event.
6686 */
6787 public function postCmd (Event $ event ) {
68- $ this ->handler ->scaffold ();
88+ $ this ->handler () ->scaffold ();
6989 }
7090
7191 /**
@@ -75,7 +95,7 @@ public function postCmd(Event $event) {
7595 * Composer package event sent on install/update/remove.
7696 */
7797 public function postPackage (PackageEvent $ event ) {
78- $ this ->handler ->onPostPackageEvent ($ event );
98+ $ this ->handler () ->onPostPackageEvent ($ event );
7999 }
80100
81101 /**
@@ -86,8 +106,28 @@ public function postPackage(PackageEvent $event) {
86106 */
87107 public function onCommand (CommandEvent $ event ) {
88108 if ($ event ->getCommandName () == 'require ' ) {
89- $ this ->handler ->beforeRequire ($ event );
109+ if ($ this ->handler ) {
110+ throw new \Error ('Core Scaffold Plugin handler instantiated too early. See https://www.drupal.org/project/drupal/issues/3104922 ' );
111+ }
112+ $ this ->requireWasCalled = TRUE ;
113+ }
114+ }
115+
116+ /**
117+ * Lazy-instantiate the handler object. It is dangerous to update a Composer
118+ * plugin if it loads any classes prior to the `composer update` operation,
119+ * and later tries to use them in a post-update hook.
120+ */
121+ protected function handler () {
122+ if (!$ this ->handler ) {
123+ $ this ->handler = new Handler ($ this ->composer , $ this ->io );
124+ // On instantiation of our handler, notify it if the 'require' command
125+ // was executed.
126+ if ($ this ->requireWasCalled ) {
127+ $ this ->handler ->requireWasCalled ();
128+ }
90129 }
130+ return $ this ->handler ;
91131 }
92132
93133}
0 commit comments