Lines 94.11% 16 / 17
Methods 75.00% 3 / 4
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 from 100.00% 9 / 9 100.00% 1 / 1 4
 summary 0.00% 0 / 1 0.00% 0 / 1 2
 [Lorekeeper\Server\Event\NamedAfterClass] name 100.00% 6 / 6 100.00% 1 / 1 1
19final readonly class LeveledUpEvent implements Event
20{
21    use NamedAfterClass;
22
23    public function __construct(
24        public PlayerLevel $level,
25        public Experience $toNextLevel,
26    ) {}
27
28    /** @return Option\Option<static> */
29    #[Override]
30    public static function from(Message $message): Option\Option
31    {
32        if (!$message instanceof JsonMessage || ($message->data['cmd'] ?? null) !== 'levelUp') {
33            return Option\none();
34        }
35
36        try {
37            $data = Type\shape([
38                'intLevel' => Type\int_range(min: 1, max: 100),
39                'intExpToLevel' => Type\uint(),
40            ], allowUnknownFields: true)->coerce($message->data);
41        } catch (CoercionException $exception) {
42            throw new MalformedEventException(static::class, 'level is missing or invalid', $exception);
43        }
44
45        return Option\some(new static(new PlayerLevel($data['intLevel']), new Experience($data['intExpToLevel'])));
46    }
47
48    #[Override]
49    public function summary(): string
50    {
51        return "Reached level {$this->level->value}";
52    }
53}

From Lorekeeper\Server\Event\NamedAfterClass

7trait NamedAfterClass
8{
9    public function name(): string
10    {
11        $class = static::class;
12
13        return (string) preg_replace(
14            '/Event$/',
15            replacement: '',
16            subject: substr($class, (int) strrpos($class, needle: '\\') + 1),
17        );
18    }
19}