diff --git a/src/Write/Event/StrategyWasAdded.php b/src/Write/Event/StrategyWasAdded.php new file mode 100644 index 0000000..f7c947a --- /dev/null +++ b/src/Write/Event/StrategyWasAdded.php @@ -0,0 +1,85 @@ +featureId = $featureId; + $this->strategyId = $strategyId; + $this->strategyType = $strategyType; + $this->segments = $segments; + $this->occurredAt = $occurredAt; + } + + /** @param WriteSegment[] $segments */ + public static function occur(string $featureId, string $strategyId, string $strategyType, array $segments): self + { + return new self($featureId, $strategyId, $strategyType, $segments, new DatetimeImmutable()); + } + + public function featureId(): FeatureId + { + return FeatureId::fromString($this->featureId); + } + + public function strategyId(): StrategyId + { + return StrategyId::fromString($this->strategyId); + } + + public function strategyType(): StrategyType + { + return StrategyType::fromString($this->strategyType); + } + + public function occurredAt(): DatetimeImmutable + { + return $this->occurredAt; + } + + /** + * @return Segment[] + */ + public function segments(): array + { + return array_map( + static function (array $segment): Segment { + return new Segment( + SegmentId::fromString($segment['segment_id']), + SegmentType::fromString($segment['segment_type']), + Payload::fromArray($segment['criteria']) + ); + }, + $this->segments + ); + } +} diff --git a/src/Write/Feature.php b/src/Write/Feature.php index 220e5a3..b9eb291 100644 --- a/src/Write/Feature.php +++ b/src/Write/Feature.php @@ -9,6 +9,7 @@ use Pheature\Core\Toggle\Write\Event\FeatureWasCreated; use JsonSerializable; use Pheature\Core\Toggle\Write\Event\FeatureWasRemoved; +use Pheature\Core\Toggle\Write\Event\StrategyWasAdded; use function array_map; use function array_values; @@ -60,6 +61,12 @@ public static function withId(FeatureId $featureId): self public function setStrategy(Strategy $strategy): void { $this->strategies[$strategy->id()->value()] = $strategy; + $this->events[] = StrategyWasAdded::occur( + $this->featureId->value(), + $strategy->id()->value(), + $strategy->type()->value(), + array_map(static fn(Segment $segment) => $segment->jsonSerialize(), $strategy->segments()) + ); } public function removeStrategy(StrategyId $strategyId): void diff --git a/src/Write/Payload.php b/src/Write/Payload.php index bdc5a87..b4d63a1 100644 --- a/src/Write/Payload.php +++ b/src/Write/Payload.php @@ -8,23 +8,16 @@ final class Payload { - /** - * @var array - */ + /** @var array */ private array $criteria; - /** - * @param array $criteria - */ + /** @param array $criteria */ private function __construct(array $criteria) { $this->criteria = $criteria; } - /** - * @param array $criteria - * @return static - */ + /** @param array $criteria */ public static function fromArray(array $criteria): self { return new self($criteria); @@ -32,17 +25,13 @@ public static function fromArray(array $criteria): self public static function fromJsonString(string $jsonPayload): self { - /** - * @var array $payload - */ + /** @var array $payload */ $payload = json_decode($jsonPayload, true, 16, JSON_THROW_ON_ERROR); return self::fromArray($payload); } - /** - * @return array - */ + /** @return array */ public function criteria(): array { return $this->criteria; diff --git a/src/Write/Segment.php b/src/Write/Segment.php index a45cf77..a9c9896 100644 --- a/src/Write/Segment.php +++ b/src/Write/Segment.php @@ -6,6 +6,10 @@ use JsonSerializable; +/** + * @phpstan-type WriteSegment array{segment_id: string, segment_type: string, criteria: array} + * @psalm-type WriteSegment array{segment_id: string, segment_type: string, criteria: array} + */ final class Segment implements JsonSerializable { private SegmentId $segmentId; @@ -35,7 +39,7 @@ public function payload(): Payload } /** - * @return array> + * @return WriteSegment */ public function jsonSerialize(): array { diff --git a/src/Write/Strategy.php b/src/Write/Strategy.php index 347d3fb..19ba2de 100644 --- a/src/Write/Strategy.php +++ b/src/Write/Strategy.php @@ -8,6 +8,11 @@ use function array_map; +/** + * @phpstan-import-type WriteSegment from Segment + * @phpstan-type WriteStrategy array{strategy_id: string, strategy_type: string, segments: WriteSegment[]} + * @psalm-type WriteStrategy array{strategy_id: string, strategy_type: string, segments: WriteSegment[]} + */ final class Strategy implements JsonSerializable { private StrategyId $strategyId; @@ -49,15 +54,7 @@ public function segments(): array return $this->segments; } - /** - * @phpstan-return array - * @phpstan-ignore-next-line - * @return array{ - * strategy_id: string, - * strategy_type: string - * segments: array|string>>, - * } - */ + /** @return WriteStrategy */ public function jsonSerialize(): array { return [ diff --git a/test/Write/FeatureTest.php b/test/Write/FeatureTest.php index 35c142d..2632722 100644 --- a/test/Write/FeatureTest.php +++ b/test/Write/FeatureTest.php @@ -7,8 +7,13 @@ use Pheature\Core\Toggle\Write\Event\FeatureWasDisabled; use Pheature\Core\Toggle\Write\Event\FeatureWasEnabled; use Pheature\Core\Toggle\Write\Event\FeatureWasRemoved; +use Pheature\Core\Toggle\Write\Event\StrategyWasAdded; use Pheature\Core\Toggle\Write\Feature; use Pheature\Core\Toggle\Write\FeatureId; +use Pheature\Core\Toggle\Write\Payload; +use Pheature\Core\Toggle\Write\Segment; +use Pheature\Core\Toggle\Write\SegmentId; +use Pheature\Core\Toggle\Write\SegmentType; use Pheature\Core\Toggle\Write\Strategy; use Pheature\Core\Toggle\Write\StrategyId; use Pheature\Core\Toggle\Write\StrategyType; @@ -21,6 +26,8 @@ final class FeatureTest extends TestCase private const FEATURE_ID = 'some_feature'; private const STRATEGY_ID = 'some_strategy'; private const STRATEGY_TYPE = 'some_strategy_type'; + private const SEGMENT_ID = 'some_segment'; + private const SEGMENT_TYPE = 'some_segment_type'; public function testItShouldBeCreatedWithId(): void { @@ -86,14 +93,33 @@ public function testItShouldSetAnStrategy(): void $strategy = new Strategy( StrategyId::fromString(self::STRATEGY_ID), StrategyType::fromString(self::STRATEGY_TYPE), - [] + [ + new Segment( + SegmentId::fromString(self::SEGMENT_ID), + SegmentType::fromString(self::SEGMENT_TYPE), + Payload::fromArray(['foo' => 'bar']) + ) + ] ); $feature = $this->createFeature(); $feature->setStrategy($strategy); $this->assertCount(1, $feature->strategies()); $events = $feature->release(); - $this->assertCount(0, $events); + $this->assertCount(1, $events); + $this->assertEventIsRecorded(StrategyWasAdded::class, $events); + + /** @var StrategyWasAdded $strategyWasAdded */ + $strategyWasAdded = $events[0]; + $this->assertSame(self::FEATURE_ID, $strategyWasAdded->featureId()->value()); + $this->assertSame(self::STRATEGY_ID, $strategyWasAdded->strategyId()->value()); + $this->assertSame(self::STRATEGY_TYPE, $strategyWasAdded->strategyType()->value()); + /** @var Segment $segment */ + $segment = $strategyWasAdded->segments()[0]; + $this->assertSame(self::SEGMENT_ID, $segment->segmentId()->value()); + $this->assertSame(self::SEGMENT_TYPE, $segment->segmentType()->value()); + $this->assertSame(['foo' => 'bar'], $segment->payload()->criteria()); + $this->assertInstanceOf(DatetimeImmutable::class, $strategyWasAdded->occurredAt()); } public function testItShouldRemoveAnStrategies(): void