Skip to content

Commit

Permalink
Remove internal Value class
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Dec 3, 2024
1 parent 6a40baa commit 2efa4b9
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 244 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ All Notable changes to `bakame/http-strucured-fields` will be documented in this
- `Dictionary::toPairs` and `Parameters::toPairs`
- `ByteSequence` class replaced by `Bytes` class
- `DataType::create` method use a specific DataType class instead.
- `Value` internal class.

## [1.3.0](https://github.com/bakame-php/http-structured-fields/compare/1.2.2...1.3.0) - 2024-01-05

Expand Down
137 changes: 106 additions & 31 deletions src/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@
use DateTimeImmutable;
use DateTimeInterface;
use DateTimeZone;
use Exception;
use Stringable;
use Throwable;

use function array_is_list;
use function count;

use const JSON_PRESERVE_ZERO_FRACTION;
use const PHP_ROUND_HALF_EVEN;

/**
* @see https://www.rfc-editor.org/rfc/rfc9651.html#section-3.3
*
Expand All @@ -25,8 +30,21 @@ final class Item
{
use ParameterAccess;

private function __construct(private readonly Value $value, private readonly Parameters $parameters)
private readonly Token|Bytes|DisplayString|DateTimeImmutable|int|float|string|bool $value;
private readonly Type $type;
private readonly Parameters $parameters;

private function __construct(Item|Token|Bytes|DisplayString|DateTimeInterface|int|float|string|bool $value, Parameters $parameters)
{
if ($value instanceof DateTimeInterface && !$value instanceof DateTimeImmutable) {
$value = DateTimeImmutable::createFromInterface($value);
}

[$this->value, $this->type] = match (true) {
$value instanceof Item => [$value->value(), $value->type()],
default => [$value, Type::fromVariable($value)],
};
$this->parameters = $parameters;
}

public static function fromRfc9651(Stringable|string $httpValue): self
Expand Down Expand Up @@ -74,7 +92,7 @@ public static function fromAssociative(
$parameters = Parameters::fromAssociative($parameters);
}

return new self(new Value($value), $parameters);
return new self($value, $parameters);
}

/**
Expand All @@ -101,7 +119,7 @@ public static function fromPair(array $pair): self
}

if (1 === count($pair)) {
return new self(new Value($pair[0]), Parameters::new());
return new self($pair[0], Parameters::new());
}

if ($pair[1] instanceof StructuredFieldProvider) {
Expand All @@ -112,7 +130,7 @@ public static function fromPair(array $pair): self
$pair[1] = Parameters::fromPairs($pair[1]);
}

return new self(new Value($pair[0]), $pair[1]);
return new self($pair[0], $pair[1]);
}

/**
Expand All @@ -125,14 +143,14 @@ public static function fromPair(array $pair): self
public static function new(mixed $value): self
{
if ($value instanceof Item) {
return new self(new Value($value->value()), $value->parameters());
return new self($value->value(), $value->parameters());
}

if (is_array($value)) {
return self::fromPair($value);
}

return self::fromValue(new Value($value)); /* @phpstan-ignore-line */
return self::fromValue($value); /* @phpstan-ignore-line */
}

/**
Expand All @@ -152,7 +170,7 @@ public static function tryNew(StructuredFieldProvider|Item|DateTimeInterface|Byt
/**
* Returns a new bare instance from value.
*/
private static function fromValue(Value $value): self
private static function fromValue(Item|Token|Bytes|DisplayString|DateTimeInterface|int|float|string|bool $value): self
{
return new self($value, Parameters::new());
}
Expand All @@ -164,7 +182,7 @@ private static function fromValue(Value $value): self
*/
public static function fromString(Stringable|string $value): self
{
return self::fromValue(Value::fromString($value));
return self::fromValue((string) $value);
}

