You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
7.8 KiB
PHTML
241 lines
7.8 KiB
PHTML
13 years ago
|
<?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.
|
||
|
*/
|
||
|
|
||
11 years ago
|
namespace Composer\EventDispatcher;
|
||
13 years ago
|
|
||
|
use Composer\IO\IOInterface;
|
||
|
use Composer\Composer;
|
||
|
use Composer\DependencyResolver\Operation\OperationInterface;
|
||
11 years ago
|
use Composer\Script;
|
||
|
use Composer\Script\CommandEvent;
|
||
|
use Composer\Script\PackageEvent;
|
||
12 years ago
|
use Composer\Util\ProcessExecutor;
|
||
13 years ago
|
|
||
|
/**
|
||
|
* The Event Dispatcher.
|
||
|
*
|
||
|
* Example in command:
|
||
|
* $dispatcher = new EventDispatcher($this->getComposer(), $this->getApplication()->getIO());
|
||
|
* // ...
|
||
|
* $dispatcher->dispatch(ScriptEvents::POST_INSTALL_CMD);
|
||
|
* // ...
|
||
|
*
|
||
|
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||
11 years ago
|
* @author Nils Adermann <naderman@naderman.de>
|
||
13 years ago
|
*/
|
||
|
class EventDispatcher
|
||
|
{
|
||
|
protected $composer;
|
||
|
protected $io;
|
||
|
protected $loader;
|
||
12 years ago
|
protected $process;
|
||
13 years ago
|
|
||
|
/**
|
||
|
* Constructor.
|
||
|
*
|
||
12 years ago
|
* @param Composer $composer The composer instance
|
||
|
* @param IOInterface $io The IOInterface instance
|
||
|
* @param ProcessExecutor $process
|
||
13 years ago
|
*/
|
||
12 years ago
|
public function __construct(Composer $composer, IOInterface $io, ProcessExecutor $process = null)
|
||
13 years ago
|
{
|
||
|
$this->composer = $composer;
|
||
|
$this->io = $io;
|
||
11 years ago
|
$this->process = $process ?: new ProcessExecutor($io);
|
||
13 years ago
|
}
|
||
|
|
||
11 years ago
|
/**
|
||
|
* Dispatch an event
|
||
|
*
|
||
|
* @param string $eventName An event name
|
||
|
* @param Event $event
|
||
|
*/
|
||
|
public function dispatch($eventName, Event $event = null)
|
||
|
{
|
||
|
if (null == $event) {
|
||
|
$event = new Event($eventName);
|
||
|
}
|
||
|
|
||
|
$this->doDispatch($event);
|
||
|
}
|
||
|
|
||
12 years ago
|
/**
|
||
|
* Dispatch a script event.
|
||
|
*
|
||
11 years ago
|
* @param string $eventName The constant in ScriptEvents
|
||
|
* @param Event $event
|
||
12 years ago
|
*/
|
||
11 years ago
|
public function dispatchScript($eventName, Script\Event $event = null)
|
||
12 years ago
|
{
|
||
12 years ago
|
if (null == $event) {
|
||
11 years ago
|
$event = new Script\Event($eventName, $this->composer, $this->io);
|
||
12 years ago
|
}
|
||
|
|
||
|
$this->doDispatch($event);
|
||
12 years ago
|
}
|
||
|
|
||
13 years ago
|
/**
|
||
|
* Dispatch a package event.
|
||
|
*
|
||
12 years ago
|
* @param string $eventName The constant in ScriptEvents
|
||
12 years ago
|
* @param boolean $devMode Whether or not we are in dev mode
|
||
13 years ago
|
* @param OperationInterface $operation The package being installed/updated/removed
|
||
|
*/
|
||
12 years ago
|
public function dispatchPackageEvent($eventName, $devMode, OperationInterface $operation)
|
||
13 years ago
|
{
|
||
12 years ago
|
$this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $operation));
|
||
13 years ago
|
}
|
||
|
|
||
|
/**
|
||
|
* Dispatch a command event.
|
||
|
*
|
||
12 years ago
|
* @param string $eventName The constant in ScriptEvents
|
||
|
* @param boolean $devMode Whether or not we are in dev mode
|
||
13 years ago
|
*/
|
||
12 years ago
|
public function dispatchCommandEvent($eventName, $devMode)
|
||
13 years ago
|
{
|
||
12 years ago
|
$this->doDispatch(new CommandEvent($eventName, $this->composer, $this->io, $devMode));
|
||
13 years ago
|
}
|
||
|
|
||
|
/**
|
||
|
* Triggers the listeners of an event.
|
||
|
*
|
||
11 years ago
|
* @param Event $event The event object to pass to the event handlers/listeners.
|
||
11 years ago
|
* @throws \RuntimeException
|
||
|
* @throws \Exception
|
||
13 years ago
|
*/
|
||
|
protected function doDispatch(Event $event)
|
||
|
{
|
||
|
$listeners = $this->getListeners($event);
|
||
|
|
||
|
foreach ($listeners as $callable) {
|
||
11 years ago
|
if ((is_array($callable) && $is_callable($callable)) || $callable instanceof Closure) {
|
||
|
$callable($event);
|
||
|
} elseif ($this->isPhpScript($callable)) {
|
||
12 years ago
|
$className = substr($callable, 0, strpos($callable, '::'));
|
||
|
$methodName = substr($callable, strpos($callable, '::') + 2);
|
||
|
|
||
|
if (!class_exists($className)) {
|
||
|
$this->io->write('<warning>Class '.$className.' is not autoloadable, can not call '.$event->getName().' script</warning>');
|
||
|
continue;
|
||
|
}
|
||
|
if (!is_callable($callable)) {
|
||
|
$this->io->write('<warning>Method '.$callable.' is not callable, can not call '.$event->getName().' script</warning>');
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
try {
|
||
12 years ago
|
$this->executeEventPhpScript($className, $methodName, $event);
|
||
12 years ago
|
} catch (\Exception $e) {
|
||
|
$message = "Script %s handling the %s event terminated with an exception";
|
||
|
$this->io->write('<error>'.sprintf($message, $callable, $event->getName()).'</error>');
|
||
|
throw $e;
|
||
|
}
|
||
|
} else {
|
||
11 years ago
|
if (0 !== ($exitCode = $this->process->execute($callable))) {
|
||
|
$event->getIO()->write(sprintf('<error>Script %s handling the %s event returned with an error</error>', $callable, $event->getName()));
|
||
|
|
||
|
throw new \RuntimeException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
|
||
12 years ago
|
}
|
||
12 years ago
|
}
|
||
11 years ago
|
|
||
|
if ($event->isPropagationStopped()) {
|
||
|
break;
|
||
|
}
|
||
13 years ago
|
}
|
||
|
}
|
||
|
|
||
12 years ago
|
/**
|
||
|
* @param string $className
|
||
|
* @param string $methodName
|
||
12 years ago
|
* @param Event $event Event invoking the PHP callable
|
||
12 years ago
|
*/
|
||
|
protected function executeEventPhpScript($className, $methodName, Event $event)
|
||
|
{
|
||
|
$className::$methodName($event);
|
||
|
}
|
||
|
|
||
11 years ago
|
protected function addListener($eventName, $listener, $priority = 0)
|
||
|
{
|
||
|
$this->listeners[$eventName][$priority][] = $listener;
|
||
|
}
|
||
|
|
||
|
protected function addSubscriber($subscriber)
|
||
|
{
|
||
|
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
|
||
|
if (is_string($params)) {
|
||
|
$this->addListener($eventName, array($subscriber, $params));
|
||
|
} elseif (is_string($params[0])) {
|
||
|
$this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
|
||
|
} else {
|
||
|
foreach ($params as $listener) {
|
||
|
$this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected function getListeners(Event $event)
|
||
|
{
|
||
|
$scriptListeners = $this->getScriptListeners($event);
|
||
|
|
||
|
if (!isset($this->listeners[$event->getName()][0])) {
|
||
|
$this->listeners[$event->getName()][0] = array();
|
||
|
}
|
||
|
krsort($this->listeners[$event->getName()]);
|
||
|
|
||
|
$listeners = $this->listeners;
|
||
|
$listeners[$event->getName()][0] = array_merge($listeners[$event->getName()][0], $scriptListeners);
|
||
|
|
||
|
return call_user_func_array('array_merge', $listeners[$event->getName()]);
|
||
|
}
|
||
|
|
||
13 years ago
|
/**
|
||
12 years ago
|
* @param Event $event Event object
|
||
13 years ago
|
* @return array Listeners
|
||
|
*/
|
||
11 years ago
|
protected function getScriptListeners(Event $event)
|
||
13 years ago
|
{
|
||
|
$package = $this->composer->getPackage();
|
||
|
$scripts = $package->getScripts();
|
||
|
|
||
13 years ago
|
if (empty($scripts[$event->getName()])) {
|
||
|
return array();
|
||
|
}
|
||
|
|
||
|
if ($this->loader) {
|
||
|
$this->loader->unregister();
|
||
13 years ago
|
}
|
||
|
|
||
12 years ago
|
$generator = $this->composer->getAutoloadGenerator();
|
||
11 years ago
|
$packages = $this->composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages();
|
||
13 years ago
|
$packageMap = $generator->buildPackageMap($this->composer->getInstallationManager(), $package, $packages);
|
||
12 years ago
|
$map = $generator->parseAutoloads($packageMap, $package);
|
||
13 years ago
|
$this->loader = $generator->createLoader($map);
|
||
|
$this->loader->register();
|
||
|
|
||
|
return $scripts[$event->getName()];
|
||
13 years ago
|
}
|
||
12 years ago
|
|
||
|
/**
|
||
|
* Checks if string given references a class path and method
|
||
|
*
|
||
12 years ago
|
* @param string $callable
|
||
12 years ago
|
* @return boolean
|
||
|
*/
|
||
|
protected function isPhpScript($callable)
|
||
|
{
|
||
12 years ago
|
return false === strpos($callable, ' ') && false !== strpos($callable, '::');
|
||
12 years ago
|
}
|
||
13 years ago
|
}
|