22
33namespace Contributte \EventDispatcher \DI ;
44
5- use Contributte \EventDispatcher \EventDispatcher ;
6- use Contributte \EventDispatcher \LazyEventDispatcher ;
5+ use Contributte \EventDispatcher \Diagnostics \DebugDispatcher ;
6+ use Contributte \EventDispatcher \Diagnostics \TracyDispatcher ;
7+ use Contributte \EventDispatcher \LazyListener ;
8+ use Contributte \EventDispatcher \Tracy \EventPanel ;
79use Nette \DI \CompilerExtension ;
10+ use Nette \DI \Container ;
811use Nette \DI \Definitions \ServiceDefinition ;
12+ use Nette \DI \Definitions \Statement ;
913use Nette \DI \ServiceCreationException ;
14+ use Nette \PhpGenerator \ClassType ;
1015use Nette \Schema \Expect ;
1116use Nette \Schema \Schema ;
1217use stdClass ;
18+ use Symfony \Component \EventDispatcher \EventDispatcher ;
1319use Symfony \Component \EventDispatcher \EventDispatcherInterface ;
1420use Symfony \Component \EventDispatcher \EventSubscriberInterface ;
21+ use Tracy \Bar ;
1522
1623/**
1724 * @method stdClass getConfig()
@@ -24,6 +31,8 @@ public function getConfigSchema(): Schema
2431 return Expect::structure ([
2532 'lazy ' => Expect::bool (true ),
2633 'autoload ' => Expect::bool (true ),
34+ 'debug ' => Expect::bool (false ),
35+ 'loggers ' => Expect::arrayOf (Expect::type (Statement::class)),
2736 ]);
2837 }
2938
@@ -32,16 +41,31 @@ public function loadConfiguration(): void
3241 $ builder = $ this ->getContainerBuilder ();
3342 $ config = $ this ->getConfig ();
3443
35- $ eventDispatcherDefinition = $ builder ->addDefinition ($ this ->prefix ('dispatcher ' ))
36- ->setType (EventDispatcherInterface::class);
44+ // Original dispatcher
45+ $ outerDispatcher = $ dispatcherDef = $ builder ->addDefinition ($ this ->prefix ('dispatcher ' ))
46+ ->setType (EventDispatcherInterface::class)
47+ ->setFactory (EventDispatcher::class)
48+ ->setAutowired (false );
49+
50+ // Dispatcher for logging
51+ if ($ config ->loggers !== []) {
52+ $ loggingDispatcherDef = $ builder ->addDefinition ($ this ->prefix ('dispatcher.logging ' ))
53+ ->setFactory (DebugDispatcher::class, [$ outerDispatcher ])
54+ ->setAutowired (false );
55+ $ outerDispatcher = $ loggingDispatcherDef ;
56+ }
3757
38- if ($ config ->lazy === true ) {
39- $ eventDispatcherDefinition
40- ->setFactory (LazyEventDispatcher::class);
41- } else {
42- $ eventDispatcherDefinition
43- ->setFactory (EventDispatcher::class);
58+ // Dispatcher for Tracy bar
59+ if ($ config ->debug === true ) {
60+ $ tracyDispatcherDef = $ builder ->addDefinition ($ this ->prefix ('dispatcher.tracy ' ))
61+ ->setType (EventDispatcherInterface::class)
62+ ->setFactory (TracyDispatcher::class, [$ outerDispatcher ])
63+ ->setAutowired (false );
64+ $ outerDispatcher = $ tracyDispatcherDef ;
4465 }
66+
67+ // Only outer dispatcher should be autowired
68+ $ outerDispatcher ->setAutowired ();
4569 }
4670
4771 public function beforeCompile (): void
@@ -57,6 +81,23 @@ public function beforeCompile(): void
5781 }
5882 }
5983
84+ public function afterCompile (ClassType $ class ): void
85+ {
86+ $ config = $ this ->getConfig ();
87+ $ builder = $ this ->getContainerBuilder ();
88+ $ initialization = $ this ->getInitialization ();
89+
90+ if ($ config ->debug ) {
91+ $ initialization ->addBody (
92+ // @phpstan-ignore-next-line
93+ $ builder ->formatPhp ('?->addPanel(?); ' , [
94+ $ builder ->getDefinitionByType (Bar::class),
95+ new Statement (EventPanel::class, [$ builder ->getDefinition ($ this ->prefix ('dispatcher.tracy ' ))]),
96+ ])
97+ );
98+ }
99+ }
100+
60101 /**
61102 * Collect listeners and subscribers
62103 */
@@ -82,36 +123,43 @@ private function doBeforeCompileLaziness(): void
82123 assert ($ dispatcher instanceof ServiceDefinition);
83124
84125 $ subscribers = $ builder ->findByType (EventSubscriberInterface::class);
85- foreach ($ subscribers as $ name => $ subscriber ) {
126+ foreach ($ subscribers as $ serviceName => $ subscriber ) {
86127 assert ($ subscriber instanceof ServiceDefinition);
87128 $ events = call_user_func ([$ subscriber ->getEntity (), 'getSubscribedEvents ' ]); // @phpstan-ignore-line
88129 assert (is_array ($ events ));
89130
90- /**
91- * ['eventName' => 'methodName']
92- * ['eventName' => ['methodName', $priority]]
93- * ['eventName' => [['methodName1', $priority], ['methodName2']]]
94- */
95- foreach ($ events as $ event => $ args ) {
96- if (is_string ($ args )) {
97- if (!method_exists ((string ) $ subscriber ->getType (), $ args )) {
98- throw new ServiceCreationException (sprintf ('Event listener %s does not have callable method %s ' , $ subscriber ->getType (), $ args ));
131+ foreach ($ events as $ event => $ params ) {
132+ if (is_string ($ params )) { // ['eventName' => 'methodName']
133+ if (!method_exists ((string ) $ subscriber ->getType (), $ params )) {
134+ throw new ServiceCreationException (sprintf ('Event listener %s does not have callable method %s ' , $ subscriber ->getType (), $ params ));
99135 }
100136
101- $ dispatcher ->addSetup ('addSubscriberLazy ' , [$ event , $ name ]);
102- } elseif (is_string ($ args [0 ])) {
103- if (!method_exists ((string ) $ subscriber ->getType (), $ args [0 ])) {
104- throw new ServiceCreationException (sprintf ('Event listener %s does not have callable method %s ' , $ subscriber ->getType (), $ args [0 ]));
137+ $ dispatcher ->addSetup ('addListener ' , [
138+ 'eventName ' => $ event ,
139+ 'listener ' => new Statement (LazyListener::class, [$ serviceName , $ params , $ builder ->getDefinitionByType (Container::class)]),
140+ 'priority ' => 0 ,
141+ ]);
142+ } elseif (is_string ($ params [0 ])) { // ['eventName' => ['methodName', $priority]]
143+ if (!method_exists ((string ) $ subscriber ->getType (), $ params [0 ])) {
144+ throw new ServiceCreationException (sprintf ('Event listener %s does not have callable method %s ' , $ subscriber ->getType (), $ params [0 ]));
105145 }
106146
107- $ dispatcher ->addSetup ('addSubscriberLazy ' , [$ event , $ name ]);
108- } else {
109- foreach ($ args as $ arg ) {
110- if (!method_exists ((string ) $ subscriber ->getType (), $ arg [0 ])) {
111- throw new ServiceCreationException (sprintf ('Event listener %s does not have callable method %s ' , $ subscriber ->getType (), $ arg [0 ]));
147+ $ dispatcher ->addSetup ('addListener ' , [
148+ 'eventName ' => $ event ,
149+ 'listener ' => new Statement (LazyListener::class, [$ serviceName , $ params [0 ], $ builder ->getDefinitionByType (Container::class)]),
150+ 'priority ' => $ params [1 ] ?? 0 ,
151+ ]);
152+ } elseif (is_array ($ params [0 ])) { // ['eventName' => [['methodName1', $priority], ['methodName2']]]
153+ foreach ($ params as $ listener ) {
154+ if (!method_exists ((string ) $ subscriber ->getType (), $ listener [0 ])) {
155+ throw new ServiceCreationException (sprintf ('Event listener %s does not have callable method %s ' , $ subscriber ->getType (), $ listener [0 ]));
112156 }
113157
114- $ dispatcher ->addSetup ('addSubscriberLazy ' , [$ event , $ name ]);
158+ $ dispatcher ->addSetup ('addListener ' , [
159+ 'eventName ' => $ event ,
160+ 'listener ' => new Statement (LazyListener::class, [$ serviceName , $ listener [0 ], $ builder ->getDefinitionByType (Container::class)]),
161+ 'priority ' => $ listener [1 ] ?? 0 ,
162+ ]);
115163 }
116164 }
117165 }
0 commit comments