/**
Expand All @@ -174,7 +192,7 @@ public static function fromString(Stringable|string $value): self
*/
public static function fromEncodedBytes(Stringable|string $value): self
{
return self::fromValue(Value::fromEncodedBytes($value));
return self::fromValue(Bytes::fromEncoded($value));
}

/**
Expand All @@ -184,7 +202,7 @@ public static function fromEncodedBytes(Stringable|string $value): self
*/
public static function fromDecodedBytes(Stringable|string $value): self
{
return self::fromValue(Value::fromDecodedBytes($value));
return self::fromValue(Bytes::fromDecoded($value));
}

/**
Expand All @@ -194,7 +212,7 @@ public static function fromDecodedBytes(Stringable|string $value): self
*/
public static function fromEncodedDisplayString(Stringable|string $value): self
{
return self::fromValue(Value::fromEncodedDisplayString($value));
return self::fromValue(DisplayString::fromEncoded($value));
}

/**
Expand All @@ -204,7 +222,7 @@ public static function fromEncodedDisplayString(Stringable|string $value): self
*/
public static function fromDecodedDisplayString(Stringable|string $value): self
{
return self::fromValue(Value::fromDecodedDisplayString($value));
return self::fromValue(DisplayString::fromDecoded($value));
}

/**
Expand All @@ -214,7 +232,7 @@ public static function fromDecodedDisplayString(Stringable|string $value): self
*/
public static function fromToken(Stringable|string $value): self
{
return self::fromValue(Value::fromToken($value));
return self::fromValue(Token::fromString($value));
}

/**
Expand All @@ -224,7 +242,7 @@ public static function fromToken(Stringable|string $value): self
*/
public static function fromTimestamp(int $timestamp): self
{
return self::fromValue(Value::fromTimestamp($timestamp));
return self::fromValue((new DateTimeImmutable())->setTimestamp($timestamp));
}

/**
Expand All @@ -234,7 +252,16 @@ public static function fromTimestamp(int $timestamp): self
*/
public static function fromDateFormat(string $format, string $datetime): self
{
return self::fromValue(Value::fromDateFormat($format, $datetime));
try {
$value = DateTimeImmutable::createFromFormat($format, $datetime);
} catch (Exception $exception) {
throw new SyntaxError('The date notation `'.$datetime.'` is incompatible with the date format `'.$format.'`.', 0, $exception);
}

return match (false) {
$value => throw new SyntaxError('The date notation `'.$datetime.'` is incompatible with the date format `'.$format.'`.'),
default => self::fromDate($value),
};
}

/**
Expand All @@ -244,7 +271,22 @@ public static function fromDateFormat(string $format, string $datetime): self
*/
public static function fromDateString(string $datetime, DateTimeZone|string|null $timezone = null): self
{
return self::fromValue(Value::fromDateString($datetime, $timezone));
$timezone ??= date_default_timezone_get();
if (!$timezone instanceof DateTimeZone) {
try {
$timezone = new DateTimeZone($timezone);
} catch (Throwable $exception) {
throw new SyntaxError('The timezone could not be instantiated.', 0, $exception);
}
}

try {
$value = new DateTimeImmutable($datetime, $timezone);
} catch (Throwable $exception) {
throw new SyntaxError('Unable to create a '.DateTimeImmutable::class.' instance with the date notation `'.$datetime.'.`', 0, $exception);
}

return self::fromDate($value);
}

/**
Expand All @@ -254,7 +296,7 @@ public static function fromDateString(string $datetime, DateTimeZone|string|null
*/
public static function fromDate(DateTimeInterface $datetime): self
{
return self::fromValue(Value::fromDate($datetime));
return self::fromValue($datetime);
}

/**
Expand All @@ -264,7 +306,7 @@ public static function fromDate(DateTimeInterface $datetime): self
*/
public static function fromDecimal(int|float $value): self
{
return self::fromValue(Value::fromDecimal($value));
return self::fromValue((float) $value);
}

