Created
December 31, 2022 03:41
-
-
Save vudaltsov/05afd6a12f51fa30ed20d1555b89244a to your computer and use it in GitHub Desktop.
Envelope
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @psalm-immutable | |
* @template TResult | |
*/ | |
interface Message | |
{ | |
} | |
/** | |
* @psalm-immutable | |
*/ | |
interface Stamp | |
{ | |
} | |
/** | |
* @psalm-immutable | |
* @template TResult | |
* @template TMessage of Message<TResult> | |
*/ | |
final class Envelope | |
{ | |
/** | |
* @param TMessage $message | |
* @param array<class-string<Stamp>, Stamp> $stamps | |
*/ | |
private function __construct( | |
public readonly Message $message, | |
public readonly array $stamps, | |
) { | |
} | |
/** | |
* @psalm-pure | |
* @template TTResult | |
* @template TTMessage of Message<TTResult> | |
* @param TTMessage $message | |
* @return self<TTResult, TTMessage> | |
*/ | |
public static function wrap(Message $message, Stamp ...$stamps): self | |
{ | |
$stampsByClass = []; | |
foreach ($stamps as $stamp) { | |
$stampsByClass[$stamp::class] = $stamp; | |
} | |
return new self($message, $stampsByClass); | |
} | |
/** | |
* @template TTMessage of Message | |
* @param TTMessage $message | |
* @return self<TResult, TTMessage> | |
*/ | |
public function withMessage(Message $message): self | |
{ | |
return new self($message, $this->stamps); | |
} | |
/** | |
* @template TStamp of Stamp | |
* @param class-string<TStamp> $class | |
*/ | |
public function hasStamp(string $class): bool | |
{ | |
return isset($this->stamps[$class]); | |
} | |
/** | |
* @template TStamp of Stamp | |
* @param class-string<TStamp> $class | |
* @return TStamp | |
*/ | |
public function stamp(string $class): Stamp | |
{ | |
return $this->stampOrNull($class) ?? throw new \RuntimeException(sprintf( | |
'Stamp "%s" is not set on the envelope with message "%s".', | |
$class, | |
$this->message::class, | |
)); | |
} | |
/** | |
* @template TStamp of Stamp | |
* @param class-string<TStamp> $class | |
* @return ?TStamp | |
*/ | |
public function stampOrNull(string $class): ?Stamp | |
{ | |
/** @var ?TStamp */ | |
return $this->stamps[$class] ?? null; | |
} | |
/** | |
* @return self<TResult, TMessage> | |
*/ | |
public function withStamps(Stamp ...$stamps): self | |
{ | |
$mergedStamps = $this->stamps; | |
foreach ($stamps as $stamp) { | |
$mergedStamps[$stamp::class] = $stamp; | |
} | |
return new self($this->message, $mergedStamps); | |
} | |
/** | |
* @param class-string<Stamp> ...$classes | |
* @return self<TResult, TMessage> | |
*/ | |
public function withoutStamps(string ...$classes): self | |
{ | |
$stamps = $this->stamps; | |
foreach ($classes as $class) { | |
unset($stamps[$class]); | |
} | |
return new self($this->message, $stamps); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment