浏览代码

Remove package trigger
Rename GetTriggerEvent on TriggerEvent
Remove get/set Application in TriggerEvent
Remove get/set Dispatcher in TriggerEvent
Add get/set Composer in TriggerEvent
Add get/set IO in TriggerEvent
Restaure ConsoleIO and IOInterface
Update Faq

François Pluchino 13 年之前
父节点
当前提交
f017074655

+ 11 - 34
doc/faqs/triggers.md

@@ -3,13 +3,12 @@
 ## What is a trigger?
 
 A trigger is an event that runs a script in a static method, defined by a 
-package or project. This event is raised before and after each action (install, 
-update).
+project. This event is raised before and after each action (install, update).
 
 
 ## Where are the event types defined?
 
-It is in the constant property in `Composer\Trigger\TriggerEvents` class.
+It is in the constant property in `Composer\\Trigger\\TriggerEvents` class.
 
 
 ## How is it defined?
@@ -17,41 +16,27 @@ It is in the constant property in `Composer\Trigger\TriggerEvents` class.
 It is defined by adding the `triggers` key in the `extra` key to a project's
 `composer.json` or package's `composer.json`.
 
-It is specified as an associative array of classes with her static method,
-associated with the event's type.
+It is specified as an array of classes with her static method,
+in associative array define the event's type.
 
 The PSR-0 must be defined, otherwise the trigger will not be triggered.
 
