Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#17] Add StrategyWasAdded event #44

Merged
merged 1 commit into from Nov 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/Write/Event/StrategyWasAdded.php
@@ -0,0 +1,85 @@
<?php

declare(strict_types=1);

namespace Pheature\Core\Toggle\Write\Event;

use Pheature\Core\Toggle\Write\FeatureId;
use DatetimeImmutable;
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\StrategyId;
use Pheature\Core\Toggle\Write\StrategyType;

/**
* @phpstan-import-type WriteSegment from Segment
*/
final class StrategyWasAdded
{
private string $featureId;
private DatetimeImmutable $occurredAt;
private string $strategyId;
private string $strategyType;
/** @var WriteSegment[] */
private array $segments;

/** @param WriteSegment[] $segments */
public function __construct(
string $featureId,
string $strategyId,
string $strategyType,
array $segments,
DatetimeImmutable $occurredAt
) {
$this->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
);
}
}
7 changes: 7 additions & 0 deletions src/Write/Feature.php
Expand Up @@ -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 Pheature\Core\Toggle\Write\Event\StrategyWasRemoved;

use function array_map;
Expand Down Expand Up @@ -61,6 +62,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
Expand Down
21 changes: 5 additions & 16 deletions src/Write/Payload.php
Expand Up @@ -8,41 +8,30 @@

final class Payload
{
/**
* @var array<string, mixed>
*/
/** @var array<array-key, mixed> */
private array $criteria;

/**
* @param array<string, mixed> $criteria
*/
/** @param array<array-key, mixed> $criteria */
private function __construct(array $criteria)
{
$this->criteria = $criteria;
}

/**
* @param array<string, mixed> $criteria
* @return static
*/
/** @param array<array-key, mixed> $criteria */
public static function fromArray(array $criteria): self
{
return new self($criteria);
}

public static function fromJsonString(string $jsonPayload): self
{
/**
* @var array<string, mixed> $payload
*/
/** @var array<array-key, mixed> $payload */
$payload = json_decode($jsonPayload, true, 16, JSON_THROW_ON_ERROR);

return self::fromArray($payload);
}

/**
* @return array<string, mixed>
*/
/** @return array<array-key, mixed> */
public function criteria(): array
{
return $this->criteria;
Expand Down
6 changes: 5 additions & 1 deletion src/Write/Segment.php
Expand Up @@ -6,6 +6,10 @@

use JsonSerializable;

/**
* @phpstan-type WriteSegment array{segment_id: string, segment_type: string, criteria: array<array-key, mixed>}
* @psalm-type WriteSegment array{segment_id: string, segment_type: string, criteria: array<array-key, mixed>}
*/
final class Segment implements JsonSerializable
{
private SegmentId $segmentId;
Expand Down Expand Up @@ -35,7 +39,7 @@ public function payload(): Payload
}

/**
* @return array<string, string|array<string, mixed>>
* @return WriteSegment
*/
public function jsonSerialize(): array
{
Expand Down
15 changes: 6 additions & 9 deletions src/Write/Strategy.php
Expand Up @@ -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;
Expand Down Expand Up @@ -49,15 +54,7 @@ public function segments(): array
return $this->segments;
}

/**
* @phpstan-return array<string, mixed>
* @phpstan-ignore-next-line
* @return array{
* strategy_id: string,
* strategy_type: string
* segments: array<array-key, array<string, array<string, mixed>|string>>,
* }
*/
/** @return WriteStrategy */
public function jsonSerialize(): array
{
return [
Expand Down
30 changes: 28 additions & 2 deletions test/Write/FeatureTest.php
Expand Up @@ -7,9 +7,14 @@
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\Event\StrategyWasRemoved;
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;
Expand All @@ -22,6 +27,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
{
Expand Down Expand Up @@ -87,14 +94,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 testItShouldRemoveAnStrategy(): void
Expand Down