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

refactor: Move code from matchers to formatters #436

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/PhpPact/Consumer/Matcher/Formatters/MinimalFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace PhpPact\Consumer\Matcher\Formatters;

use PhpPact\Consumer\Matcher\Model\FormatterInterface;
use PhpPact\Consumer\Matcher\Model\GeneratorInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

class MinimalFormatter implements FormatterInterface
{
/**
* @return array<string, string>
*/
public function format(MatcherInterface $matcher, ?GeneratorInterface $generator, mixed $value): array
{
return [
'pact:matcher:type' => $matcher->getType(),
] + $matcher->getAttributes()->getData();
}
}
26 changes: 26 additions & 0 deletions src/PhpPact/Consumer/Matcher/Formatters/ValueOptionalFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace PhpPact\Consumer\Matcher\Formatters;

use PhpPact\Consumer\Matcher\Model\FormatterInterface;
use PhpPact\Consumer\Matcher\Model\GeneratorInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

class ValueOptionalFormatter implements FormatterInterface
{
/**
* @return array<string, mixed>
*/
public function format(MatcherInterface $matcher, ?GeneratorInterface $generator, mixed $value): array
{
$data = [
'pact:matcher:type' => $matcher->getType(),
];

if ($generator) {
return $data + ['pact:generator:type' => $generator->getType()] + $matcher->getAttributes()->merge($generator->getAttributes())->getData();
}

return $data + $matcher->getAttributes()->getData() + ['value' => $value];
}
}
17 changes: 17 additions & 0 deletions src/PhpPact/Consumer/Matcher/Formatters/ValueRequiredFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace PhpPact\Consumer\Matcher\Formatters;

use PhpPact\Consumer\Matcher\Model\GeneratorInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

class ValueRequiredFormatter extends ValueOptionalFormatter
{
/**
* @return array<string, mixed>
*/
public function format(MatcherInterface $matcher, ?GeneratorInterface $generator, mixed $value): array
{
return parent::format($matcher, $generator, $value) + ['value' => $value];
}
}
1 change: 1 addition & 0 deletions src/PhpPact/Consumer/Matcher/Matchers/AbstractDateTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ abstract class AbstractDateTime extends GeneratorAwareMatcher
{
public function __construct(protected string $format, private ?string $value = null)
{
parent::__construct();
}

/**
Expand Down
49 changes: 49 additions & 0 deletions src/PhpPact/Consumer/Matcher/Matchers/AbstractMatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace PhpPact\Consumer\Matcher\Matchers;

use PhpPact\Consumer\Matcher\Formatters\ValueOptionalFormatter;
use PhpPact\Consumer\Matcher\Model\Attributes;
use PhpPact\Consumer\Matcher\Model\FormatterAwareInterface;
use PhpPact\Consumer\Matcher\Model\FormatterInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

abstract class AbstractMatcher implements MatcherInterface, FormatterAwareInterface
{
private FormatterInterface $formatter;

public function __construct()
{
$this->formatter = new ValueOptionalFormatter();
}

public function setFormatter(FormatterInterface $formatter): void
{
$this->formatter = $formatter;
}

public function getFormatter(): FormatterInterface
{
return $this->formatter;
}

/**
* @return array<string, mixed>
*/
public function jsonSerialize(): array
{
return $this->getFormatter()->format($this, null, $this->getValue());
}

public function getAttributes(): Attributes
{
return new Attributes($this, $this->getAttributesData());
}

/**
* @return array<string, mixed>
*/
abstract protected function getAttributesData(): array;

abstract protected function getValue(): mixed;
}
20 changes: 13 additions & 7 deletions src/PhpPact/Consumer/Matcher/Matchers/ArrayContains.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,35 @@

namespace PhpPact\Consumer\Matcher\Matchers;

use PhpPact\Consumer\Matcher\Model\MatcherInterface;
use PhpPact\Consumer\Matcher\Formatters\MinimalFormatter;

/**
* Checks if all the variants are present in an array.
*/
class ArrayContains implements MatcherInterface
class ArrayContains extends AbstractMatcher
{
/**
* @param array<mixed> $variants
*/
public function __construct(private array $variants)
{
$this->setFormatter(new MinimalFormatter());
}

/**
* @return array<string, mixed>
*/
public function jsonSerialize(): array
protected function getAttributesData(): array
{
return [
'pact:matcher:type' => $this->getType(),
'variants' => array_values($this->variants),
];
return ['variants' => array_values($this->variants)];
}

/**
* @todo Change return type to `null`
*/
protected function getValue(): mixed
{
return null;
}

public function getType(): string
Expand Down
1 change: 1 addition & 0 deletions src/PhpPact/Consumer/Matcher/Matchers/Boolean.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public function __construct(private ?bool $value = null)
if ($value === null) {
$this->setGenerator(new RandomBoolean());
}
parent::__construct();
}

public function getType(): string
Expand Down
20 changes: 9 additions & 11 deletions src/PhpPact/Consumer/Matcher/Matchers/ContentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,24 @@

namespace PhpPact\Consumer\Matcher\Matchers;

use PhpPact\Consumer\Matcher\Model\MatcherInterface;

/**
* Match binary data by its content type (magic file check)
*/
class ContentType implements MatcherInterface
class ContentType extends AbstractMatcher
{
public function __construct(private string $contentType)
{
parent::__construct();
}

protected function getAttributesData(): array
{
return [];
}

/**
* @return array<string, string>
*/
public function jsonSerialize(): array
protected function getValue(): string
{
return [
'value' => $this->contentType,
'pact:matcher:type' => $this->getType(),
];
return $this->contentType;
}

public function getType(): string
Expand Down
1 change: 1 addition & 0 deletions src/PhpPact/Consumer/Matcher/Matchers/Decimal.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public function __construct(private ?float $value = null)
if ($value === null) {
$this->setGenerator(new RandomDecimal());
}
parent::__construct();
}

