Skip to content

Commit

Permalink
Simplify Key/Value Converter implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Aug 19, 2023
1 parent 870dd3d commit 3e34e6d
Showing 1 changed file with 42 additions and 37 deletions.
79 changes: 42 additions & 37 deletions interfaces/KeyValuePair/Converter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Stringable;
use function explode;
use function implode;
use function is_string;
use function preg_match;
use function str_replace;
use const PHP_QUERY_RFC1738;
Expand All @@ -29,12 +30,12 @@ final class Converter

/**
* @param non-empty-string $separator
* @param array<string> $toRFC3986Encoding
* @param array<string> $toEncoding
* @param array<string> $fromRfc3986 contains all the RFC3986 encoded characters to be converted
* @param array<string> $toEncoding contains all the expected encoded characters
*/
private function __construct(
private readonly string $separator,
private readonly array $toRFC3986Encoding = [],
private readonly array $fromRfc3986 = [],
private readonly array $toEncoding = [],
) {
}
Expand All @@ -61,8 +62,7 @@ public static function fromRFC3986(string $separator = '&'): self
public static function fromRFC1738(string $separator = '&'): self
{
return self::new($separator)
->withRfc3986Output('%20')
->withEncodingOutput('+');
->withEncodingMap(['%20' => '+']);
}

public static function fromEncodingType(int $encType): self
Expand All @@ -79,13 +79,25 @@ public static function fromEncodingType(int $encType): self
*/
public function toPairs(Stringable|string|bool|null $value): array
{
$filteredValue = $this->filterValue($value);
$value = match (true) {
$value instanceof UriComponentInterface => $value->value(),
$value instanceof Stringable => (string) $value,
default => $value,
};

$value = match (true) {
null === $value => null,
false === $value => '0',
true === $value => '1',
1 === preg_match(self::REGEXP_INVALID_CHARS, $value) => throw new SyntaxError('Invalid query string: `'.$value.'`.'),
default => str_replace($this->toEncoding, $this->fromRfc3986, $value),
};

return array_map(
fn (string $pair): array => explode('=', $pair, 2) + [1 => null],
match (true) {
null === $filteredValue => [],
default => explode($this->separator, $filteredValue),
null === $value => [],
default => explode($this->separator, $value),
}
);
}
Expand All @@ -106,7 +118,7 @@ public function toValue(iterable $pairs): ?string

return match (true) {
[] === $filteredPairs => null,
default => str_replace($this->toRFC3986Encoding, $this->toEncoding, implode($this->separator, $filteredPairs)),
default => str_replace($this->fromRfc3986, $this->toEncoding, implode($this->separator, $filteredPairs)),
};
}

Expand All @@ -118,40 +130,33 @@ public function withSeparator(string $separator): self
return match (true) {
'' === $separator => throw new SyntaxError('The separator character can not be the empty string.'), /* @phpstan-ignore-line */
$separator === $this->separator => $this,
default => new self($separator, $this->toRFC3986Encoding, $this->toEncoding),
};
}

public function withRfc3986Output(string ...$encoding): self
{
return match (true) {
$encoding === $this->toRFC3986Encoding => $this,
default => new self($this->separator, $encoding, $this->toEncoding),
};
}

public function withEncodingOutput(string ...$encoding): self
{
return match (true) {
$encoding === $this->toEncoding => $this,
default => new self($this->separator, $this->toRFC3986Encoding, $encoding),
default => new self($separator, $this->fromRfc3986, $this->toEncoding),
};
}

private function filterValue(Stringable|string|bool|null $query): ?string
/**
* Sets the conversion map.
*
* Each key from the iterable structure represents the RFC3986 encoded characters as string,
* while eache value represents the expected output encoded characters
*/
public function withEncodingMap(iterable $encodingMap): self
{
$query = match (true) {
$query instanceof UriComponentInterface => $query->value(),
$query instanceof Stringable => (string) $query,
default => $query,
};
$fromRfc3986 = [];
$toEncoding = [];
foreach ($encodingMap as $from => $to) {
[$fromRfc3986[], $toEncoding[]] = match (true) {
!is_string($from) => throw new SyntaxError('The encoding output must be a string; `'.gettype($from).'` given.'),
$to instanceof Stringable,
is_string($to) => [$from, (string) $to],
default => throw new SyntaxError('The encoding output must be a string; `'.gettype($to).'` given.'),
};
}

return match (true) {
null === $query => null,
false === $query => '0',
true === $query => '1',
1 === preg_match(self::REGEXP_INVALID_CHARS, $query) => throw new SyntaxError('Invalid query string: `'.$query.'`.'),
default => str_replace($this->toEncoding, $this->toRFC3986Encoding, $query),
$fromRfc3986 !== $this->fromRfc3986,
$toEncoding !== $this->toEncoding => new self($this->separator, $fromRfc3986, $toEncoding),
default => $this,
};
}
}

0 comments on commit 3e34e6d

Please sign in to comment.