/**
Expand All @@ -274,23 +316,23 @@ public static function fromDecimal(int|float $value): self
*/
public static function fromInteger(int|float $value): self
{
return self::fromValue(Value::fromInteger($value));
return self::fromValue((int) $value);
}

/**
* Returns a new instance for the boolean true type.
*/
public static function true(): self
{
return self::fromValue(Value::true());
return self::fromValue(true);
}

/**
* Returns a new instance for the boolean false type.
*/
public static function false(): self
{
return self::fromValue(Value::false());
return self::fromValue(false);
}

/**
Expand All @@ -306,7 +348,7 @@ public static function false(): self
*/
public function value(?callable $validate = null): Bytes|Token|DisplayString|DateTimeImmutable|string|int|float|bool
{
$value = $this->value->value;
$value = $this->value;
if (null === $validate) {
return $value;
}
Expand All @@ -320,12 +362,12 @@ public function value(?callable $validate = null): Bytes|Token|DisplayString|Dat
$exceptionMessage = "The item value '{value}' failed validation.";
}

throw new Violation(strtr($exceptionMessage, ['{value}' => $this->value->serialize()]));
throw new Violation(strtr($exceptionMessage, ['{value}' => $this->serialize()]));
}

public function type(): Type
{
return $this->value->type;
return $this->type;
}

/**
Expand All @@ -337,7 +379,34 @@ public function toHttpValue(?Ietf $rfc = Ietf::Rfc9651): string
{
$rfc ??= Ietf::Rfc9651;

return $this->value->serialize($rfc).$this->parameters->toHttpValue($rfc);
return $this->serialize($rfc).$this->parameters->toHttpValue($rfc);
}

/**
* Serialize the Item value according to RFC8941.
*
* @see https://www.rfc-editor.org/rfc/rfc9651.html#section-4.1
*/
private function serialize(?Ietf $rfc = Ietf::Rfc9651): string
{
$rfc ??= Ietf::Rfc9651;
if (!$rfc->supports($this->type)) {
throw MissingFeature::dueToLackOfSupport($this->type(), $rfc);
}

$value = $this->value;

return match (true) {
$value instanceof DateTimeImmutable => '@'.$value->getTimestamp(),
$value instanceof Token => $value->toString(),
$value instanceof Bytes => ':'.$value->encoded().':',
$value instanceof DisplayString => '%"'.$value->encoded().'"',
is_int($value) => (string) $value,
is_float($value) => (string) json_encode(round($value, 3, PHP_ROUND_HALF_EVEN), JSON_PRESERVE_ZERO_FRACTION),
$value,
false === $value => '?'.($value ? '1' : '0'),
default => '"'.preg_replace('/(["\\\])/', '\\\$1', $value).'"',
};
}

public function toRfc9651(): string
Expand All @@ -360,7 +429,7 @@ public function __toString(): string
*/
public function toPair(): array
{
return [$this->value->value, $this->parameters];
return [$this->value, $this->parameters];
}

public function equals(mixed $other): bool
Expand Down Expand Up @@ -396,11 +465,17 @@ public function when(callable|bool $condition, callable $onSuccess, ?callable $o
*
* @throws SyntaxError If the value is invalid or not supported
*/
public function withValue(
DateTimeInterface|Bytes|Token|DisplayString|string|int|float|bool $value
): self {
$value = new Value($value);
if ($value->equals($this->value)) {
public function withValue(DateTimeInterface|Bytes|Token|DisplayString|string|int|float|bool $value): self
{
$isEqual = match (true) {
$this->value instanceof Bytes,
$this->value instanceof Token,
$this->value instanceof DisplayString => $this->value->equals($value),
$this->value instanceof DateTimeInterface && $value instanceof DateTimeInterface => $value == $this->value,
default => $value === $this->value,
};

if ($isEqual) {
return $this;
}

Expand Down
Loading

0 comments on commit 2efa4b9

Please sign in to comment.