-For any given package:
-
-```json
-{
-    "extra": {
-        "triggers": {
-            "MyVendor\MyPackage\MyClass::myStaticMethod" : "post_install",
-            "MyVendor\MyPackage\MyClass::myStaticMethod2" : "post_update",
-        }
-    },
-    "autoload": {
-        "psr-0": {
-            "MyVendor\MyPackage": ""
-        }
-    }
-}
-```
-
 For any given project:
 ```json
 {
     "extra": {
         "triggers": {
-            "MyVendor\MyPackage2\MyClass2::myStaticMethod2" : "post_install",
-            "MyVendor\MyPackage2\MyClass2::myStaticMethod3" : "post_update",
+            "post_install": [
+                "MyVendor\\MyRootPackage\\MyClass::myStaticMethod"
+            ],
+            "post_update": [
+                "MyVendor\\MyRootPackage\\MyClass::myStaticMethod2"
+            ]
         }
     },
     "autoload": {
         "psr-0": {
-            "MyVendor\MyPackage": "my/folder/path/that/contains/triggers/from/the/root/project"
+            "MyVendor\\MyRootPackage": "my/folder/path/that/contains/triggers/from/the/root/project"
         }
     }
 }
@@ -59,12 +44,4 @@ For any given project:
 
 ## Informations:
 
-The project's triggers are executed after the package's triggers.
 A declared trigger with non existent file will be ignored.
-
-For example:
-If you declare a trigger for a package pre install, as this trigger isn't 
-downloaded yet, it won't run.
-
-On the other hand, if you declare a pre-update package trigger, as the file 
-already exist, the actual vendor's version of the trigger will be run.

+ 2 - 3
src/Composer/Command/InstallCommand.php

@@ -13,9 +13,7 @@
 namespace Composer\Command;
 
 use Composer\Trigger\TriggerEvents;
-
 use Composer\Trigger\TriggerDispatcher;
-
 use Composer\Autoload\AutoloadGenerator;
 use Composer\DependencyResolver;
 use Composer\DependencyResolver\Pool;
@@ -69,7 +67,8 @@ EOT
         $dryRun = (Boolean) $input->getOption('dry-run');
         $verbose = $dryRun || $input->getOption('verbose');
         $composer = $this->getComposer();
-        $dispatcher = new TriggerDispatcher($this->getApplication());
+        $io = $this->getApplication()->getIO();
+        $dispatcher = new TriggerDispatcher($this->getComposer(), $io);
 
         if ($preferSource) {
             $composer->getDownloadManager()->setPreferSource(true);

+ 0 - 32
src/Composer/IO/ConsoleIO.php

@@ -46,38 +46,6 @@ class ConsoleIO implements IOInterface
         $this->helperSet = $helperSet;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public function getArguments()
-    {
-        return $this->input->getArguments();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public function getArgument($name)
-    {
-        return $this->input->getArgument($name);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public function getOptions()
-    {
-        return $this->input->getOptions();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public function getOption($name)
-    {
-        return $this->input->getOption($name);
-    }
-
     /**
      * {@inheritDoc}
      */

+ 1 - 33
src/Composer/IO/IOInterface.php

@@ -18,39 +18,7 @@ namespace Composer\IO;
  * @author François Pluchino <francois.pluchino@opendisplay.com>
  */
 interface IOInterface
-{
-    /**
-     * Returns all the given arguments merged with the default values.
-     *
-     * @return array
-     */
-    function getArguments();
-
-    /**
-     * Gets argument by name.
-     *
-     * @param string $name The name of the argument
-     *
-     * @return mixed
-     */
-    function getArgument($name);
-
-    /**
-     * Returns all the given options merged with the default values.
-     *
-     * @return array
-     */
-    function getOptions();
-
-    /**
-     * Gets an option by name.
-     *
-     * @param string $name The name of the option
-     *
-     * @return mixed
-     */
-    function getOption($name);
-
+{
     /**
      * Is this input means interactive?
      *

+ 0 - 108
src/Composer/Trigger/GetTriggerEvent.php

@@ -1,108 +0,0 @@
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- *     Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Trigger;
-
-use Composer\Console\Application;
-
-/**
- * The Trigger Event.
- *
- * @author François Pluchino <francois.pluchino@opendisplay.com>
- */
-class GetTriggerEvent
-{
-    /**
-     * @var TriggerDispatcher Dispatcher that dispatched this event
-     */
-    private $dispatcher;
-
-    /**
-     * @var string This event's name
-     */
-    private $name;
-
-    /**
-     * @var Application The application instance
-     */
-    private $application;
-
-    /**
-     * Returns the TriggerDispatcher that dispatches this Event
-     *
-     * @return TriggerDispatcher
-     */
-    public function getDispatcher()
-    {
-        return $this->dispatcher;
-    }
-
-    /**
-     * Stores the TriggerDispatcher that dispatches this Event
-     *
-     * @param TriggerDispatcher $dispatcher
-     */
-    public function setDispatcher(TriggerDispatcher $dispatcher)
-    {
-        $this->dispatcher = $dispatcher;
-    }
-
-    /**
-     * Returns the event's name.
-     *
-     * @return string The event name
-     */
-    public function getName()
-    {
-        return $this->name;
-    }
-
-    /**
-     * Stores the event's name.
-     *
-     * @param string $name The event name
-     */
-    public function setName($name)
-    {
-        $this->name = $name;
-    }
-
-    /**
-     * Returns the application instance.
-     *
-     * @return Application
-     */
-    public function getApplication()
-    {
-        return $this->application;
-    }
-
-    /**
-     * Stores the application instance.
-     *
-     * @param Application $application
-     */
-    public function setApplication(Application $application)
-    {
-        $this->application = $application;
-    }
-
-    /**
-     * Returns the composer instance.
-     *
-     * @return Composer
-     */
-    public function getComposer()
-    {
-        return $this->application->getComposer();
-    }
-}

+ 48 - 82
src/Composer/Trigger/TriggerDispatcher.php

@@ -16,33 +16,36 @@ use Composer\Json\JsonFile;
 use Composer\Repository\FilesystemRepository;
 use Composer\Autoload\ClassLoader;
 use Composer\Package\PackageInterface;
-use Composer\Console\Application;
+use Composer\IO\IOInterface;
 use Composer\Composer;
 
 /**
  * The Trigger Dispatcher.
  *
  * Example in command:
- *     $dispatcher = new TriggerDispatcher($this->getApplication());
+ *     $dispatcher = new TriggerDispatcher($this->getComposer(), $this->getApplication()->getIO());
  *     // ...
- *     $dispatcher->dispatch(TriggerEvents::PRE_INSTALL);
+ *     $dispatcher->dispatch(TriggerEvents::POST_INSTALL);
  *     // ...
  *
  * @author François Pluchino <francois.pluchino@opendisplay.com>
  */
 class TriggerDispatcher
 {
-    protected $application;
+    protected $composer;
+    protected $io;
     protected $loader;
 
     /**
      * Constructor.
      *
-     * @param Application $application
+     * @param Composer    $composer The composer instance
+     * @param IOInterface $io       The IOInterface instance
      */
-    public function __construct(Application $application)
+    public function __construct(Composer $composer, IOInterface $io)
     {
-        $this->application = $application;
+        $this->composer = $composer;
+        $this->io = $io;
         $this->loader = new ClassLoader();
     }
 
@@ -53,11 +56,11 @@ class TriggerDispatcher
      */
     public function dispatch($eventName)
     {
-        $event = new GetTriggerEvent();
-
-        $event->setDispatcher($this);
+        $event = new TriggerEvent();
+
         $event->setName($eventName);
-        $event->setApplication($this->application);
+        $event->setComposer($this->composer);
+        $event->setIO($this->io);
 
         $this->doDispatch($event);
     }
@@ -65,109 +68,72 @@ class TriggerDispatcher
     /**
      * Triggers the listeners of an event.
      *
-     * @param GetTriggerEvent $event The event object to pass to the event handlers/listeners.
+     * @param TriggerEvent $event The event object to pass to the event handlers/listeners.
      */
-    protected function doDispatch(GetTriggerEvent $event)
+    protected function doDispatch(TriggerEvent $event)
     {
         $listeners = $this->getListeners($event);
 
-        foreach ($listeners as $method => $eventType) {
-            if ($eventType === $event->getName()) {
-                $className = substr($method, 0, strpos($method, '::'));
-                $methodName = substr($method, strpos($method, '::') + 2);
+        foreach ($listeners as $method) {
+            $className = substr($method, 0, strpos($method, '::'));
+            $methodName = substr($method, strpos($method, '::') + 2);
 
-                try {
-                    $refMethod = new \ReflectionMethod($className, $methodName);
+            try {
+                $refMethod = new \ReflectionMethod($className, $methodName);
 
-                    // execute only if all conditions are validates
-                    if ($refMethod->isPublic()
-                            && $refMethod->isStatic()
-                            && !$refMethod->isAbstract()
-                            && 1 === $refMethod->getNumberOfParameters()) {
-                        $className::$methodName($event);
-                    }
+                // execute only if all conditions are validates
+                if ($refMethod->isPublic()
+                        && $refMethod->isStatic()
+                        && !$refMethod->isAbstract()
+                        && 1 === $refMethod->getNumberOfParameters()) {
+                    $className::$methodName($event);
+                }
 
-                } catch (\ReflectionException $ex) {}//silent execpetion
-            }
+            } catch (\ReflectionException $ex) {}//silent execpetion
         }
     }
 
     /**
      * Register namespaces in ClassLoader.
      *
-     * @param GetTriggerEvent $event The event object
-     *
-     * @return array The listener classes with event type
-     */
-    protected function getListeners(GetTriggerEvent $event)
-    {
-        $listeners = array();
-        $composer = $this->application->getComposer();
-        $vendorDir = $composer->getInstallationManager()->getVendorPath(true);
-        $installedFile = $vendorDir . '/.composer/installed.json';
-
-        // get the list of package installed
-        // $composer->getRepositoryManager()->getLocalRepository() not used
-        // because the list is not refreshed for the post event
-        $fsr = new FilesystemRepository(new JsonFile($installedFile));
-        $packages = $fsr->getPackages();
-
-        foreach ($packages as $package) {
-            $listeners = array_merge_recursive($listeners, $this->getListenerClasses($package));
-        }
-
-        // add root package
-        $listeners = array_merge_recursive($listeners, $this->getListenerClasses($composer->getPackage(), true));
-
-        return $listeners;
-    }
-
-    /**
-     * Get listeners and register the namespace on Classloader.
-     *
-     * @param PackageInterface $package The package objet
-     * @param boolean $root             For root composer
+     * @param TriggerEvent $event The event object
      *
      * @return array The listener classes with event type
      */
-    private function getListenerClasses(PackageInterface $package, $root = false)
+    protected function getListeners(TriggerEvent $event)
     {
-        $composer = $this->application->getComposer();
-        $installDir = $composer->getInstallationManager()->getVendorPath(true)
-                        . '/' . $package->getName();
-        $ex = $package->getExtra();
-        $al = $package->getAutoload();
-        $searchListeners = array();
-        $searchNamespaces = array();
-        $listeners = array();
+        $package = $this->composer->getPackage();
+        $ex = $package->getExtra();
+        $al = $package->getAutoload();
+        $searchListeners = array();
+        $searchNamespaces = array();
+        $listeners = array();
         $namespaces = array();
 
         // get classes
-        if (isset($ex['triggers'])) {
-            foreach ($ex['triggers'] as $method => $event) {
-                $searchListeners[$method] = $event;
+        if (isset($ex['triggers'][$event->getName()])) {
+            foreach ($ex['triggers'][$event->getName()] as $method) {
+                $searchListeners[] = $method;
             }
         }
 
         // get namespaces
         if (isset($al['psr-0'])) {
             foreach ($al['psr-0'] as $ns => $path) {
-                $dir = $root ? realpath('.') : $installDir;
-
-                $path = trim($dir . '/' . $path, '/');
+                $path = trim(realpath('.') . '/' . $path, '/');
                 $searchNamespaces[$ns] = $path;
             }
         }
-
-        // filter class::method have not a namespace registered
+
+        // filter class::method have not a namespace registered
         foreach ($searchNamespaces as $ns => $path) {
-            foreach ($searchListeners as $method => $event) {
+            foreach ($searchListeners as $method) {
                 if (0 === strpos($method, $ns)) {
-                    $listeners[$method] = $event;
+                    $listeners[] = $method;
 
-                    if (!in_array($ns, array_keys($namespaces))) {
-                        $namespaces[$ns] = $path;
-                    }
+                    if (!in_array($ns, array_keys($namespaces))) {
+                        $namespaces[$ns] = $path;
+                    }
                 }
             }
         }

+ 99 - 0
src/Composer/Trigger/TriggerEvent.php

@@ -0,0 +1,99 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Trigger;
+
+use Composer\Composer;
+use Composer\IO\IOInterface;
+
+/**
+ * The Trigger Event.
+ *
+ * @author François Pluchino <francois.pluchino@opendisplay.com>
+ */
+class TriggerEvent
+{
+    /**
+     * @var string This event's name
+     */
+    private $name;
+
+    /**
+     * @var Composer The composer instance
+     */
+    private $composer;
+
+    /**
+     * @var IOInterface The IO instance
+     */
+    private $io;
+
+    /**
+     * Returns the event's name.
+     *
+     * @return string The event name
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Stores the event's name.
+     *
+     * @param string $name The event name
+     */
+    public function setName($name)
+    {
+        $this->name = $name;
+    }
+
+    /**
+     * Returns the composer instance.
+     *
+     * @return Composer
+     */
+    public function getComposer()
+    {
+        return $this->composer;
+    }
+
+    /**
+     * Stores the composer instance.
+     *
+     * @param Composer $composer
+     */
+    public function setComposer(Composer $composer)
+    {
+        $this->composer = $composer;
+    }
+
+    /**
+     * Returns the IO instance.
+     *
+     * @return IOInterface
+     */
+    public function getIO()
+    {
+        return $this->io;
+    }
+
+    /**
+     * Stores the IO instance.
+     *
+     * @param IOInterface $io
+     */
+    public function setIO(IOInterface $io)
+    {
+        $this->io = $io;
+    }
+}

+ 25 - 1
src/Composer/Trigger/TriggerEvents.php

@@ -51,7 +51,7 @@ class TriggerEvents
      * @var string
      */
     const PRE_UPDATE = 'pre_update';
-
+
     /**
      * The POST_UPDATE event occurs at end update packages.
      *
@@ -62,4 +62,28 @@ class TriggerEvents
      * @var string
      */
     const POST_UPDATE = 'post_update';
+
+    /**
+     * The PRE_UNINSTALL event occurs at begging uninstallation packages.
+     *
+     * This event allows you to execute a trigger after any other code in the
+     * composer is executed. The event listener method receives a
+     * Composer\Trigger\TriggerEvent instance.
+     *
+     * @var string
+     */
+    const PRE_UNINSTALL = 'pre_uninstall';
+    //TODO add the dispatcher when the uninstall command will be doing
+
+    /**
+     * The PRE_UNINSTALL event occurs at end uninstallation packages.
+     *
+     * This event allows you to execute a trigger after any other code in the
+     * composer is executed. The event listener method receives a
+     * Composer\Trigger\TriggerEvent instance.
+     *
+     * @var string
+     */
+    const POST_UNINSTALL = 'post_uninstall';
+    //TODO add the dispatcher when the uninstall command will be doing
 }