2010-02-17 13:54:36 +00:00
< ? php
/*
2010-04-07 01:51:29 +01:00
* This file is part of the Symfony package .
2010-02-17 13:54:36 +00:00
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2010-02-17 13:54:36 +00:00
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
2011-01-15 13:29:43 +00:00
namespace Symfony\Bundle\FrameworkBundle\Debug ;
2011-03-13 18:16:56 +00:00
use Symfony\Bundle\FrameworkBundle\ContainerAwareEventDispatcher ;
2011-01-15 13:29:43 +00:00
use Symfony\Component\HttpKernel\Log\LoggerInterface ;
2011-03-13 18:16:56 +00:00
use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcherInterface ;
2011-01-23 17:02:16 +00:00
use Symfony\Component\DependencyInjection\ContainerInterface ;
2011-03-13 18:16:56 +00:00
use Symfony\Component\EventDispatcher\Event ;
2011-01-15 13:29:43 +00:00
2010-02-17 13:54:36 +00:00
/**
2011-03-13 18:16:56 +00:00
* Extends the ContainerAwareEventDispatcher to add some debugging tools .
2010-02-17 13:54:36 +00:00
*
2011-03-06 11:40:06 +00:00
* @ author Fabien Potencier < fabien @ symfony . com >
2010-02-17 13:54:36 +00:00
*/
2011-03-13 18:16:56 +00:00
class TraceableEventDispatcher extends ContainerAwareEventDispatcher implements TraceableEventDispatcherInterface
2010-02-17 13:54:36 +00:00
{
2011-04-06 08:35:15 +01:00
private $logger ;
private $called ;
private $container ;
2010-05-06 12:25:53 +01:00
/**
* Constructor .
*
2011-01-23 17:02:16 +00:00
* @ param ContainerInterface $container A ContainerInterface instance
* @ param LoggerInterface $logger A LoggerInterface instance
2010-05-06 12:25:53 +01:00
*/
2011-01-23 17:02:16 +00:00
public function __construct ( ContainerInterface $container , LoggerInterface $logger = null )
2010-02-17 13:54:36 +00:00
{
2011-01-23 17:02:16 +00:00
parent :: __construct ( $container );
2011-04-06 08:14:12 +01:00
$this -> container = $container ;
2010-05-06 12:25:53 +01:00
$this -> logger = $logger ;
2010-08-27 10:24:30 +01:00
$this -> called = array ();
2010-02-17 13:54:36 +00:00
}
2011-04-06 08:14:12 +01:00
/**
* { @ inheritDoc }
*
* @ throws \RuntimeException if the listener method is not callable
*/
2011-05-05 18:02:52 +01:00
public function addListener ( $eventName , $listener , $priority = 0 )
2011-04-06 08:14:12 +01:00
{
2011-05-05 18:02:52 +01:00
if ( ! is_callable ( $listener )) {
if ( is_string ( $listener )) {
2011-05-26 10:53:37 +01:00
$typeDefinition = '[string] ' . $listener ;
2011-05-05 18:02:52 +01:00
} elseif ( is_array ( $listener )) {
2011-05-26 10:53:37 +01:00
$typeDefinition = '[array] ' . $listener [ 0 ] . ', ' . $listener [ 1 ];
2011-05-05 18:02:52 +01:00
} elseif ( is_object ( $listener )) {
2011-05-26 10:53:37 +01:00
$typeDefinition = '[object] ' . get_class ( $listener );
2011-05-05 18:02:52 +01:00
} else {
2011-05-26 10:53:37 +01:00
$typeDefinition = '[?] ' . var_export ( $listener , true );
2011-04-06 08:14:12 +01:00
}
2011-05-26 10:53:37 +01:00
$msg = sprintf ( 'The given callback (%s) for event "%s" is not callable.' , $typeDefinition , $eventName );
2011-05-05 18:02:52 +01:00
if ( null !== $this -> logger ) {
$this -> logger -> err ( $msg );
}
throw new \RuntimeException ( $msg );
2011-04-06 08:14:12 +01:00
}
2011-04-13 13:07:54 +01:00
2011-05-05 18:02:52 +01:00
parent :: addListener ( $eventName , $listener , $priority );
2011-04-06 08:14:12 +01:00
}
2010-05-06 12:25:53 +01:00
/**
2011-01-09 10:25:50 +00:00
* { @ inheritDoc }
2010-05-06 12:25:53 +01:00
*/
2011-05-05 08:15:48 +01:00
protected function doDispatch ( $listeners , $eventName , Event $event )
2010-02-17 13:54:36 +00:00
{
2011-05-05 08:15:48 +01:00
foreach ( $listeners as $listener ) {
2011-05-05 18:02:52 +01:00
// TODO: remove this before final release, temporary transitional code
if ( is_object ( $listener ) && method_exists ( $listener , $eventName )) {
2011-05-05 08:15:48 +01:00
$listener -> $eventName ( $event );
2011-05-05 18:02:52 +01:00
trigger_error ( 'Event listeners should now be registered using a complete callback as the listener instead of just an instance. Adjust your code ASAP.' , E_USER_DEPRECATED );
} else {
// only this call should remain
call_user_func ( $listener , $event );
2011-05-05 08:15:48 +01:00
}
2010-02-17 13:54:36 +00:00
2011-05-05 18:02:52 +01:00
$info = $this -> getListenerInfo ( $listener , $eventName );
2011-05-05 08:15:48 +01:00
if ( null !== $this -> logger ) {
2011-05-05 18:02:52 +01:00
$this -> logger -> debug ( sprintf ( 'Notified event "%s" to listener "%s".' , $eventName , $info [ 'pretty' ]));
2011-05-05 08:15:48 +01:00
}
2011-03-13 17:10:39 +00:00
2011-05-05 18:02:52 +01:00
$this -> called [ $eventName . '.' . $info [ 'pretty' ]] = $info ;
2011-01-24 15:46:04 +00:00
2011-05-05 08:15:48 +01:00
if ( $event -> isPropagationStopped ()) {
if ( null !== $this -> logger ) {
2011-05-05 18:02:52 +01:00
$this -> logger -> debug ( sprintf ( 'Listener "%s" stopped propagation of the event "%s".' , $info [ 'pretty' ], $eventName ));
2011-03-13 17:10:39 +00:00
2011-05-05 08:15:48 +01:00
$skippedListeners = $this -> getListeners ( $eventName );
$skipped = false ;
2011-03-13 17:10:39 +00:00
2011-05-05 08:15:48 +01:00
foreach ( $skippedListeners as $skippedListener ) {
if ( $skipped ) {
2011-05-26 10:53:37 +01:00
if ( is_object ( $skippedListener )) {
$typeDefinition = get_class ( $skippedListener );
} elseif ( is_array ( $skippedListener )) {
if ( is_object ( $skippedListener [ 0 ])) {
$typeDefinition = get_class ( $skippedListener );
} else {
$typeDefinition = implode ( '::' , $skippedListener );
}
} else {
$typeDefinition = $skippedListener ;
}
$this -> logger -> debug ( sprintf ( 'Listener "%s" was not called for event "%s".' , $typeDefinition , $eventName ));
2011-05-05 08:15:48 +01:00
}
2010-02-17 13:54:36 +00:00
2011-05-05 08:15:48 +01:00
if ( $skippedListener === $listener ) {
$skipped = true ;
}
}
2011-03-13 17:10:39 +00:00
}
2011-05-05 08:15:48 +01:00
break ;
2011-03-13 17:10:39 +00:00
}
2010-05-06 12:25:53 +01:00
}
2010-02-17 13:54:36 +00:00
}
2011-01-09 10:25:50 +00:00
/**
* { @ inheritDoc }
*/
public function getCalledListeners ()
2010-08-27 10:24:30 +01:00
{
return $this -> called ;
}
2011-01-09 10:25:50 +00:00
/**
* { @ inheritDoc }
*/
public function getNotCalledListeners ()
2010-08-27 10:24:30 +01:00
{
$notCalled = array ();
2011-05-05 18:02:52 +01:00
foreach ( $this -> getListeners () as $name => $listeners ) {
foreach ( $listeners as $listener ) {
$info = $this -> getListenerInfo ( $listener , $name );
if ( ! isset ( $this -> called [ $name . '.' . $info [ 'pretty' ]])) {
$notCalled [ $name . '.' . $info [ 'pretty' ]] = $info ;
2010-08-27 10:24:30 +01:00
}
}
}
return $notCalled ;
}
2011-04-06 08:31:06 +01:00
/**
* Returns information about the listener
2011-04-15 20:12:02 +01:00
*
2011-04-06 08:31:06 +01:00
* @ param object $listener The listener
* @ param string $eventName The event name
2011-04-15 20:12:02 +01:00
*
2011-04-06 08:31:06 +01:00
* @ return array Informations about the listener
*/
private function getListenerInfo ( $listener , $eventName )
2010-02-17 13:54:36 +00:00
{
2011-04-04 23:43:53 +01:00
$info = array ( 'event' => $eventName );
if ( $listener instanceof \Closure ) {
2011-05-05 18:02:52 +01:00
$info += array (
'type' => 'Closure' ,
'pretty' => 'closure'
);
} elseif ( is_string ( $listener )) {
try {
$r = new \ReflectionFunction ( $listener );
$file = $r -> getFileName ();
$line = $r -> getStartLine ();
} catch ( \ReflectionException $e ) {
$file = null ;
$line = null ;
}
$info += array (
'type' => 'Function' ,
'function' => $listener ,
'file' => $file ,
'line' => $line ,
'pretty' => $listener ,
);
} elseif ( is_array ( $listener ) || ( is_object ( $listener ) && is_callable ( $listener ))) {
if ( ! is_array ( $listener )) {
$listener = array ( $listener , '__invoke' );
}
$class = get_class ( $listener [ 0 ]);
2011-04-04 23:43:53 +01:00
try {
2011-05-05 18:02:52 +01:00
$r = new \ReflectionMethod ( $class , $listener [ 1 ]);
2011-04-06 08:14:12 +01:00
$file = $r -> getFileName ();
$line = $r -> getStartLine ();
2011-04-04 23:43:53 +01:00
} catch ( \ReflectionException $e ) {
2011-04-06 08:14:12 +01:00
$file = null ;
$line = null ;
2011-03-13 17:10:39 +00:00
}
2011-04-06 08:14:12 +01:00
$info += array (
'type' => 'Method' ,
'class' => $class ,
2011-05-05 18:02:52 +01:00
'method' => $listener [ 1 ],
2011-04-06 08:14:12 +01:00
'file' => $file ,
2011-05-05 18:02:52 +01:00
'line' => $line ,
'pretty' => $class . '::' . $listener [ 1 ],
2011-04-06 08:14:12 +01:00
);
2010-05-06 12:25:53 +01:00
}
2011-04-04 23:43:53 +01:00
return $info ;
2010-08-27 10:24:30 +01:00
}
2010-02-17 13:54:36 +00:00
}