Commit | Line | Data |
---|---|---|
fc9b680f TO |
1 | <?php |
2 | ||
3 | namespace Civi\Core\Event; | |
4 | ||
5 | /** | |
6 | * A ServiceListener is a `callable` (supporting "__invoke()") which references | |
7 | * a method of a service-object. | |
8 | * | |
9 | * The following two callables are conceptually similar: | |
10 | * | |
11 | * (A) addListener('some.event', [Civi::service('foo'), 'doBar']); | |
12 | * (B) addListener('some.event', new ServiceListener(['foo', 'doBar'])); | |
13 | * | |
14 | * The difference is that (A) immediately instantiates the 'foo' service, | |
15 | * whereas (B) instantiates `foo` lazily. (B) is more amenable to serialization, | |
16 | * caching, etc. If you have a long-tail of many services/listeners/etc that | |
17 | * are not required for every page-load, then (B) should perform better. | |
18 | * | |
19 | * @package Civi\Core\Event | |
20 | */ | |
21 | class ServiceListener { | |
22 | ||
23 | /** | |
24 | * @var array | |
25 | * Ex: ['service_name', 'someMethod'] | |
26 | */ | |
27 | private $inertCb = NULL; | |
28 | ||
29 | /** | |
30 | * @var array|null | |
31 | * Ex: [$svcObj, 'someMethod'] | |
32 | */ | |
33 | private $liveCb = NULL; | |
34 | ||
35 | /** | |
36 | * @var \Symfony\Component\DependencyInjection\ContainerInterface | |
37 | */ | |
38 | private $container = NULL; | |
39 | ||
40 | /** | |
41 | * @param array $callback | |
42 | * Ex: ['service_name', 'someMethod'] | |
43 | */ | |
44 | public function __construct($callback) { | |
45 | $this->inertCb = $callback; | |
46 | } | |
47 | ||
48 | public function __invoke(...$args) { | |
49 | if ($this->liveCb === NULL) { | |
50 | $c = $this->container ?: \Civi::container(); | |
51 | $this->liveCb = [$c->get($this->inertCb[0]), $this->inertCb[1]]; | |
52 | } | |
53 | return call_user_func_array($this->liveCb, $args); | |
54 | } | |
55 | ||
56 | public function __toString() { | |
57 | $class = NULL; | |
58 | if (\Civi\Core\Container::isContainerBooted()) { | |
59 | try { | |
60 | $c = $this->container ?: \Civi::container(); | |
61 | $class = $c->findDefinition($this->inertCb[0])->getClass(); | |
62 | } | |
63 | catch (Throwable $t) { | |
64 | } | |
65 | } | |
66 | if ($class) { | |
b90e57be | 67 | return sprintf('$(%s)->%s($e) [%s]', $this->inertCb[0], $this->inertCb[1], $class); |
fc9b680f TO |
68 | } |
69 | else { | |
b90e57be | 70 | return sprintf('\$(%s)->%s($e)', $this->inertCb[0], $this->inertCb[1]); |
fc9b680f TO |
71 | } |
72 | } | |
73 | ||
74 | public function __sleep() { | |
75 | return ['inertCb']; | |
76 | } | |
77 | ||
78 | /** | |
79 | * @param \Symfony\Component\DependencyInjection\ContainerInterface $container | |
80 | * @return static | |
81 | */ | |
82 | public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container) { | |
83 | $this->container = $container; | |
84 | return $this; | |
85 | } | |
86 | ||
87 | } |