Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.65% covered (success)
95.65%
22 / 23
85.71% covered (warning)
85.71%
6 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Pipeline
95.65% covered (success)
95.65%
22 / 23
85.71% covered (warning)
85.71%
6 / 7
11
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 send
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 waitFor
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 orFailOn
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 start
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 handles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 handle
92.86% covered (success)
92.86%
13 / 14
0.00% covered (danger)
0.00%
0 / 1
5.01
1<?php
2
3declare(strict_types=1);
4
5namespace AqwSocketClient\Scripts;
6
7use AqwSocketClient\Interfaces\CommandInterface;
8use AqwSocketClient\Interfaces\EventInterface;
9use Closure;
10use Override;
11
12/**
13 * Fluent DSL for simple linear event flows.
14 *
15 * Use Pipeline::send() to create a pipeline. Chain waitFor() and orFailOn()
16 * to declare the expected success and failure events.
17 *
18 * Pipeline and class-based scripts are interchangeable inside SequenceScript.
19 */
20final class Pipeline extends AbstractScript
21{
22    public ?EventInterface $matchedEvent = null;
23
24    /** @var class-string<EventInterface> */
25    private string $successClass;
26
27    /** @var Closure|null */
28    private ?Closure $successCallback = null;
29
30    /** @var list<class-string<EventInterface>> */
31    private array $failureClasses = [];
32
33    private function __construct(
34        private readonly CommandInterface $initialCommand,
35    ) {}
36
37    public static function send(CommandInterface $command): self
38    {
39        return new self($command);
40    }
41
42    /**
43     * @template T of EventInterface
44     * @param class-string<T> $eventClass
45     * @param (Closure(T, ClientContext): ?CommandInterface)|null $callback
46     */
47    public function waitFor(string $eventClass, ?Closure $callback = null): self
48    {
49        $this->successClass = $eventClass;
50        $this->successCallback = $callback;
51        return $this;
52    }
53
54    /**
55     * @param class-string<EventInterface> $eventClass
56     */
57    public function orFailOn(string $eventClass): self
58    {
59        $this->failureClasses[] = $eventClass;
60        return $this;
61    }
62
63    #[Override]
64    public function start(ClientContext $context): ?CommandInterface
65    {
66        return $this->initialCommand;
67    }
68
69    #[Override]
70    public function handles(): array
71    {
72        return [$this->successClass, ...$this->failureClasses];
73    }
74
75    #[Override]
76    public function handle(EventInterface $event, ClientContext $context): ?CommandInterface
77    {
78        if ($event instanceof $this->successClass) {
79            $this->matchedEvent = $event;
80            /** @var CommandInterface|null */
81            $command = null;
82
83            if ($this->successCallback !== null) {
84                /** @var CommandInterface|null */
85                $command = ($this->successCallback)($event, $context);
86            }
87
88            $this->success();
89            return $command;
90        }
91
92        foreach ($this->failureClasses as $failureClass) {
93            if (!$event instanceof $failureClass) {
94                continue;
95            }
96
97            $this->matchedEvent = $event;
98            $this->failed();
99            return null;
100        }
101
102        return null;
103    }
104}