Repository navigation
Expand file tree
/
Copy pathMessenger.php
More file actions
94 lines (86 loc) · 3.93 KB
/
Copy pathMessenger.php
File metadata and controls
94 lines (86 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
declare(strict_types=1);
namespace Testo;
use Testo\Core\Log\Level;
use Testo\Core\Log\Message;
use Testo\Core\Log\MessageLog;
use Testo\Event\Message\MessageReceived;
use Testo\Messenger\Channel;
/**
* Central message hub.
*
* Producers — the output-buffer trap, test code, middleware, or other plugins — write
* messages into named channels through this service. Every write is recorded into the active
* scope's buffer and announced via a {@see MessageReceived} event.
*
* Buffers are nested per suite / case / test via {@see scope()} — an isolated child that is
* dropped on exit — while the {@see MessageReceived} event stream stays global. {@see fork()}
* adds a *mergeable* branch on top of the active scope: its messages fold into the parent only
* if committed, so a repeated or retried execution can keep one attempt and drop the rest.
*
* This interface is meant to be **consumed, not implemented** by userland code: inject or
* type-hint it to talk to the messenger. The implementation is provided by the framework
* ({@see \Testo\Messenger\Internal\MessengerHub}) — new methods may be added in minor releases,
* which is safe for consumers but would break external implementations.
*
* @api
*/
interface Messenger
{
/**
* Record a message in the given channel.
*
* Builds a {@see Message}, stores it in the active scope's buffer and announces it via a
* {@see MessageReceived} event (the global firehose — fired once per write, regardless of scope).
*
* @param non-empty-string $channel
* @param array<string, mixed> $context Structured context attached to the message.
*/
public function log(string $channel, string $content, Level $level = Level::Info, array $context = []): void;
/**
* Obtain a channel-bound writer handle.
*
* @param non-empty-string $name
*/
public function channel(string $name): Channel;
/**
* Run the given closure within a forked scope.
*
* The active state is swapped for a fresh child for the duration of the call and restored
* afterwards; the child (and its message buffer) is destroyed on exit. {@see getMessages()}
* inside the closure observes only what was written within it. Fiber-aware: the parent state
* is restored across suspension points.
*
* @template T
* @param \Closure(self): T $scope
* @return T
*/
public function scope(\Closure $scope): mixed;
/**
* Run the given closure within a fork: a mergeable child branch of the active scope.
*
* Messages logged while the fork is active accumulate in an isolated child buffer. The closure
* receives a `$commit` callable that folds the branch's messages into the parent scope; if it is
* never called, the branch's messages are discarded. `$commit` may be invoked inside the closure
* or kept and called later — a retried/repeated execution decides whether to keep an attempt only
* after seeing its result. The active state is restored once the closure returns. Fiber-aware:
* the parent state is restored across suspension points.
*
* Lets a repeated/retried execution stay tentative — commit the attempt whose output should
* survive, drop the rest — so {@see getMessages()} doesn't accumulate every attempt.
*
* With `$holdEvents`, the {@see MessageReceived} events of messages logged inside the fork are
* buffered instead of dispatched live, and released only on commit (discarded if the fork is
* dropped). Use it so a discarded attempt stays invisible in real-time consumers too, not just
* absent from {@see getMessages()}.
*
* @template T
* @param \Closure(callable(): void): T $fork Receives the `$commit` callable.
* @return T
*/
public function fork(\Closure $fork, bool $holdEvents = false): mixed;
/**
* Messages recorded in the active scope.
*/
public function getMessages(): MessageLog;
}