public function getType(): string
Expand Down
21 changes: 13 additions & 8 deletions src/PhpPact/Consumer/Matcher/Matchers/EachKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,31 @@
/**
* Allows defining matching rules to apply to the keys in a map
*/
class EachKey implements MatcherInterface
class EachKey extends AbstractMatcher
{
/**
* @param array<mixed>|object $value
* @param MatcherInterface[] $rules
*/
public function __construct(private object|array $value, private array $rules)
{
parent::__construct();
}

/**
* @return array<string, mixed>
* @return array<string, MatcherInterface[]>
*/
public function jsonSerialize(): array
protected function getAttributesData(): array
{
return [
'pact:matcher:type' => $this->getType(),
'value' => $this->value,
'rules' => array_map(fn (MatcherInterface $rule) => $rule, $this->rules),
];
return ['rules' => array_map(fn (MatcherInterface $rule) => $rule, $this->rules)];
}

/**
* @return array<mixed>|object
*/
protected function getValue(): object|array
{
return $this->value;
}

public function getType(): string
Expand Down
21 changes: 13 additions & 8 deletions src/PhpPact/Consumer/Matcher/Matchers/EachValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,31 @@
/**
* Allows defining matching rules to apply to the values in a collection. For maps, delgates to the Values matcher.
*/
class EachValue implements MatcherInterface
class EachValue extends AbstractMatcher
{
/**
* @param array<mixed>|object $value
* @param MatcherInterface[] $rules
*/
public function __construct(private object|array $value, private array $rules)
{
parent::__construct();
}

/**
* @return array<string, mixed>
* @return array<string, MatcherInterface[]>
*/
public function jsonSerialize(): array
protected function getAttributesData(): array
{
return [
'pact:matcher:type' => $this->getType(),
'value' => $this->value,
'rules' => array_map(fn (MatcherInterface $rule) => $rule, $this->rules),
];
return ['rules' => array_map(fn (MatcherInterface $rule) => $rule, $this->rules)];
}

/**
* @return array<mixed>|object
*/
protected function getValue(): object|array
{
return $this->value;
}

public function getType(): string
Expand Down
19 changes: 10 additions & 9 deletions src/PhpPact/Consumer/Matcher/Matchers/Equality.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,30 @@

namespace PhpPact\Consumer\Matcher\Matchers;

use PhpPact\Consumer\Matcher\Model\MatcherInterface;

/**
* This is the default matcher, and relies on the equals operator
*/
class Equality implements MatcherInterface
class Equality extends AbstractMatcher
{
/**
* @param object|array<mixed>|string|float|int|bool|null $value
*/
public function __construct(private object|array|string|float|int|bool|null $value)
{
parent::__construct();
}

protected function getAttributesData(): array
{
return [];
}

/**
* @return array<string, mixed>
* @return object|array<mixed>|string|float|int|bool|null
*/
public function jsonSerialize(): array
protected function getValue(): object|array|string|float|int|bool|null
{
return [
'pact:matcher:type' => $this->getType(),
'value' => $this->value
];
return $this->value;
}

public function getType(): string
Expand Down
29 changes: 3 additions & 26 deletions src/PhpPact/Consumer/Matcher/Matchers/GeneratorAwareMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@

use PhpPact\Consumer\Matcher\Exception\GeneratorNotRequiredException;
use PhpPact\Consumer\Matcher\Exception\GeneratorRequiredException;
use PhpPact\Consumer\Matcher\Model\Attributes;
use PhpPact\Consumer\Matcher\Model\GeneratorAwareInterface;
use PhpPact\Consumer\Matcher\Model\GeneratorInterface;
use PhpPact\Consumer\Matcher\Model\MatcherInterface;

abstract class GeneratorAwareMatcher implements MatcherInterface, GeneratorAwareInterface
abstract class GeneratorAwareMatcher extends AbstractMatcher implements GeneratorAwareInterface
{
private ?GeneratorInterface $generator = null;

Expand All @@ -28,37 +26,16 @@ public function getGenerator(): ?GeneratorInterface
*/
public function jsonSerialize(): array
{
$data = [
'pact:matcher:type' => $this->getType(),
];

if (null === $this->getValue()) {
if (!$this->generator) {
throw new GeneratorRequiredException(sprintf("Generator is required for matcher '%s' when example value is not set", $this->getType()));
}

return $data + ['pact:generator:type' => $this->generator->getType()] + $this->getMergedAttributes()->getData();
return $this->getFormatter()->format($this, $this->generator, null);
} elseif ($this->generator) {
throw new GeneratorNotRequiredException(sprintf("Generator '%s' is not required for matcher '%s' when example value is set", $this->generator->getType(), $this->getType()));
}

return $data + $this->getAttributes()->getData() + ['value' => $this->getValue()];
}

protected function getAttributes(): Attributes
{
return new Attributes($this, $this->getAttributesData());
}

protected function getMergedAttributes(): Attributes
{
return $this->getAttributes()->merge($this->generator->getAttributes());
return $this->getFormatter()->format($this, $this->generator, $this->getValue());
}

/**
* @return array<string, mixed>
*/
abstract protected function getAttributesData(): array;

abstract protected function getValue(): mixed;
}
Loading