From 2ad83a4e20d1d1d523fa490bc7db53b48c9fd032 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 17:12:40 +0200 Subject: [PATCH 01/51] avoid keeping header objects in memory when not necessary --- src/Header/Age.php | 21 +++++++++++---------- src/Header/Authorization.php | 21 +++++++++++---------- src/Header/ContentLength.php | 21 +++++++++++---------- src/Header/ContentLocation.php | 21 +++++++++++---------- src/Header/ContentRange.php | 21 +++++++++++---------- src/Header/ContentType.php | 21 +++++++++++---------- src/Header/Cookie.php | 21 +++++++++++---------- src/Header/Date.php | 21 +++++++++++---------- src/Header/Expires.php | 21 +++++++++++---------- src/Header/Host.php | 21 +++++++++++---------- src/Header/IfModifiedSince.php | 21 +++++++++++---------- src/Header/IfUnmodifiedSince.php | 21 +++++++++++---------- src/Header/LastModified.php | 21 +++++++++++---------- src/Header/Location.php | 23 ++++++++++++----------- src/Header/Range.php | 21 +++++++++++---------- src/Header/Referrer.php | 21 +++++++++++---------- src/Header/SetCookie.php | 13 ++++++++----- 17 files changed, 185 insertions(+), 166 deletions(-) diff --git a/src/Header/Age.php b/src/Header/Age.php index 68e212e..10b1182 100644 --- a/src/Header/Age.php +++ b/src/Header/Age.php @@ -11,13 +11,9 @@ */ final class Age implements HeaderInterface { - private Header $header; - private AgeValue $value; - - public function __construct(AgeValue $age) - { - $this->header = new Header('Age', $age); - $this->value = $age; + public function __construct( + private AgeValue $value, + ) { } /** @@ -31,13 +27,13 @@ public static function of(int $age): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } /** @@ -51,6 +47,11 @@ public function age(): int #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Age', $this->value); } } diff --git a/src/Header/Authorization.php b/src/Header/Authorization.php index c8ada45..fc6f414 100644 --- a/src/Header/Authorization.php +++ b/src/Header/Authorization.php @@ -11,13 +11,9 @@ */ final class Authorization implements HeaderInterface { - private Header $header; - private AuthorizationValue $value; - - public function __construct(AuthorizationValue $authorization) - { - $this->header = new Header('Authorization', $authorization); - $this->value = $authorization; + public function __construct( + private AuthorizationValue $value, + ) { } /** @@ -31,13 +27,13 @@ public static function of(string $scheme, string $parameter): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function scheme(): string @@ -53,6 +49,11 @@ public function parameter(): string #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Authorization', $this->value); } } diff --git a/src/Header/ContentLength.php b/src/Header/ContentLength.php index 2d733ce..5418e64 100644 --- a/src/Header/ContentLength.php +++ b/src/Header/ContentLength.php @@ -11,13 +11,9 @@ */ final class ContentLength implements HeaderInterface { - private Header $header; - private ContentLengthValue $value; - - public function __construct(ContentLengthValue $length) - { - $this->header = new Header('Content-Length', $length); - $this->value = $length; + public function __construct( + private ContentLengthValue $value, + ) { } /** @@ -31,13 +27,13 @@ public static function of(int $length): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } /** @@ -51,6 +47,11 @@ public function length(): int #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Content-Length', $this->value); } } diff --git a/src/Header/ContentLocation.php b/src/Header/ContentLocation.php index 80c0037..23ac048 100644 --- a/src/Header/ContentLocation.php +++ b/src/Header/ContentLocation.php @@ -12,13 +12,9 @@ */ final class ContentLocation implements HeaderInterface { - private Header $header; - private LocationValue $value; - - public function __construct(LocationValue $location) - { - $this->header = new Header('Content-Location', $location); - $this->value = $location; + public function __construct( + private LocationValue $value, + ) { } /** @@ -32,13 +28,13 @@ public static function of(Url $location): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function url(): Url @@ -49,6 +45,11 @@ public function url(): Url #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Content-Location', $this->value); } } diff --git a/src/Header/ContentRange.php b/src/Header/ContentRange.php index 93173d9..6e6d258 100644 --- a/src/Header/ContentRange.php +++ b/src/Header/ContentRange.php @@ -11,13 +11,9 @@ */ final class ContentRange implements HeaderInterface { - private Header $header; - private ContentRangeValue $range; - - public function __construct(ContentRangeValue $range) - { - $this->header = new Header('Content-Range', $range); - $this->range = $range; + public function __construct( + private ContentRangeValue $range, + ) { } /** @@ -40,13 +36,13 @@ public static function of( #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function range(): ContentRangeValue @@ -57,6 +53,11 @@ public function range(): ContentRangeValue #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Content-Range', $this->range); } } diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index 5e94d1a..ab9fc92 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -11,13 +11,9 @@ */ final class ContentType implements HeaderInterface { - private Header $header; - private ContentTypeValue $content; - - public function __construct(ContentTypeValue $content) - { - $this->header = new Header('Content-Type', $content); - $this->content = $content; + public function __construct( + private ContentTypeValue $content, + ) { } /** @@ -38,13 +34,13 @@ public static function of( #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function content(): ContentTypeValue @@ -55,6 +51,11 @@ public function content(): ContentTypeValue #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Content-Type', $this->content); } } diff --git a/src/Header/Cookie.php b/src/Header/Cookie.php index 18cd2e9..ba2c4e5 100644 --- a/src/Header/Cookie.php +++ b/src/Header/Cookie.php @@ -14,13 +14,9 @@ */ final class Cookie implements HeaderInterface { - private Header $header; - private CookieValue $value; - - public function __construct(CookieValue $value) - { - $this->header = new Header('Cookie', $value); - $this->value = $value; + public function __construct( + private CookieValue $value, + ) { } /** @@ -35,13 +31,13 @@ public static function of(Parameter ...$parameters): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } /** @@ -55,6 +51,11 @@ public function parameters(): Map #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Cookie', $this->value); } } diff --git a/src/Header/Date.php b/src/Header/Date.php index 28fc48c..36f0e8d 100644 --- a/src/Header/Date.php +++ b/src/Header/Date.php @@ -12,13 +12,9 @@ */ final class Date implements HeaderInterface { - private Header $header; - private DateValue $value; - - public function __construct(DateValue $date) - { - $this->header = new Header('Date', $date); - $this->value = $date; + public function __construct( + private DateValue $value, + ) { } /** @@ -32,13 +28,13 @@ public static function of(PointInTime $point): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function date(): PointInTime @@ -49,6 +45,11 @@ public function date(): PointInTime #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Date', $this->value); } } diff --git a/src/Header/Expires.php b/src/Header/Expires.php index d0208fe..d512103 100644 --- a/src/Header/Expires.php +++ b/src/Header/Expires.php @@ -12,13 +12,9 @@ */ final class Expires implements HeaderInterface { - private Header $header; - private DateValue $value; - - public function __construct(DateValue $date) - { - $this->header = new Header('Expires', $date); - $this->value = $date; + public function __construct( + private DateValue $value, + ) { } /** @@ -32,13 +28,13 @@ public static function of(PointInTime $point): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function date(): PointInTime @@ -49,6 +45,11 @@ public function date(): PointInTime #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Expires', $this->value); } } diff --git a/src/Header/Host.php b/src/Header/Host.php index b8fd608..e569297 100644 --- a/src/Header/Host.php +++ b/src/Header/Host.php @@ -15,13 +15,9 @@ */ final class Host implements HeaderInterface { - private Header $header; - private HostValue $value; - - public function __construct(HostValue $host) - { - $this->header = new Header('Host', $host); - $this->value = $host; + public function __construct( + private HostValue $value, + ) { } /** @@ -35,13 +31,13 @@ public static function of(UrlHost $host, Port $port): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function host(): UrlHost @@ -57,6 +53,11 @@ public function port(): Port #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Host', $this->value); } } diff --git a/src/Header/IfModifiedSince.php b/src/Header/IfModifiedSince.php index 5431961..19cd865 100644 --- a/src/Header/IfModifiedSince.php +++ b/src/Header/IfModifiedSince.php @@ -12,13 +12,9 @@ */ final class IfModifiedSince implements HeaderInterface { - private Header $header; - private DateValue $value; - - public function __construct(DateValue $date) - { - $this->header = new Header('If-Modified-Since', $date); - $this->value = $date; + public function __construct( + private DateValue $value, + ) { } /** @@ -32,13 +28,13 @@ public static function of(PointInTime $point): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function date(): PointInTime @@ -49,6 +45,11 @@ public function date(): PointInTime #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('If-Modified-Since', $this->value); } } diff --git a/src/Header/IfUnmodifiedSince.php b/src/Header/IfUnmodifiedSince.php index 92e6de5..0029d85 100644 --- a/src/Header/IfUnmodifiedSince.php +++ b/src/Header/IfUnmodifiedSince.php @@ -12,13 +12,9 @@ */ final class IfUnmodifiedSince implements HeaderInterface { - private Header $header; - private DateValue $value; - - public function __construct(DateValue $date) - { - $this->header = new Header('If-Unmodified-Since', $date); - $this->value = $date; + public function __construct( + private DateValue $value, + ) { } /** @@ -32,13 +28,13 @@ public static function of(PointInTime $point): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function date(): PointInTime @@ -49,6 +45,11 @@ public function date(): PointInTime #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('If-Unmodified-Since', $this->value); } } diff --git a/src/Header/LastModified.php b/src/Header/LastModified.php index 0f796c9..b8f88ae 100644 --- a/src/Header/LastModified.php +++ b/src/Header/LastModified.php @@ -12,13 +12,9 @@ */ final class LastModified implements HeaderInterface { - private Header $header; - private DateValue $value; - - public function __construct(DateValue $date) - { - $this->header = new Header('Last-Modified', $date); - $this->value = $date; + public function __construct( + private DateValue $value, + ) { } /** @@ -32,13 +28,13 @@ public static function of(PointInTime $point): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function date(): PointInTime @@ -49,6 +45,11 @@ public function date(): PointInTime #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Last-Modified', $this->value); } } diff --git a/src/Header/Location.php b/src/Header/Location.php index e32ace4..0d3cacc 100644 --- a/src/Header/Location.php +++ b/src/Header/Location.php @@ -12,13 +12,9 @@ */ final class Location implements HeaderInterface { - private Header $header; - private Url $url; - - public function __construct(LocationValue $location) - { - $this->header = new Header('Location', $location); - $this->url = $location->url(); + public function __construct( + private LocationValue $location, + ) { } /** @@ -32,23 +28,28 @@ public static function of(Url $location): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function url(): Url { - return $this->url; + return $this->location->url(); } #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Location', $this->location); } } diff --git a/src/Header/Range.php b/src/Header/Range.php index 73df1e5..ffdf38c 100644 --- a/src/Header/Range.php +++ b/src/Header/Range.php @@ -11,13 +11,9 @@ */ final class Range implements HeaderInterface { - private Header $header; - private RangeValue $range; - - public function __construct(RangeValue $range) - { - $this->header = new Header('Range', $range); - $this->range = $range; + public function __construct( + private RangeValue $range, + ) { } /** @@ -38,13 +34,13 @@ public static function of( #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function range(): RangeValue @@ -55,6 +51,11 @@ public function range(): RangeValue #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Range', $this->range); } } diff --git a/src/Header/Referrer.php b/src/Header/Referrer.php index 06abc1b..52dc60c 100644 --- a/src/Header/Referrer.php +++ b/src/Header/Referrer.php @@ -12,13 +12,9 @@ */ final class Referrer implements HeaderInterface { - private Header $header; - private ReferrerValue $referrer; - - public function __construct(ReferrerValue $referrer) - { - $this->header = new Header('Referer', $referrer); - $this->referrer = $referrer; + public function __construct( + private ReferrerValue $referrer, + ) { } /** @@ -32,13 +28,13 @@ public static function of(Url $referrer): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } public function referrer(): Url @@ -49,6 +45,11 @@ public function referrer(): Url #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Referer', $this->referrer); } } diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index d1cface..3c8d986 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -11,7 +11,6 @@ */ final class SetCookie implements HeaderInterface { - private Header $header; /** @var Sequence */ private Sequence $cookies; @@ -20,7 +19,6 @@ final class SetCookie implements HeaderInterface */ public function __construct(CookieValue ...$values) { - $this->header = new Header('Set-Cookie', ...$values); $this->cookies = Sequence::of(...$values); } @@ -36,13 +34,13 @@ public static function of(Parameter ...$values): self #[\Override] public function name(): string { - return $this->header->name(); + return $this->header()->name(); } #[\Override] public function values(): Sequence { - return $this->header->values(); + return $this->header()->values(); } /** @@ -56,6 +54,11 @@ public function cookies(): Sequence #[\Override] public function toString(): string { - return $this->header->toString(); + return $this->header()->toString(); + } + + private function header(): Header + { + return new Header('Set-Cookie', ...$this->cookies->toList()); } } From eb9ea727216cca87ae68575c79b29edcddc41de5 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 17:25:18 +0200 Subject: [PATCH 02/51] remove AcceptRangesValue --- CHANGELOG.md | 2 + src/Factory/Header/Factories.php | 5 +-- src/Header/AcceptRanges.php | 43 ++++++++++++++----- src/Header/AcceptRangesValue.php | 48 ---------------------- tests/Header/AcceptRangesTest.php | 57 ++++++++++++++++++-------- tests/Header/AcceptRangesValueTest.php | 44 -------------------- 6 files changed, 75 insertions(+), 124 deletions(-) delete mode 100644 src/Header/AcceptRangesValue.php delete mode 100644 tests/Header/AcceptRangesValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 287500e..4d06f71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - `Innmind\Http\Factory\HeadersFactory` is now a final class - Classes in `Innmind\Http\Factory\Header\` are now internal - `Innmind\Http\Header::values()` now returns an `Innmind\Immutable\Sequence` to allow for ordered values +- `Innmind\Http\Header\AcceptRanges` constructor is now private, use `::of()` or `::maybe()` named constructors ### Removed @@ -28,6 +29,7 @@ - `Innmind\Http\Factory\ServerRequest\ServerRequestFactory` - `Innmind\Http\Factory\Header\HeadersFactory` - `Innmind\Http\Factory\HeaderFactory` +- `Innmind\Http\Header\AcceptRangesValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 1e75629..66330a0 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -14,7 +14,6 @@ Header\AcceptLanguage, Header\AcceptLanguageValue, Header\AcceptRanges, - Header\AcceptRangesValue, Header\Age, Header\AgeValue, Header\Allow, @@ -241,9 +240,7 @@ public function try(Clock $clock, Str $value): Maybe ->maybe(static fn($values, $value) => $value->map($values)) ->map(static fn($values) => new AcceptLanguage(...$values->toList())), - self::acceptRanges => AcceptRangesValue::of($value->toString())->map( - static fn($value) => new AcceptRanges($value), - ), + self::acceptRanges => AcceptRanges::maybe($value->toString()), self::age => Maybe::just($value->toString()) ->filter(\is_numeric(...)) diff --git a/src/Header/AcceptRanges.php b/src/Header/AcceptRanges.php index 617b235..8d55f8f 100644 --- a/src/Header/AcceptRanges.php +++ b/src/Header/AcceptRanges.php @@ -3,44 +3,67 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; +use Innmind\Http\{ + Header as HeaderInterface, + Exception\DomainException, +}; +use Innmind\Immutable\{ + Sequence, + Str, + Maybe, +}; /** * @psalm-immutable */ final class AcceptRanges implements HeaderInterface { - private Header $header; + private function __construct( + private string $ranges, + ) { + } - public function __construct(AcceptRangesValue $ranges) + /** + * @psalm-pure + * + * @throws DomainException + */ + public static function of(string $range): self { - $this->header = new Header('Accept-Ranges', $ranges); + return self::maybe($range)->match( + static fn($self) => $self, + static fn() => throw new DomainException($range), + ); } /** * @psalm-pure + * + * @return Maybe */ - public static function of(string $range): self + public static function maybe(string $range): Maybe { - return new self(new AcceptRangesValue($range)); + return Maybe::just($range) + ->map(Str::of(...)) + ->filter(static fn($range) => $range->matches('~^\w+$~')) + ->map(static fn() => new self($range)); } #[\Override] public function name(): string { - return $this->header->name(); + return 'Accept-Ranges'; } #[\Override] public function values(): Sequence { - return $this->header->values(); + return Sequence::of(new Value\Value($this->ranges)); } #[\Override] public function toString(): string { - return $this->header->toString(); + return (new Header($this->name(), ...$this->values()->toList()))->toString(); } } diff --git a/src/Header/AcceptRangesValue.php b/src/Header/AcceptRangesValue.php deleted file mode 100644 index 58d9bbd..0000000 --- a/src/Header/AcceptRangesValue.php +++ /dev/null @@ -1,48 +0,0 @@ -matches('~^\w+$~')) { - throw new DomainException($range); - } - - $this->range = $range; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(string $range): Maybe - { - try { - return Maybe::just(new self($range)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - #[\Override] - public function toString(): string - { - return $this->range; - } -} diff --git a/tests/Header/AcceptRangesTest.php b/tests/Header/AcceptRangesTest.php index 727b042..d74207d 100644 --- a/tests/Header/AcceptRangesTest.php +++ b/tests/Header/AcceptRangesTest.php @@ -6,38 +6,59 @@ use Innmind\Http\{ Header\AcceptRanges, Header, - Header\AcceptRangesValue }; use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; class AcceptRangesTest extends TestCase { - public function testInterface() - { - $h = new AcceptRanges( - $ar = new AcceptRangesValue('bytes'), - ); - - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Accept-Ranges', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($ar, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); - $this->assertSame('Accept-Ranges: bytes', $h->toString()); - } - public function testOf() { $header = AcceptRanges::of('bytes'); $this->assertInstanceOf(AcceptRanges::class, $header); + $this->assertInstanceOf(Header::class, $header); $this->assertSame('Accept-Ranges', $header->name()); $values = $header->values(); $this->assertInstanceOf(Sequence::class, $values); $this->assertSame('Accept-Ranges: bytes', $header->toString()); } + + public function testValid() + { + $this->assertInstanceOf( + AcceptRanges::class, + AcceptRanges::of('bytes'), + ); + $this->assertInstanceOf( + AcceptRanges::class, + AcceptRanges::of('none'), + ); + $this->assertInstanceOf( + AcceptRanges::class, + AcceptRanges::of('whatever'), + ); + } + + #[DataProvider('invalids')] + public function testReturnNothingWhenInvalidAcceptRangeValue($value) + { + $this->expectException(DomainException::class); + $this->expectExceptionMessage($value); + + $this->assertNull(AcceptRanges::maybe($value)->match( + static fn($header) => $header, + static fn() => null, + )); + } + + public static function invalids(): array + { + return [ + ['*'], + ['foo/bar'], + ['bar;q=0.8'], + ]; + } } diff --git a/tests/Header/AcceptRangesValueTest.php b/tests/Header/AcceptRangesValueTest.php deleted file mode 100644 index bab123d..0000000 --- a/tests/Header/AcceptRangesValueTest.php +++ /dev/null @@ -1,44 +0,0 @@ -assertInstanceOf(Value::class, $a); - $this->assertSame('bytes', $a->toString()); - - new AcceptRangesValue('none'); - new AcceptRangesValue('whatever'); - } - - #[DataProvider('invalids')] - public function testThrowWhenInvalidAcceptRangeValue($value) - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage($value); - - new AcceptRangesValue($value); - } - - public static function invalids(): array - { - return [ - ['*'], - ['foo/bar'], - ['bar;q=0.8'], - ]; - } -} From 686524217fcd7c47fb97bc0d52b896fdfecb4b05 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 17:31:49 +0200 Subject: [PATCH 03/51] remove AgeValue --- CHANGELOG.md | 2 ++ src/Factory/Header/Factories.php | 4 +-- src/Header/Age.php | 35 ++++++++++++++++---- src/Header/AgeValue.php | 55 -------------------------------- tests/Header/AgeTest.php | 28 ++++++---------- tests/Header/AgeValueTest.php | 32 ------------------- 6 files changed, 40 insertions(+), 116 deletions(-) delete mode 100644 src/Header/AgeValue.php delete mode 100644 tests/Header/AgeValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d06f71..6841675 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Classes in `Innmind\Http\Factory\Header\` are now internal - `Innmind\Http\Header::values()` now returns an `Innmind\Immutable\Sequence` to allow for ordered values - `Innmind\Http\Header\AcceptRanges` constructor is now private, use `::of()` or `::maybe()` named constructors +- `Innmind\Http\Header\Age` constructor is now private, use `::of()` or `::maybe()` named constructors ### Removed @@ -30,6 +31,7 @@ - `Innmind\Http\Factory\Header\HeadersFactory` - `Innmind\Http\Factory\HeaderFactory` - `Innmind\Http\Header\AcceptRangesValue` +- `Innmind\Http\Header\AgeValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 66330a0..8506094 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -15,7 +15,6 @@ Header\AcceptLanguageValue, Header\AcceptRanges, Header\Age, - Header\AgeValue, Header\Allow, Header\AllowValue, Header\Authorization, @@ -245,8 +244,7 @@ public function try(Clock $clock, Str $value): Maybe self::age => Maybe::just($value->toString()) ->filter(\is_numeric(...)) ->map(static fn($age) => (int) $age) - ->flatMap(AgeValue::of(...)) - ->map(static fn($value) => new Age($value)), + ->flatMap(Age::maybe(...)), self::allow => $value ->split(',') diff --git a/src/Header/Age.php b/src/Header/Age.php index 10b1182..478a3dd 100644 --- a/src/Header/Age.php +++ b/src/Header/Age.php @@ -4,24 +4,45 @@ namespace Innmind\Http\Header; use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; +use Innmind\Immutable\{ + Sequence, + Maybe, +}; /** * @psalm-immutable */ final class Age implements HeaderInterface { - public function __construct( - private AgeValue $value, + /** + * @param int<0, max> $age + */ + private function __construct( + private int $age, ) { } /** * @psalm-pure + * + * @param int<0, max> $age */ public static function of(int $age): self { - return new self(new AgeValue($age)); + return new self($age); + } + + /** + * @psalm-pure + * + * @return Maybe + */ + public static function maybe(int $age): Maybe + { + return Maybe::of(match (true) { + $age >= 0 => $age, + default => null, + })->map(static fn($age) => new self($age)); } #[\Override] @@ -37,11 +58,11 @@ public function values(): Sequence } /** - * @return 0|positive-int + * @return int<0, max> */ public function age(): int { - return $this->value->age(); + return $this->age; } #[\Override] @@ -52,6 +73,6 @@ public function toString(): string private function header(): Header { - return new Header('Age', $this->value); + return new Header('Age', new Value\Value((string) $this->age)); } } diff --git a/src/Header/AgeValue.php b/src/Header/AgeValue.php deleted file mode 100644 index 7f04303..0000000 --- a/src/Header/AgeValue.php +++ /dev/null @@ -1,55 +0,0 @@ -age = $age; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(int $age): Maybe - { - try { - return Maybe::just(new self($age)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - /** - * @return 0|positive-int - */ - public function age(): int - { - return $this->age; - } - - #[\Override] - public function toString(): string - { - return (string) $this->age; - } -} diff --git a/tests/Header/AgeTest.php b/tests/Header/AgeTest.php index c166611..90a3a93 100644 --- a/tests/Header/AgeTest.php +++ b/tests/Header/AgeTest.php @@ -6,39 +6,29 @@ use Innmind\Http\{ Header\Age, Header, - Header\AgeValue }; use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class AgeTest extends TestCase { - public function testInterface() - { - $h = new Age( - $av = new AgeValue(42), - ); - - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Age', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($av, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); - $this->assertSame('Age: 42', $h->toString()); - $this->assertSame(42, $h->age()); - } - public function testOf() { $header = Age::of(42); $this->assertInstanceOf(Age::class, $header); + $this->assertInstanceOf(Header::class, $header); $this->assertSame('Age', $header->name()); $values = $header->values(); $this->assertInstanceOf(Sequence::class, $values); $this->assertSame('Age: 42', $header->toString()); } + + public function testReturnNothingWhenInvalidAgeValue() + { + $this->assertNull(Age::maybe(-1)->match( + static fn($header) => $header, + static fn() => null, + )); + } } diff --git a/tests/Header/AgeValueTest.php b/tests/Header/AgeValueTest.php deleted file mode 100644 index e6fea38..0000000 --- a/tests/Header/AgeValueTest.php +++ /dev/null @@ -1,32 +0,0 @@ -assertInstanceOf(Value::class, $a); - $this->assertSame('42', $a->toString()); - - new AgeValue(0); - } - - public function testThrowWhenInvalidAgeValue() - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage('-1'); - - new AgeValue(-1); - } -} From 7eb11bb933106d54c9e3f559441d88fabcd4c429 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 17:39:36 +0200 Subject: [PATCH 04/51] remove AuthorizationValue --- CHANGELOG.md | 2 + src/Factory/Header/Factories.php | 4 +- src/Header/Authorization.php | 47 +++++++++++++++--- src/Header/AuthorizationValue.php | 64 ------------------------- tests/Header/AuthorizationTest.php | 60 +++++++++++++++-------- tests/Header/AuthorizationValueTest.php | 48 ------------------- 6 files changed, 84 insertions(+), 141 deletions(-) delete mode 100644 src/Header/AuthorizationValue.php delete mode 100644 tests/Header/AuthorizationValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6841675..adbeff6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - `Innmind\Http\Header::values()` now returns an `Innmind\Immutable\Sequence` to allow for ordered values - `Innmind\Http\Header\AcceptRanges` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\Age` constructor is now private, use `::of()` or `::maybe()` named constructors +- `Innmind\Http\Header\Authorization` constructor is now private, use `::of()` or `::maybe()` named constructors ### Removed @@ -32,6 +33,7 @@ - `Innmind\Http\Factory\HeaderFactory` - `Innmind\Http\Header\AcceptRangesValue` - `Innmind\Http\Header\AgeValue` +- `Innmind\Http\Header\AuthorizationValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 8506094..bbda9bb 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -18,7 +18,6 @@ Header\Allow, Header\AllowValue, Header\Authorization, - Header\AuthorizationValue, Header\CacheControl, Header\CacheControlValue, Header\ContentEncoding, @@ -598,7 +597,6 @@ private static function authorization(Str $value): Maybe return $matches ->get('scheme') ->map(static fn($scheme) => $scheme->toString()) - ->flatMap(static fn($scheme) => AuthorizationValue::of($scheme, $param)) - ->map(static fn($value) => new Authorization($value)); + ->flatMap(static fn($scheme) => Authorization::maybe($scheme, $param)); } } diff --git a/src/Header/Authorization.php b/src/Header/Authorization.php index fc6f414..d86f187 100644 --- a/src/Header/Authorization.php +++ b/src/Header/Authorization.php @@ -3,8 +3,15 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; +use Innmind\Http\{ + Header as HeaderInterface, + Exception\DomainException, +}; +use Innmind\Immutable\{ + Sequence, + Str, + Maybe, +}; /** * @psalm-immutable @@ -12,7 +19,8 @@ final class Authorization implements HeaderInterface { public function __construct( - private AuthorizationValue $value, + private string $scheme, + private string $parameter, ) { } @@ -21,7 +29,23 @@ public function __construct( */ public static function of(string $scheme, string $parameter): self { - return new self(new AuthorizationValue($scheme, $parameter)); + return self::maybe($scheme, $parameter)->match( + static fn($self) => $self, + static fn() => throw new DomainException($scheme), + ); + } + + /** + * @psalm-pure + * + * @return Maybe + */ + public static function maybe(string $scheme, string $parameter): Maybe + { + return Maybe::just($scheme) + ->map(Str::of(...)) + ->filter(static fn($scheme) => $scheme->matches('~^\w+$~')) + ->map(static fn() => new self($scheme, $parameter)); } #[\Override] @@ -38,12 +62,12 @@ public function values(): Sequence public function scheme(): string { - return $this->value->scheme(); + return $this->scheme; } public function parameter(): string { - return $this->value->parameter(); + return $this->parameter; } #[\Override] @@ -54,6 +78,15 @@ public function toString(): string private function header(): Header { - return new Header('Authorization', $this->value); + return new Header( + 'Authorization', + new Value\Value( + Str::of($this->scheme) + ->append(' ') + ->append($this->parameter) + ->trim() + ->toString(), + ), + ); } } diff --git a/src/Header/AuthorizationValue.php b/src/Header/AuthorizationValue.php deleted file mode 100644 index eb8c617..0000000 --- a/src/Header/AuthorizationValue.php +++ /dev/null @@ -1,64 +0,0 @@ -matches('~^\w+$~')) { - throw new DomainException($scheme); - } - - $this->scheme = $scheme; - $this->parameter = $parameter; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(string $scheme, string $parameter): Maybe - { - try { - return Maybe::just(new self($scheme, $parameter)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function scheme(): string - { - return $this->scheme; - } - - public function parameter(): string - { - return $this->parameter; - } - - #[\Override] - public function toString(): string - { - return Str::of($this->scheme) - ->append(' ') - ->append($this->parameter) - ->trim() - ->toString(); - } -} diff --git a/tests/Header/AuthorizationTest.php b/tests/Header/AuthorizationTest.php index cd6f902..40487d7 100644 --- a/tests/Header/AuthorizationTest.php +++ b/tests/Header/AuthorizationTest.php @@ -6,37 +6,59 @@ use Innmind\Http\{ Header\Authorization, Header, - Header\AuthorizationValue }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; class AuthorizationTest extends TestCase { - public function testInterface() - { - $h = new Authorization( - $av = new AuthorizationValue('Basic', ''), - ); - - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Authorization', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($av, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); - $this->assertSame('Authorization: Basic', $h->toString()); - } - public function testOf() { $header = Authorization::of('Basic', 'foo'); $this->assertInstanceOf(Authorization::class, $header); + $this->assertInstanceOf(Header::class, $header); $this->assertSame('Authorization: Basic foo', $header->toString()); $this->assertSame('Basic', $header->scheme()); $this->assertSame('foo', $header->parameter()); } + + public function testValids() + { + $this->assertInstanceOf( + Authorization::class, + Authorization::of('Basic', 'realm'), + ); + $this->assertInstanceOf( + Authorization::class, + Authorization::of('Basic', ''), + ); + $this->assertInstanceOf( + Authorization::class, + Authorization::of('Basic', 'realm="some value"'), + ); + $this->assertInstanceOf( + Authorization::class, + Authorization::of('Foo', ''), + ); + } + + #[DataProvider('invalids')] + public function testReturnNothingWhenInvalidAuthorizationValue($value) + { + $this->assertNull(Authorization::maybe($value, '')->match( + static fn($header) => $header, + static fn() => null, + )); + } + + public static function invalids(): array + { + return [ + ['foo@bar'], + ['foo/bar'], + ['"Basic"realm'], + ['"Basic" realm'], + ]; + } } diff --git a/tests/Header/AuthorizationValueTest.php b/tests/Header/AuthorizationValueTest.php deleted file mode 100644 index 1bbe603..0000000 --- a/tests/Header/AuthorizationValueTest.php +++ /dev/null @@ -1,48 +0,0 @@ -assertInstanceOf(Value::class, $a); - $this->assertSame('Basic', $a->scheme()); - $this->assertSame('realm', $a->parameter()); - $this->assertSame('Basic realm', $a->toString()); - - new AuthorizationValue('Basic', ''); - new AuthorizationValue('Basic', 'realm="some value"'); - new AuthorizationValue('Foo', ''); - } - - #[DataProvider('invalids')] - public function testThrowWhenInvalidAuthorizationValue($value) - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage($value); - - new AuthorizationValue($value, ''); - } - - public static function invalids(): array - { - return [ - ['foo@bar'], - ['foo/bar'], - ['"Basic"realm'], - ['"Basic" realm'], - ]; - } -} From 3e4471eacc0ab2f0b7b0d9c1b911f551c6179c59 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 17:47:00 +0200 Subject: [PATCH 05/51] remove ContentEncodingValue --- CHANGELOG.md | 2 + src/Factory/Header/Factories.php | 5 +-- src/Header/ContentEncoding.php | 43 ++++++++++++++----- src/Header/ContentEncodingValue.php | 48 --------------------- tests/Header/ContentEncodingTest.php | 52 +++++++++++++++-------- tests/Header/ContentEncodingValueTest.php | 45 -------------------- 6 files changed, 71 insertions(+), 124 deletions(-) delete mode 100644 src/Header/ContentEncodingValue.php delete mode 100644 tests/Header/ContentEncodingValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index adbeff6..aa55cff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - `Innmind\Http\Header\AcceptRanges` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\Age` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\Authorization` constructor is now private, use `::of()` or `::maybe()` named constructors +- `Innmind\Http\Header\ContentEncoding` constructor is now private, use `::of()` or `::maybe()` named constructors ### Removed @@ -34,6 +35,7 @@ - `Innmind\Http\Header\AcceptRangesValue` - `Innmind\Http\Header\AgeValue` - `Innmind\Http\Header\AuthorizationValue` +- `Innmind\Http\Header\ContentEncodingValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index bbda9bb..da9d094 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -21,7 +21,6 @@ Header\CacheControl, Header\CacheControlValue, Header\ContentEncoding, - Header\ContentEncodingValue, Header\ContentLanguage, Header\ContentLanguageValue, Header\ContentLength, @@ -308,9 +307,7 @@ public function try(Clock $clock, Str $value): Maybe )) ->keep(Instance::of(CacheControl::class)), - self::contentEncoding => ContentEncodingValue::of($value->toString())->map( - static fn($value) => new ContentEncoding($value), - ), + self::contentEncoding => ContentEncoding::maybe($value->toString()), self::contentLanguage => $value ->split(',') diff --git a/src/Header/ContentEncoding.php b/src/Header/ContentEncoding.php index f406f7c..20a088f 100644 --- a/src/Header/ContentEncoding.php +++ b/src/Header/ContentEncoding.php @@ -3,44 +3,67 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; +use Innmind\Http\{ + Header as HeaderInterface, + Exception\DomainException, +}; +use Innmind\Immutable\{ + Sequence, + Maybe, + Str, +}; /** * @psalm-immutable */ final class ContentEncoding implements HeaderInterface { - private Header $header; + private function __construct( + private string $encoding, + ) { + } - public function __construct(ContentEncodingValue $encoding) + /** + * @psalm-pure + * + * @throws DomainException + */ + public static function of(string $encoding): self { - $this->header = new Header('Content-Encoding', $encoding); + return self::maybe($encoding)->match( + static fn($self) => $self, + static fn() => throw new DomainException($encoding), + ); } /** * @psalm-pure + * + * @return Maybe */ - public static function of(string $coding): self + public static function maybe(string $encoding): Maybe { - return new self(new ContentEncodingValue($coding)); + return Maybe::just($encoding) + ->map(Str::of(...)) + ->filter(static fn($encoding) => $encoding->matches('~^[\w\-]+$~')) + ->map(static fn() => new self($encoding)); } #[\Override] public function name(): string { - return $this->header->name(); + return 'Content-Encoding'; } #[\Override] public function values(): Sequence { - return $this->header->values(); + return Sequence::of(new Value\Value($this->encoding)); } #[\Override] public function toString(): string { - return $this->header->toString(); + return (new Header($this->name(), ...$this->values()->toList()))->toString(); } } diff --git a/src/Header/ContentEncodingValue.php b/src/Header/ContentEncodingValue.php deleted file mode 100644 index c724bb5..0000000 --- a/src/Header/ContentEncodingValue.php +++ /dev/null @@ -1,48 +0,0 @@ -matches('~^[\w\-]+$~')) { - throw new DomainException($coding); - } - - $this->coding = $coding; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(string $coding): Maybe - { - try { - return Maybe::just(new self($coding)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - #[\Override] - public function toString(): string - { - return $this->coding; - } -} diff --git a/tests/Header/ContentEncodingTest.php b/tests/Header/ContentEncodingTest.php index 8dd3cb7..f2f19b1 100644 --- a/tests/Header/ContentEncodingTest.php +++ b/tests/Header/ContentEncodingTest.php @@ -6,35 +6,53 @@ use Innmind\Http\{ Header\ContentEncoding, Header, - Header\ContentEncodingValue }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; class ContentEncodingTest extends TestCase { - public function testInterface() + public function testOf() { - $h = new ContentEncoding( - $ce = new ContentEncodingValue('compress'), + $header = ContentEncoding::of('compress'); + + $this->assertInstanceOf(ContentEncoding::class, $header); + $this->assertInstanceOf(Header::class, $header); + $this->assertSame('Content-Encoding: compress', $header->toString()); + } + + public function testValids() + { + $this->assertInstanceOf( + ContentEncoding::class, + ContentEncoding::of('compress'), + ); + $this->assertInstanceOf( + ContentEncoding::class, + ContentEncoding::of('x-compress'), ); + $this->assertInstanceOf( + ContentEncoding::class, + ContentEncoding::of('identity'), + ); + } - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Content-Encoding', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($ce, $v->find(static fn() => true)->match( - static fn($first) => $first, + #[DataProvider('invalids')] + public function testReturnNothingWhenInvalidContentEncodingValue($value) + { + $this->assertNull(ContentEncoding::maybe($value)->match( + static fn($header) => $header, static fn() => null, )); - $this->assertSame('Content-Encoding: compress', $h->toString()); } - public function testOf() + public static function invalids(): array { - $header = ContentEncoding::of('compress'); - - $this->assertInstanceOf(ContentEncoding::class, $header); - $this->assertSame('Content-Encoding: compress', $header->toString()); + return [ + ['*'], + ['@'], + ['bar+suffix'], + ['foo/bar'], + ]; } } diff --git a/tests/Header/ContentEncodingValueTest.php b/tests/Header/ContentEncodingValueTest.php deleted file mode 100644 index bdf463a..0000000 --- a/tests/Header/ContentEncodingValueTest.php +++ /dev/null @@ -1,45 +0,0 @@ -assertInstanceOf(Value::class, $a); - $this->assertSame('compress', $a->toString()); - - new ContentEncodingValue('identity'); - new ContentEncodingValue('x-compress'); - } - - #[DataProvider('invalids')] - public function testThrowWhenInvalidContentEncodingValue($value) - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage($value); - - new ContentEncodingValue($value); - } - - public static function invalids(): array - { - return [ - ['*'], - ['@'], - ['bar+suffix'], - ['foo/bar'], - ]; - } -} From b54117f709f029ab3fc42cc797c601d3d2206a82 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 17:50:52 +0200 Subject: [PATCH 06/51] CS --- src/Header/Age.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Header/Age.php b/src/Header/Age.php index 478a3dd..3ca57b5 100644 --- a/src/Header/Age.php +++ b/src/Header/Age.php @@ -40,9 +40,9 @@ public static function of(int $age): self public static function maybe(int $age): Maybe { return Maybe::of(match (true) { - $age >= 0 => $age, + $age >= 0 => new self($age), default => null, - })->map(static fn($age) => new self($age)); + }); } #[\Override] From 0e27dce19aa8042a183a62d74bde37ee01771153 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 17:52:58 +0200 Subject: [PATCH 07/51] remove ContentLengthValue --- CHANGELOG.md | 2 + src/Factory/Header/Factories.php | 4 +- src/Header/ContentLength.php | 35 ++++++++++++---- src/Header/ContentLengthValue.php | 54 ------------------------- tests/Header/ContentLengthTest.php | 29 +++++-------- tests/Header/ContentLengthValueTest.php | 32 --------------- 6 files changed, 40 insertions(+), 116 deletions(-) delete mode 100644 src/Header/ContentLengthValue.php delete mode 100644 tests/Header/ContentLengthValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index aa55cff..c17bac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - `Innmind\Http\Header\Age` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\Authorization` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentEncoding` constructor is now private, use `::of()` or `::maybe()` named constructors +- `Innmind\Http\Header\ContentLength` constructor is now private, use `::of()` or `::maybe()` named constructors ### Removed @@ -36,6 +37,7 @@ - `Innmind\Http\Header\AgeValue` - `Innmind\Http\Header\AuthorizationValue` - `Innmind\Http\Header\ContentEncodingValue` +- `Innmind\Http\Header\ContentLengthValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index da9d094..9966ee4 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -24,7 +24,6 @@ Header\ContentLanguage, Header\ContentLanguageValue, Header\ContentLength, - Header\ContentLengthValue, Header\ContentLocation, Header\ContentRange, Header\ContentRangeValue, @@ -320,8 +319,7 @@ public function try(Clock $clock, Str $value): Maybe self::contentLength => Maybe::just($value->toString()) ->filter(\is_numeric(...)) ->map(static fn($length) => (int) $length) - ->flatMap(ContentLengthValue::of(...)) - ->map(static fn($value) => new ContentLength($value)), + ->flatMap(ContentLength::maybe(...)), self::contentLocation => Url::maybe($value->toString())->map( ContentLocation::of(...), diff --git a/src/Header/ContentLength.php b/src/Header/ContentLength.php index 5418e64..c2b1122 100644 --- a/src/Header/ContentLength.php +++ b/src/Header/ContentLength.php @@ -4,24 +4,45 @@ namespace Innmind\Http\Header; use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; +use Innmind\Immutable\{ + Sequence, + Maybe, +}; /** * @psalm-immutable */ final class ContentLength implements HeaderInterface { - public function __construct( - private ContentLengthValue $value, + /** + * @param int<0, max> $length + */ + private function __construct( + private int $length, ) { } /** * @psalm-pure + * + * @param int<0, max> $length */ public static function of(int $length): self { - return new self(new ContentLengthValue($length)); + return new self($length); + } + + /** + * @psalm-pure + * + * @return Maybe + */ + public static function maybe(int $length): Maybe + { + return Maybe::of(match (true) { + $length >= 0 => new self($length), + default => null, + }); } #[\Override] @@ -37,11 +58,11 @@ public function values(): Sequence } /** - * @return 0|positive-int + * @return int<0, max> */ public function length(): int { - return $this->value->length(); + return $this->length; } #[\Override] @@ -52,6 +73,6 @@ public function toString(): string private function header(): Header { - return new Header('Content-Length', $this->value); + return new Header('Content-Length', new Value\Value((string) $this->length)); } } diff --git a/src/Header/ContentLengthValue.php b/src/Header/ContentLengthValue.php deleted file mode 100644 index 224d937..0000000 --- a/src/Header/ContentLengthValue.php +++ /dev/null @@ -1,54 +0,0 @@ -length = $length; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(int $length): Maybe - { - try { - return Maybe::just(new self($length)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - /** - * @return 0|positive-int - */ - public function length(): int - { - return $this->length; - } - - #[\Override] - public function toString(): string - { - return (string) $this->length; - } -} diff --git a/tests/Header/ContentLengthTest.php b/tests/Header/ContentLengthTest.php index 3382c8f..7a2f644 100644 --- a/tests/Header/ContentLengthTest.php +++ b/tests/Header/ContentLengthTest.php @@ -6,36 +6,25 @@ use Innmind\Http\{ Header\ContentLength, Header, - Header\ContentLengthValue }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class ContentLengthTest extends TestCase { - public function testInterface() - { - $h = new ContentLength( - $av = new ContentLengthValue(42), - ); - - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Content-Length', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($av, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); - $this->assertSame('Content-Length: 42', $h->toString()); - $this->assertSame(42, $h->length()); - } - public function testOf() { $header = ContentLength::of(42); $this->assertInstanceOf(ContentLength::class, $header); + $this->assertInstanceOf(Header::class, $header); $this->assertSame('Content-Length: 42', $header->toString()); } + + public function testReturnNothingWhenInvalidContentLengthValue() + { + $this->assertNull(ContentLength::maybe(-1)->match( + static fn($header) => $header, + static fn() => null, + )); + } } diff --git a/tests/Header/ContentLengthValueTest.php b/tests/Header/ContentLengthValueTest.php deleted file mode 100644 index 4106946..0000000 --- a/tests/Header/ContentLengthValueTest.php +++ /dev/null @@ -1,32 +0,0 @@ -assertInstanceOf(Value::class, $a); - $this->assertSame('42', $a->toString()); - - new ContentLengthValue(0); - } - - public function testThrowWhenInvalidContentLengthValue() - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage('-1'); - - new ContentLengthValue(-1); - } -} From 87cc8814d0210b6aa59443e8dbeb9577549c1c7b Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 17:55:35 +0200 Subject: [PATCH 08/51] make ContentLocation constructor private --- CHANGELOG.md | 1 + src/Header/ContentLocation.php | 10 +++++----- tests/Header/ContentLocationTest.php | 9 +-------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c17bac4..f05acc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - `Innmind\Http\Header\Authorization` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentEncoding` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentLength` constructor is now private, use `::of()` or `::maybe()` named constructors +- `Innmind\Http\Header\ContentLocation` constructor is now private, use `::of()` or `::maybe()` named constructors ### Removed diff --git a/src/Header/ContentLocation.php b/src/Header/ContentLocation.php index 23ac048..2c11653 100644 --- a/src/Header/ContentLocation.php +++ b/src/Header/ContentLocation.php @@ -12,8 +12,8 @@ */ final class ContentLocation implements HeaderInterface { - public function __construct( - private LocationValue $value, + private function __construct( + private Url $url, ) { } @@ -22,7 +22,7 @@ public function __construct( */ public static function of(Url $location): self { - return new self(new LocationValue($location)); + return new self($location); } #[\Override] @@ -39,7 +39,7 @@ public function values(): Sequence public function url(): Url { - return $this->value->url(); + return $this->url; } #[\Override] @@ -50,6 +50,6 @@ public function toString(): string private function header(): Header { - return new Header('Content-Location', $this->value); + return new Header('Content-Location', new Value\Value($this->url->toString())); } } diff --git a/tests/Header/ContentLocationTest.php b/tests/Header/ContentLocationTest.php index e55e819..4e9dc8c 100644 --- a/tests/Header/ContentLocationTest.php +++ b/tests/Header/ContentLocationTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\ContentLocation, Header, - Header\LocationValue }; use Innmind\Immutable\Sequence; use Innmind\Url\Url; @@ -16,18 +15,12 @@ class ContentLocationTest extends TestCase { public function testInterface() { - $h = new ContentLocation( - $av = new LocationValue(Url::of('/foo/bar')), - ); + $h = ContentLocation::of(Url::of('/foo/bar')); $this->assertInstanceOf(Header::class, $h); $this->assertSame('Content-Location', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($av, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); $this->assertSame('Content-Location: /foo/bar', $h->toString()); $this->assertSame('/foo/bar', $h->url()->toString()); } From c1df49b8b2281187ea5cc25a7734b85aac7ecfa1 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:05:58 +0200 Subject: [PATCH 09/51] remove ContentRangeValue --- CHANGELOG.md | 2 + src/Factory/Header/Factories.php | 6 +- src/Header/ContentRange.php | 93 +++++++++++++++++++++--- src/Header/ContentRangeValue.php | 98 -------------------------- tests/Header/ContentRangeTest.php | 51 +++++++++----- tests/Header/ContentRangeValueTest.php | 58 --------------- 6 files changed, 122 insertions(+), 186 deletions(-) delete mode 100644 src/Header/ContentRangeValue.php delete mode 100644 tests/Header/ContentRangeValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f05acc3..064c18e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - `Innmind\Http\Header\ContentEncoding` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentLength` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentLocation` constructor is now private, use `::of()` or `::maybe()` named constructors +- `Innmind\Http\Header\ContentRange` constructor is now private, use `::of()` or `::maybe()` named constructors ### Removed @@ -39,6 +40,7 @@ - `Innmind\Http\Header\AuthorizationValue` - `Innmind\Http\Header\ContentEncodingValue` - `Innmind\Http\Header\ContentLengthValue` +- `Innmind\Http\Header\ContentRangeValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 9966ee4..e2e4732 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -26,7 +26,6 @@ Header\ContentLength, Header\ContentLocation, Header\ContentRange, - Header\ContentRangeValue, Header\ContentType, Header\ContentTypeValue, Header\Cookie, @@ -562,13 +561,12 @@ private static function contentRange(Str $value): Maybe ); return Maybe::all($matches->get('unit'), $matches->get('first'), $matches->get('last')) - ->flatMap(static fn(Str $unit, Str $first, Str $last) => ContentRangeValue::of( + ->flatMap(static fn(Str $unit, Str $first, Str $last) => ContentRange::maybe( $unit->toString(), (int) $first->toString(), (int) $last->toString(), $length, - )) - ->map(static fn($value) => new ContentRange($value)); + )); } /** diff --git a/src/Header/ContentRange.php b/src/Header/ContentRange.php index 6e6d258..04b30d5 100644 --- a/src/Header/ContentRange.php +++ b/src/Header/ContentRange.php @@ -3,16 +3,31 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; +use Innmind\Http\{ + Header as HeaderInterface, + Exception\DomainException, +}; +use Innmind\Immutable\{ + Sequence, + Str, + Maybe, +}; /** * @psalm-immutable */ final class ContentRange implements HeaderInterface { - public function __construct( - private ContentRangeValue $range, + /** + * @param int<0, max> $firstPosition + * @param int<0, max> $lastPosition + * @param ?int<0, max> $length + */ + private function __construct( + private string $unit, + private int $firstPosition, + private int $lastPosition, + private ?int $length, ) { } @@ -25,7 +40,36 @@ public static function of( int $lastPosition, ?int $length = null, ): self { - return new self(new ContentRangeValue( + return self::maybe($unit, $firstPosition, $lastPosition, $length)->match( + static fn($self) => $self, + static fn() => throw new DomainException($unit), + ); + } + + /** + * @psalm-pure + * + * @return Maybe + */ + public static function maybe( + string $unit, + int $firstPosition, + int $lastPosition, + ?int $length = null, + ): Maybe { + if ( + !Str::of($unit)->matches('~^\w+$~') || + $firstPosition < 0 || + $lastPosition < 0 || + ($length !== null && $length < 0) || + $firstPosition > $lastPosition || + ($length !== null && $lastPosition > $length) + ) { + /** @var Maybe */ + return Maybe::nothing(); + } + + return Maybe::just(new self( $unit, $firstPosition, $lastPosition, @@ -45,9 +89,33 @@ public function values(): Sequence return $this->header()->values(); } - public function range(): ContentRangeValue + public function unit(): string + { + return $this->unit; + } + + /** + * @return int<0, max> + */ + public function firstPosition(): int + { + return $this->firstPosition; + } + + /** + * @return int<0, max> + */ + public function lastPosition(): int + { + return $this->lastPosition; + } + + /** + * @return Maybe> + */ + public function length(): Maybe { - return $this->range; + return Maybe::of($this->length); } #[\Override] @@ -58,6 +126,15 @@ public function toString(): string private function header(): Header { - return new Header('Content-Range', $this->range); + return new Header( + 'Content-Range', + new Value\Value(\sprintf( + '%s %s-%s/%s', + $this->unit, + $this->firstPosition, + $this->lastPosition, + $this->length ?? '*', + )), + ); } } diff --git a/src/Header/ContentRangeValue.php b/src/Header/ContentRangeValue.php deleted file mode 100644 index 6c99e4d..0000000 --- a/src/Header/ContentRangeValue.php +++ /dev/null @@ -1,98 +0,0 @@ -matches('~^\w+$~') || - $firstPosition < 0 || - $lastPosition < 0 || - ($length !== null && $length < 0) || - $firstPosition > $lastPosition || - ($length !== null && $lastPosition > $length) - ) { - throw new DomainException($unit); - } - - $this->unit = $unit; - $this->firstPosition = $firstPosition; - $this->lastPosition = $lastPosition; - $this->length = $length; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of( - string $unit, - int $firstPosition, - int $lastPosition, - ?int $length = null, - ): Maybe { - try { - return Maybe::just(new self($unit, $firstPosition, $lastPosition, $length)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function unit(): string - { - return $this->unit; - } - - public function firstPosition(): int - { - return $this->firstPosition; - } - - public function lastPosition(): int - { - return $this->lastPosition; - } - - /** - * @return Maybe - */ - public function length(): Maybe - { - return Maybe::of($this->length); - } - - #[\Override] - public function toString(): string - { - return \sprintf( - '%s %s-%s/%s', - $this->unit, - $this->firstPosition, - $this->lastPosition, - $this->length ?? '*', - ); - } -} diff --git a/tests/Header/ContentRangeTest.php b/tests/Header/ContentRangeTest.php index a0cfc0c..d878b52 100644 --- a/tests/Header/ContentRangeTest.php +++ b/tests/Header/ContentRangeTest.php @@ -6,36 +6,51 @@ use Innmind\Http\{ Header\ContentRange, Header, - Header\ContentRangeValue }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; class ContentRangeTest extends TestCase { - public function testInterface() + public function testOf() + { + $header = ContentRange::of('bytes', 0, 42); + + $this->assertInstanceOf(ContentRange::class, $header); + $this->assertInstanceOf(Header::class, $header); + $this->assertSame('Content-Range: bytes 0-42/*', $header->toString()); + } + + public function testValids() { - $h = new ContentRange( - $cr = new ContentRangeValue('bytes', 0, 42), + $this->assertSame( + 'Content-Range: resources 0-42/*', + ContentRange::of('resources', 0, 42)->toString(), ); + $this->assertSame( + 'Content-Range: resources 0-499/1234', + ContentRange::of('resources', 0, 499, 1234)->toString(), + ); + } - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Content-Range', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($cr, $v->find(static fn() => true)->match( - static fn($first) => $first, + #[DataProvider('invalids')] + public function testReturnNothingWhenInvalidContentRangeValue($unit, $first, $last, $length) + { + $this->assertNull(ContentRange::maybe($unit, $first, $last, $length)->match( + static fn($header) => $header, static fn() => null, )); - $this->assertSame('Content-Range: bytes 0-42/*', $h->toString()); - $this->assertSame('bytes 0-42/*', $h->range()->toString()); } - public function testOf() + public static function invalids() { - $header = ContentRange::of('bytes', 0, 42); - - $this->assertInstanceOf(ContentRange::class, $header); - $this->assertSame('Content-Range: bytes 0-42/*', $header->toString()); + return [ + ['', 0, 42, null], + ['foo', -1, 42, null], + ['foo', 0, -42, null], + ['foo', 0, 42, -42], + ['foo', 100, 42, 142], + ['foo', 100, 142, 42], + ]; } } diff --git a/tests/Header/ContentRangeValueTest.php b/tests/Header/ContentRangeValueTest.php deleted file mode 100644 index e62da12..0000000 --- a/tests/Header/ContentRangeValueTest.php +++ /dev/null @@ -1,58 +0,0 @@ -assertInstanceOf(Value::class, $h); - $this->assertSame('resources', $h->unit()); - $this->assertSame(0, $h->firstPosition()); - $this->assertSame(42, $h->lastPosition()); - $this->assertFalse($h->length()->match( - static fn() => true, - static fn() => false, - )); - $this->assertSame('resources 0-42/*', $h->toString()); - - $h = new ContentRangeValue('bytes', 0, 499, 1234); - $this->assertSame(1234, $h->length()->match( - static fn($length) => $length, - static fn() => null, - )); - $this->assertSame('bytes 0-499/1234', $h->toString()); - } - - #[DataProvider('invalids')] - public function testThrowWhenInvalidContentRangeValue($unit, $first, $last, $length) - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage($unit); - - new ContentRangeValue($unit, $first, $last, $length); - } - - public static function invalids() - { - return [ - ['', 0, 42, null], - ['foo', -1, 42, null], - ['foo', 0, -42, null], - ['foo', 0, 42, -42], - ['foo', 100, 42, 142], - ['foo', 100, 142, 42], - ]; - } -} From 9005a23bcf1b1a7c844c62e2f71c2be77dce81a9 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:27:37 +0200 Subject: [PATCH 10/51] remove ContentTypeValue --- CHANGELOG.md | 2 + src/Factory/Header/Factories.php | 17 +---- src/Header/ContentType.php | 54 +++++++++++---- src/Header/ContentTypeValue.php | 98 --------------------------- tests/Header/ContentTypeTest.php | 46 +++++++------ tests/Header/ContentTypeValueTest.php | 66 ------------------ tests/HeadersTest.php | 44 +++++++----- tests/Request/StringableTest.php | 6 +- tests/Response/StringableTest.php | 6 +- 9 files changed, 104 insertions(+), 235 deletions(-) delete mode 100644 src/Header/ContentTypeValue.php delete mode 100644 tests/Header/ContentTypeValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 064c18e..1ebde14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - `Innmind\Http\Header\ContentLength` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentLocation` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentRange` constructor is now private, use `::of()` or `::maybe()` named constructors +- `Innmind\Http\Header\ContentType` constructor is now private, use `::of()` named constructor ### Removed @@ -41,6 +42,7 @@ - `Innmind\Http\Header\ContentEncodingValue` - `Innmind\Http\Header\ContentLengthValue` - `Innmind\Http\Header\ContentRangeValue` +- `Innmind\Http\Header\ContentTypeValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index e2e4732..e0b7c64 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -27,7 +27,6 @@ Header\ContentLocation, Header\ContentRange, Header\ContentType, - Header\ContentTypeValue, Header\Cookie, Header\Date, Header\Expires, @@ -326,19 +325,9 @@ public function try(Clock $clock, Str $value): Maybe self::contentRange => self::contentRange($value->trim()), - self::contentType => MediaType::maybe($value->toString()) - ->flatMap(static fn($mediaType) => ContentTypeValue::of( - $mediaType->topLevel(), - $mediaType->subType(), - ...$mediaType - ->parameters() - ->map(static fn($param) => new Parameter\Parameter( - $param->name(), - $param->value(), - )) - ->toList(), - )) - ->map(static fn($value) => new ContentType($value)), + self::contentType => MediaType::maybe($value->toString())->map( + ContentType::of(...), + ), self::cookie => Maybe::just($value) ->filter(static fn($value) => $value->matches( diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index ab9fc92..b37a643 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -4,31 +4,28 @@ namespace Innmind\Http\Header; use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; +use Innmind\MediaType\MediaType; +use Innmind\Immutable\{ + Sequence, + Str, +}; /** * @psalm-immutable */ final class ContentType implements HeaderInterface { - public function __construct( - private ContentTypeValue $content, + private function __construct( + private MediaType $content, ) { } /** * @psalm-pure */ - public static function of( - string $type, - string $subType, - Parameter ...$parameters, - ): self { - return new self(new ContentTypeValue( - $type, - $subType, - ...$parameters, - )); + public static function of(MediaType $content): self + { + return new self($content); } #[\Override] @@ -43,7 +40,7 @@ public function values(): Sequence return $this->header()->values(); } - public function content(): ContentTypeValue + public function content(): MediaType { return $this->content; } @@ -56,6 +53,33 @@ public function toString(): string private function header(): Header { - return new Header('Content-Type', $this->content); + $mediaType = new MediaType( + $this->content->topLevel(), + $this->content->subType(), + $this->content->suffix(), + ); + $parameters = Str::of(';')->join( + $this + ->content + ->parameters() + ->map(static fn($parameter) => new Parameter\Parameter( // to make sure it's of the HTTP format + $parameter->name(), + $parameter->value(), + )) + ->map(static fn($parameter) => $parameter->toString()), + ); + + $content = $mediaType->toString(); + + if (!$parameters->empty()) { + $content .= ';'; + } + + $content .= $parameters->toString(); + + return new Header( + 'Content-Type', + new Value\Value($content), + ); } } diff --git a/src/Header/ContentTypeValue.php b/src/Header/ContentTypeValue.php deleted file mode 100644 index e5e93d0..0000000 --- a/src/Header/ContentTypeValue.php +++ /dev/null @@ -1,98 +0,0 @@ - */ - private Map $parameters; - - public function __construct( - string $type, - string $subType, - Parameter ...$parameters, - ) { - $media = Str::of('%s/%s')->sprintf($type, $subType); - /** @var Map */ - $this->parameters = Map::of(); - - if (!$media->matches('~^[\w\-.]+/[\w\-.]+$~')) { - throw new DomainException($media->toString()); - } - - foreach ($parameters as $parameter) { - $this->parameters = ($this->parameters)( - $parameter->name(), - $parameter, - ); - } - - $this->type = $type; - $this->subType = $subType; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of( - string $type, - string $subType, - Parameter ...$parameters, - ): Maybe { - try { - return Maybe::just(new self($type, $subType, ...$parameters)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function type(): string - { - return $this->type; - } - - public function subType(): string - { - return $this->subType; - } - - /** - * @return Map - */ - public function parameters(): Map - { - return $this->parameters; - } - - #[\Override] - public function toString(): string - { - $parameters = $this->parameters->values()->map( - static fn($paramater) => $paramater->toString(), - ); - $parameters = Str::of(';')->join($parameters); - $parameters = !$parameters->empty() ? $parameters->prepend(';') : $parameters; - - return Str::of($this->type) - ->append('/') - ->append($this->subType) - ->append($parameters->toString()) - ->toString(); - } -} diff --git a/tests/Header/ContentTypeTest.php b/tests/Header/ContentTypeTest.php index 891525b..e9c3abc 100644 --- a/tests/Header/ContentTypeTest.php +++ b/tests/Header/ContentTypeTest.php @@ -6,45 +6,51 @@ use Innmind\Http\{ Header\ContentType, Header, - Header\ContentTypeValue, - Header\Parameter }; +use Innmind\MediaType\MediaType; use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; class ContentTypeTest extends TestCase { public function testInterface() { - $h = new ContentType( - $ct = new ContentTypeValue( - 'text', - 'html', - new Parameter\Parameter('charset', 'UTF-8'), - ), + $h = ContentType::of( + $ct = MediaType::of('text/html; charset="UTF-8"'), ); $this->assertInstanceOf(Header::class, $h); $this->assertSame('Content-Type', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($ct, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); + $this->assertSame($ct, $h->content()); $this->assertSame('Content-Type: text/html;charset=UTF-8', $h->toString()); - $this->assertSame('text/html;charset=UTF-8', $h->content()->toString()); + $this->assertSame('text/html; charset=UTF-8', $h->content()->toString()); } - public function testOf() + #[DataProvider('invalids')] + public function testReturnNothingWhenInvalidContentTypeValue($type, $sub) { - $header = ContentType::of( - 'text', - 'html', - new Parameter\Parameter('charset', 'UTF-8'), + $this->assertNull( + MediaType::maybe("$type/$sub") + ->map(ContentType::of(...)) + ->match( + static fn($header) => $header, + static fn() => null, + ), ); + } - $this->assertInstanceOf(ContentType::class, $header); - $this->assertSame('Content-Type: text/html;charset=UTF-8', $header->toString()); + public static function invalids(): array + { + return [ + ['*', '*'], + ['*', 'octet-stream'], + ['text', '*'], + ['foo/bar', ''], + ['foo', 'bar+suffix'], + ['foo', 'bar, level=1'], + ]; } } diff --git a/tests/Header/ContentTypeValueTest.php b/tests/Header/ContentTypeValueTest.php deleted file mode 100644 index b6377d3..0000000 --- a/tests/Header/ContentTypeValueTest.php +++ /dev/null @@ -1,66 +0,0 @@ -assertInstanceOf(Value::class, $a); - $this->assertSame('text', $a->type()); - $this->assertSame('x-c', $a->subType()); - $this->assertSame($p, $a->parameters()->get('charset')->match( - static fn($charset) => $charset, - static fn() => null, - )); - $this->assertSame('text/x-c;charset=UTF-8', $a->toString()); - - new ContentTypeValue( - 'application', - 'octet-stream', - ); - new ContentTypeValue( - 'application', - 'octet-stream', - new Parameter\Parameter('charset', 'UTF-8'), - new Parameter\Parameter('level', '1'), - ); - } - - #[DataProvider('invalids')] - public function testThrowWhenInvalidContentTypeValue($type, $sub) - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage("$type/$sub"); - - new ContentTypeValue($type, $sub); - } - - public static function invalids(): array - { - return [ - ['*', '*'], - ['*', 'octet-stream'], - ['text', '*'], - ['foo/bar', ''], - ['foo', 'bar+suffix'], - ['foo', 'bar, level=1'], - ]; - } -} diff --git a/tests/HeadersTest.php b/tests/HeadersTest.php index 8a60b2e..3a0fc47 100644 --- a/tests/HeadersTest.php +++ b/tests/HeadersTest.php @@ -9,9 +9,9 @@ Header\Header, Header\Allow, Header\ContentType, - Header\ContentTypeValue, Header\Value\Value, }; +use Innmind\MediaType\MediaType; use Innmind\Immutable\SideEffect; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -20,10 +20,9 @@ class HeadersTest extends TestCase public function testInterface() { $hs = Headers::of( - $ct = new ContentType( - new ContentTypeValue( - 'application', - 'json', + $ct = ContentType::of( + MediaType::of( + 'application/json', ), ), ); @@ -45,10 +44,9 @@ public function testInterface() public function testOf() { $headers = Headers::of( - new ContentType( - new ContentTypeValue( - 'application', - 'json', + ContentType::of( + MediaType::of( + 'application/json', ), ), ); @@ -68,8 +66,12 @@ public function testReturnNothingWhenAccessingUnknownHeader() public function testAdd() { $headers1 = Headers::of(); - $headers2 = ($headers1)(ContentType::of('application', 'json')); - $headers3 = ($headers2)($header = ContentType::of('application', 'json')); + $headers2 = ($headers1)(ContentType::of( + MediaType::of('application/json'), + )); + $headers3 = ($headers2)($header = ContentType::of( + MediaType::of('application/json'), + )); $this->assertNotSame($headers1, $headers2); $this->assertInstanceOf(Headers::class, $headers2); @@ -84,7 +86,9 @@ public function testAdd() public function testForeach() { $headers = Headers::of( - ContentType::of('application', 'json'), + ContentType::of( + MediaType::of('application/json'), + ), new Header('x-foo'), ); @@ -101,7 +105,9 @@ public function testForeach() public function testReduce() { $headers = Headers::of( - ContentType::of('application', 'json'), + ContentType::of( + MediaType::of('application/json'), + ), new Header('x-foo'), ); @@ -120,7 +126,9 @@ static function($carry, $header) { public function testFind() { $headers = Headers::of( - ContentType::of('application', 'json'), + ContentType::of( + MediaType::of('application/json'), + ), new Header('Allow'), ); @@ -146,7 +154,9 @@ public function testFind() public function testFilter() { $headers = Headers::of( - ContentType::of('application', 'json'), + ContentType::of( + MediaType::of('application/json'), + ), new Header('x-foo'), ); @@ -167,7 +177,9 @@ public function testFilter() public function testAll() { $headers = Headers::of( - $contentType = ContentType::of('application', 'json'), + $contentType = ContentType::of( + MediaType::of('application/json'), + ), $foo = new Header('x-foo'), ); diff --git a/tests/Request/StringableTest.php b/tests/Request/StringableTest.php index 275bdb4..c5d63e4 100644 --- a/tests/Request/StringableTest.php +++ b/tests/Request/StringableTest.php @@ -10,9 +10,9 @@ ProtocolVersion, Headers, Header\ContentType, - Header\ContentTypeValue }; use Innmind\Filesystem\File\Content; +use Innmind\MediaType\MediaType; use Innmind\Url\Url; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -25,8 +25,8 @@ public function testInterface() Method::post, ProtocolVersion::v20, Headers::of( - new ContentType( - new ContentTypeValue('text', 'plain'), + ContentType::of( + MediaType::of('text/plain'), ), ), Content::ofString('some body'), diff --git a/tests/Response/StringableTest.php b/tests/Response/StringableTest.php index 95c2ba9..571b844 100644 --- a/tests/Response/StringableTest.php +++ b/tests/Response/StringableTest.php @@ -10,11 +10,11 @@ ProtocolVersion, Headers, Header\ContentType, - Header\ContentTypeValue, Header\Allow, Header\AllowValue }; use Innmind\Filesystem\File\Content; +use Innmind\MediaType\MediaType; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class StringableTest extends TestCase @@ -25,8 +25,8 @@ public function testInterface() $code = StatusCode::ok, ProtocolVersion::v20, Headers::of( - new ContentType( - new ContentTypeValue('text', 'plain'), + ContentType::of( + MediaType::of('text/plain'), ), new Allow( new AllowValue('GET'), From 4b5a2a6e30eedcdacd680598dcc9c2eb3e0e0420 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:27:48 +0200 Subject: [PATCH 11/51] remove reference to undefined method --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ebde14..6b101cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ - `Innmind\Http\Header\Authorization` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentEncoding` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentLength` constructor is now private, use `::of()` or `::maybe()` named constructors -- `Innmind\Http\Header\ContentLocation` constructor is now private, use `::of()` or `::maybe()` named constructors +- `Innmind\Http\Header\ContentLocation` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\ContentRange` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentType` constructor is now private, use `::of()` named constructor From 2a25646ef91540d1cdb1d23684b21073ae7e08a2 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:31:32 +0200 Subject: [PATCH 12/51] make Date constructor private --- CHANGELOG.md | 1 + src/Header/Date.php | 28 +++++++++++++++++++++------- tests/Header/DateTest.php | 12 +++--------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b101cd..14637ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - `Innmind\Http\Header\ContentLocation` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\ContentRange` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentType` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Date` constructor is now private, use `::of()` named constructor ### Removed diff --git a/src/Header/Date.php b/src/Header/Date.php index 36f0e8d..f94e748 100644 --- a/src/Header/Date.php +++ b/src/Header/Date.php @@ -3,8 +3,14 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\TimeContinuum\PointInTime; +use Innmind\Http\{ + Header as HeaderInterface, + TimeContinuum\Format\Http, +}; +use Innmind\TimeContinuum\{ + PointInTime, + Offset, +}; use Innmind\Immutable\Sequence; /** @@ -12,8 +18,8 @@ */ final class Date implements HeaderInterface { - public function __construct( - private DateValue $value, + private function __construct( + private PointInTime $point, ) { } @@ -22,7 +28,7 @@ public function __construct( */ public static function of(PointInTime $point): self { - return new self(new DateValue($point)); + return new self($point); } #[\Override] @@ -39,7 +45,7 @@ public function values(): Sequence public function date(): PointInTime { - return $this->value->date(); + return $this->point; } #[\Override] @@ -50,6 +56,14 @@ public function toString(): string private function header(): Header { - return new Header('Date', $this->value); + return new Header( + 'Date', + new Value\Value( + $this + ->point + ->changeOffset(Offset::utc()) + ->format(Http::new()), + ), + ); } } diff --git a/tests/Header/DateTest.php b/tests/Header/DateTest.php index b89b93b..dc8b243 100644 --- a/tests/Header/DateTest.php +++ b/tests/Header/DateTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\Date, Header, - Header\DateValue }; use Innmind\TimeContinuum\PointInTime; use Innmind\Immutable\Sequence; @@ -16,22 +15,17 @@ class DateTest extends TestCase { public function testInterface() { - $h = new Date( - $d = new DateValue(PointInTime::at( + $h = Date::of( + PointInTime::at( new \DateTimeImmutable('2016-01-01 12:12:12+0200'), - )), + ), ); $this->assertInstanceOf(Header::class, $h); $this->assertSame('Date', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($d, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); $this->assertSame('Date: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); - $this->assertSame($d->date(), $h->date()); } public function testOf() From 54c7f97e455e46b83175dc55b61922a093594507 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:33:46 +0200 Subject: [PATCH 13/51] make Expires constructor private --- CHANGELOG.md | 1 + src/Header/Expires.php | 28 +++++++++++++++++++++------- tests/Header/ExpiresTest.php | 12 +++--------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14637ce..5f7dcd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - `Innmind\Http\Header\ContentRange` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\ContentType` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Date` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Expires` constructor is now private, use `::of()` named constructor ### Removed diff --git a/src/Header/Expires.php b/src/Header/Expires.php index d512103..8833eaa 100644 --- a/src/Header/Expires.php +++ b/src/Header/Expires.php @@ -3,8 +3,14 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\TimeContinuum\PointInTime; +use Innmind\Http\{ + Header as HeaderInterface, + TimeContinuum\Format\Http, +}; +use Innmind\TimeContinuum\{ + PointInTime, + Offset, +}; use Innmind\Immutable\Sequence; /** @@ -12,8 +18,8 @@ */ final class Expires implements HeaderInterface { - public function __construct( - private DateValue $value, + private function __construct( + private PointInTime $point, ) { } @@ -22,7 +28,7 @@ public function __construct( */ public static function of(PointInTime $point): self { - return new self(new DateValue($point)); + return new self($point); } #[\Override] @@ -39,7 +45,7 @@ public function values(): Sequence public function date(): PointInTime { - return $this->value->date(); + return $this->point; } #[\Override] @@ -50,6 +56,14 @@ public function toString(): string private function header(): Header { - return new Header('Expires', $this->value); + return new Header( + 'Expires', + new Value\Value( + $this + ->point + ->changeOffset(Offset::utc()) + ->format(Http::new()), + ), + ); } } diff --git a/tests/Header/ExpiresTest.php b/tests/Header/ExpiresTest.php index 8a4b4bb..9ca63ef 100644 --- a/tests/Header/ExpiresTest.php +++ b/tests/Header/ExpiresTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\Expires, Header, - Header\DateValue }; use Innmind\TimeContinuum\PointInTime; use Innmind\Immutable\Sequence; @@ -16,22 +15,17 @@ class ExpiresTest extends TestCase { public function testInterface() { - $h = new Expires( - $d = new DateValue(PointInTime::at( + $h = Expires::of( + PointInTime::at( new \DateTimeImmutable('2016-01-01 12:12:12+0200'), - )), + ), ); $this->assertInstanceOf(Header::class, $h); $this->assertSame('Expires', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($d, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); $this->assertSame('Expires: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); - $this->assertSame($d->date(), $h->date()); } public function testOf() From 019329ba3df3a6257cfc760627634cbb0fcacd94 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:37:48 +0200 Subject: [PATCH 14/51] remove HostValue --- CHANGELOG.md | 2 ++ src/Header/Host.php | 18 ++++++++----- src/Header/HostValue.php | 37 -------------------------- tests/Header/HostTest.php | 14 +++------- tests/Header/HostValueTest.php | 31 --------------------- tests/ServerRequest/StringableTest.php | 25 +++++++---------- 6 files changed, 27 insertions(+), 100 deletions(-) delete mode 100644 src/Header/HostValue.php delete mode 100644 tests/Header/HostValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f7dcd2..a1533a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - `Innmind\Http\Header\ContentType` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Date` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Expires` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Host` constructor is now private, use `::of()` named constructor ### Removed @@ -45,6 +46,7 @@ - `Innmind\Http\Header\ContentLengthValue` - `Innmind\Http\Header\ContentRangeValue` - `Innmind\Http\Header\ContentTypeValue` +- `Innmind\Http\Header\HostValue` ### Fixed diff --git a/src/Header/Host.php b/src/Header/Host.php index e569297..9fbbe10 100644 --- a/src/Header/Host.php +++ b/src/Header/Host.php @@ -15,8 +15,9 @@ */ final class Host implements HeaderInterface { - public function __construct( - private HostValue $value, + private function __construct( + private UrlHost $host, + private Port $port, ) { } @@ -25,7 +26,7 @@ public function __construct( */ public static function of(UrlHost $host, Port $port): self { - return new self(new HostValue($host, $port)); + return new self($host, $port); } #[\Override] @@ -42,12 +43,12 @@ public function values(): Sequence public function host(): UrlHost { - return $this->value->host(); + return $this->host; } public function port(): Port { - return $this->value->port(); + return $this->port; } #[\Override] @@ -58,6 +59,11 @@ public function toString(): string private function header(): Header { - return new Header('Host', $this->value); + return new Header( + 'Host', + new Value\Value( + $this->host->toString().$this->port->format(), + ), + ); } } diff --git a/src/Header/HostValue.php b/src/Header/HostValue.php deleted file mode 100644 index a78b044..0000000 --- a/src/Header/HostValue.php +++ /dev/null @@ -1,37 +0,0 @@ -host; - } - - public function port(): Port - { - return $this->port; - } - - #[\Override] - public function toString(): string - { - return $this->host->toString().$this->port->format(); - } -} diff --git a/tests/Header/HostTest.php b/tests/Header/HostTest.php index 174ed0e..c561259 100644 --- a/tests/Header/HostTest.php +++ b/tests/Header/HostTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\Host, Header, - Header\HostValue }; use Innmind\Immutable\Sequence; use Innmind\Url\Authority\{ @@ -19,21 +18,16 @@ class HostTest extends TestCase { public function testInterface() { - $h = new Host( - $av = new HostValue(UrlHost::of('example.com'), Port::none()), + $h = Host::of( + UrlHost::of('example.com'), + Port::of(8080), ); $this->assertInstanceOf(Header::class, $h); $this->assertSame('Host', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($av, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); - $this->assertSame('Host: example.com', $h->toString()); - $this->assertSame($av->host(), $h->host()); - $this->assertSame($av->port(), $h->port()); + $this->assertSame('Host: example.com:8080', $h->toString()); } public function testOf() diff --git a/tests/Header/HostValueTest.php b/tests/Header/HostValueTest.php deleted file mode 100644 index 94dde4a..0000000 --- a/tests/Header/HostValueTest.php +++ /dev/null @@ -1,31 +0,0 @@ -assertInstanceOf(Value::class, $h); - $this->assertSame($host, $h->host()); - $this->assertSame($p, $h->port()); - $this->assertSame('example.com', $h->toString()); - $this->assertSame( - 'example.com:8080', - (new HostValue(Host::of('example.com'), Port::of(8080)))->toString(), - ); - } -} diff --git a/tests/ServerRequest/StringableTest.php b/tests/ServerRequest/StringableTest.php index 0d11dda..622527a 100644 --- a/tests/ServerRequest/StringableTest.php +++ b/tests/ServerRequest/StringableTest.php @@ -12,7 +12,6 @@ ProtocolVersion, Headers, Header\Host, - Header\HostValue }; use Innmind\Filesystem\File\Content; use Innmind\Url\Url; @@ -27,11 +26,9 @@ public function testInterface() Method::post, ProtocolVersion::v20, Headers::of( - new Host( - new HostValue( - $url->authority()->host(), - $url->authority()->port(), - ), + Host::of( + $url->authority()->host(), + $url->authority()->port(), ), ), Content::ofString('some body'), @@ -54,11 +51,9 @@ public function testIntegrateQuery() Method::post, ProtocolVersion::v20, Headers::of( - new Host( - new HostValue( - $url->authority()->host(), - $url->authority()->port(), - ), + Host::of( + $url->authority()->host(), + $url->authority()->port(), ), ), Content::ofString('some body'), @@ -88,11 +83,9 @@ public function testIntegrateFormWhenNoBody() Method::post, ProtocolVersion::v20, Headers::of( - new Host( - new HostValue( - $url->authority()->host(), - $url->authority()->port(), - ), + Host::of( + $url->authority()->host(), + $url->authority()->port(), ), ), null, From 2495d88a8d4d50cb1a6fed84f2d559bcca254b06 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:39:51 +0200 Subject: [PATCH 15/51] make IfModifiedSince constructor private --- CHANGELOG.md | 1 + src/Header/IfModifiedSince.php | 28 +++++++++++++++++++++------- tests/Header/IfModifiedSinceTest.php | 12 +++--------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1533a6..0523425 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - `Innmind\Http\Header\Date` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Expires` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Host` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\IfModifiedSince` constructor is now private, use `::of()` named constructor ### Removed diff --git a/src/Header/IfModifiedSince.php b/src/Header/IfModifiedSince.php index 19cd865..b4c44d5 100644 --- a/src/Header/IfModifiedSince.php +++ b/src/Header/IfModifiedSince.php @@ -3,8 +3,14 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\TimeContinuum\PointInTime; +use Innmind\Http\{ + Header as HeaderInterface, + TimeContinuum\Format\Http, +}; +use Innmind\TimeContinuum\{ + PointInTime, + Offset, +}; use Innmind\Immutable\Sequence; /** @@ -12,8 +18,8 @@ */ final class IfModifiedSince implements HeaderInterface { - public function __construct( - private DateValue $value, + private function __construct( + private PointInTime $point, ) { } @@ -22,7 +28,7 @@ public function __construct( */ public static function of(PointInTime $point): self { - return new self(new DateValue($point)); + return new self($point); } #[\Override] @@ -39,7 +45,7 @@ public function values(): Sequence public function date(): PointInTime { - return $this->value->date(); + return $this->point; } #[\Override] @@ -50,6 +56,14 @@ public function toString(): string private function header(): Header { - return new Header('If-Modified-Since', $this->value); + return new Header( + 'If-Modified-Since', + new Value\Value( + $this + ->point + ->changeOffset(Offset::utc()) + ->format(Http::new()), + ), + ); } } diff --git a/tests/Header/IfModifiedSinceTest.php b/tests/Header/IfModifiedSinceTest.php index bcb7aca..8e19827 100644 --- a/tests/Header/IfModifiedSinceTest.php +++ b/tests/Header/IfModifiedSinceTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\IfModifiedSince, Header, - Header\DateValue }; use Innmind\TimeContinuum\PointInTime; use Innmind\Immutable\Sequence; @@ -16,22 +15,17 @@ class IfModifiedSinceTest extends TestCase { public function testInterface() { - $h = new IfModifiedSince( - $d = new DateValue(PointInTime::at( + $h = IfModifiedSince::of( + PointInTime::at( new \DateTimeImmutable('2016-01-01 12:12:12+0200'), - )), + ), ); $this->assertInstanceOf(Header::class, $h); $this->assertSame('If-Modified-Since', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($d, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); $this->assertSame('If-Modified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); - $this->assertSame($d->date(), $h->date()); } public function testOf() From 613c22e09d6bc2f45a70bc921d985127e19dcf45 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:41:43 +0200 Subject: [PATCH 16/51] make IfUnmodifiedSince constructor private --- CHANGELOG.md | 1 + src/Header/IfUnmodifiedSince.php | 28 +++++++++++++++++++------- tests/Header/IfUnmodifiedSinceTest.php | 12 +++-------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0523425..36d56fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - `Innmind\Http\Header\Expires` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Host` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\IfModifiedSince` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\IfUnmodifiedSince` constructor is now private, use `::of()` named constructor ### Removed diff --git a/src/Header/IfUnmodifiedSince.php b/src/Header/IfUnmodifiedSince.php index 0029d85..2c3ad03 100644 --- a/src/Header/IfUnmodifiedSince.php +++ b/src/Header/IfUnmodifiedSince.php @@ -3,8 +3,14 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\TimeContinuum\PointInTime; +use Innmind\Http\{ + Header as HeaderInterface, + TimeContinuum\Format\Http, +}; +use Innmind\TimeContinuum\{ + PointInTime, + Offset, +}; use Innmind\Immutable\Sequence; /** @@ -12,8 +18,8 @@ */ final class IfUnmodifiedSince implements HeaderInterface { - public function __construct( - private DateValue $value, + private function __construct( + private PointInTime $point, ) { } @@ -22,7 +28,7 @@ public function __construct( */ public static function of(PointInTime $point): self { - return new self(new DateValue($point)); + return new self($point); } #[\Override] @@ -39,7 +45,7 @@ public function values(): Sequence public function date(): PointInTime { - return $this->value->date(); + return $this->point; } #[\Override] @@ -50,6 +56,14 @@ public function toString(): string private function header(): Header { - return new Header('If-Unmodified-Since', $this->value); + return new Header( + 'If-Unmodified-Since', + new Value\Value( + $this + ->point + ->changeOffset(Offset::utc()) + ->format(Http::new()), + ), + ); } } diff --git a/tests/Header/IfUnmodifiedSinceTest.php b/tests/Header/IfUnmodifiedSinceTest.php index 1b30734..7ba797c 100644 --- a/tests/Header/IfUnmodifiedSinceTest.php +++ b/tests/Header/IfUnmodifiedSinceTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\IfUnmodifiedSince, Header, - Header\DateValue }; use Innmind\TimeContinuum\PointInTime; use Innmind\Immutable\Sequence; @@ -16,22 +15,17 @@ class IfUnmodifiedSinceTest extends TestCase { public function testInterface() { - $h = new IfUnmodifiedSince( - $d = new DateValue(PointInTime::at( + $h = IfUnmodifiedSince::of( + PointInTime::at( new \DateTimeImmutable('2016-01-01 12:12:12+0200'), - )), + ), ); $this->assertInstanceOf(Header::class, $h); $this->assertSame('If-Unmodified-Since', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($d, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); $this->assertSame('If-Unmodified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); - $this->assertSame($d->date(), $h->date()); } public function testOf() From c246505d1f955f36134475d13d4fc7c05eeeb652 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:43:14 +0200 Subject: [PATCH 17/51] make LastModified constructor private --- CHANGELOG.md | 1 + src/Header/LastModified.php | 28 +++++++++++++++++++++------- tests/Header/LastModifiedTest.php | 12 +++--------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36d56fb..b90f1cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - `Innmind\Http\Header\Host` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\IfModifiedSince` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\IfUnmodifiedSince` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\LastModified` constructor is now private, use `::of()` named constructor ### Removed diff --git a/src/Header/LastModified.php b/src/Header/LastModified.php index b8f88ae..6de6898 100644 --- a/src/Header/LastModified.php +++ b/src/Header/LastModified.php @@ -3,8 +3,14 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\TimeContinuum\PointInTime; +use Innmind\Http\{ + Header as HeaderInterface, + TimeContinuum\Format\Http, +}; +use Innmind\TimeContinuum\{ + PointInTime, + Offset, +}; use Innmind\Immutable\Sequence; /** @@ -12,8 +18,8 @@ */ final class LastModified implements HeaderInterface { - public function __construct( - private DateValue $value, + private function __construct( + private PointInTime $point, ) { } @@ -22,7 +28,7 @@ public function __construct( */ public static function of(PointInTime $point): self { - return new self(new DateValue($point)); + return new self($point); } #[\Override] @@ -39,7 +45,7 @@ public function values(): Sequence public function date(): PointInTime { - return $this->value->date(); + return $this->point; } #[\Override] @@ -50,6 +56,14 @@ public function toString(): string private function header(): Header { - return new Header('Last-Modified', $this->value); + return new Header( + 'Last-Modified', + new Value\Value( + $this + ->point + ->changeOffset(Offset::utc()) + ->format(Http::new()), + ), + ); } } diff --git a/tests/Header/LastModifiedTest.php b/tests/Header/LastModifiedTest.php index c4b7bf7..4b4cd7b 100644 --- a/tests/Header/LastModifiedTest.php +++ b/tests/Header/LastModifiedTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\LastModified, Header, - Header\DateValue }; use Innmind\TimeContinuum\PointInTime; use Innmind\Immutable\Sequence; @@ -16,22 +15,17 @@ class LastModifiedTest extends TestCase { public function testInterface() { - $h = new LastModified( - $d = new DateValue(PointInTime::at( + $h = LastModified::of( + PointInTime::at( new \DateTimeImmutable('2016-01-01 12:12:12+0200'), - )), + ), ); $this->assertInstanceOf(Header::class, $h); $this->assertSame('Last-Modified', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($d, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); $this->assertSame('Last-Modified: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); - $this->assertSame($d->date(), $h->date()); } public function testOf() From 6f1f47559762f1ceb8d9c3bff715e17bf76ad1d8 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:44:01 +0200 Subject: [PATCH 18/51] remove DateValue --- CHANGELOG.md | 1 + src/Header/DateValue.php | 32 -------------------------------- tests/Header/DateValueTest.php | 24 ------------------------ 3 files changed, 1 insertion(+), 56 deletions(-) delete mode 100644 src/Header/DateValue.php delete mode 100644 tests/Header/DateValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b90f1cc..230177b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ - `Innmind\Http\Header\ContentRangeValue` - `Innmind\Http\Header\ContentTypeValue` - `Innmind\Http\Header\HostValue` +- `Innmind\Http\Header\DateValue` ### Fixed diff --git a/src/Header/DateValue.php b/src/Header/DateValue.php deleted file mode 100644 index c6af059..0000000 --- a/src/Header/DateValue.php +++ /dev/null @@ -1,32 +0,0 @@ -date; - } - - #[\Override] - public function toString(): string - { - return $this->date->changeOffset(Offset::utc())->format(Http::new()); - } -} diff --git a/tests/Header/DateValueTest.php b/tests/Header/DateValueTest.php deleted file mode 100644 index 842415b..0000000 --- a/tests/Header/DateValueTest.php +++ /dev/null @@ -1,24 +0,0 @@ -assertInstanceOf(Value::class, $h); - $this->assertSame('Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); - } -} From 52765c39ff1019ba601c4b167610ad564d6b34ab Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:46:07 +0200 Subject: [PATCH 19/51] remove LocationValue --- CHANGELOG.md | 2 ++ src/Header/Location.php | 13 ++++++++----- src/Header/LocationValue.php | 28 ---------------------------- tests/Header/LocationTest.php | 9 ++------- tests/Header/LocationValueTest.php | 22 ---------------------- 5 files changed, 12 insertions(+), 62 deletions(-) delete mode 100644 src/Header/LocationValue.php delete mode 100644 tests/Header/LocationValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 230177b..40784c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ - `Innmind\Http\Header\IfModifiedSince` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\IfUnmodifiedSince` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\LastModified` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Location` constructor is now private, use `::of()` named constructor ### Removed @@ -51,6 +52,7 @@ - `Innmind\Http\Header\ContentTypeValue` - `Innmind\Http\Header\HostValue` - `Innmind\Http\Header\DateValue` +- `Innmind\Http\Header\LocationValue` ### Fixed diff --git a/src/Header/Location.php b/src/Header/Location.php index 0d3cacc..2676853 100644 --- a/src/Header/Location.php +++ b/src/Header/Location.php @@ -12,8 +12,8 @@ */ final class Location implements HeaderInterface { - public function __construct( - private LocationValue $location, + private function __construct( + private Url $location, ) { } @@ -22,7 +22,7 @@ public function __construct( */ public static function of(Url $location): self { - return new self(new LocationValue($location)); + return new self($location); } #[\Override] @@ -39,7 +39,7 @@ public function values(): Sequence public function url(): Url { - return $this->location->url(); + return $this->location; } #[\Override] @@ -50,6 +50,9 @@ public function toString(): string private function header(): Header { - return new Header('Location', $this->location); + return new Header( + 'Location', + new Value\Value($this->location->toString()), + ); } } diff --git a/src/Header/LocationValue.php b/src/Header/LocationValue.php deleted file mode 100644 index 7b17a81..0000000 --- a/src/Header/LocationValue.php +++ /dev/null @@ -1,28 +0,0 @@ -url; - } - - #[\Override] - public function toString(): string - { - return $this->url->toString(); - } -} diff --git a/tests/Header/LocationTest.php b/tests/Header/LocationTest.php index 68115bb..673eae4 100644 --- a/tests/Header/LocationTest.php +++ b/tests/Header/LocationTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\Location, Header, - Header\LocationValue }; use Innmind\Immutable\Sequence; use Innmind\Url\Url; @@ -16,18 +15,14 @@ class LocationTest extends TestCase { public function testInterface() { - $h = new Location( - $av = new LocationValue(Url::of('/foo/bar')), + $h = Location::of( + Url::of('/foo/bar'), ); $this->assertInstanceOf(Header::class, $h); $this->assertSame('Location', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($av, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); $this->assertSame('Location: /foo/bar', $h->toString()); } diff --git a/tests/Header/LocationValueTest.php b/tests/Header/LocationValueTest.php deleted file mode 100644 index 934b4a8..0000000 --- a/tests/Header/LocationValueTest.php +++ /dev/null @@ -1,22 +0,0 @@ -assertInstanceOf(Value::class, $a); - $this->assertSame('/foo/bar', $a->toString()); - } -} From ae676ef91357607a3c00dacf301c3e3d072393c4 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:53:41 +0200 Subject: [PATCH 20/51] remove RangeValue --- CHANGELOG.md | 2 + src/Factory/Header/Factories.php | 6 +-- src/Header/Range.php | 85 +++++++++++++++++++++++++++----- src/Header/RangeValue.php | 83 ------------------------------- tests/Header/RangeTest.php | 38 ++++++++++---- tests/Header/RangeValueTest.php | 45 ----------------- 6 files changed, 106 insertions(+), 153 deletions(-) delete mode 100644 src/Header/RangeValue.php delete mode 100644 tests/Header/RangeValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 40784c0..19f7d9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - `Innmind\Http\Header\IfUnmodifiedSince` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\LastModified` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Location` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Range` constructor is now private, use `::of()` or `::maybe()` named constructors ### Removed @@ -53,6 +54,7 @@ - `Innmind\Http\Header\HostValue` - `Innmind\Http\Header\DateValue` - `Innmind\Http\Header\LocationValue` +- `Innmind\Http\Header\RangeValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index e0b7c64..0ba9f80 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -38,7 +38,6 @@ Header\LinkValue, Header\Location, Header\Range, - Header\RangeValue, Header\Referrer, Header\Parameter, Header\Parameter\Quality, @@ -521,12 +520,11 @@ private static function range(Str $value): Maybe $matches->get('first')->filter(\is_numeric(...)), $matches->get('last')->filter(\is_numeric(...)), ) - ->flatMap(static fn(string $unit, string $first, string $last) => RangeValue::of( + ->flatMap(static fn(string $unit, string $first, string $last) => Range::maybe( $unit, (int) $first, (int) $last, - )) - ->map(static fn($value) => new Range($value)); + )); } /** diff --git a/src/Header/Range.php b/src/Header/Range.php index ffdf38c..ffba9b1 100644 --- a/src/Header/Range.php +++ b/src/Header/Range.php @@ -3,32 +3,69 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; +use Innmind\Http\{ + Header as HeaderInterface, + Exception\DomainException, +}; +use Innmind\Immutable\{ + Sequence, + Str, + Maybe, +}; /** * @psalm-immutable */ final class Range implements HeaderInterface { - public function __construct( - private RangeValue $range, + /** + * @param int<0, max> $firstPosition + * @param int<0, max> $lastPosition + */ + private function __construct( + private string $unit, + private int $firstPosition, + private int $lastPosition, ) { } /** * @psalm-pure + * + * @throws DomainException */ public static function of( string $unit, int $firstPosition, int $lastPosition, ): self { - return new self(new RangeValue( - $unit, - $firstPosition, - $lastPosition, - )); + return self::maybe($unit, $firstPosition, $lastPosition)->match( + static fn($self) => $self, + static fn() => throw new DomainException($unit), + ); + } + + /** + * @psalm-pure + * + * @return Maybe + */ + public static function maybe( + string $unit, + int $firstPosition, + int $lastPosition, + ): Maybe { + if ( + !Str::of($unit)->matches('~^\w+$~') || + $firstPosition < 0 || + $lastPosition < 0 || + $firstPosition > $lastPosition + ) { + /** @var Maybe */ + return Maybe::nothing(); + } + + return Maybe::just(new self($unit, $firstPosition, $lastPosition)); } #[\Override] @@ -43,9 +80,25 @@ public function values(): Sequence return $this->header()->values(); } - public function range(): RangeValue + public function unit(): string + { + return $this->unit; + } + + /** + * @return int<0, max> + */ + public function firstPosition(): int + { + return $this->firstPosition; + } + + /** + * @return int<0, max> + */ + public function lastPosition(): int { - return $this->range; + return $this->lastPosition; } #[\Override] @@ -56,6 +109,14 @@ public function toString(): string private function header(): Header { - return new Header('Range', $this->range); + return new Header( + 'Range', + new Value\Value(\sprintf( + '%s=%s-%s', + $this->unit, + $this->firstPosition, + $this->lastPosition, + )), + ); } } diff --git a/src/Header/RangeValue.php b/src/Header/RangeValue.php deleted file mode 100644 index e89c1df..0000000 --- a/src/Header/RangeValue.php +++ /dev/null @@ -1,83 +0,0 @@ -matches('~^\w+$~') || - $firstPosition < 0 || - $lastPosition < 0 || - $firstPosition > $lastPosition - ) { - throw new DomainException($unit); - } - - $this->unit = $unit; - $this->firstPosition = $firstPosition; - $this->lastPosition = $lastPosition; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of( - string $unit, - int $firstPosition, - int $lastPosition, - ): Maybe { - try { - return Maybe::just(new self($unit, $firstPosition, $lastPosition)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function unit(): string - { - return $this->unit; - } - - public function firstPosition(): int - { - return $this->firstPosition; - } - - public function lastPosition(): int - { - return $this->lastPosition; - } - - #[\Override] - public function toString(): string - { - return \sprintf( - '%s=%s-%s', - $this->unit, - $this->firstPosition, - $this->lastPosition, - ); - } -} diff --git a/tests/Header/RangeTest.php b/tests/Header/RangeTest.php index 84def87..762b20c 100644 --- a/tests/Header/RangeTest.php +++ b/tests/Header/RangeTest.php @@ -6,29 +6,22 @@ use Innmind\Http\{ Header\Range, Header, - Header\RangeValue }; use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; class RangeTest extends TestCase { public function testInterface() { - $h = new Range( - $cr = new RangeValue('bytes', 0, 42), - ); + $h = Range::of('bytes', 0, 42); $this->assertInstanceOf(Header::class, $h); $this->assertSame('Range', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($cr, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); $this->assertSame('Range: bytes=0-42', $h->toString()); - $this->assertSame($cr, $h->range()); } public function testOf() @@ -38,4 +31,31 @@ public function testOf() $this->assertInstanceOf(Range::class, $header); $this->assertSame('Range: bytes=0-42', $header->toString()); } + + public function testValid() + { + $this->assertSame( + 'Range: resources=0-42', + Range::of('resources', 0, 42)->toString(), + ); + } + + #[DataProvider('invalids')] + public function testReturnNothingWhenInvalidRangeValue($unit, $first, $last) + { + $this->assertNull(Range::maybe($unit, $first, $last)->match( + static fn($header) => $header, + static fn() => null, + )); + } + + public static function invalids() + { + return [ + ['', 0, 42], + ['foo', -1, 42], + ['foo', 0, -42], + ['foo', 100, 42], + ]; + } } diff --git a/tests/Header/RangeValueTest.php b/tests/Header/RangeValueTest.php deleted file mode 100644 index 4c381a6..0000000 --- a/tests/Header/RangeValueTest.php +++ /dev/null @@ -1,45 +0,0 @@ -assertInstanceOf(Value::class, $h); - $this->assertSame('resources', $h->unit()); - $this->assertSame(0, $h->firstPosition()); - $this->assertSame(42, $h->lastPosition()); - $this->assertSame('resources=0-42', $h->toString()); - } - - #[DataProvider('invalids')] - public function testThrowWhenInvalidRangeValue($unit, $first, $last) - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage($unit); - - new RangeValue($unit, $first, $last); - } - - public static function invalids() - { - return [ - ['', 0, 42], - ['foo', -1, 42], - ['foo', 0, -42], - ['foo', 100, 42], - ]; - } -} From 54953942a23ee18b31dde2b93891ed9b9643f08d Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 18:55:31 +0200 Subject: [PATCH 21/51] remove ReferrerValue --- CHANGELOG.md | 2 ++ src/Header/Referrer.php | 13 ++++++++----- src/Header/ReferrerValue.php | 28 ---------------------------- tests/Header/ReferrerTest.php | 9 ++------- tests/Header/ReferrerValueTest.php | 22 ---------------------- 5 files changed, 12 insertions(+), 62 deletions(-) delete mode 100644 src/Header/ReferrerValue.php delete mode 100644 tests/Header/ReferrerValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 19f7d9e..23fcd60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ - `Innmind\Http\Header\LastModified` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Location` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Range` constructor is now private, use `::of()` or `::maybe()` named constructors +- `Innmind\Http\Header\Referrer` constructor is now private, use `::of()` named constructor ### Removed @@ -55,6 +56,7 @@ - `Innmind\Http\Header\DateValue` - `Innmind\Http\Header\LocationValue` - `Innmind\Http\Header\RangeValue` +- `Innmind\Http\Header\ReferrerValue` ### Fixed diff --git a/src/Header/Referrer.php b/src/Header/Referrer.php index 52dc60c..e210250 100644 --- a/src/Header/Referrer.php +++ b/src/Header/Referrer.php @@ -12,8 +12,8 @@ */ final class Referrer implements HeaderInterface { - public function __construct( - private ReferrerValue $referrer, + private function __construct( + private Url $referrer, ) { } @@ -22,7 +22,7 @@ public function __construct( */ public static function of(Url $referrer): self { - return new self(new ReferrerValue($referrer)); + return new self($referrer); } #[\Override] @@ -39,7 +39,7 @@ public function values(): Sequence public function referrer(): Url { - return $this->referrer->url(); + return $this->referrer; } #[\Override] @@ -50,6 +50,9 @@ public function toString(): string private function header(): Header { - return new Header('Referer', $this->referrer); + return new Header( + 'Referer', + new Value\Value($this->referrer->toString()), + ); } } diff --git a/src/Header/ReferrerValue.php b/src/Header/ReferrerValue.php deleted file mode 100644 index 4d3dc86..0000000 --- a/src/Header/ReferrerValue.php +++ /dev/null @@ -1,28 +0,0 @@ -url; - } - - #[\Override] - public function toString(): string - { - return $this->url->toString(); - } -} diff --git a/tests/Header/ReferrerTest.php b/tests/Header/ReferrerTest.php index c860a63..27f493c 100644 --- a/tests/Header/ReferrerTest.php +++ b/tests/Header/ReferrerTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\Referrer, Header, - Header\ReferrerValue }; use Innmind\Immutable\Sequence; use Innmind\Url\Url; @@ -16,18 +15,14 @@ class ReferrerTest extends TestCase { public function testInterface() { - $h = new Referrer( - $av = new ReferrerValue(Url::of('/foo/bar')), + $h = Referrer::of( + Url::of('/foo/bar'), ); $this->assertInstanceOf(Header::class, $h); $this->assertSame('Referer', $h->name()); $v = $h->values(); $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($av, $v->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); $this->assertSame('Referer: /foo/bar', $h->toString()); $this->assertSame('/foo/bar', $h->referrer()->toString()); } diff --git a/tests/Header/ReferrerValueTest.php b/tests/Header/ReferrerValueTest.php deleted file mode 100644 index 3652a7c..0000000 --- a/tests/Header/ReferrerValueTest.php +++ /dev/null @@ -1,22 +0,0 @@ -assertInstanceOf(Value::class, $a); - $this->assertSame('/foo/bar', $a->toString()); - } -} From d2e66e426fbf0d3684e8d3f44e88700806c9eec7 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 19:21:41 +0200 Subject: [PATCH 22/51] add Header\Provider --- CHANGELOG.md | 4 ++++ src/Header/Provider.php | 14 ++++++++++++ src/Headers.php | 48 +++++++++++++++++++++++++---------------- 3 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 src/Header/Provider.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 23fcd60..5dc29f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- `Innmind\Http\Header\Provider` + ### Changed - Requires `innmind/filesystem:~8.0` diff --git a/src/Header/Provider.php b/src/Header/Provider.php new file mode 100644 index 0000000..47386c8 --- /dev/null +++ b/src/Header/Provider.php @@ -0,0 +1,14 @@ + $headers + * @param Map $headers */ private function __construct( - private Sequence $headers, + private Map $headers, ) { } - public function __invoke(Header $header): self + public function __invoke(Header|Header\Provider $header): self { - $name = self::normalize($header->name()); + $name = self::normalize(match (true) { + $header instanceof Header => $header->name(), + default => $header->toHeader()->name(), + }); - return new self( - $this - ->headers - ->filter(static fn($header) => self::normalize($header->name()) !== $name) - ->add($header), - ); + return new self(($this->headers)($name, $header)); } /** * @no-named-arguments * @psalm-pure */ - public static function of(Header ...$headers): self + public static function of(Header|Header\Provider ...$headers): self { return Sequence::of(...$headers)->reduce( - new self(Sequence::of()), + new self(Map::of()), static fn(self $headers, $header) => ($headers)($header), ); } @@ -57,11 +56,17 @@ public function get(string $name): Maybe { $normalized = self::normalize($name); - return $this->headers->find(static fn($header) => self::normalize($header->name()) === $normalized); + return $this + ->headers + ->get($normalized) + ->map(static fn($header) => match (true) { + $header instanceof Header => $header, + default => $header->toHeader(), + }); } /** - * @template T of Header + * @template T of Header\Provider * * @param class-string $type * @@ -71,6 +76,7 @@ public function find(string $type): Maybe { return $this ->headers + ->values() ->keep(Instance::of($type)) ->first(); } @@ -93,7 +99,10 @@ public function contains(string $name): bool */ public function filter(callable $filter): self { - return new self($this->headers->filter($filter)); + return new self($this->headers->filter(static fn($_, $header) => match (true) { + $header instanceof Header => $filter($header), + default => $filter($header->toHeader()), + })); } /** @@ -101,7 +110,7 @@ public function filter(callable $filter): self */ public function foreach(callable $function): SideEffect { - return $this->headers->foreach($function); + return $this->all()->foreach($function); } /** @@ -114,7 +123,7 @@ public function foreach(callable $function): SideEffect */ public function reduce($carry, callable $reducer) { - return $this->headers->reduce($carry, $reducer); + return $this->all()->reduce($carry, $reducer); } #[\Override] @@ -128,7 +137,10 @@ public function count(): int */ public function all(): Sequence { - return $this->headers; + return $this->headers->values()->map(static fn($header) => match (true) { + $header instanceof Header => $header, + default => $header->toHeader(), + }); } /** From 879f721359b61cfa16dd23f9cd3cd5ab5c8f6039 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 20:06:27 +0200 Subject: [PATCH 23/51] make all custom headers implement Header\Provider --- CHANGELOG.md | 1 + src/Factory/Header/Factories.php | 3 +- src/Factory/Header/Factory.php | 2 +- src/Header/Accept.php | 21 ++---------- src/Header/AcceptCharset.php | 21 ++---------- src/Header/AcceptEncoding.php | 21 ++---------- src/Header/AcceptLanguage.php | 21 ++---------- src/Header/AcceptRanges.php | 27 ++++------------ src/Header/Age.php | 27 ++-------------- src/Header/Allow.php | 21 ++---------- src/Header/Authorization.php | 27 ++-------------- src/Header/CacheControl.php | 21 ++---------- src/Header/ContentEncoding.php | 27 ++++------------ src/Header/ContentLanguage.php | 21 ++---------- src/Header/ContentLength.php | 32 ++++--------------- src/Header/ContentLocation.php | 28 ++++------------ src/Header/ContentRange.php | 27 ++-------------- src/Header/ContentType.php | 27 ++-------------- src/Header/Cookie.php | 27 ++-------------- src/Header/Date.php | 27 ++-------------- src/Header/Expires.php | 27 ++-------------- src/Header/Host.php | 23 ++----------- src/Header/IfModifiedSince.php | 27 ++-------------- src/Header/IfUnmodifiedSince.php | 27 ++-------------- src/Header/LastModified.php | 27 ++-------------- src/Header/Link.php | 21 ++---------- src/Header/Location.php | 23 ++----------- src/Header/Range.php | 27 ++-------------- src/Header/Referrer.php | 23 ++----------- src/Header/SetCookie.php | 22 ++----------- src/Header/WWWAuthenticate.php | 21 ++---------- .../Header/AcceptCharsetFactoryTest.php | 2 +- .../Header/AcceptEncodingFactoryTest.php | 2 +- tests/Factory/Header/AcceptFactoryTest.php | 2 +- .../Header/AcceptLanguageFactoryTest.php | 2 +- .../Header/AcceptRangesFactoryTest.php | 2 +- tests/Factory/Header/AgeFactoryTest.php | 2 +- tests/Factory/Header/AllowFactoryTest.php | 2 +- .../Header/AuthorizationFactoryTest.php | 2 +- .../Header/CacheControlFactoryTest.php | 2 +- .../Header/ContentEncodingFactoryTest.php | 2 +- .../Header/ContentLanguageFactoryTest.php | 2 +- .../Header/ContentLengthFactoryTest.php | 2 +- .../Header/ContentLocationFactoryTest.php | 2 +- .../Header/ContentRangeFactoryTest.php | 4 +-- .../Factory/Header/ContentTypeFactoryTest.php | 6 ++-- tests/Factory/Header/CookieFactoryTest.php | 4 +-- tests/Factory/Header/DateFactoryTest.php | 2 +- tests/Factory/Header/ExpiresFactoryTest.php | 2 +- tests/Factory/Header/HostFactoryTest.php | 2 +- .../Header/IfModifiedSinceFactoryTest.php | 2 +- .../Header/IfUnmodifiedSinceFactoryTest.php | 2 +- .../Header/LastModifiedFactoryTest.php | 2 +- tests/Factory/Header/LinkFactoryTest.php | 4 +-- tests/Factory/Header/LocationFactoryTest.php | 2 +- tests/Factory/Header/RangeFactoryTest.php | 2 +- tests/Factory/Header/ReferrerFactoryTest.php | 2 +- tests/Header/AcceptCharsetTest.php | 8 ++--- tests/Header/AcceptEncodingTest.php | 8 ++--- tests/Header/AcceptLanguageTest.php | 8 ++--- tests/Header/AcceptRangesTest.php | 8 ++--- tests/Header/AcceptTest.php | 6 ++-- tests/Header/AgeTest.php | 8 ++--- tests/Header/AllowTest.php | 11 +++---- tests/Header/AuthorizationTest.php | 4 +-- tests/Header/CacheControlTest.php | 6 ++-- tests/Header/ContentEncodingTest.php | 4 +-- tests/Header/ContentLanguageTest.php | 10 +++--- tests/Header/ContentLengthTest.php | 4 +-- tests/Header/ContentLocationTest.php | 10 ++---- tests/Header/ContentRangeTest.php | 8 ++--- tests/Header/ContentTypeTest.php | 9 ++---- tests/Header/CookieTest.php | 15 ++------- tests/Header/DateTest.php | 10 ++---- tests/Header/ExpiresTest.php | 12 +++---- tests/Header/HostTest.php | 10 ++---- tests/Header/IfModifiedSinceTest.php | 10 ++---- tests/Header/IfUnmodifiedSinceTest.php | 10 ++---- tests/Header/LastModifiedTest.php | 10 ++---- tests/Header/LinkTest.php | 8 ++--- tests/Header/LocationTest.php | 10 ++---- tests/Header/RangeTest.php | 12 +++---- tests/Header/ReferrerTest.php | 10 ++---- tests/Header/SetCookieTest.php | 14 ++------ tests/Header/WWWAuthenticateTest.php | 11 ++----- tests/HeadersTest.php | 12 +++---- 86 files changed, 216 insertions(+), 809 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dc29f0..a1e618a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ - `Innmind\Http\Header\Location` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Range` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\Referrer` constructor is now private, use `::of()` named constructor +- All custom headers now implements `Innmind\Http\Header\Provider` ### Removed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 0ba9f80..6b1bb16 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -37,6 +37,7 @@ Header\Link, Header\LinkValue, Header\Location, + Header\Provider, Header\Range, Header\Referrer, Header\Parameter, @@ -127,7 +128,7 @@ public static function of(Str $name): ?self } /** - * @return Maybe
+ * @return Maybe */ public function try(Clock $clock, Str $value): Maybe { diff --git a/src/Factory/Header/Factory.php b/src/Factory/Header/Factory.php index 929bab9..63331e8 100644 --- a/src/Factory/Header/Factory.php +++ b/src/Factory/Header/Factory.php @@ -21,7 +21,7 @@ private function __construct( ) { } - public function __invoke(Str $name, Str $value): Header + public function __invoke(Str $name, Str $value): Header|Header\Provider { $factory = Factories::of($name); diff --git a/src/Header/Accept.php b/src/Header/Accept.php index 0798eb4..65f7040 100644 --- a/src/Header/Accept.php +++ b/src/Header/Accept.php @@ -3,13 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; - /** * @psalm-immutable */ -final class Accept implements HeaderInterface +final class Accept implements Provider { private Header $header; @@ -19,20 +16,8 @@ public function __construct(AcceptValue $first, AcceptValue ...$values) } #[\Override] - public function name(): string - { - return $this->header->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header->values(); - } - - #[\Override] - public function toString(): string + public function toHeader(): Header { - return $this->header->toString(); + return $this->header; } } diff --git a/src/Header/AcceptCharset.php b/src/Header/AcceptCharset.php index cbf63c0..e31c5bc 100644 --- a/src/Header/AcceptCharset.php +++ b/src/Header/AcceptCharset.php @@ -3,13 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; - /** * @psalm-immutable */ -final class AcceptCharset implements HeaderInterface +final class AcceptCharset implements Provider { private Header $header; @@ -22,20 +19,8 @@ public function __construct(AcceptCharsetValue ...$values) } #[\Override] - public function name(): string - { - return $this->header->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header->values(); - } - - #[\Override] - public function toString(): string + public function toHeader(): Header { - return $this->header->toString(); + return $this->header; } } diff --git a/src/Header/AcceptEncoding.php b/src/Header/AcceptEncoding.php index d57efff..fe29e0e 100644 --- a/src/Header/AcceptEncoding.php +++ b/src/Header/AcceptEncoding.php @@ -3,13 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; - /** * @psalm-immutable */ -final class AcceptEncoding implements HeaderInterface +final class AcceptEncoding implements Provider { private Header $header; @@ -22,20 +19,8 @@ public function __construct(AcceptEncodingValue ...$values) } #[\Override] - public function name(): string - { - return $this->header->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header->values(); - } - - #[\Override] - public function toString(): string + public function toHeader(): Header { - return $this->header->toString(); + return $this->header; } } diff --git a/src/Header/AcceptLanguage.php b/src/Header/AcceptLanguage.php index 6734051..9ff7b14 100644 --- a/src/Header/AcceptLanguage.php +++ b/src/Header/AcceptLanguage.php @@ -3,13 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; - /** * @psalm-immutable */ -final class AcceptLanguage implements HeaderInterface +final class AcceptLanguage implements Provider { private Header $header; @@ -22,20 +19,8 @@ public function __construct(AcceptLanguageValue ...$values) } #[\Override] - public function name(): string - { - return $this->header->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header->values(); - } - - #[\Override] - public function toString(): string + public function toHeader(): Header { - return $this->header->toString(); + return $this->header; } } diff --git a/src/Header/AcceptRanges.php b/src/Header/AcceptRanges.php index 8d55f8f..6fa4b1f 100644 --- a/src/Header/AcceptRanges.php +++ b/src/Header/AcceptRanges.php @@ -3,12 +3,8 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - Exception\DomainException, -}; +use Innmind\Http\Exception\DomainException; use Innmind\Immutable\{ - Sequence, Str, Maybe, }; @@ -16,7 +12,7 @@ /** * @psalm-immutable */ -final class AcceptRanges implements HeaderInterface +final class AcceptRanges implements Provider { private function __construct( private string $ranges, @@ -50,20 +46,11 @@ public static function maybe(string $range): Maybe } #[\Override] - public function name(): string - { - return 'Accept-Ranges'; - } - - #[\Override] - public function values(): Sequence + public function toHeader(): Header { - return Sequence::of(new Value\Value($this->ranges)); - } - - #[\Override] - public function toString(): string - { - return (new Header($this->name(), ...$this->values()->toList()))->toString(); + return new Header( + 'Accept-Ranges', + new Value\Value($this->ranges), + ); } } diff --git a/src/Header/Age.php b/src/Header/Age.php index 3ca57b5..e34e611 100644 --- a/src/Header/Age.php +++ b/src/Header/Age.php @@ -3,16 +3,12 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\{ - Sequence, - Maybe, -}; +use Innmind\Immutable\Maybe; /** * @psalm-immutable */ -final class Age implements HeaderInterface +final class Age implements Provider { /** * @param int<0, max> $age @@ -45,18 +41,6 @@ public static function maybe(int $age): Maybe }); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - /** * @return int<0, max> */ @@ -66,12 +50,7 @@ public function age(): int } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header('Age', new Value\Value((string) $this->age)); } diff --git a/src/Header/Allow.php b/src/Header/Allow.php index 5a3ebdc..a5b484b 100644 --- a/src/Header/Allow.php +++ b/src/Header/Allow.php @@ -3,13 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; - /** * @psalm-immutable */ -final class Allow implements HeaderInterface +final class Allow implements Provider { private Header $header; @@ -34,20 +31,8 @@ public static function of(string ...$values): self } #[\Override] - public function name(): string - { - return $this->header->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header->values(); - } - - #[\Override] - public function toString(): string + public function toHeader(): Header { - return $this->header->toString(); + return $this->header; } } diff --git a/src/Header/Authorization.php b/src/Header/Authorization.php index d86f187..744ad9e 100644 --- a/src/Header/Authorization.php +++ b/src/Header/Authorization.php @@ -3,12 +3,8 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - Exception\DomainException, -}; +use Innmind\Http\Exception\DomainException; use Innmind\Immutable\{ - Sequence, Str, Maybe, }; @@ -16,7 +12,7 @@ /** * @psalm-immutable */ -final class Authorization implements HeaderInterface +final class Authorization implements Provider { public function __construct( private string $scheme, @@ -48,18 +44,6 @@ public static function maybe(string $scheme, string $parameter): Maybe ->map(static fn() => new self($scheme, $parameter)); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function scheme(): string { return $this->scheme; @@ -71,12 +55,7 @@ public function parameter(): string } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'Authorization', diff --git a/src/Header/CacheControl.php b/src/Header/CacheControl.php index bde726a..d4a3f40 100644 --- a/src/Header/CacheControl.php +++ b/src/Header/CacheControl.php @@ -3,13 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; - /** * @psalm-immutable */ -final class CacheControl implements HeaderInterface +final class CacheControl implements Provider { private Header $header; @@ -19,20 +16,8 @@ public function __construct(CacheControlValue $first, CacheControlValue ...$valu } #[\Override] - public function name(): string - { - return $this->header->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header->values(); - } - - #[\Override] - public function toString(): string + public function toHeader(): Header { - return $this->header->toString(); + return $this->header; } } diff --git a/src/Header/ContentEncoding.php b/src/Header/ContentEncoding.php index 20a088f..b0cb858 100644 --- a/src/Header/ContentEncoding.php +++ b/src/Header/ContentEncoding.php @@ -3,12 +3,8 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - Exception\DomainException, -}; +use Innmind\Http\Exception\DomainException; use Innmind\Immutable\{ - Sequence, Maybe, Str, }; @@ -16,7 +12,7 @@ /** * @psalm-immutable */ -final class ContentEncoding implements HeaderInterface +final class ContentEncoding implements Provider { private function __construct( private string $encoding, @@ -50,20 +46,11 @@ public static function maybe(string $encoding): Maybe } #[\Override] - public function name(): string - { - return 'Content-Encoding'; - } - - #[\Override] - public function values(): Sequence + public function toHeader(): Header { - return Sequence::of(new Value\Value($this->encoding)); - } - - #[\Override] - public function toString(): string - { - return (new Header($this->name(), ...$this->values()->toList()))->toString(); + return new Header( + 'Content-Encoding', + new Value\Value($this->encoding), + ); } } diff --git a/src/Header/ContentLanguage.php b/src/Header/ContentLanguage.php index 5a9a6c0..d153a1b 100644 --- a/src/Header/ContentLanguage.php +++ b/src/Header/ContentLanguage.php @@ -3,13 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; - /** * @psalm-immutable */ -final class ContentLanguage implements HeaderInterface +final class ContentLanguage implements Provider { private Header $header; @@ -34,20 +31,8 @@ public static function of(string ...$values): self } #[\Override] - public function name(): string - { - return $this->header->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header->values(); - } - - #[\Override] - public function toString(): string + public function toHeader(): Header { - return $this->header->toString(); + return $this->header; } } diff --git a/src/Header/ContentLength.php b/src/Header/ContentLength.php index c2b1122..2e9dd1a 100644 --- a/src/Header/ContentLength.php +++ b/src/Header/ContentLength.php @@ -3,16 +3,12 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\{ - Sequence, - Maybe, -}; +use Innmind\Immutable\Maybe; /** * @psalm-immutable */ -final class ContentLength implements HeaderInterface +final class ContentLength implements Provider { /** * @param int<0, max> $length @@ -45,18 +41,6 @@ public static function maybe(int $length): Maybe }); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - /** * @return int<0, max> */ @@ -66,13 +50,11 @@ public function length(): int } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { - return new Header('Content-Length', new Value\Value((string) $this->length)); + return new Header( + 'Content-Length', + new Value\Value((string) $this->length), + ); } } diff --git a/src/Header/ContentLocation.php b/src/Header/ContentLocation.php index 2c11653..052d1c8 100644 --- a/src/Header/ContentLocation.php +++ b/src/Header/ContentLocation.php @@ -3,14 +3,12 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; use Innmind\Url\Url; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class ContentLocation implements HeaderInterface +final class ContentLocation implements Provider { private function __construct( private Url $url, @@ -25,31 +23,17 @@ public static function of(Url $location): self return new self($location); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function url(): Url { return $this->url; } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { - return new Header('Content-Location', new Value\Value($this->url->toString())); + return new Header( + 'Content-Location', + new Value\Value($this->url->toString()), + ); } } diff --git a/src/Header/ContentRange.php b/src/Header/ContentRange.php index 04b30d5..e4e2d32 100644 --- a/src/Header/ContentRange.php +++ b/src/Header/ContentRange.php @@ -3,12 +3,8 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - Exception\DomainException, -}; +use Innmind\Http\Exception\DomainException; use Innmind\Immutable\{ - Sequence, Str, Maybe, }; @@ -16,7 +12,7 @@ /** * @psalm-immutable */ -final class ContentRange implements HeaderInterface +final class ContentRange implements Provider { /** * @param int<0, max> $firstPosition @@ -77,18 +73,6 @@ public static function maybe( )); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function unit(): string { return $this->unit; @@ -119,12 +103,7 @@ public function length(): Maybe } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'Content-Range', diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index b37a643..f340588 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -3,17 +3,13 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; use Innmind\MediaType\MediaType; -use Innmind\Immutable\{ - Sequence, - Str, -}; +use Innmind\Immutable\Str; /** * @psalm-immutable */ -final class ContentType implements HeaderInterface +final class ContentType implements Provider { private function __construct( private MediaType $content, @@ -28,30 +24,13 @@ public static function of(MediaType $content): self return new self($content); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function content(): MediaType { return $this->content; } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { $mediaType = new MediaType( $this->content->topLevel(), diff --git a/src/Header/Cookie.php b/src/Header/Cookie.php index ba2c4e5..132890f 100644 --- a/src/Header/Cookie.php +++ b/src/Header/Cookie.php @@ -3,16 +3,12 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\{ - Sequence, - Map, -}; +use Innmind\Immutable\Map; /** * @psalm-immutable */ -final class Cookie implements HeaderInterface +final class Cookie implements Provider { public function __construct( private CookieValue $value, @@ -28,18 +24,6 @@ public static function of(Parameter ...$parameters): self return new self(new CookieValue(...$parameters)); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - /** * @return Map */ @@ -49,12 +33,7 @@ public function parameters(): Map } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header('Cookie', $this->value); } diff --git a/src/Header/Date.php b/src/Header/Date.php index f94e748..7b34ab4 100644 --- a/src/Header/Date.php +++ b/src/Header/Date.php @@ -3,20 +3,16 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - TimeContinuum\Format\Http, -}; +use Innmind\Http\TimeContinuum\Format\Http; use Innmind\TimeContinuum\{ PointInTime, Offset, }; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class Date implements HeaderInterface +final class Date implements Provider { private function __construct( private PointInTime $point, @@ -31,30 +27,13 @@ public static function of(PointInTime $point): self return new self($point); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function date(): PointInTime { return $this->point; } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'Date', diff --git a/src/Header/Expires.php b/src/Header/Expires.php index 8833eaa..ad8e132 100644 --- a/src/Header/Expires.php +++ b/src/Header/Expires.php @@ -3,20 +3,16 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - TimeContinuum\Format\Http, -}; +use Innmind\Http\TimeContinuum\Format\Http; use Innmind\TimeContinuum\{ PointInTime, Offset, }; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class Expires implements HeaderInterface +final class Expires implements Provider { private function __construct( private PointInTime $point, @@ -31,30 +27,13 @@ public static function of(PointInTime $point): self return new self($point); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function date(): PointInTime { return $this->point; } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'Expires', diff --git a/src/Header/Host.php b/src/Header/Host.php index 9fbbe10..dd168c7 100644 --- a/src/Header/Host.php +++ b/src/Header/Host.php @@ -3,17 +3,15 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; use Innmind\Url\Authority\{ Host as UrlHost, Port, }; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class Host implements HeaderInterface +final class Host implements Provider { private function __construct( private UrlHost $host, @@ -29,18 +27,6 @@ public static function of(UrlHost $host, Port $port): self return new self($host, $port); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function host(): UrlHost { return $this->host; @@ -52,12 +38,7 @@ public function port(): Port } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'Host', diff --git a/src/Header/IfModifiedSince.php b/src/Header/IfModifiedSince.php index b4c44d5..42fa1f8 100644 --- a/src/Header/IfModifiedSince.php +++ b/src/Header/IfModifiedSince.php @@ -3,20 +3,16 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - TimeContinuum\Format\Http, -}; +use Innmind\Http\TimeContinuum\Format\Http; use Innmind\TimeContinuum\{ PointInTime, Offset, }; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class IfModifiedSince implements HeaderInterface +final class IfModifiedSince implements Provider { private function __construct( private PointInTime $point, @@ -31,30 +27,13 @@ public static function of(PointInTime $point): self return new self($point); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function date(): PointInTime { return $this->point; } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'If-Modified-Since', diff --git a/src/Header/IfUnmodifiedSince.php b/src/Header/IfUnmodifiedSince.php index 2c3ad03..cc06c62 100644 --- a/src/Header/IfUnmodifiedSince.php +++ b/src/Header/IfUnmodifiedSince.php @@ -3,20 +3,16 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - TimeContinuum\Format\Http, -}; +use Innmind\Http\TimeContinuum\Format\Http; use Innmind\TimeContinuum\{ PointInTime, Offset, }; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class IfUnmodifiedSince implements HeaderInterface +final class IfUnmodifiedSince implements Provider { private function __construct( private PointInTime $point, @@ -31,30 +27,13 @@ public static function of(PointInTime $point): self return new self($point); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function date(): PointInTime { return $this->point; } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'If-Unmodified-Since', diff --git a/src/Header/LastModified.php b/src/Header/LastModified.php index 6de6898..98210c2 100644 --- a/src/Header/LastModified.php +++ b/src/Header/LastModified.php @@ -3,20 +3,16 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - TimeContinuum\Format\Http, -}; +use Innmind\Http\TimeContinuum\Format\Http; use Innmind\TimeContinuum\{ PointInTime, Offset, }; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class LastModified implements HeaderInterface +final class LastModified implements Provider { private function __construct( private PointInTime $point, @@ -31,30 +27,13 @@ public static function of(PointInTime $point): self return new self($point); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function date(): PointInTime { return $this->point; } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'Last-Modified', diff --git a/src/Header/Link.php b/src/Header/Link.php index ab8323a..3e17b2a 100644 --- a/src/Header/Link.php +++ b/src/Header/Link.php @@ -3,13 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; - /** * @psalm-immutable */ -final class Link implements HeaderInterface +final class Link implements Provider { private Header $header; @@ -22,20 +19,8 @@ public function __construct(LinkValue ...$values) } #[\Override] - public function name(): string - { - return $this->header->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header->values(); - } - - #[\Override] - public function toString(): string + public function toHeader(): Header { - return $this->header->toString(); + return $this->header; } } diff --git a/src/Header/Location.php b/src/Header/Location.php index 2676853..5a0a013 100644 --- a/src/Header/Location.php +++ b/src/Header/Location.php @@ -3,14 +3,12 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; use Innmind\Url\Url; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class Location implements HeaderInterface +final class Location implements Provider { private function __construct( private Url $location, @@ -25,30 +23,13 @@ public static function of(Url $location): self return new self($location); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function url(): Url { return $this->location; } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'Location', diff --git a/src/Header/Range.php b/src/Header/Range.php index ffba9b1..4b69c7f 100644 --- a/src/Header/Range.php +++ b/src/Header/Range.php @@ -3,12 +3,8 @@ namespace Innmind\Http\Header; -use Innmind\Http\{ - Header as HeaderInterface, - Exception\DomainException, -}; +use Innmind\Http\Exception\DomainException; use Innmind\Immutable\{ - Sequence, Str, Maybe, }; @@ -16,7 +12,7 @@ /** * @psalm-immutable */ -final class Range implements HeaderInterface +final class Range implements Provider { /** * @param int<0, max> $firstPosition @@ -68,18 +64,6 @@ public static function maybe( return Maybe::just(new self($unit, $firstPosition, $lastPosition)); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function unit(): string { return $this->unit; @@ -102,12 +86,7 @@ public function lastPosition(): int } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'Range', diff --git a/src/Header/Referrer.php b/src/Header/Referrer.php index e210250..835d2c8 100644 --- a/src/Header/Referrer.php +++ b/src/Header/Referrer.php @@ -3,14 +3,12 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; use Innmind\Url\Url; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class Referrer implements HeaderInterface +final class Referrer implements Provider { private function __construct( private Url $referrer, @@ -25,30 +23,13 @@ public static function of(Url $referrer): self return new self($referrer); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - public function referrer(): Url { return $this->referrer; } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header( 'Referer', diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index 3c8d986..c222ee4 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -3,13 +3,12 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class SetCookie implements HeaderInterface +final class SetCookie implements Provider { /** @var Sequence */ private Sequence $cookies; @@ -31,18 +30,6 @@ public static function of(Parameter ...$values): self return new self(new CookieValue(...$values)); } - #[\Override] - public function name(): string - { - return $this->header()->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header()->values(); - } - /** * @return Sequence */ @@ -52,12 +39,7 @@ public function cookies(): Sequence } #[\Override] - public function toString(): string - { - return $this->header()->toString(); - } - - private function header(): Header + public function toHeader(): Header { return new Header('Set-Cookie', ...$this->cookies->toList()); } diff --git a/src/Header/WWWAuthenticate.php b/src/Header/WWWAuthenticate.php index d459ac7..eff538e 100644 --- a/src/Header/WWWAuthenticate.php +++ b/src/Header/WWWAuthenticate.php @@ -3,13 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header as HeaderInterface; -use Innmind\Immutable\Sequence; - /** * @psalm-immutable */ -final class WWWAuthenticate implements HeaderInterface +final class WWWAuthenticate implements Provider { private Header $header; @@ -22,20 +19,8 @@ public function __construct(WWWAuthenticateValue ...$values) } #[\Override] - public function name(): string - { - return $this->header->name(); - } - - #[\Override] - public function values(): Sequence - { - return $this->header->values(); - } - - #[\Override] - public function toString(): string + public function toHeader(): Header { - return $this->header->toString(); + return $this->header; } } diff --git a/tests/Factory/Header/AcceptCharsetFactoryTest.php b/tests/Factory/Header/AcceptCharsetFactoryTest.php index 3c21068..194b461 100644 --- a/tests/Factory/Header/AcceptCharsetFactoryTest.php +++ b/tests/Factory/Header/AcceptCharsetFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(AcceptCharset::class, $h); $this->assertSame( 'Accept-Charset: iso-8859-5;q=1, unicode-1-1;q=0.8', - $h->toString(), + $h->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/AcceptEncodingFactoryTest.php b/tests/Factory/Header/AcceptEncodingFactoryTest.php index 8918f21..383491b 100644 --- a/tests/Factory/Header/AcceptEncodingFactoryTest.php +++ b/tests/Factory/Header/AcceptEncodingFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(AcceptEncoding::class, $h); $this->assertSame( 'Accept-Encoding: gzip;q=1, identity;q=0.5, *;q=0', - $h->toString(), + $h->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/AcceptFactoryTest.php b/tests/Factory/Header/AcceptFactoryTest.php index e40e8ea..abde4dd 100644 --- a/tests/Factory/Header/AcceptFactoryTest.php +++ b/tests/Factory/Header/AcceptFactoryTest.php @@ -24,7 +24,7 @@ public function testMake() ); $this->assertInstanceOf(Accept::class, $h); - $this->assertSame('Accept: audio/*;q=0.2;level=1, audio/basic', $h->toString()); + $this->assertSame('Accept: audio/*;q=0.2;level=1, audio/basic', $h->toHeader()->toString()); } public function testReturnNothingWhenNotValid() diff --git a/tests/Factory/Header/AcceptLanguageFactoryTest.php b/tests/Factory/Header/AcceptLanguageFactoryTest.php index a106aff..41d5f70 100644 --- a/tests/Factory/Header/AcceptLanguageFactoryTest.php +++ b/tests/Factory/Header/AcceptLanguageFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(AcceptLanguage::class, $h); $this->assertSame( 'Accept-Language: da;q=1, en-gb;q=0.8, en;q=0.7', - $h->toString(), + $h->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/AcceptRangesFactoryTest.php b/tests/Factory/Header/AcceptRangesFactoryTest.php index 403d84b..38cf4fd 100644 --- a/tests/Factory/Header/AcceptRangesFactoryTest.php +++ b/tests/Factory/Header/AcceptRangesFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(AcceptRanges::class, $header); - $this->assertSame('Accept-Ranges: bytes', $header->toString()); + $this->assertSame('Accept-Ranges: bytes', $header->toHeader()->toString()); } } diff --git a/tests/Factory/Header/AgeFactoryTest.php b/tests/Factory/Header/AgeFactoryTest.php index 400f7d5..158ff8b 100644 --- a/tests/Factory/Header/AgeFactoryTest.php +++ b/tests/Factory/Header/AgeFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(Age::class, $header); - $this->assertSame('Age: 42', $header->toString()); + $this->assertSame('Age: 42', $header->toHeader()->toString()); } } diff --git a/tests/Factory/Header/AllowFactoryTest.php b/tests/Factory/Header/AllowFactoryTest.php index 748cbd7..f152b6a 100644 --- a/tests/Factory/Header/AllowFactoryTest.php +++ b/tests/Factory/Header/AllowFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(Allow::class, $header); - $this->assertSame('Allow: GET, POST', $header->toString()); + $this->assertSame('Allow: GET, POST', $header->toHeader()->toString()); } } diff --git a/tests/Factory/Header/AuthorizationFactoryTest.php b/tests/Factory/Header/AuthorizationFactoryTest.php index 0832762..6f0d594 100644 --- a/tests/Factory/Header/AuthorizationFactoryTest.php +++ b/tests/Factory/Header/AuthorizationFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(Authorization::class, $h); $this->assertSame( 'Authorization: Basic realm="WallyWorld"', - $h->toString(), + $h->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/CacheControlFactoryTest.php b/tests/Factory/Header/CacheControlFactoryTest.php index 2d6ffb3..c5ca0f2 100644 --- a/tests/Factory/Header/CacheControlFactoryTest.php +++ b/tests/Factory/Header/CacheControlFactoryTest.php @@ -25,7 +25,7 @@ public function testMake() $this->assertInstanceOf(CacheControl::class, $h); $this->assertSame( 'Cache-Control: no-cache="field", no-store, max-age=42, max-stale=42, min-fresh=42, no-transform, only-if-cached, public, private="field", must-revalidate, proxy-revalidate, s-maxage=42, immutable', - $h->toString(), + $h->toHeader()->toString(), ); } } diff --git a/tests/Factory/Header/ContentEncodingFactoryTest.php b/tests/Factory/Header/ContentEncodingFactoryTest.php index 6d18fff..67009c4 100644 --- a/tests/Factory/Header/ContentEncodingFactoryTest.php +++ b/tests/Factory/Header/ContentEncodingFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(ContentEncoding::class, $header); - $this->assertSame('Content-Encoding: x-gzip', $header->toString()); + $this->assertSame('Content-Encoding: x-gzip', $header->toHeader()->toString()); } } diff --git a/tests/Factory/Header/ContentLanguageFactoryTest.php b/tests/Factory/Header/ContentLanguageFactoryTest.php index 70c7222..743b34f 100644 --- a/tests/Factory/Header/ContentLanguageFactoryTest.php +++ b/tests/Factory/Header/ContentLanguageFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(ContentLanguage::class, $header); - $this->assertSame('Content-Language: fr-FR, fr-CA', $header->toString()); + $this->assertSame('Content-Language: fr-FR, fr-CA', $header->toHeader()->toString()); } } diff --git a/tests/Factory/Header/ContentLengthFactoryTest.php b/tests/Factory/Header/ContentLengthFactoryTest.php index 659f0f5..68a6170 100644 --- a/tests/Factory/Header/ContentLengthFactoryTest.php +++ b/tests/Factory/Header/ContentLengthFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(ContentLength::class, $header); - $this->assertSame('Content-Length: 42', $header->toString()); + $this->assertSame('Content-Length: 42', $header->toHeader()->toString()); } } diff --git a/tests/Factory/Header/ContentLocationFactoryTest.php b/tests/Factory/Header/ContentLocationFactoryTest.php index d4a36b6..b2cb044 100644 --- a/tests/Factory/Header/ContentLocationFactoryTest.php +++ b/tests/Factory/Header/ContentLocationFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(ContentLocation::class, $header); - $this->assertSame('Content-Location: http://example.com/', $header->toString()); + $this->assertSame('Content-Location: http://example.com/', $header->toHeader()->toString()); } } diff --git a/tests/Factory/Header/ContentRangeFactoryTest.php b/tests/Factory/Header/ContentRangeFactoryTest.php index d8a1e01..98e01d8 100644 --- a/tests/Factory/Header/ContentRangeFactoryTest.php +++ b/tests/Factory/Header/ContentRangeFactoryTest.php @@ -22,7 +22,7 @@ public function testMakeWithoutLength() ); $this->assertInstanceOf(ContentRange::class, $header); - $this->assertSame('Content-Range: bytes 0-42/*', $header->toString()); + $this->assertSame('Content-Range: bytes 0-42/*', $header->toHeader()->toString()); } public function testMakeWithLength() @@ -33,7 +33,7 @@ public function testMakeWithLength() ); $this->assertInstanceOf(ContentRange::class, $header); - $this->assertSame('Content-Range: bytes 0-42/66', $header->toString()); + $this->assertSame('Content-Range: bytes 0-42/66', $header->toHeader()->toString()); } public function testReturnNothingWhenNotValid() diff --git a/tests/Factory/Header/ContentTypeFactoryTest.php b/tests/Factory/Header/ContentTypeFactoryTest.php index ccf6be5..3af9d43 100644 --- a/tests/Factory/Header/ContentTypeFactoryTest.php +++ b/tests/Factory/Header/ContentTypeFactoryTest.php @@ -22,7 +22,7 @@ public function testMakeWithoutParameters() ); $this->assertInstanceOf(ContentType::class, $header); - $this->assertSame('Content-Type: image/gif', $header->toString()); + $this->assertSame('Content-Type: image/gif', $header->toHeader()->toString()); } public function testMakeWithParameters() @@ -33,7 +33,7 @@ public function testMakeWithParameters() ); $this->assertInstanceOf(ContentType::class, $header); - $this->assertSame('Content-Type: image/gif;foo=bar;q=0.5', $header->toString()); + $this->assertSame('Content-Type: image/gif;foo=bar;q=0.5', $header->toHeader()->toString()); } public function testReturnNothingWhenNotValid() @@ -57,7 +57,7 @@ public function testFormEncoded() $this->assertInstanceOf(ContentType::class, $header); $this->assertSame( 'Content-Type: application/x-www-form-urlencoded', - $header->toString(), + $header->toHeader()->toString(), ); } } diff --git a/tests/Factory/Header/CookieFactoryTest.php b/tests/Factory/Header/CookieFactoryTest.php index f25e1b6..5c5a34a 100644 --- a/tests/Factory/Header/CookieFactoryTest.php +++ b/tests/Factory/Header/CookieFactoryTest.php @@ -21,10 +21,10 @@ public function testMake() ); $this->assertInstanceOf(Cookie::class, $header); - $this->assertSame('Cookie: foo=bar; bar=baz; baz=foo', $header->toString()); + $this->assertSame('Cookie: foo=bar; bar=baz; baz=foo', $header->toHeader()->toString()); $this->assertSame( 'Cookie: ', - Factory::new(Clock::live())(Str::of('Cookie'), Str::of(''))->toString(), + Factory::new(Clock::live())(Str::of('Cookie'), Str::of(''))->toHeader()->toString(), ); } } diff --git a/tests/Factory/Header/DateFactoryTest.php b/tests/Factory/Header/DateFactoryTest.php index a70f3dd..41ca8de 100644 --- a/tests/Factory/Header/DateFactoryTest.php +++ b/tests/Factory/Header/DateFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(Date::class, $h); $this->assertSame( 'Date: Tue, 15 Nov 1994 08:12:31 GMT', - $h->toString(), + $h->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/ExpiresFactoryTest.php b/tests/Factory/Header/ExpiresFactoryTest.php index 124235f..e41b507 100644 --- a/tests/Factory/Header/ExpiresFactoryTest.php +++ b/tests/Factory/Header/ExpiresFactoryTest.php @@ -24,7 +24,7 @@ public function testMake() $this->assertInstanceOf(Expires::class, $header); $this->assertSame( 'Expires: Tue, 15 Nov 1994 08:12:31 GMT', - $header->toString(), + $header->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/HostFactoryTest.php b/tests/Factory/Header/HostFactoryTest.php index 260c7d1..34c24e6 100644 --- a/tests/Factory/Header/HostFactoryTest.php +++ b/tests/Factory/Header/HostFactoryTest.php @@ -28,7 +28,7 @@ public function testMake(string $host) $this->assertInstanceOf(Host::class, $h); $this->assertSame( 'Host: '.$host, - $h->toString(), + $h->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/IfModifiedSinceFactoryTest.php b/tests/Factory/Header/IfModifiedSinceFactoryTest.php index 10ab921..7e1db6a 100644 --- a/tests/Factory/Header/IfModifiedSinceFactoryTest.php +++ b/tests/Factory/Header/IfModifiedSinceFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(IfModifiedSince::class, $h); $this->assertSame( 'If-Modified-Since: Tue, 15 Nov 1994 08:12:31 GMT', - $h->toString(), + $h->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/IfUnmodifiedSinceFactoryTest.php b/tests/Factory/Header/IfUnmodifiedSinceFactoryTest.php index 6af5d96..2b17b03 100644 --- a/tests/Factory/Header/IfUnmodifiedSinceFactoryTest.php +++ b/tests/Factory/Header/IfUnmodifiedSinceFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(IfUnmodifiedSince::class, $h); $this->assertSame( 'If-Unmodified-Since: Tue, 15 Nov 1994 08:12:31 GMT', - $h->toString(), + $h->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/LastModifiedFactoryTest.php b/tests/Factory/Header/LastModifiedFactoryTest.php index cf47758..61c4dbf 100644 --- a/tests/Factory/Header/LastModifiedFactoryTest.php +++ b/tests/Factory/Header/LastModifiedFactoryTest.php @@ -24,7 +24,7 @@ public function testMake() $this->assertInstanceOf(LastModified::class, $header); $this->assertSame( 'Last-Modified: Tue, 15 Nov 1994 08:12:31 GMT', - $header->toString(), + $header->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/LinkFactoryTest.php b/tests/Factory/Header/LinkFactoryTest.php index 45a7df0..d303b3b 100644 --- a/tests/Factory/Header/LinkFactoryTest.php +++ b/tests/Factory/Header/LinkFactoryTest.php @@ -24,7 +24,7 @@ public function testMake() $this->assertInstanceOf(Link::class, $header); $this->assertSame( 'Link: ; rel="next";title=foo;bar=baz, ; rel="related"', - $header->toString(), + $header->toHeader()->toString(), ); } @@ -38,7 +38,7 @@ public function testMakeWithComplexParameterValue() $this->assertInstanceOf(Link::class, $header); $this->assertSame( 'Link: ; rel="next";title=!#$%&\'()*+-./0123456789:<=>?@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMOPQRSTUVWXYZ[]^_`{|}~', - $header->toString(), + $header->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/LocationFactoryTest.php b/tests/Factory/Header/LocationFactoryTest.php index e212cae..948ac53 100644 --- a/tests/Factory/Header/LocationFactoryTest.php +++ b/tests/Factory/Header/LocationFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(Location::class, $header); - $this->assertSame('Location: http://example.com/', $header->toString()); + $this->assertSame('Location: http://example.com/', $header->toHeader()->toString()); } } diff --git a/tests/Factory/Header/RangeFactoryTest.php b/tests/Factory/Header/RangeFactoryTest.php index eae0c64..b6de084 100644 --- a/tests/Factory/Header/RangeFactoryTest.php +++ b/tests/Factory/Header/RangeFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(Range::class, $h); $this->assertSame( 'Range: bytes=0-42', - $h->toString(), + $h->toHeader()->toString(), ); } diff --git a/tests/Factory/Header/ReferrerFactoryTest.php b/tests/Factory/Header/ReferrerFactoryTest.php index 66e493c..cca79c1 100644 --- a/tests/Factory/Header/ReferrerFactoryTest.php +++ b/tests/Factory/Header/ReferrerFactoryTest.php @@ -25,7 +25,7 @@ public function testMake() $this->assertInstanceOf(Referrer::class, $h); $this->assertSame( 'Referer: http://www.w3.org/hypertext/DataSources/Overview.html', - $h->toString(), + $h->toHeader()->toString(), ); } } diff --git a/tests/Header/AcceptCharsetTest.php b/tests/Header/AcceptCharsetTest.php index c37ef11..6fdf9c1 100644 --- a/tests/Header/AcceptCharsetTest.php +++ b/tests/Header/AcceptCharsetTest.php @@ -19,14 +19,12 @@ public function testInterface() $v = new AcceptCharsetValue('unicode-1-1', new Quality(0.8)), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Accept-Charset', $h->name()); - $this->assertTrue($h->values()->contains($v)); - $this->assertSame('Accept-Charset: unicode-1-1;q=0.8', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Accept-Charset: unicode-1-1;q=0.8', $h->toHeader()->toString()); } public function testWithoutValues() { - $this->assertSame('Accept-Charset: ', (new AcceptCharset)->toString()); + $this->assertSame('Accept-Charset: ', (new AcceptCharset)->toHeader()->toString()); } } diff --git a/tests/Header/AcceptEncodingTest.php b/tests/Header/AcceptEncodingTest.php index b93cec7..8b195cf 100644 --- a/tests/Header/AcceptEncodingTest.php +++ b/tests/Header/AcceptEncodingTest.php @@ -19,14 +19,12 @@ public function testInterface() $v = new AcceptEncodingValue('compress', new Quality(1)), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Accept-Encoding', $h->name()); - $this->assertTrue($h->values()->contains($v)); - $this->assertSame('Accept-Encoding: compress;q=1', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Accept-Encoding: compress;q=1', $h->toHeader()->toString()); } public function testWithoutValues() { - $this->assertSame('Accept-Encoding: ', (new AcceptEncoding)->toString()); + $this->assertSame('Accept-Encoding: ', (new AcceptEncoding)->toHeader()->toString()); } } diff --git a/tests/Header/AcceptLanguageTest.php b/tests/Header/AcceptLanguageTest.php index e9d5e82..a7a38c3 100644 --- a/tests/Header/AcceptLanguageTest.php +++ b/tests/Header/AcceptLanguageTest.php @@ -19,14 +19,12 @@ public function testInterface() $v = new AcceptLanguageValue('fr', new Quality(0.8)), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Accept-Language', $h->name()); - $this->assertTrue($h->values()->contains($v)); - $this->assertSame('Accept-Language: fr;q=0.8', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Accept-Language: fr;q=0.8', $h->toHeader()->toString()); } public function testWithoutValues() { - $this->assertSame('Accept-Language: ', (new AcceptLanguage)->toString()); + $this->assertSame('Accept-Language: ', (new AcceptLanguage)->toHeader()->toString()); } } diff --git a/tests/Header/AcceptRangesTest.php b/tests/Header/AcceptRangesTest.php index d74207d..3efb4f3 100644 --- a/tests/Header/AcceptRangesTest.php +++ b/tests/Header/AcceptRangesTest.php @@ -7,7 +7,6 @@ Header\AcceptRanges, Header, }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -18,11 +17,8 @@ public function testOf() $header = AcceptRanges::of('bytes'); $this->assertInstanceOf(AcceptRanges::class, $header); - $this->assertInstanceOf(Header::class, $header); - $this->assertSame('Accept-Ranges', $header->name()); - $values = $header->values(); - $this->assertInstanceOf(Sequence::class, $values); - $this->assertSame('Accept-Ranges: bytes', $header->toString()); + $this->assertInstanceOf(Header\Provider::class, $header); + $this->assertSame('Accept-Ranges: bytes', $header->toHeader()->toString()); } public function testValid() diff --git a/tests/Header/AcceptTest.php b/tests/Header/AcceptTest.php index 0a6d4ef..5f30c5c 100644 --- a/tests/Header/AcceptTest.php +++ b/tests/Header/AcceptTest.php @@ -23,9 +23,7 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Accept', $h->name()); - $this->assertTrue($h->values()->contains($v)); - $this->assertSame('Accept: text/html;q=0.8', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Accept: text/html;q=0.8', $h->toHeader()->toString()); } } diff --git a/tests/Header/AgeTest.php b/tests/Header/AgeTest.php index 90a3a93..9dbed01 100644 --- a/tests/Header/AgeTest.php +++ b/tests/Header/AgeTest.php @@ -7,7 +7,6 @@ Header\Age, Header, }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class AgeTest extends TestCase @@ -17,11 +16,8 @@ public function testOf() $header = Age::of(42); $this->assertInstanceOf(Age::class, $header); - $this->assertInstanceOf(Header::class, $header); - $this->assertSame('Age', $header->name()); - $values = $header->values(); - $this->assertInstanceOf(Sequence::class, $values); - $this->assertSame('Age: 42', $header->toString()); + $this->assertInstanceOf(Header\Provider::class, $header); + $this->assertSame('Age: 42', $header->toHeader()->toString()); } public function testReturnNothingWhenInvalidAgeValue() diff --git a/tests/Header/AllowTest.php b/tests/Header/AllowTest.php index 97811ff..7d27b6f 100644 --- a/tests/Header/AllowTest.php +++ b/tests/Header/AllowTest.php @@ -18,15 +18,13 @@ public function testInterface() $v = new AllowValue('GET'), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Allow', $h->name()); - $this->assertTrue($h->values()->contains($v)); - $this->assertSame('Allow: GET', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Allow: GET', $h->toHeader()->toString()); } public function testWithoutValues() { - $this->assertSame('Allow: ', (new Allow)->toString()); + $this->assertSame('Allow: ', (new Allow)->toHeader()->toString()); } public function testOf() @@ -34,7 +32,6 @@ public function testOf() $header = Allow::of('GET'); $this->assertInstanceOf(Allow::class, $header); - $this->assertSame('Allow', $header->name()); - $this->assertSame('Allow: GET', $header->toString()); + $this->assertSame('Allow: GET', $header->toHeader()->toString()); } } diff --git a/tests/Header/AuthorizationTest.php b/tests/Header/AuthorizationTest.php index 40487d7..5459007 100644 --- a/tests/Header/AuthorizationTest.php +++ b/tests/Header/AuthorizationTest.php @@ -17,8 +17,8 @@ public function testOf() $header = Authorization::of('Basic', 'foo'); $this->assertInstanceOf(Authorization::class, $header); - $this->assertInstanceOf(Header::class, $header); - $this->assertSame('Authorization: Basic foo', $header->toString()); + $this->assertInstanceOf(Header\Provider::class, $header); + $this->assertSame('Authorization: Basic foo', $header->toHeader()->toString()); $this->assertSame('Basic', $header->scheme()); $this->assertSame('foo', $header->parameter()); } diff --git a/tests/Header/CacheControlTest.php b/tests/Header/CacheControlTest.php index d4f9d6b..fe897cf 100644 --- a/tests/Header/CacheControlTest.php +++ b/tests/Header/CacheControlTest.php @@ -18,9 +18,7 @@ public function testInterface() $v = new PublicCache, ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Cache-Control', $h->name()); - $this->assertTrue($h->values()->contains($v)); - $this->assertSame('Cache-Control: public', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Cache-Control: public', $h->toHeader()->toString()); } } diff --git a/tests/Header/ContentEncodingTest.php b/tests/Header/ContentEncodingTest.php index f2f19b1..7d39553 100644 --- a/tests/Header/ContentEncodingTest.php +++ b/tests/Header/ContentEncodingTest.php @@ -17,8 +17,8 @@ public function testOf() $header = ContentEncoding::of('compress'); $this->assertInstanceOf(ContentEncoding::class, $header); - $this->assertInstanceOf(Header::class, $header); - $this->assertSame('Content-Encoding: compress', $header->toString()); + $this->assertInstanceOf(Header\Provider::class, $header); + $this->assertSame('Content-Encoding: compress', $header->toHeader()->toString()); } public function testValids() diff --git a/tests/Header/ContentLanguageTest.php b/tests/Header/ContentLanguageTest.php index db5bd55..a4aeb4d 100644 --- a/tests/Header/ContentLanguageTest.php +++ b/tests/Header/ContentLanguageTest.php @@ -18,10 +18,8 @@ public function testInterface() $v = new ContentLanguageValue('fr'), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Content-Language', $h->name()); - $this->assertTrue($h->values()->contains($v)); - $this->assertSame('Content-Language: fr', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Content-Language: fr', $h->toHeader()->toString()); } public function test() @@ -29,11 +27,11 @@ public function test() $header = ContentLanguage::of('fr'); $this->assertInstanceOf(ContentLanguage::class, $header); - $this->assertSame('Content-Language: fr', $header->toString()); + $this->assertSame('Content-Language: fr', $header->toHeader()->toString()); } public function testWithoutValues() { - $this->assertSame('Content-Language: ', (new ContentLanguage)->toString()); + $this->assertSame('Content-Language: ', (new ContentLanguage)->toHeader()->toString()); } } diff --git a/tests/Header/ContentLengthTest.php b/tests/Header/ContentLengthTest.php index 7a2f644..a0bf4b2 100644 --- a/tests/Header/ContentLengthTest.php +++ b/tests/Header/ContentLengthTest.php @@ -16,8 +16,8 @@ public function testOf() $header = ContentLength::of(42); $this->assertInstanceOf(ContentLength::class, $header); - $this->assertInstanceOf(Header::class, $header); - $this->assertSame('Content-Length: 42', $header->toString()); + $this->assertInstanceOf(Header\Provider::class, $header); + $this->assertSame('Content-Length: 42', $header->toHeader()->toString()); } public function testReturnNothingWhenInvalidContentLengthValue() diff --git a/tests/Header/ContentLocationTest.php b/tests/Header/ContentLocationTest.php index 4e9dc8c..717e1d7 100644 --- a/tests/Header/ContentLocationTest.php +++ b/tests/Header/ContentLocationTest.php @@ -7,7 +7,6 @@ Header\ContentLocation, Header, }; -use Innmind\Immutable\Sequence; use Innmind\Url\Url; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -17,11 +16,8 @@ public function testInterface() { $h = ContentLocation::of(Url::of('/foo/bar')); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Content-Location', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('Content-Location: /foo/bar', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Content-Location: /foo/bar', $h->toHeader()->toString()); $this->assertSame('/foo/bar', $h->url()->toString()); } @@ -30,6 +26,6 @@ public function testOf() $header = ContentLocation::of(Url::of('/foo/bar')); $this->assertInstanceOf(ContentLocation::class, $header); - $this->assertSame('Content-Location: /foo/bar', $header->toString()); + $this->assertSame('Content-Location: /foo/bar', $header->toHeader()->toString()); } } diff --git a/tests/Header/ContentRangeTest.php b/tests/Header/ContentRangeTest.php index d878b52..d1253cb 100644 --- a/tests/Header/ContentRangeTest.php +++ b/tests/Header/ContentRangeTest.php @@ -17,19 +17,19 @@ public function testOf() $header = ContentRange::of('bytes', 0, 42); $this->assertInstanceOf(ContentRange::class, $header); - $this->assertInstanceOf(Header::class, $header); - $this->assertSame('Content-Range: bytes 0-42/*', $header->toString()); + $this->assertInstanceOf(Header\Provider::class, $header); + $this->assertSame('Content-Range: bytes 0-42/*', $header->toHeader()->toString()); } public function testValids() { $this->assertSame( 'Content-Range: resources 0-42/*', - ContentRange::of('resources', 0, 42)->toString(), + ContentRange::of('resources', 0, 42)->toHeader()->toString(), ); $this->assertSame( 'Content-Range: resources 0-499/1234', - ContentRange::of('resources', 0, 499, 1234)->toString(), + ContentRange::of('resources', 0, 499, 1234)->toHeader()->toString(), ); } diff --git a/tests/Header/ContentTypeTest.php b/tests/Header/ContentTypeTest.php index e9c3abc..245f75b 100644 --- a/tests/Header/ContentTypeTest.php +++ b/tests/Header/ContentTypeTest.php @@ -8,7 +8,6 @@ Header, }; use Innmind\MediaType\MediaType; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -20,12 +19,8 @@ public function testInterface() $ct = MediaType::of('text/html; charset="UTF-8"'), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Content-Type', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame($ct, $h->content()); - $this->assertSame('Content-Type: text/html;charset=UTF-8', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Content-Type: text/html;charset=UTF-8', $h->toHeader()->toString()); $this->assertSame('text/html; charset=UTF-8', $h->content()->toString()); } diff --git a/tests/Header/CookieTest.php b/tests/Header/CookieTest.php index eb81768..bb4b9e0 100644 --- a/tests/Header/CookieTest.php +++ b/tests/Header/CookieTest.php @@ -9,7 +9,6 @@ Header\CookieValue, Header\Parameter\Parameter }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class CookieTest extends TestCase @@ -20,16 +19,8 @@ public function testInterface() $value = new CookieValue(new Parameter('foo', 'bar')), ); - $this->assertInstanceOf(Header::class, $cookie); - $this->assertSame('Cookie', $cookie->name()); - $values = $cookie->values(); - $this->assertInstanceOf(Sequence::class, $values); - $this->assertSame($value, $values->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); - $this->assertSame('Cookie: foo=bar', $cookie->toString()); - $this->assertSame($value->parameters(), $cookie->parameters()); + $this->assertInstanceOf(Header\Provider::class, $cookie); + $this->assertSame('Cookie: foo=bar', $cookie->toHeader()->toString()); } public function testOf() @@ -37,6 +28,6 @@ public function testOf() $cookie = Cookie::of(new Parameter('foo', 'bar')); $this->assertInstanceOf(Cookie::class, $cookie); - $this->assertSame('Cookie: foo=bar', $cookie->toString()); + $this->assertSame('Cookie: foo=bar', $cookie->toHeader()->toString()); } } diff --git a/tests/Header/DateTest.php b/tests/Header/DateTest.php index dc8b243..327635c 100644 --- a/tests/Header/DateTest.php +++ b/tests/Header/DateTest.php @@ -8,7 +8,6 @@ Header, }; use Innmind\TimeContinuum\PointInTime; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class DateTest extends TestCase @@ -21,11 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Date', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('Date: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Date: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); } public function testOf() @@ -35,6 +31,6 @@ public function testOf() )); $this->assertInstanceOf(Date::class, $header); - $this->assertSame('Date: Fri, 01 Jan 2016 10:12:12 GMT', $header->toString()); + $this->assertSame('Date: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); } } diff --git a/tests/Header/ExpiresTest.php b/tests/Header/ExpiresTest.php index 9ca63ef..64c49d7 100644 --- a/tests/Header/ExpiresTest.php +++ b/tests/Header/ExpiresTest.php @@ -8,7 +8,6 @@ Header, }; use Innmind\TimeContinuum\PointInTime; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class ExpiresTest extends TestCase @@ -21,11 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Expires', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('Expires: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Expires: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); } public function testOf() @@ -34,7 +30,7 @@ public function testOf() new \DateTimeImmutable('2016-01-01 12:12:12+0200'), )); - $this->assertInstanceOf(Header::class, $header); - $this->assertSame('Expires: Fri, 01 Jan 2016 10:12:12 GMT', $header->toString()); + $this->assertInstanceOf(Header\Provider::class, $header); + $this->assertSame('Expires: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); } } diff --git a/tests/Header/HostTest.php b/tests/Header/HostTest.php index c561259..d94e6e6 100644 --- a/tests/Header/HostTest.php +++ b/tests/Header/HostTest.php @@ -7,7 +7,6 @@ Header\Host, Header, }; -use Innmind\Immutable\Sequence; use Innmind\Url\Authority\{ Host as UrlHost, Port, @@ -23,11 +22,8 @@ public function testInterface() Port::of(8080), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Host', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('Host: example.com:8080', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Host: example.com:8080', $h->toHeader()->toString()); } public function testOf() @@ -35,6 +31,6 @@ public function testOf() $header = Host::of(UrlHost::of('example.com'), Port::none()); $this->assertInstanceOf(Host::class, $header); - $this->assertSame('Host: example.com', $header->toString()); + $this->assertSame('Host: example.com', $header->toHeader()->toString()); } } diff --git a/tests/Header/IfModifiedSinceTest.php b/tests/Header/IfModifiedSinceTest.php index 8e19827..d3e5cf5 100644 --- a/tests/Header/IfModifiedSinceTest.php +++ b/tests/Header/IfModifiedSinceTest.php @@ -8,7 +8,6 @@ Header, }; use Innmind\TimeContinuum\PointInTime; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class IfModifiedSinceTest extends TestCase @@ -21,11 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('If-Modified-Since', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('If-Modified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('If-Modified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); } public function testOf() @@ -35,6 +31,6 @@ public function testOf() )); $this->assertInstanceOf(IfModifiedSince::class, $header); - $this->assertSame('If-Modified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $header->toString()); + $this->assertSame('If-Modified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); } } diff --git a/tests/Header/IfUnmodifiedSinceTest.php b/tests/Header/IfUnmodifiedSinceTest.php index 7ba797c..76bdc68 100644 --- a/tests/Header/IfUnmodifiedSinceTest.php +++ b/tests/Header/IfUnmodifiedSinceTest.php @@ -8,7 +8,6 @@ Header, }; use Innmind\TimeContinuum\PointInTime; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class IfUnmodifiedSinceTest extends TestCase @@ -21,11 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('If-Unmodified-Since', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('If-Unmodified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('If-Unmodified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); } public function testOf() @@ -35,6 +31,6 @@ public function testOf() )); $this->assertInstanceOf(IfUnmodifiedSince::class, $header); - $this->assertSame('If-Unmodified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $header->toString()); + $this->assertSame('If-Unmodified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); } } diff --git a/tests/Header/LastModifiedTest.php b/tests/Header/LastModifiedTest.php index 4b4cd7b..8b1ce62 100644 --- a/tests/Header/LastModifiedTest.php +++ b/tests/Header/LastModifiedTest.php @@ -8,7 +8,6 @@ Header, }; use Innmind\TimeContinuum\PointInTime; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class LastModifiedTest extends TestCase @@ -21,11 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Last-Modified', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('Last-Modified: Fri, 01 Jan 2016 10:12:12 GMT', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Last-Modified: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); } public function testOf() @@ -35,6 +31,6 @@ public function testOf() )); $this->assertInstanceOf(LastModified::class, $header); - $this->assertSame('Last-Modified: Fri, 01 Jan 2016 10:12:12 GMT', $header->toString()); + $this->assertSame('Last-Modified: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); } } diff --git a/tests/Header/LinkTest.php b/tests/Header/LinkTest.php index 98e4725..c8cee47 100644 --- a/tests/Header/LinkTest.php +++ b/tests/Header/LinkTest.php @@ -24,17 +24,15 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Link', $h->name()); - $this->assertTrue($h->values()->contains($v)); + $this->assertInstanceOf(Header\Provider::class, $h); $this->assertSame( 'Link: ; rel="some relation";title=Foo', - $h->toString(), + $h->toHeader()->toString(), ); } public function testWithoutValues() { - $this->assertSame('Link: ', (new Link)->toString()); + $this->assertSame('Link: ', (new Link)->toHeader()->toString()); } } diff --git a/tests/Header/LocationTest.php b/tests/Header/LocationTest.php index 673eae4..d95d59c 100644 --- a/tests/Header/LocationTest.php +++ b/tests/Header/LocationTest.php @@ -7,7 +7,6 @@ Header\Location, Header, }; -use Innmind\Immutable\Sequence; use Innmind\Url\Url; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -19,11 +18,8 @@ public function testInterface() Url::of('/foo/bar'), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Location', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('Location: /foo/bar', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Location: /foo/bar', $h->toHeader()->toString()); } public function testOf() @@ -31,6 +27,6 @@ public function testOf() $header = Location::of(Url::of('/foo/bar')); $this->assertInstanceOf(Location::class, $header); - $this->assertSame('Location: /foo/bar', $header->toString()); + $this->assertSame('Location: /foo/bar', $header->toHeader()->toString()); } } diff --git a/tests/Header/RangeTest.php b/tests/Header/RangeTest.php index 762b20c..25d56de 100644 --- a/tests/Header/RangeTest.php +++ b/tests/Header/RangeTest.php @@ -7,7 +7,6 @@ Header\Range, Header, }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -17,11 +16,8 @@ public function testInterface() { $h = Range::of('bytes', 0, 42); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Range', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('Range: bytes=0-42', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Range: bytes=0-42', $h->toHeader()->toString()); } public function testOf() @@ -29,14 +25,14 @@ public function testOf() $header = Range::of('bytes', 0, 42); $this->assertInstanceOf(Range::class, $header); - $this->assertSame('Range: bytes=0-42', $header->toString()); + $this->assertSame('Range: bytes=0-42', $header->toHeader()->toString()); } public function testValid() { $this->assertSame( 'Range: resources=0-42', - Range::of('resources', 0, 42)->toString(), + Range::of('resources', 0, 42)->toHeader()->toString(), ); } diff --git a/tests/Header/ReferrerTest.php b/tests/Header/ReferrerTest.php index 27f493c..46a85bd 100644 --- a/tests/Header/ReferrerTest.php +++ b/tests/Header/ReferrerTest.php @@ -7,7 +7,6 @@ Header\Referrer, Header, }; -use Innmind\Immutable\Sequence; use Innmind\Url\Url; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -19,11 +18,8 @@ public function testInterface() Url::of('/foo/bar'), ); - $this->assertInstanceOf(Header::class, $h); - $this->assertSame('Referer', $h->name()); - $v = $h->values(); - $this->assertInstanceOf(Sequence::class, $v); - $this->assertSame('Referer: /foo/bar', $h->toString()); + $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertSame('Referer: /foo/bar', $h->toHeader()->toString()); $this->assertSame('/foo/bar', $h->referrer()->toString()); } @@ -32,6 +28,6 @@ public function testOf() $header = Referrer::of(Url::of('/foo/bar')); $this->assertInstanceOf(Referrer::class, $header); - $this->assertSame('Referer: /foo/bar', $header->toString()); + $this->assertSame('Referer: /foo/bar', $header->toHeader()->toString()); } } diff --git a/tests/Header/SetCookieTest.php b/tests/Header/SetCookieTest.php index b29beec..a130e92 100644 --- a/tests/Header/SetCookieTest.php +++ b/tests/Header/SetCookieTest.php @@ -10,7 +10,6 @@ Header\Parameter\Parameter, Header\CookieParameter\Secure }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class SetCookieTest extends TestCase @@ -27,15 +26,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header::class, $cookie); - $this->assertSame('Set-Cookie', $cookie->name()); - $values = $cookie->values(); - $this->assertInstanceOf(Sequence::class, $values); - $this->assertSame($value, $values->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); - $this->assertSame('Set-Cookie: foo=bar; Secure, bar=baz', $cookie->toString()); + $this->assertInstanceOf(Header\Provider::class, $cookie); + $this->assertSame('Set-Cookie: foo=bar; Secure, bar=baz', $cookie->toHeader()->toString()); } public function testOf() @@ -46,6 +38,6 @@ public function testOf() ); $this->assertInstanceOf(SetCookie::class, $cookie); - $this->assertSame('Set-Cookie: foo=bar; bar=baz', $cookie->toString()); + $this->assertSame('Set-Cookie: foo=bar; bar=baz', $cookie->toHeader()->toString()); } } diff --git a/tests/Header/WWWAuthenticateTest.php b/tests/Header/WWWAuthenticateTest.php index 9f2cbd8..92e8bde 100644 --- a/tests/Header/WWWAuthenticateTest.php +++ b/tests/Header/WWWAuthenticateTest.php @@ -8,7 +8,6 @@ Header\WWWAuthenticateValue, Header }; -use Innmind\Immutable\Sequence; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class WWWAuthenticateTest extends TestCase @@ -19,13 +18,7 @@ public function testInterface() $value = new WWWAuthenticateValue('Bearer', 'some value'), ); - $this->assertInstanceOf(Header::class, $header); - $this->assertInstanceOf(Sequence::class, $header->values()); - $this->assertCount(1, $header->values()); - $this->assertSame($value, $header->values()->find(static fn() => true)->match( - static fn($first) => $first, - static fn() => null, - )); - $this->assertSame('WWW-Authenticate: Bearer realm="some value"', $header->toString()); + $this->assertInstanceOf(Header\Provider::class, $header); + $this->assertSame('WWW-Authenticate: Bearer realm="some value"', $header->toHeader()->toString()); } } diff --git a/tests/HeadersTest.php b/tests/HeadersTest.php index 3a0fc47..a84a3ea 100644 --- a/tests/HeadersTest.php +++ b/tests/HeadersTest.php @@ -30,11 +30,11 @@ public function testInterface() $this->assertTrue($hs->contains('content-type')); $this->assertTrue($hs->contains('Content-Type')); $this->assertFalse($hs->contains('content_type')); - $this->assertSame($ct, $hs->get('content-type')->match( + $this->assertEquals($ct->toHeader(), $hs->get('content-type')->match( static fn($header) => $header, static fn() => null, )); - $this->assertSame($ct, $hs->get('Content-Type')->match( + $this->assertEquals($ct->toHeader(), $hs->get('Content-Type')->match( static fn($header) => $header, static fn() => null, )); @@ -71,7 +71,7 @@ public function testAdd() )); $headers3 = ($headers2)($header = ContentType::of( MediaType::of('application/json'), - )); + )->toHeader()); $this->assertNotSame($headers1, $headers2); $this->assertInstanceOf(Headers::class, $headers2); @@ -170,7 +170,7 @@ public function testFilter() ); $this->assertCount( 1, - $headers->filter(static fn($header) => $header instanceof ContentType), + $headers->filter(static fn($header) => $header->name() === 'Content-Type'), ); } @@ -183,8 +183,8 @@ public function testAll() $foo = new Header('x-foo'), ); - $this->assertSame( - [$contentType, $foo], + $this->assertEquals( + [$contentType->toHeader(), $foo], $headers->all()->toList(), ); } From 915009c17bbd7f1e3943a726752a466621c848f0 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 20:15:26 +0200 Subject: [PATCH 24/51] make Header a final class --- CHANGELOG.md | 1 + src/Factory/Header/Factory.php | 2 +- src/Header.php | 42 +++++++++++++++++++++++---- src/Header/Accept.php | 2 ++ src/Header/AcceptCharset.php | 2 ++ src/Header/AcceptEncoding.php | 2 ++ src/Header/AcceptLanguage.php | 2 ++ src/Header/AcceptRanges.php | 5 +++- src/Header/Age.php | 1 + src/Header/Allow.php | 2 ++ src/Header/Authorization.php | 5 +++- src/Header/CacheControl.php | 2 ++ src/Header/ContentEncoding.php | 5 +++- src/Header/ContentLanguage.php | 2 ++ src/Header/ContentLength.php | 1 + src/Header/ContentLocation.php | 1 + src/Header/ContentRange.php | 5 +++- src/Header/ContentType.php | 1 + src/Header/Cookie.php | 1 + src/Header/Date.php | 5 +++- src/Header/Expires.php | 5 +++- src/Header/Header.php | 50 -------------------------------- src/Header/Host.php | 1 + src/Header/IfModifiedSince.php | 5 +++- src/Header/IfUnmodifiedSince.php | 5 +++- src/Header/LastModified.php | 5 +++- src/Header/Link.php | 2 ++ src/Header/Location.php | 1 + src/Header/Range.php | 5 +++- src/Header/Referrer.php | 1 + src/Header/SetCookie.php | 1 + src/Header/WWWAuthenticate.php | 2 ++ src/ResponseSender.php | 2 +- tests/Header/HeaderTest.php | 4 +-- tests/HeadersTest.php | 5 ++-- 35 files changed, 110 insertions(+), 73 deletions(-) delete mode 100644 src/Header/Header.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a1e618a..6240534 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - `Innmind\Http\Header\Range` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\Referrer` constructor is now private, use `::of()` named constructor - All custom headers now implements `Innmind\Http\Header\Provider` +- `Innmind\Http\Header` is now a final class ### Removed diff --git a/src/Factory/Header/Factory.php b/src/Factory/Header/Factory.php index 63331e8..f17b5d5 100644 --- a/src/Factory/Header/Factory.php +++ b/src/Factory/Header/Factory.php @@ -53,7 +53,7 @@ private static function default(Str $name, Str $value): Header ->map(static fn($value) => new Value\Value($value->toString())) ->toList(); - return new Header\Header( + return new Header( $name->toString(), ...$values, ); diff --git a/src/Header.php b/src/Header.php index dcf2387..c8e16f2 100644 --- a/src/Header.php +++ b/src/Header.php @@ -3,18 +3,48 @@ namespace Innmind\Http; -use Innmind\Immutable\Sequence; +use Innmind\Http\Header\Value; +use Innmind\Immutable\{ + Sequence, + Str, +}; /** * @psalm-immutable */ -interface Header +final class Header { - public function name(): string; + private string $name; + /** @var Sequence */ + private Sequence $values; /** - * @return Sequence + * @no-named-arguments */ - public function values(): Sequence; - public function toString(): string; + public function __construct(string $name, Value ...$values) + { + $this->name = $name; + $this->values = Sequence::of(...$values); + } + + public function name(): string + { + return $this->name; + } + + /** + * @return Sequence + */ + public function values(): Sequence + { + return $this->values; + } + + public function toString(): string + { + $values = $this->values->map(static fn($value) => $value->toString()); + $values = Str::of(', ')->join($values); + + return $values->prepend("{$this->name}: ")->toString(); + } } diff --git a/src/Header/Accept.php b/src/Header/Accept.php index 65f7040..535a1f7 100644 --- a/src/Header/Accept.php +++ b/src/Header/Accept.php @@ -3,6 +3,8 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; + /** * @psalm-immutable */ diff --git a/src/Header/AcceptCharset.php b/src/Header/AcceptCharset.php index e31c5bc..5bb850c 100644 --- a/src/Header/AcceptCharset.php +++ b/src/Header/AcceptCharset.php @@ -3,6 +3,8 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; + /** * @psalm-immutable */ diff --git a/src/Header/AcceptEncoding.php b/src/Header/AcceptEncoding.php index fe29e0e..6e1e68d 100644 --- a/src/Header/AcceptEncoding.php +++ b/src/Header/AcceptEncoding.php @@ -3,6 +3,8 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; + /** * @psalm-immutable */ diff --git a/src/Header/AcceptLanguage.php b/src/Header/AcceptLanguage.php index 9ff7b14..b3ba8ec 100644 --- a/src/Header/AcceptLanguage.php +++ b/src/Header/AcceptLanguage.php @@ -3,6 +3,8 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; + /** * @psalm-immutable */ diff --git a/src/Header/AcceptRanges.php b/src/Header/AcceptRanges.php index 6fa4b1f..2ae6551 100644 --- a/src/Header/AcceptRanges.php +++ b/src/Header/AcceptRanges.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Exception\DomainException; +use Innmind\Http\{ + Header, + Exception\DomainException, +}; use Innmind\Immutable\{ Str, Maybe, diff --git a/src/Header/Age.php b/src/Header/Age.php index e34e611..0d99835 100644 --- a/src/Header/Age.php +++ b/src/Header/Age.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; use Innmind\Immutable\Maybe; /** diff --git a/src/Header/Allow.php b/src/Header/Allow.php index a5b484b..45c5a09 100644 --- a/src/Header/Allow.php +++ b/src/Header/Allow.php @@ -3,6 +3,8 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; + /** * @psalm-immutable */ diff --git a/src/Header/Authorization.php b/src/Header/Authorization.php index 744ad9e..5ec3000 100644 --- a/src/Header/Authorization.php +++ b/src/Header/Authorization.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Exception\DomainException; +use Innmind\Http\{ + Header, + Exception\DomainException, +}; use Innmind\Immutable\{ Str, Maybe, diff --git a/src/Header/CacheControl.php b/src/Header/CacheControl.php index d4a3f40..732ef51 100644 --- a/src/Header/CacheControl.php +++ b/src/Header/CacheControl.php @@ -3,6 +3,8 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; + /** * @psalm-immutable */ diff --git a/src/Header/ContentEncoding.php b/src/Header/ContentEncoding.php index b0cb858..91abdcc 100644 --- a/src/Header/ContentEncoding.php +++ b/src/Header/ContentEncoding.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Exception\DomainException; +use Innmind\Http\{ + Header, + Exception\DomainException, +}; use Innmind\Immutable\{ Maybe, Str, diff --git a/src/Header/ContentLanguage.php b/src/Header/ContentLanguage.php index d153a1b..c6f3507 100644 --- a/src/Header/ContentLanguage.php +++ b/src/Header/ContentLanguage.php @@ -3,6 +3,8 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; + /** * @psalm-immutable */ diff --git a/src/Header/ContentLength.php b/src/Header/ContentLength.php index 2e9dd1a..c045520 100644 --- a/src/Header/ContentLength.php +++ b/src/Header/ContentLength.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; use Innmind\Immutable\Maybe; /** diff --git a/src/Header/ContentLocation.php b/src/Header/ContentLocation.php index 052d1c8..ca171a1 100644 --- a/src/Header/ContentLocation.php +++ b/src/Header/ContentLocation.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; use Innmind\Url\Url; /** diff --git a/src/Header/ContentRange.php b/src/Header/ContentRange.php index e4e2d32..642a5b2 100644 --- a/src/Header/ContentRange.php +++ b/src/Header/ContentRange.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Exception\DomainException; +use Innmind\Http\{ + Header, + Exception\DomainException, +}; use Innmind\Immutable\{ Str, Maybe, diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index f340588..dcb69ec 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; use Innmind\MediaType\MediaType; use Innmind\Immutable\Str; diff --git a/src/Header/Cookie.php b/src/Header/Cookie.php index 132890f..639d13c 100644 --- a/src/Header/Cookie.php +++ b/src/Header/Cookie.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; use Innmind\Immutable\Map; /** diff --git a/src/Header/Date.php b/src/Header/Date.php index 7b34ab4..b3adf26 100644 --- a/src/Header/Date.php +++ b/src/Header/Date.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\TimeContinuum\Format\Http; +use Innmind\Http\{ + Header, + TimeContinuum\Format\Http, +}; use Innmind\TimeContinuum\{ PointInTime, Offset, diff --git a/src/Header/Expires.php b/src/Header/Expires.php index ad8e132..c59f792 100644 --- a/src/Header/Expires.php +++ b/src/Header/Expires.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\TimeContinuum\Format\Http; +use Innmind\Http\{ + Header, + TimeContinuum\Format\Http, +}; use Innmind\TimeContinuum\{ PointInTime, Offset, diff --git a/src/Header/Header.php b/src/Header/Header.php deleted file mode 100644 index 37a5d3e..0000000 --- a/src/Header/Header.php +++ /dev/null @@ -1,50 +0,0 @@ - */ - private Sequence $values; - - /** - * @no-named-arguments - */ - public function __construct(string $name, Value ...$values) - { - $this->name = $name; - $this->values = Sequence::of(...$values); - } - - #[\Override] - public function name(): string - { - return $this->name; - } - - #[\Override] - public function values(): Sequence - { - return $this->values; - } - - #[\Override] - public function toString(): string - { - $values = $this->values->map(static fn($value) => $value->toString()); - $values = Str::of(', ')->join($values); - - return $values->prepend("{$this->name}: ")->toString(); - } -} diff --git a/src/Header/Host.php b/src/Header/Host.php index dd168c7..3a4ab29 100644 --- a/src/Header/Host.php +++ b/src/Header/Host.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; use Innmind\Url\Authority\{ Host as UrlHost, Port, diff --git a/src/Header/IfModifiedSince.php b/src/Header/IfModifiedSince.php index 42fa1f8..9214c16 100644 --- a/src/Header/IfModifiedSince.php +++ b/src/Header/IfModifiedSince.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\TimeContinuum\Format\Http; +use Innmind\Http\{ + Header, + TimeContinuum\Format\Http, +}; use Innmind\TimeContinuum\{ PointInTime, Offset, diff --git a/src/Header/IfUnmodifiedSince.php b/src/Header/IfUnmodifiedSince.php index cc06c62..25cd217 100644 --- a/src/Header/IfUnmodifiedSince.php +++ b/src/Header/IfUnmodifiedSince.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\TimeContinuum\Format\Http; +use Innmind\Http\{ + Header, + TimeContinuum\Format\Http, +}; use Innmind\TimeContinuum\{ PointInTime, Offset, diff --git a/src/Header/LastModified.php b/src/Header/LastModified.php index 98210c2..d26b5fe 100644 --- a/src/Header/LastModified.php +++ b/src/Header/LastModified.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\TimeContinuum\Format\Http; +use Innmind\Http\{ + Header, + TimeContinuum\Format\Http, +}; use Innmind\TimeContinuum\{ PointInTime, Offset, diff --git a/src/Header/Link.php b/src/Header/Link.php index 3e17b2a..583081d 100644 --- a/src/Header/Link.php +++ b/src/Header/Link.php @@ -3,6 +3,8 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; + /** * @psalm-immutable */ diff --git a/src/Header/Location.php b/src/Header/Location.php index 5a0a013..5383444 100644 --- a/src/Header/Location.php +++ b/src/Header/Location.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; use Innmind\Url\Url; /** diff --git a/src/Header/Range.php b/src/Header/Range.php index 4b69c7f..dc5e54e 100644 --- a/src/Header/Range.php +++ b/src/Header/Range.php @@ -3,7 +3,10 @@ namespace Innmind\Http\Header; -use Innmind\Http\Exception\DomainException; +use Innmind\Http\{ + Header, + Exception\DomainException, +}; use Innmind\Immutable\{ Str, Maybe, diff --git a/src/Header/Referrer.php b/src/Header/Referrer.php index 835d2c8..21fa660 100644 --- a/src/Header/Referrer.php +++ b/src/Header/Referrer.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; use Innmind\Url\Url; /** diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index c222ee4..f6771ac 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; use Innmind\Immutable\Sequence; /** diff --git a/src/Header/WWWAuthenticate.php b/src/Header/WWWAuthenticate.php index eff538e..82caa0e 100644 --- a/src/Header/WWWAuthenticate.php +++ b/src/Header/WWWAuthenticate.php @@ -3,6 +3,8 @@ namespace Innmind\Http\Header; +use Innmind\Http\Header; + /** * @psalm-immutable */ diff --git a/src/ResponseSender.php b/src/ResponseSender.php index 3a1dbb8..8f879d3 100644 --- a/src/ResponseSender.php +++ b/src/ResponseSender.php @@ -50,7 +50,7 @@ public function __invoke(Response $response): Attempt fn() => ($headers)(Date::of($this->clock->now())), ); - $_ = $headers->foreach(function(Header $header): void { + $_ = $headers->foreach(function($header): void { if ($header instanceof SetCookie) { $this->sendCookie($header); diff --git a/tests/Header/HeaderTest.php b/tests/Header/HeaderTest.php index 0543a9b..ee8f81d 100644 --- a/tests/Header/HeaderTest.php +++ b/tests/Header/HeaderTest.php @@ -13,7 +13,7 @@ class HeaderTest extends TestCase { public function testInterface() { - $h = new Header\Header( + $h = new Header( 'Accept', $v1 = new Value\Value('application/json'), $v2 = new Value\Value('*/*'), @@ -28,6 +28,6 @@ public function testInterface() public function testWithoutValues() { - $this->assertSame('X-Foo: ', (new Header\Header('X-Foo'))->toString()); + $this->assertSame('X-Foo: ', (new Header('X-Foo'))->toString()); } } diff --git a/tests/HeadersTest.php b/tests/HeadersTest.php index a84a3ea..f7b6a0a 100644 --- a/tests/HeadersTest.php +++ b/tests/HeadersTest.php @@ -5,8 +5,7 @@ use Innmind\Http\{ Headers, - Header as HeaderInterface, - Header\Header, + Header, Header\Allow, Header\ContentType, Header\Value\Value, @@ -95,7 +94,7 @@ public function testForeach() $called = 0; $this->assertInstanceOf( SideEffect::class, - $headers->foreach(static function(HeaderInterface $header) use (&$called) { + $headers->foreach(static function($header) use (&$called) { ++$called; }), ); From e79f7f4b64a6d00b93c1021137f0570c447a40c7 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 19 Apr 2025 20:17:17 +0200 Subject: [PATCH 25/51] give access to the providers in Headers::foreach() --- src/Headers.php | 4 ++-- src/ResponseSender.php | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Headers.php b/src/Headers.php index a01548f..0cf019b 100644 --- a/src/Headers.php +++ b/src/Headers.php @@ -106,11 +106,11 @@ public function filter(callable $filter): self } /** - * @param callable(Header): void $function + * @param callable(Header|Header\Provider): void $function */ public function foreach(callable $function): SideEffect { - return $this->all()->foreach($function); + return $this->headers->values()->foreach($function); } /** diff --git a/src/ResponseSender.php b/src/ResponseSender.php index 8f879d3..5fb17aa 100644 --- a/src/ResponseSender.php +++ b/src/ResponseSender.php @@ -57,6 +57,10 @@ public function __invoke(Response $response): Attempt return; } + if ($header instanceof Header\Provider) { + $header = $header->toHeader(); + } + \header($header->toString(), false); }); From 0db005c4cdfc3fa35cf72fc6c09aa9f877a435c3 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 10:37:57 +0200 Subject: [PATCH 26/51] rename Provider to Custom --- CHANGELOG.md | 4 ++-- src/Factory/Header/Factories.php | 4 ++-- src/Factory/Header/Factory.php | 2 +- src/Header/Accept.php | 4 ++-- src/Header/AcceptCharset.php | 4 ++-- src/Header/AcceptEncoding.php | 4 ++-- src/Header/AcceptLanguage.php | 4 ++-- src/Header/AcceptRanges.php | 4 ++-- src/Header/Age.php | 4 ++-- src/Header/Allow.php | 4 ++-- src/Header/Authorization.php | 4 ++-- src/Header/CacheControl.php | 4 ++-- src/Header/ContentEncoding.php | 4 ++-- src/Header/ContentLanguage.php | 4 ++-- src/Header/ContentLength.php | 4 ++-- src/Header/ContentLocation.php | 4 ++-- src/Header/ContentRange.php | 4 ++-- src/Header/ContentType.php | 4 ++-- src/Header/Cookie.php | 4 ++-- src/Header/{Provider.php => Custom.php} | 4 ++-- src/Header/Date.php | 4 ++-- src/Header/Expires.php | 4 ++-- src/Header/Host.php | 4 ++-- src/Header/IfModifiedSince.php | 4 ++-- src/Header/IfUnmodifiedSince.php | 4 ++-- src/Header/LastModified.php | 4 ++-- src/Header/Link.php | 4 ++-- src/Header/Location.php | 4 ++-- src/Header/Range.php | 4 ++-- src/Header/Referrer.php | 4 ++-- src/Header/SetCookie.php | 4 ++-- src/Header/WWWAuthenticate.php | 4 ++-- src/Headers.php | 18 +++++++++--------- src/ResponseSender.php | 4 ++-- .../Header/AcceptCharsetFactoryTest.php | 2 +- .../Header/AcceptEncodingFactoryTest.php | 2 +- tests/Factory/Header/AcceptFactoryTest.php | 2 +- .../Header/AcceptLanguageFactoryTest.php | 2 +- .../Factory/Header/AcceptRangesFactoryTest.php | 2 +- tests/Factory/Header/AgeFactoryTest.php | 2 +- tests/Factory/Header/AllowFactoryTest.php | 2 +- .../Header/AuthorizationFactoryTest.php | 2 +- .../Factory/Header/CacheControlFactoryTest.php | 2 +- .../Header/ContentEncodingFactoryTest.php | 2 +- .../Header/ContentLanguageFactoryTest.php | 2 +- .../Header/ContentLengthFactoryTest.php | 2 +- .../Header/ContentLocationFactoryTest.php | 2 +- .../Factory/Header/ContentRangeFactoryTest.php | 4 ++-- .../Factory/Header/ContentTypeFactoryTest.php | 6 +++--- tests/Factory/Header/CookieFactoryTest.php | 4 ++-- tests/Factory/Header/DateFactoryTest.php | 2 +- tests/Factory/Header/ExpiresFactoryTest.php | 2 +- tests/Factory/Header/HostFactoryTest.php | 2 +- .../Header/IfModifiedSinceFactoryTest.php | 2 +- .../Header/IfUnmodifiedSinceFactoryTest.php | 2 +- .../Factory/Header/LastModifiedFactoryTest.php | 2 +- tests/Factory/Header/LinkFactoryTest.php | 4 ++-- tests/Factory/Header/LocationFactoryTest.php | 2 +- tests/Factory/Header/RangeFactoryTest.php | 2 +- tests/Factory/Header/ReferrerFactoryTest.php | 2 +- tests/Header/AcceptCharsetTest.php | 6 +++--- tests/Header/AcceptEncodingTest.php | 6 +++--- tests/Header/AcceptLanguageTest.php | 6 +++--- tests/Header/AcceptRangesTest.php | 4 ++-- tests/Header/AcceptTest.php | 4 ++-- tests/Header/AgeTest.php | 4 ++-- tests/Header/AllowTest.php | 8 ++++---- tests/Header/AuthorizationTest.php | 4 ++-- tests/Header/CacheControlTest.php | 4 ++-- tests/Header/ContentEncodingTest.php | 4 ++-- tests/Header/ContentLanguageTest.php | 8 ++++---- tests/Header/ContentLengthTest.php | 4 ++-- tests/Header/ContentLocationTest.php | 6 +++--- tests/Header/ContentRangeTest.php | 8 ++++---- tests/Header/ContentTypeTest.php | 4 ++-- tests/Header/CookieTest.php | 6 +++--- tests/Header/DateTest.php | 6 +++--- tests/Header/ExpiresTest.php | 8 ++++---- tests/Header/HostTest.php | 6 +++--- tests/Header/IfModifiedSinceTest.php | 6 +++--- tests/Header/IfUnmodifiedSinceTest.php | 6 +++--- tests/Header/LastModifiedTest.php | 6 +++--- tests/Header/LinkTest.php | 6 +++--- tests/Header/LocationTest.php | 6 +++--- tests/Header/RangeTest.php | 8 ++++---- tests/Header/ReferrerTest.php | 6 +++--- tests/Header/SetCookieTest.php | 6 +++--- tests/Header/WWWAuthenticateTest.php | 4 ++-- tests/HeadersTest.php | 8 ++++---- 89 files changed, 189 insertions(+), 189 deletions(-) rename src/Header/{Provider.php => Custom.php} (67%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6240534..86752ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Added -- `Innmind\Http\Header\Provider` +- `Innmind\Http\Header\Custom` ### Changed @@ -38,7 +38,7 @@ - `Innmind\Http\Header\Location` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Range` constructor is now private, use `::of()` or `::maybe()` named constructors - `Innmind\Http\Header\Referrer` constructor is now private, use `::of()` named constructor -- All custom headers now implements `Innmind\Http\Header\Provider` +- All custom headers now implements `Innmind\Http\Header\Custom` - `Innmind\Http\Header` is now a final class ### Removed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 6b1bb16..b6712f6 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -37,7 +37,7 @@ Header\Link, Header\LinkValue, Header\Location, - Header\Provider, + Header\Custom, Header\Range, Header\Referrer, Header\Parameter, @@ -128,7 +128,7 @@ public static function of(Str $name): ?self } /** - * @return Maybe + * @return Maybe */ public function try(Clock $clock, Str $value): Maybe { diff --git a/src/Factory/Header/Factory.php b/src/Factory/Header/Factory.php index f17b5d5..386a45e 100644 --- a/src/Factory/Header/Factory.php +++ b/src/Factory/Header/Factory.php @@ -21,7 +21,7 @@ private function __construct( ) { } - public function __invoke(Str $name, Str $value): Header|Header\Provider + public function __invoke(Str $name, Str $value): Header|Header\Custom { $factory = Factories::of($name); diff --git a/src/Header/Accept.php b/src/Header/Accept.php index 535a1f7..5967917 100644 --- a/src/Header/Accept.php +++ b/src/Header/Accept.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -final class Accept implements Provider +final class Accept implements Custom { private Header $header; @@ -18,7 +18,7 @@ public function __construct(AcceptValue $first, AcceptValue ...$values) } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return $this->header; } diff --git a/src/Header/AcceptCharset.php b/src/Header/AcceptCharset.php index 5bb850c..228c3a0 100644 --- a/src/Header/AcceptCharset.php +++ b/src/Header/AcceptCharset.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -final class AcceptCharset implements Provider +final class AcceptCharset implements Custom { private Header $header; @@ -21,7 +21,7 @@ public function __construct(AcceptCharsetValue ...$values) } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return $this->header; } diff --git a/src/Header/AcceptEncoding.php b/src/Header/AcceptEncoding.php index 6e1e68d..c2b065f 100644 --- a/src/Header/AcceptEncoding.php +++ b/src/Header/AcceptEncoding.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -final class AcceptEncoding implements Provider +final class AcceptEncoding implements Custom { private Header $header; @@ -21,7 +21,7 @@ public function __construct(AcceptEncodingValue ...$values) } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return $this->header; } diff --git a/src/Header/AcceptLanguage.php b/src/Header/AcceptLanguage.php index b3ba8ec..d22015a 100644 --- a/src/Header/AcceptLanguage.php +++ b/src/Header/AcceptLanguage.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -final class AcceptLanguage implements Provider +final class AcceptLanguage implements Custom { private Header $header; @@ -21,7 +21,7 @@ public function __construct(AcceptLanguageValue ...$values) } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return $this->header; } diff --git a/src/Header/AcceptRanges.php b/src/Header/AcceptRanges.php index 2ae6551..52e6f24 100644 --- a/src/Header/AcceptRanges.php +++ b/src/Header/AcceptRanges.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class AcceptRanges implements Provider +final class AcceptRanges implements Custom { private function __construct( private string $ranges, @@ -49,7 +49,7 @@ public static function maybe(string $range): Maybe } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Accept-Ranges', diff --git a/src/Header/Age.php b/src/Header/Age.php index 0d99835..d17a98a 100644 --- a/src/Header/Age.php +++ b/src/Header/Age.php @@ -9,7 +9,7 @@ /** * @psalm-immutable */ -final class Age implements Provider +final class Age implements Custom { /** * @param int<0, max> $age @@ -51,7 +51,7 @@ public function age(): int } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header('Age', new Value\Value((string) $this->age)); } diff --git a/src/Header/Allow.php b/src/Header/Allow.php index 45c5a09..51ab7cf 100644 --- a/src/Header/Allow.php +++ b/src/Header/Allow.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -final class Allow implements Provider +final class Allow implements Custom { private Header $header; @@ -33,7 +33,7 @@ public static function of(string ...$values): self } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return $this->header; } diff --git a/src/Header/Authorization.php b/src/Header/Authorization.php index 5ec3000..5c6c4a4 100644 --- a/src/Header/Authorization.php +++ b/src/Header/Authorization.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class Authorization implements Provider +final class Authorization implements Custom { public function __construct( private string $scheme, @@ -58,7 +58,7 @@ public function parameter(): string } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Authorization', diff --git a/src/Header/CacheControl.php b/src/Header/CacheControl.php index 732ef51..25bbdf4 100644 --- a/src/Header/CacheControl.php +++ b/src/Header/CacheControl.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -final class CacheControl implements Provider +final class CacheControl implements Custom { private Header $header; @@ -18,7 +18,7 @@ public function __construct(CacheControlValue $first, CacheControlValue ...$valu } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return $this->header; } diff --git a/src/Header/ContentEncoding.php b/src/Header/ContentEncoding.php index 91abdcc..721e421 100644 --- a/src/Header/ContentEncoding.php +++ b/src/Header/ContentEncoding.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class ContentEncoding implements Provider +final class ContentEncoding implements Custom { private function __construct( private string $encoding, @@ -49,7 +49,7 @@ public static function maybe(string $encoding): Maybe } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Content-Encoding', diff --git a/src/Header/ContentLanguage.php b/src/Header/ContentLanguage.php index c6f3507..0eb9040 100644 --- a/src/Header/ContentLanguage.php +++ b/src/Header/ContentLanguage.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -final class ContentLanguage implements Provider +final class ContentLanguage implements Custom { private Header $header; @@ -33,7 +33,7 @@ public static function of(string ...$values): self } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return $this->header; } diff --git a/src/Header/ContentLength.php b/src/Header/ContentLength.php index c045520..7bf74de 100644 --- a/src/Header/ContentLength.php +++ b/src/Header/ContentLength.php @@ -9,7 +9,7 @@ /** * @psalm-immutable */ -final class ContentLength implements Provider +final class ContentLength implements Custom { /** * @param int<0, max> $length @@ -51,7 +51,7 @@ public function length(): int } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Content-Length', diff --git a/src/Header/ContentLocation.php b/src/Header/ContentLocation.php index ca171a1..b96d8d6 100644 --- a/src/Header/ContentLocation.php +++ b/src/Header/ContentLocation.php @@ -9,7 +9,7 @@ /** * @psalm-immutable */ -final class ContentLocation implements Provider +final class ContentLocation implements Custom { private function __construct( private Url $url, @@ -30,7 +30,7 @@ public function url(): Url } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Content-Location', diff --git a/src/Header/ContentRange.php b/src/Header/ContentRange.php index 642a5b2..60b3198 100644 --- a/src/Header/ContentRange.php +++ b/src/Header/ContentRange.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class ContentRange implements Provider +final class ContentRange implements Custom { /** * @param int<0, max> $firstPosition @@ -106,7 +106,7 @@ public function length(): Maybe } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Content-Range', diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index dcb69ec..ad4bf10 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -10,7 +10,7 @@ /** * @psalm-immutable */ -final class ContentType implements Provider +final class ContentType implements Custom { private function __construct( private MediaType $content, @@ -31,7 +31,7 @@ public function content(): MediaType } #[\Override] - public function toHeader(): Header + public function normalize(): Header { $mediaType = new MediaType( $this->content->topLevel(), diff --git a/src/Header/Cookie.php b/src/Header/Cookie.php index 639d13c..7fef46f 100644 --- a/src/Header/Cookie.php +++ b/src/Header/Cookie.php @@ -9,7 +9,7 @@ /** * @psalm-immutable */ -final class Cookie implements Provider +final class Cookie implements Custom { public function __construct( private CookieValue $value, @@ -34,7 +34,7 @@ public function parameters(): Map } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header('Cookie', $this->value); } diff --git a/src/Header/Provider.php b/src/Header/Custom.php similarity index 67% rename from src/Header/Provider.php rename to src/Header/Custom.php index 47386c8..ae595e5 100644 --- a/src/Header/Provider.php +++ b/src/Header/Custom.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -interface Provider +interface Custom { - public function toHeader(): Header; + public function normalize(): Header; } diff --git a/src/Header/Date.php b/src/Header/Date.php index b3adf26..8be8a41 100644 --- a/src/Header/Date.php +++ b/src/Header/Date.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class Date implements Provider +final class Date implements Custom { private function __construct( private PointInTime $point, @@ -36,7 +36,7 @@ public function date(): PointInTime } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Date', diff --git a/src/Header/Expires.php b/src/Header/Expires.php index c59f792..f5d4253 100644 --- a/src/Header/Expires.php +++ b/src/Header/Expires.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class Expires implements Provider +final class Expires implements Custom { private function __construct( private PointInTime $point, @@ -36,7 +36,7 @@ public function date(): PointInTime } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Expires', diff --git a/src/Header/Host.php b/src/Header/Host.php index 3a4ab29..6b70a12 100644 --- a/src/Header/Host.php +++ b/src/Header/Host.php @@ -12,7 +12,7 @@ /** * @psalm-immutable */ -final class Host implements Provider +final class Host implements Custom { private function __construct( private UrlHost $host, @@ -39,7 +39,7 @@ public function port(): Port } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Host', diff --git a/src/Header/IfModifiedSince.php b/src/Header/IfModifiedSince.php index 9214c16..35cc7eb 100644 --- a/src/Header/IfModifiedSince.php +++ b/src/Header/IfModifiedSince.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class IfModifiedSince implements Provider +final class IfModifiedSince implements Custom { private function __construct( private PointInTime $point, @@ -36,7 +36,7 @@ public function date(): PointInTime } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'If-Modified-Since', diff --git a/src/Header/IfUnmodifiedSince.php b/src/Header/IfUnmodifiedSince.php index 25cd217..53e2caf 100644 --- a/src/Header/IfUnmodifiedSince.php +++ b/src/Header/IfUnmodifiedSince.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class IfUnmodifiedSince implements Provider +final class IfUnmodifiedSince implements Custom { private function __construct( private PointInTime $point, @@ -36,7 +36,7 @@ public function date(): PointInTime } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'If-Unmodified-Since', diff --git a/src/Header/LastModified.php b/src/Header/LastModified.php index d26b5fe..6a7396e 100644 --- a/src/Header/LastModified.php +++ b/src/Header/LastModified.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class LastModified implements Provider +final class LastModified implements Custom { private function __construct( private PointInTime $point, @@ -36,7 +36,7 @@ public function date(): PointInTime } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Last-Modified', diff --git a/src/Header/Link.php b/src/Header/Link.php index 583081d..c2346b8 100644 --- a/src/Header/Link.php +++ b/src/Header/Link.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -final class Link implements Provider +final class Link implements Custom { private Header $header; @@ -21,7 +21,7 @@ public function __construct(LinkValue ...$values) } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return $this->header; } diff --git a/src/Header/Location.php b/src/Header/Location.php index 5383444..acac015 100644 --- a/src/Header/Location.php +++ b/src/Header/Location.php @@ -9,7 +9,7 @@ /** * @psalm-immutable */ -final class Location implements Provider +final class Location implements Custom { private function __construct( private Url $location, @@ -30,7 +30,7 @@ public function url(): Url } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Location', diff --git a/src/Header/Range.php b/src/Header/Range.php index dc5e54e..c7e0d89 100644 --- a/src/Header/Range.php +++ b/src/Header/Range.php @@ -15,7 +15,7 @@ /** * @psalm-immutable */ -final class Range implements Provider +final class Range implements Custom { /** * @param int<0, max> $firstPosition @@ -89,7 +89,7 @@ public function lastPosition(): int } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Range', diff --git a/src/Header/Referrer.php b/src/Header/Referrer.php index 21fa660..cc8c802 100644 --- a/src/Header/Referrer.php +++ b/src/Header/Referrer.php @@ -9,7 +9,7 @@ /** * @psalm-immutable */ -final class Referrer implements Provider +final class Referrer implements Custom { private function __construct( private Url $referrer, @@ -30,7 +30,7 @@ public function referrer(): Url } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header( 'Referer', diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index f6771ac..c7c8d40 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -9,7 +9,7 @@ /** * @psalm-immutable */ -final class SetCookie implements Provider +final class SetCookie implements Custom { /** @var Sequence */ private Sequence $cookies; @@ -40,7 +40,7 @@ public function cookies(): Sequence } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return new Header('Set-Cookie', ...$this->cookies->toList()); } diff --git a/src/Header/WWWAuthenticate.php b/src/Header/WWWAuthenticate.php index 82caa0e..21763df 100644 --- a/src/Header/WWWAuthenticate.php +++ b/src/Header/WWWAuthenticate.php @@ -8,7 +8,7 @@ /** * @psalm-immutable */ -final class WWWAuthenticate implements Provider +final class WWWAuthenticate implements Custom { private Header $header; @@ -21,7 +21,7 @@ public function __construct(WWWAuthenticateValue ...$values) } #[\Override] - public function toHeader(): Header + public function normalize(): Header { return $this->header; } diff --git a/src/Headers.php b/src/Headers.php index 0cf019b..fe20299 100644 --- a/src/Headers.php +++ b/src/Headers.php @@ -18,18 +18,18 @@ final class Headers implements \Countable { /** - * @param Map $headers + * @param Map $headers */ private function __construct( private Map $headers, ) { } - public function __invoke(Header|Header\Provider $header): self + public function __invoke(Header|Header\Custom $header): self { $name = self::normalize(match (true) { $header instanceof Header => $header->name(), - default => $header->toHeader()->name(), + default => $header->normalize()->name(), }); return new self(($this->headers)($name, $header)); @@ -39,7 +39,7 @@ public function __invoke(Header|Header\Provider $header): self * @no-named-arguments * @psalm-pure */ - public static function of(Header|Header\Provider ...$headers): self + public static function of(Header|Header\Custom ...$headers): self { return Sequence::of(...$headers)->reduce( new self(Map::of()), @@ -61,12 +61,12 @@ public function get(string $name): Maybe ->get($normalized) ->map(static fn($header) => match (true) { $header instanceof Header => $header, - default => $header->toHeader(), + default => $header->normalize(), }); } /** - * @template T of Header\Provider + * @template T of Header\Custom * * @param class-string $type * @@ -101,12 +101,12 @@ public function filter(callable $filter): self { return new self($this->headers->filter(static fn($_, $header) => match (true) { $header instanceof Header => $filter($header), - default => $filter($header->toHeader()), + default => $filter($header->normalize()), })); } /** - * @param callable(Header|Header\Provider): void $function + * @param callable(Header|Header\Custom): void $function */ public function foreach(callable $function): SideEffect { @@ -139,7 +139,7 @@ public function all(): Sequence { return $this->headers->values()->map(static fn($header) => match (true) { $header instanceof Header => $header, - default => $header->toHeader(), + default => $header->normalize(), }); } diff --git a/src/ResponseSender.php b/src/ResponseSender.php index 5fb17aa..864e004 100644 --- a/src/ResponseSender.php +++ b/src/ResponseSender.php @@ -57,8 +57,8 @@ public function __invoke(Response $response): Attempt return; } - if ($header instanceof Header\Provider) { - $header = $header->toHeader(); + if ($header instanceof Header\Custom) { + $header = $header->normalize(); } \header($header->toString(), false); diff --git a/tests/Factory/Header/AcceptCharsetFactoryTest.php b/tests/Factory/Header/AcceptCharsetFactoryTest.php index 194b461..7dbb5c6 100644 --- a/tests/Factory/Header/AcceptCharsetFactoryTest.php +++ b/tests/Factory/Header/AcceptCharsetFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(AcceptCharset::class, $h); $this->assertSame( 'Accept-Charset: iso-8859-5;q=1, unicode-1-1;q=0.8', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } diff --git a/tests/Factory/Header/AcceptEncodingFactoryTest.php b/tests/Factory/Header/AcceptEncodingFactoryTest.php index 383491b..e29f74a 100644 --- a/tests/Factory/Header/AcceptEncodingFactoryTest.php +++ b/tests/Factory/Header/AcceptEncodingFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(AcceptEncoding::class, $h); $this->assertSame( 'Accept-Encoding: gzip;q=1, identity;q=0.5, *;q=0', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } diff --git a/tests/Factory/Header/AcceptFactoryTest.php b/tests/Factory/Header/AcceptFactoryTest.php index abde4dd..f152999 100644 --- a/tests/Factory/Header/AcceptFactoryTest.php +++ b/tests/Factory/Header/AcceptFactoryTest.php @@ -24,7 +24,7 @@ public function testMake() ); $this->assertInstanceOf(Accept::class, $h); - $this->assertSame('Accept: audio/*;q=0.2;level=1, audio/basic', $h->toHeader()->toString()); + $this->assertSame('Accept: audio/*;q=0.2;level=1, audio/basic', $h->normalize()->toString()); } public function testReturnNothingWhenNotValid() diff --git a/tests/Factory/Header/AcceptLanguageFactoryTest.php b/tests/Factory/Header/AcceptLanguageFactoryTest.php index 41d5f70..5471d42 100644 --- a/tests/Factory/Header/AcceptLanguageFactoryTest.php +++ b/tests/Factory/Header/AcceptLanguageFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(AcceptLanguage::class, $h); $this->assertSame( 'Accept-Language: da;q=1, en-gb;q=0.8, en;q=0.7', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } diff --git a/tests/Factory/Header/AcceptRangesFactoryTest.php b/tests/Factory/Header/AcceptRangesFactoryTest.php index 38cf4fd..1c0b504 100644 --- a/tests/Factory/Header/AcceptRangesFactoryTest.php +++ b/tests/Factory/Header/AcceptRangesFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(AcceptRanges::class, $header); - $this->assertSame('Accept-Ranges: bytes', $header->toHeader()->toString()); + $this->assertSame('Accept-Ranges: bytes', $header->normalize()->toString()); } } diff --git a/tests/Factory/Header/AgeFactoryTest.php b/tests/Factory/Header/AgeFactoryTest.php index 158ff8b..24df4ce 100644 --- a/tests/Factory/Header/AgeFactoryTest.php +++ b/tests/Factory/Header/AgeFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(Age::class, $header); - $this->assertSame('Age: 42', $header->toHeader()->toString()); + $this->assertSame('Age: 42', $header->normalize()->toString()); } } diff --git a/tests/Factory/Header/AllowFactoryTest.php b/tests/Factory/Header/AllowFactoryTest.php index f152b6a..a96f502 100644 --- a/tests/Factory/Header/AllowFactoryTest.php +++ b/tests/Factory/Header/AllowFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(Allow::class, $header); - $this->assertSame('Allow: GET, POST', $header->toHeader()->toString()); + $this->assertSame('Allow: GET, POST', $header->normalize()->toString()); } } diff --git a/tests/Factory/Header/AuthorizationFactoryTest.php b/tests/Factory/Header/AuthorizationFactoryTest.php index 6f0d594..a08acf0 100644 --- a/tests/Factory/Header/AuthorizationFactoryTest.php +++ b/tests/Factory/Header/AuthorizationFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(Authorization::class, $h); $this->assertSame( 'Authorization: Basic realm="WallyWorld"', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } diff --git a/tests/Factory/Header/CacheControlFactoryTest.php b/tests/Factory/Header/CacheControlFactoryTest.php index c5ca0f2..dfbb3d5 100644 --- a/tests/Factory/Header/CacheControlFactoryTest.php +++ b/tests/Factory/Header/CacheControlFactoryTest.php @@ -25,7 +25,7 @@ public function testMake() $this->assertInstanceOf(CacheControl::class, $h); $this->assertSame( 'Cache-Control: no-cache="field", no-store, max-age=42, max-stale=42, min-fresh=42, no-transform, only-if-cached, public, private="field", must-revalidate, proxy-revalidate, s-maxage=42, immutable', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } } diff --git a/tests/Factory/Header/ContentEncodingFactoryTest.php b/tests/Factory/Header/ContentEncodingFactoryTest.php index 67009c4..16082d6 100644 --- a/tests/Factory/Header/ContentEncodingFactoryTest.php +++ b/tests/Factory/Header/ContentEncodingFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(ContentEncoding::class, $header); - $this->assertSame('Content-Encoding: x-gzip', $header->toHeader()->toString()); + $this->assertSame('Content-Encoding: x-gzip', $header->normalize()->toString()); } } diff --git a/tests/Factory/Header/ContentLanguageFactoryTest.php b/tests/Factory/Header/ContentLanguageFactoryTest.php index 743b34f..cd0f0e2 100644 --- a/tests/Factory/Header/ContentLanguageFactoryTest.php +++ b/tests/Factory/Header/ContentLanguageFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(ContentLanguage::class, $header); - $this->assertSame('Content-Language: fr-FR, fr-CA', $header->toHeader()->toString()); + $this->assertSame('Content-Language: fr-FR, fr-CA', $header->normalize()->toString()); } } diff --git a/tests/Factory/Header/ContentLengthFactoryTest.php b/tests/Factory/Header/ContentLengthFactoryTest.php index 68a6170..bae5045 100644 --- a/tests/Factory/Header/ContentLengthFactoryTest.php +++ b/tests/Factory/Header/ContentLengthFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(ContentLength::class, $header); - $this->assertSame('Content-Length: 42', $header->toHeader()->toString()); + $this->assertSame('Content-Length: 42', $header->normalize()->toString()); } } diff --git a/tests/Factory/Header/ContentLocationFactoryTest.php b/tests/Factory/Header/ContentLocationFactoryTest.php index b2cb044..154f3d0 100644 --- a/tests/Factory/Header/ContentLocationFactoryTest.php +++ b/tests/Factory/Header/ContentLocationFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(ContentLocation::class, $header); - $this->assertSame('Content-Location: http://example.com/', $header->toHeader()->toString()); + $this->assertSame('Content-Location: http://example.com/', $header->normalize()->toString()); } } diff --git a/tests/Factory/Header/ContentRangeFactoryTest.php b/tests/Factory/Header/ContentRangeFactoryTest.php index 98e01d8..8a4b86b 100644 --- a/tests/Factory/Header/ContentRangeFactoryTest.php +++ b/tests/Factory/Header/ContentRangeFactoryTest.php @@ -22,7 +22,7 @@ public function testMakeWithoutLength() ); $this->assertInstanceOf(ContentRange::class, $header); - $this->assertSame('Content-Range: bytes 0-42/*', $header->toHeader()->toString()); + $this->assertSame('Content-Range: bytes 0-42/*', $header->normalize()->toString()); } public function testMakeWithLength() @@ -33,7 +33,7 @@ public function testMakeWithLength() ); $this->assertInstanceOf(ContentRange::class, $header); - $this->assertSame('Content-Range: bytes 0-42/66', $header->toHeader()->toString()); + $this->assertSame('Content-Range: bytes 0-42/66', $header->normalize()->toString()); } public function testReturnNothingWhenNotValid() diff --git a/tests/Factory/Header/ContentTypeFactoryTest.php b/tests/Factory/Header/ContentTypeFactoryTest.php index 3af9d43..b250e03 100644 --- a/tests/Factory/Header/ContentTypeFactoryTest.php +++ b/tests/Factory/Header/ContentTypeFactoryTest.php @@ -22,7 +22,7 @@ public function testMakeWithoutParameters() ); $this->assertInstanceOf(ContentType::class, $header); - $this->assertSame('Content-Type: image/gif', $header->toHeader()->toString()); + $this->assertSame('Content-Type: image/gif', $header->normalize()->toString()); } public function testMakeWithParameters() @@ -33,7 +33,7 @@ public function testMakeWithParameters() ); $this->assertInstanceOf(ContentType::class, $header); - $this->assertSame('Content-Type: image/gif;foo=bar;q=0.5', $header->toHeader()->toString()); + $this->assertSame('Content-Type: image/gif;foo=bar;q=0.5', $header->normalize()->toString()); } public function testReturnNothingWhenNotValid() @@ -57,7 +57,7 @@ public function testFormEncoded() $this->assertInstanceOf(ContentType::class, $header); $this->assertSame( 'Content-Type: application/x-www-form-urlencoded', - $header->toHeader()->toString(), + $header->normalize()->toString(), ); } } diff --git a/tests/Factory/Header/CookieFactoryTest.php b/tests/Factory/Header/CookieFactoryTest.php index 5c5a34a..e04c9cc 100644 --- a/tests/Factory/Header/CookieFactoryTest.php +++ b/tests/Factory/Header/CookieFactoryTest.php @@ -21,10 +21,10 @@ public function testMake() ); $this->assertInstanceOf(Cookie::class, $header); - $this->assertSame('Cookie: foo=bar; bar=baz; baz=foo', $header->toHeader()->toString()); + $this->assertSame('Cookie: foo=bar; bar=baz; baz=foo', $header->normalize()->toString()); $this->assertSame( 'Cookie: ', - Factory::new(Clock::live())(Str::of('Cookie'), Str::of(''))->toHeader()->toString(), + Factory::new(Clock::live())(Str::of('Cookie'), Str::of(''))->normalize()->toString(), ); } } diff --git a/tests/Factory/Header/DateFactoryTest.php b/tests/Factory/Header/DateFactoryTest.php index 41ca8de..200e5d3 100644 --- a/tests/Factory/Header/DateFactoryTest.php +++ b/tests/Factory/Header/DateFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(Date::class, $h); $this->assertSame( 'Date: Tue, 15 Nov 1994 08:12:31 GMT', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } diff --git a/tests/Factory/Header/ExpiresFactoryTest.php b/tests/Factory/Header/ExpiresFactoryTest.php index e41b507..43b0fab 100644 --- a/tests/Factory/Header/ExpiresFactoryTest.php +++ b/tests/Factory/Header/ExpiresFactoryTest.php @@ -24,7 +24,7 @@ public function testMake() $this->assertInstanceOf(Expires::class, $header); $this->assertSame( 'Expires: Tue, 15 Nov 1994 08:12:31 GMT', - $header->toHeader()->toString(), + $header->normalize()->toString(), ); } diff --git a/tests/Factory/Header/HostFactoryTest.php b/tests/Factory/Header/HostFactoryTest.php index 34c24e6..a968c1c 100644 --- a/tests/Factory/Header/HostFactoryTest.php +++ b/tests/Factory/Header/HostFactoryTest.php @@ -28,7 +28,7 @@ public function testMake(string $host) $this->assertInstanceOf(Host::class, $h); $this->assertSame( 'Host: '.$host, - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } diff --git a/tests/Factory/Header/IfModifiedSinceFactoryTest.php b/tests/Factory/Header/IfModifiedSinceFactoryTest.php index 7e1db6a..edd2111 100644 --- a/tests/Factory/Header/IfModifiedSinceFactoryTest.php +++ b/tests/Factory/Header/IfModifiedSinceFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(IfModifiedSince::class, $h); $this->assertSame( 'If-Modified-Since: Tue, 15 Nov 1994 08:12:31 GMT', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } diff --git a/tests/Factory/Header/IfUnmodifiedSinceFactoryTest.php b/tests/Factory/Header/IfUnmodifiedSinceFactoryTest.php index 2b17b03..bebc669 100644 --- a/tests/Factory/Header/IfUnmodifiedSinceFactoryTest.php +++ b/tests/Factory/Header/IfUnmodifiedSinceFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(IfUnmodifiedSince::class, $h); $this->assertSame( 'If-Unmodified-Since: Tue, 15 Nov 1994 08:12:31 GMT', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } diff --git a/tests/Factory/Header/LastModifiedFactoryTest.php b/tests/Factory/Header/LastModifiedFactoryTest.php index 61c4dbf..5594177 100644 --- a/tests/Factory/Header/LastModifiedFactoryTest.php +++ b/tests/Factory/Header/LastModifiedFactoryTest.php @@ -24,7 +24,7 @@ public function testMake() $this->assertInstanceOf(LastModified::class, $header); $this->assertSame( 'Last-Modified: Tue, 15 Nov 1994 08:12:31 GMT', - $header->toHeader()->toString(), + $header->normalize()->toString(), ); } diff --git a/tests/Factory/Header/LinkFactoryTest.php b/tests/Factory/Header/LinkFactoryTest.php index d303b3b..13e25fc 100644 --- a/tests/Factory/Header/LinkFactoryTest.php +++ b/tests/Factory/Header/LinkFactoryTest.php @@ -24,7 +24,7 @@ public function testMake() $this->assertInstanceOf(Link::class, $header); $this->assertSame( 'Link: ; rel="next";title=foo;bar=baz, ; rel="related"', - $header->toHeader()->toString(), + $header->normalize()->toString(), ); } @@ -38,7 +38,7 @@ public function testMakeWithComplexParameterValue() $this->assertInstanceOf(Link::class, $header); $this->assertSame( 'Link: ; rel="next";title=!#$%&\'()*+-./0123456789:<=>?@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMOPQRSTUVWXYZ[]^_`{|}~', - $header->toHeader()->toString(), + $header->normalize()->toString(), ); } diff --git a/tests/Factory/Header/LocationFactoryTest.php b/tests/Factory/Header/LocationFactoryTest.php index 948ac53..26dcc12 100644 --- a/tests/Factory/Header/LocationFactoryTest.php +++ b/tests/Factory/Header/LocationFactoryTest.php @@ -21,6 +21,6 @@ public function testMake() ); $this->assertInstanceOf(Location::class, $header); - $this->assertSame('Location: http://example.com/', $header->toHeader()->toString()); + $this->assertSame('Location: http://example.com/', $header->normalize()->toString()); } } diff --git a/tests/Factory/Header/RangeFactoryTest.php b/tests/Factory/Header/RangeFactoryTest.php index b6de084..e62838a 100644 --- a/tests/Factory/Header/RangeFactoryTest.php +++ b/tests/Factory/Header/RangeFactoryTest.php @@ -26,7 +26,7 @@ public function testMake() $this->assertInstanceOf(Range::class, $h); $this->assertSame( 'Range: bytes=0-42', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } diff --git a/tests/Factory/Header/ReferrerFactoryTest.php b/tests/Factory/Header/ReferrerFactoryTest.php index cca79c1..3a242f3 100644 --- a/tests/Factory/Header/ReferrerFactoryTest.php +++ b/tests/Factory/Header/ReferrerFactoryTest.php @@ -25,7 +25,7 @@ public function testMake() $this->assertInstanceOf(Referrer::class, $h); $this->assertSame( 'Referer: http://www.w3.org/hypertext/DataSources/Overview.html', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } } diff --git a/tests/Header/AcceptCharsetTest.php b/tests/Header/AcceptCharsetTest.php index 6fdf9c1..78c1f25 100644 --- a/tests/Header/AcceptCharsetTest.php +++ b/tests/Header/AcceptCharsetTest.php @@ -19,12 +19,12 @@ public function testInterface() $v = new AcceptCharsetValue('unicode-1-1', new Quality(0.8)), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Accept-Charset: unicode-1-1;q=0.8', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Accept-Charset: unicode-1-1;q=0.8', $h->normalize()->toString()); } public function testWithoutValues() { - $this->assertSame('Accept-Charset: ', (new AcceptCharset)->toHeader()->toString()); + $this->assertSame('Accept-Charset: ', (new AcceptCharset)->normalize()->toString()); } } diff --git a/tests/Header/AcceptEncodingTest.php b/tests/Header/AcceptEncodingTest.php index 8b195cf..d3e542d 100644 --- a/tests/Header/AcceptEncodingTest.php +++ b/tests/Header/AcceptEncodingTest.php @@ -19,12 +19,12 @@ public function testInterface() $v = new AcceptEncodingValue('compress', new Quality(1)), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Accept-Encoding: compress;q=1', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Accept-Encoding: compress;q=1', $h->normalize()->toString()); } public function testWithoutValues() { - $this->assertSame('Accept-Encoding: ', (new AcceptEncoding)->toHeader()->toString()); + $this->assertSame('Accept-Encoding: ', (new AcceptEncoding)->normalize()->toString()); } } diff --git a/tests/Header/AcceptLanguageTest.php b/tests/Header/AcceptLanguageTest.php index a7a38c3..d49dab3 100644 --- a/tests/Header/AcceptLanguageTest.php +++ b/tests/Header/AcceptLanguageTest.php @@ -19,12 +19,12 @@ public function testInterface() $v = new AcceptLanguageValue('fr', new Quality(0.8)), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Accept-Language: fr;q=0.8', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Accept-Language: fr;q=0.8', $h->normalize()->toString()); } public function testWithoutValues() { - $this->assertSame('Accept-Language: ', (new AcceptLanguage)->toHeader()->toString()); + $this->assertSame('Accept-Language: ', (new AcceptLanguage)->normalize()->toString()); } } diff --git a/tests/Header/AcceptRangesTest.php b/tests/Header/AcceptRangesTest.php index 3efb4f3..1c99712 100644 --- a/tests/Header/AcceptRangesTest.php +++ b/tests/Header/AcceptRangesTest.php @@ -17,8 +17,8 @@ public function testOf() $header = AcceptRanges::of('bytes'); $this->assertInstanceOf(AcceptRanges::class, $header); - $this->assertInstanceOf(Header\Provider::class, $header); - $this->assertSame('Accept-Ranges: bytes', $header->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $header); + $this->assertSame('Accept-Ranges: bytes', $header->normalize()->toString()); } public function testValid() diff --git a/tests/Header/AcceptTest.php b/tests/Header/AcceptTest.php index 5f30c5c..79d664a 100644 --- a/tests/Header/AcceptTest.php +++ b/tests/Header/AcceptTest.php @@ -23,7 +23,7 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Accept: text/html;q=0.8', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Accept: text/html;q=0.8', $h->normalize()->toString()); } } diff --git a/tests/Header/AgeTest.php b/tests/Header/AgeTest.php index 9dbed01..aee5249 100644 --- a/tests/Header/AgeTest.php +++ b/tests/Header/AgeTest.php @@ -16,8 +16,8 @@ public function testOf() $header = Age::of(42); $this->assertInstanceOf(Age::class, $header); - $this->assertInstanceOf(Header\Provider::class, $header); - $this->assertSame('Age: 42', $header->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $header); + $this->assertSame('Age: 42', $header->normalize()->toString()); } public function testReturnNothingWhenInvalidAgeValue() diff --git a/tests/Header/AllowTest.php b/tests/Header/AllowTest.php index 7d27b6f..beb1aac 100644 --- a/tests/Header/AllowTest.php +++ b/tests/Header/AllowTest.php @@ -18,13 +18,13 @@ public function testInterface() $v = new AllowValue('GET'), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Allow: GET', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Allow: GET', $h->normalize()->toString()); } public function testWithoutValues() { - $this->assertSame('Allow: ', (new Allow)->toHeader()->toString()); + $this->assertSame('Allow: ', (new Allow)->normalize()->toString()); } public function testOf() @@ -32,6 +32,6 @@ public function testOf() $header = Allow::of('GET'); $this->assertInstanceOf(Allow::class, $header); - $this->assertSame('Allow: GET', $header->toHeader()->toString()); + $this->assertSame('Allow: GET', $header->normalize()->toString()); } } diff --git a/tests/Header/AuthorizationTest.php b/tests/Header/AuthorizationTest.php index 5459007..decc574 100644 --- a/tests/Header/AuthorizationTest.php +++ b/tests/Header/AuthorizationTest.php @@ -17,8 +17,8 @@ public function testOf() $header = Authorization::of('Basic', 'foo'); $this->assertInstanceOf(Authorization::class, $header); - $this->assertInstanceOf(Header\Provider::class, $header); - $this->assertSame('Authorization: Basic foo', $header->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $header); + $this->assertSame('Authorization: Basic foo', $header->normalize()->toString()); $this->assertSame('Basic', $header->scheme()); $this->assertSame('foo', $header->parameter()); } diff --git a/tests/Header/CacheControlTest.php b/tests/Header/CacheControlTest.php index fe897cf..0a22e4c 100644 --- a/tests/Header/CacheControlTest.php +++ b/tests/Header/CacheControlTest.php @@ -18,7 +18,7 @@ public function testInterface() $v = new PublicCache, ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Cache-Control: public', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Cache-Control: public', $h->normalize()->toString()); } } diff --git a/tests/Header/ContentEncodingTest.php b/tests/Header/ContentEncodingTest.php index 7d39553..cb46a65 100644 --- a/tests/Header/ContentEncodingTest.php +++ b/tests/Header/ContentEncodingTest.php @@ -17,8 +17,8 @@ public function testOf() $header = ContentEncoding::of('compress'); $this->assertInstanceOf(ContentEncoding::class, $header); - $this->assertInstanceOf(Header\Provider::class, $header); - $this->assertSame('Content-Encoding: compress', $header->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $header); + $this->assertSame('Content-Encoding: compress', $header->normalize()->toString()); } public function testValids() diff --git a/tests/Header/ContentLanguageTest.php b/tests/Header/ContentLanguageTest.php index a4aeb4d..6c3e7d7 100644 --- a/tests/Header/ContentLanguageTest.php +++ b/tests/Header/ContentLanguageTest.php @@ -18,8 +18,8 @@ public function testInterface() $v = new ContentLanguageValue('fr'), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Content-Language: fr', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Content-Language: fr', $h->normalize()->toString()); } public function test() @@ -27,11 +27,11 @@ public function test() $header = ContentLanguage::of('fr'); $this->assertInstanceOf(ContentLanguage::class, $header); - $this->assertSame('Content-Language: fr', $header->toHeader()->toString()); + $this->assertSame('Content-Language: fr', $header->normalize()->toString()); } public function testWithoutValues() { - $this->assertSame('Content-Language: ', (new ContentLanguage)->toHeader()->toString()); + $this->assertSame('Content-Language: ', (new ContentLanguage)->normalize()->toString()); } } diff --git a/tests/Header/ContentLengthTest.php b/tests/Header/ContentLengthTest.php index a0bf4b2..c5d912b 100644 --- a/tests/Header/ContentLengthTest.php +++ b/tests/Header/ContentLengthTest.php @@ -16,8 +16,8 @@ public function testOf() $header = ContentLength::of(42); $this->assertInstanceOf(ContentLength::class, $header); - $this->assertInstanceOf(Header\Provider::class, $header); - $this->assertSame('Content-Length: 42', $header->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $header); + $this->assertSame('Content-Length: 42', $header->normalize()->toString()); } public function testReturnNothingWhenInvalidContentLengthValue() diff --git a/tests/Header/ContentLocationTest.php b/tests/Header/ContentLocationTest.php index 717e1d7..72296af 100644 --- a/tests/Header/ContentLocationTest.php +++ b/tests/Header/ContentLocationTest.php @@ -16,8 +16,8 @@ public function testInterface() { $h = ContentLocation::of(Url::of('/foo/bar')); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Content-Location: /foo/bar', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Content-Location: /foo/bar', $h->normalize()->toString()); $this->assertSame('/foo/bar', $h->url()->toString()); } @@ -26,6 +26,6 @@ public function testOf() $header = ContentLocation::of(Url::of('/foo/bar')); $this->assertInstanceOf(ContentLocation::class, $header); - $this->assertSame('Content-Location: /foo/bar', $header->toHeader()->toString()); + $this->assertSame('Content-Location: /foo/bar', $header->normalize()->toString()); } } diff --git a/tests/Header/ContentRangeTest.php b/tests/Header/ContentRangeTest.php index d1253cb..acd35ce 100644 --- a/tests/Header/ContentRangeTest.php +++ b/tests/Header/ContentRangeTest.php @@ -17,19 +17,19 @@ public function testOf() $header = ContentRange::of('bytes', 0, 42); $this->assertInstanceOf(ContentRange::class, $header); - $this->assertInstanceOf(Header\Provider::class, $header); - $this->assertSame('Content-Range: bytes 0-42/*', $header->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $header); + $this->assertSame('Content-Range: bytes 0-42/*', $header->normalize()->toString()); } public function testValids() { $this->assertSame( 'Content-Range: resources 0-42/*', - ContentRange::of('resources', 0, 42)->toHeader()->toString(), + ContentRange::of('resources', 0, 42)->normalize()->toString(), ); $this->assertSame( 'Content-Range: resources 0-499/1234', - ContentRange::of('resources', 0, 499, 1234)->toHeader()->toString(), + ContentRange::of('resources', 0, 499, 1234)->normalize()->toString(), ); } diff --git a/tests/Header/ContentTypeTest.php b/tests/Header/ContentTypeTest.php index 245f75b..869091e 100644 --- a/tests/Header/ContentTypeTest.php +++ b/tests/Header/ContentTypeTest.php @@ -19,8 +19,8 @@ public function testInterface() $ct = MediaType::of('text/html; charset="UTF-8"'), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Content-Type: text/html;charset=UTF-8', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Content-Type: text/html;charset=UTF-8', $h->normalize()->toString()); $this->assertSame('text/html; charset=UTF-8', $h->content()->toString()); } diff --git a/tests/Header/CookieTest.php b/tests/Header/CookieTest.php index bb4b9e0..3e254e7 100644 --- a/tests/Header/CookieTest.php +++ b/tests/Header/CookieTest.php @@ -19,8 +19,8 @@ public function testInterface() $value = new CookieValue(new Parameter('foo', 'bar')), ); - $this->assertInstanceOf(Header\Provider::class, $cookie); - $this->assertSame('Cookie: foo=bar', $cookie->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $cookie); + $this->assertSame('Cookie: foo=bar', $cookie->normalize()->toString()); } public function testOf() @@ -28,6 +28,6 @@ public function testOf() $cookie = Cookie::of(new Parameter('foo', 'bar')); $this->assertInstanceOf(Cookie::class, $cookie); - $this->assertSame('Cookie: foo=bar', $cookie->toHeader()->toString()); + $this->assertSame('Cookie: foo=bar', $cookie->normalize()->toString()); } } diff --git a/tests/Header/DateTest.php b/tests/Header/DateTest.php index 327635c..41f92cb 100644 --- a/tests/Header/DateTest.php +++ b/tests/Header/DateTest.php @@ -20,8 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Date: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Date: Fri, 01 Jan 2016 10:12:12 GMT', $h->normalize()->toString()); } public function testOf() @@ -31,6 +31,6 @@ public function testOf() )); $this->assertInstanceOf(Date::class, $header); - $this->assertSame('Date: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); + $this->assertSame('Date: Fri, 01 Jan 2016 10:12:12 GMT', $header->normalize()->toString()); } } diff --git a/tests/Header/ExpiresTest.php b/tests/Header/ExpiresTest.php index 64c49d7..a40a2bd 100644 --- a/tests/Header/ExpiresTest.php +++ b/tests/Header/ExpiresTest.php @@ -20,8 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Expires: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Expires: Fri, 01 Jan 2016 10:12:12 GMT', $h->normalize()->toString()); } public function testOf() @@ -30,7 +30,7 @@ public function testOf() new \DateTimeImmutable('2016-01-01 12:12:12+0200'), )); - $this->assertInstanceOf(Header\Provider::class, $header); - $this->assertSame('Expires: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $header); + $this->assertSame('Expires: Fri, 01 Jan 2016 10:12:12 GMT', $header->normalize()->toString()); } } diff --git a/tests/Header/HostTest.php b/tests/Header/HostTest.php index d94e6e6..5ce8321 100644 --- a/tests/Header/HostTest.php +++ b/tests/Header/HostTest.php @@ -22,8 +22,8 @@ public function testInterface() Port::of(8080), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Host: example.com:8080', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Host: example.com:8080', $h->normalize()->toString()); } public function testOf() @@ -31,6 +31,6 @@ public function testOf() $header = Host::of(UrlHost::of('example.com'), Port::none()); $this->assertInstanceOf(Host::class, $header); - $this->assertSame('Host: example.com', $header->toHeader()->toString()); + $this->assertSame('Host: example.com', $header->normalize()->toString()); } } diff --git a/tests/Header/IfModifiedSinceTest.php b/tests/Header/IfModifiedSinceTest.php index d3e5cf5..93b2295 100644 --- a/tests/Header/IfModifiedSinceTest.php +++ b/tests/Header/IfModifiedSinceTest.php @@ -20,8 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('If-Modified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('If-Modified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->normalize()->toString()); } public function testOf() @@ -31,6 +31,6 @@ public function testOf() )); $this->assertInstanceOf(IfModifiedSince::class, $header); - $this->assertSame('If-Modified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); + $this->assertSame('If-Modified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $header->normalize()->toString()); } } diff --git a/tests/Header/IfUnmodifiedSinceTest.php b/tests/Header/IfUnmodifiedSinceTest.php index 76bdc68..49c36cc 100644 --- a/tests/Header/IfUnmodifiedSinceTest.php +++ b/tests/Header/IfUnmodifiedSinceTest.php @@ -20,8 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('If-Unmodified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('If-Unmodified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $h->normalize()->toString()); } public function testOf() @@ -31,6 +31,6 @@ public function testOf() )); $this->assertInstanceOf(IfUnmodifiedSince::class, $header); - $this->assertSame('If-Unmodified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); + $this->assertSame('If-Unmodified-Since: Fri, 01 Jan 2016 10:12:12 GMT', $header->normalize()->toString()); } } diff --git a/tests/Header/LastModifiedTest.php b/tests/Header/LastModifiedTest.php index 8b1ce62..687c3a1 100644 --- a/tests/Header/LastModifiedTest.php +++ b/tests/Header/LastModifiedTest.php @@ -20,8 +20,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Last-Modified: Fri, 01 Jan 2016 10:12:12 GMT', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Last-Modified: Fri, 01 Jan 2016 10:12:12 GMT', $h->normalize()->toString()); } public function testOf() @@ -31,6 +31,6 @@ public function testOf() )); $this->assertInstanceOf(LastModified::class, $header); - $this->assertSame('Last-Modified: Fri, 01 Jan 2016 10:12:12 GMT', $header->toHeader()->toString()); + $this->assertSame('Last-Modified: Fri, 01 Jan 2016 10:12:12 GMT', $header->normalize()->toString()); } } diff --git a/tests/Header/LinkTest.php b/tests/Header/LinkTest.php index c8cee47..ca2beec 100644 --- a/tests/Header/LinkTest.php +++ b/tests/Header/LinkTest.php @@ -24,15 +24,15 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header\Provider::class, $h); + $this->assertInstanceOf(Header\Custom::class, $h); $this->assertSame( 'Link: ; rel="some relation";title=Foo', - $h->toHeader()->toString(), + $h->normalize()->toString(), ); } public function testWithoutValues() { - $this->assertSame('Link: ', (new Link)->toHeader()->toString()); + $this->assertSame('Link: ', (new Link)->normalize()->toString()); } } diff --git a/tests/Header/LocationTest.php b/tests/Header/LocationTest.php index d95d59c..3c05c15 100644 --- a/tests/Header/LocationTest.php +++ b/tests/Header/LocationTest.php @@ -18,8 +18,8 @@ public function testInterface() Url::of('/foo/bar'), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Location: /foo/bar', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Location: /foo/bar', $h->normalize()->toString()); } public function testOf() @@ -27,6 +27,6 @@ public function testOf() $header = Location::of(Url::of('/foo/bar')); $this->assertInstanceOf(Location::class, $header); - $this->assertSame('Location: /foo/bar', $header->toHeader()->toString()); + $this->assertSame('Location: /foo/bar', $header->normalize()->toString()); } } diff --git a/tests/Header/RangeTest.php b/tests/Header/RangeTest.php index 25d56de..51dd16f 100644 --- a/tests/Header/RangeTest.php +++ b/tests/Header/RangeTest.php @@ -16,8 +16,8 @@ public function testInterface() { $h = Range::of('bytes', 0, 42); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Range: bytes=0-42', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Range: bytes=0-42', $h->normalize()->toString()); } public function testOf() @@ -25,14 +25,14 @@ public function testOf() $header = Range::of('bytes', 0, 42); $this->assertInstanceOf(Range::class, $header); - $this->assertSame('Range: bytes=0-42', $header->toHeader()->toString()); + $this->assertSame('Range: bytes=0-42', $header->normalize()->toString()); } public function testValid() { $this->assertSame( 'Range: resources=0-42', - Range::of('resources', 0, 42)->toHeader()->toString(), + Range::of('resources', 0, 42)->normalize()->toString(), ); } diff --git a/tests/Header/ReferrerTest.php b/tests/Header/ReferrerTest.php index 46a85bd..5beb66e 100644 --- a/tests/Header/ReferrerTest.php +++ b/tests/Header/ReferrerTest.php @@ -18,8 +18,8 @@ public function testInterface() Url::of('/foo/bar'), ); - $this->assertInstanceOf(Header\Provider::class, $h); - $this->assertSame('Referer: /foo/bar', $h->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $h); + $this->assertSame('Referer: /foo/bar', $h->normalize()->toString()); $this->assertSame('/foo/bar', $h->referrer()->toString()); } @@ -28,6 +28,6 @@ public function testOf() $header = Referrer::of(Url::of('/foo/bar')); $this->assertInstanceOf(Referrer::class, $header); - $this->assertSame('Referer: /foo/bar', $header->toHeader()->toString()); + $this->assertSame('Referer: /foo/bar', $header->normalize()->toString()); } } diff --git a/tests/Header/SetCookieTest.php b/tests/Header/SetCookieTest.php index a130e92..0cbc22c 100644 --- a/tests/Header/SetCookieTest.php +++ b/tests/Header/SetCookieTest.php @@ -26,8 +26,8 @@ public function testInterface() ), ); - $this->assertInstanceOf(Header\Provider::class, $cookie); - $this->assertSame('Set-Cookie: foo=bar; Secure, bar=baz', $cookie->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $cookie); + $this->assertSame('Set-Cookie: foo=bar; Secure, bar=baz', $cookie->normalize()->toString()); } public function testOf() @@ -38,6 +38,6 @@ public function testOf() ); $this->assertInstanceOf(SetCookie::class, $cookie); - $this->assertSame('Set-Cookie: foo=bar; bar=baz', $cookie->toHeader()->toString()); + $this->assertSame('Set-Cookie: foo=bar; bar=baz', $cookie->normalize()->toString()); } } diff --git a/tests/Header/WWWAuthenticateTest.php b/tests/Header/WWWAuthenticateTest.php index 92e8bde..3e1f2f2 100644 --- a/tests/Header/WWWAuthenticateTest.php +++ b/tests/Header/WWWAuthenticateTest.php @@ -18,7 +18,7 @@ public function testInterface() $value = new WWWAuthenticateValue('Bearer', 'some value'), ); - $this->assertInstanceOf(Header\Provider::class, $header); - $this->assertSame('WWW-Authenticate: Bearer realm="some value"', $header->toHeader()->toString()); + $this->assertInstanceOf(Header\Custom::class, $header); + $this->assertSame('WWW-Authenticate: Bearer realm="some value"', $header->normalize()->toString()); } } diff --git a/tests/HeadersTest.php b/tests/HeadersTest.php index f7b6a0a..dd70065 100644 --- a/tests/HeadersTest.php +++ b/tests/HeadersTest.php @@ -29,11 +29,11 @@ public function testInterface() $this->assertTrue($hs->contains('content-type')); $this->assertTrue($hs->contains('Content-Type')); $this->assertFalse($hs->contains('content_type')); - $this->assertEquals($ct->toHeader(), $hs->get('content-type')->match( + $this->assertEquals($ct->normalize(), $hs->get('content-type')->match( static fn($header) => $header, static fn() => null, )); - $this->assertEquals($ct->toHeader(), $hs->get('Content-Type')->match( + $this->assertEquals($ct->normalize(), $hs->get('Content-Type')->match( static fn($header) => $header, static fn() => null, )); @@ -70,7 +70,7 @@ public function testAdd() )); $headers3 = ($headers2)($header = ContentType::of( MediaType::of('application/json'), - )->toHeader()); + )->normalize()); $this->assertNotSame($headers1, $headers2); $this->assertInstanceOf(Headers::class, $headers2); @@ -183,7 +183,7 @@ public function testAll() ); $this->assertEquals( - [$contentType->toHeader(), $foo], + [$contentType->normalize(), $foo], $headers->all()->toList(), ); } From 3b985a8a067f548145692a6404b4a38c510d1338 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 11:18:06 +0200 Subject: [PATCH 27/51] make Accept constructor private --- CHANGELOG.md | 3 + src/Factory/Header/Factories.php | 7 +-- src/Header/Accept.php | 29 +++++++-- .../{AcceptValue.php => Accept/MediaType.php} | 60 ++++++++----------- tests/Header/AcceptTest.php | 20 ++++--- tests/Header/AcceptValueTest.php | 41 ++++++++----- 6 files changed, 94 insertions(+), 66 deletions(-) rename src/Header/{AcceptValue.php => Accept/MediaType.php} (67%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86752ff..3110de8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added - `Innmind\Http\Header\Custom` +- `Innmind\Http\Header\Accept\MediaType` ### Changed @@ -40,6 +41,7 @@ - `Innmind\Http\Header\Referrer` constructor is now private, use `::of()` named constructor - All custom headers now implements `Innmind\Http\Header\Custom` - `Innmind\Http\Header` is now a final class +- `Innmind\Http\Header\Accept` constructor is now private, use `::of()` named constructor ### Removed @@ -63,6 +65,7 @@ - `Innmind\Http\Header\LocationValue` - `Innmind\Http\Header\RangeValue` - `Innmind\Http\Header\ReferrerValue` +- `Innmind\Http\Header\AcceptValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index b6712f6..2008aa0 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -10,7 +10,6 @@ Header\AcceptEncoding, Header\AcceptEncodingValue, Header\Accept, - Header\AcceptValue, Header\AcceptLanguage, Header\AcceptLanguageValue, Header\AcceptRanges, @@ -197,16 +196,16 @@ public function try(Clock $clock, Str $value): Maybe $matches->get('type'), $matches->get('subType'), $params, - )->flatMap(static fn(Str $type, Str $subType, array $params) => AcceptValue::of( + )->flatMap(static fn(Str $type, Str $subType, array $params) => Accept\MediaType::maybe( $type->toString(), $subType->toString(), ...$params, )); }) - ->sink(self::values(AcceptValue::class)) + ->sink(self::values(Accept\MediaType::class)) ->maybe(static fn($values, $value) => $value->map($values)) ->map(static fn($values) => $values->match( - static fn($first, $rest) => new Accept($first, ...$rest->toList()), + static fn($first, $rest) => Accept::of($first, ...$rest->toList()), static fn() => null, )) ->keep(Instance::of(Accept::class)), diff --git a/src/Header/Accept.php b/src/Header/Accept.php index 5967917..5fb2b0b 100644 --- a/src/Header/Accept.php +++ b/src/Header/Accept.php @@ -3,23 +3,42 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Header\Accept\MediaType, +}; +use Innmind\Immutable\Sequence; /** * @psalm-immutable */ final class Accept implements Custom { - private Header $header; + /** + * @param Sequence $values + */ + private function __construct( + private Sequence $values, + ) { + } - public function __construct(AcceptValue $first, AcceptValue ...$values) + /** + * @psalm-pure + */ + public static function of(MediaType $first, MediaType ...$values): self { - $this->header = new Header('Accept', $first, ...$values); + return new self(Sequence::of($first, ...$values)); } #[\Override] public function normalize(): Header { - return $this->header; + return new Header( + 'Accept', + ...$this + ->values + ->map(static fn($value) => new Value\Value($value->toString())) + ->toList(), + ); } } diff --git a/src/Header/AcceptValue.php b/src/Header/Accept/MediaType.php similarity index 67% rename from src/Header/AcceptValue.php rename to src/Header/Accept/MediaType.php index 88580de..3888c8a 100644 --- a/src/Header/AcceptValue.php +++ b/src/Header/Accept/MediaType.php @@ -1,9 +1,11 @@ */ - private Map $parameters; + private function __construct( + private string $type, + private string $subType, + /** @var Map */ + private Map $parameters, + ) { + } - public function __construct( + /** + * @psalm-pure + * + * @return Maybe + */ + public static function maybe( string $type, string $subType, Parameter ...$parameters, - ) { + ): Maybe { $media = Str::of('%s/%s')->sprintf($type, $subType); - /** @var Map */ - $this->parameters = Map::of(); if ( !$media->matches('~^\*/\*$~') && !$media->matches('~^[\w\-.]+/\*$~') && !$media->matches('~^[\w\-.]+/[\w\-.]+$~') ) { - throw new DomainException($media->toString()); + /** @var Maybe */ + return Maybe::nothing(); } + /** @var Map */ + $map = Map::of(); + foreach ($parameters as $parameter) { - $this->parameters = ($this->parameters)( + $map = ($map)( $parameter->name(), $parameter, ); } - $this->type = $type; - $this->subType = $subType; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of( - string $type, - string $subType, - Parameter ...$parameters, - ): Maybe { - try { - return Maybe::just(new self($type, $subType, ...$parameters)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } + return Maybe::just(new self($type, $subType, $map)); } public function type(): string @@ -84,7 +77,6 @@ public function parameters(): Map return $this->parameters; } - #[\Override] public function toString(): string { $parameters = $this->parameters->values()->map( diff --git a/tests/Header/AcceptTest.php b/tests/Header/AcceptTest.php index 79d664a..5ede356 100644 --- a/tests/Header/AcceptTest.php +++ b/tests/Header/AcceptTest.php @@ -6,8 +6,7 @@ use Innmind\Http\{ Header\Accept, Header, - Header\AcceptValue, - Header\Parameter\Quality + Header\Parameter\Quality, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -15,13 +14,16 @@ class AcceptTest extends TestCase { public function testInterface() { - $h = new Accept( - $v = new AcceptValue( - 'text', - 'html', - new Quality(0.8), - ), - ); + $h = Accept\MediaType::maybe( + 'text', + 'html', + new Quality(0.8), + ) + ->map(Accept::of(...)) + ->match( + static fn($header) => $header, + static fn() => null, + ); $this->assertInstanceOf(Header\Custom::class, $h); $this->assertSame('Accept: text/html;q=0.8', $h->normalize()->toString()); diff --git a/tests/Header/AcceptValueTest.php b/tests/Header/AcceptValueTest.php index 9d9257a..6cc25a5 100644 --- a/tests/Header/AcceptValueTest.php +++ b/tests/Header/AcceptValueTest.php @@ -4,11 +4,9 @@ namespace Tests\Innmind\Http\Header; use Innmind\Http\{ - Header\AcceptValue, - Header\Value, + Header\Accept\MediaType, Header\Parameter\Quality, Header\Parameter, - Exception\DomainException, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -17,13 +15,16 @@ class AcceptValueTest extends TestCase { public function testInterface() { - $a = new AcceptValue( + $a = MediaType::maybe( 'text', 'x-c', $q = new Quality(0.8), + )->match( + static fn($mediaType) => $mediaType, + static fn() => null, ); - $this->assertInstanceOf(Value::class, $a); + $this->assertInstanceOf(MediaType::class, $a); $this->assertSame('text', $a->type()); $this->assertSame('x-c', $a->subType()); $this->assertSame($q, $a->parameters()->get('q')->match( @@ -32,33 +33,45 @@ public function testInterface() )); $this->assertSame('text/x-c;q=0.8', $a->toString()); - new AcceptValue( + MediaType::maybe( '*', '*', + )->match( + static fn($mediaType) => $mediaType, + static fn() => throw new \Exception, ); - new AcceptValue( + MediaType::maybe( 'application', '*', + )->match( + static fn($mediaType) => $mediaType, + static fn() => throw new \Exception, ); - new AcceptValue( + MediaType::maybe( 'application', 'octet-stream', + )->match( + static fn($mediaType) => $mediaType, + static fn() => throw new \Exception, ); - new AcceptValue( + MediaType::maybe( 'application', 'octet-stream', new Quality(0.4), new Parameter\Parameter('level', '1'), + )->match( + static fn($mediaType) => $mediaType, + static fn() => throw new \Exception, ); } #[DataProvider('invalids')] - public function testThrowWhenInvalidAcceptValue($type, $sub) + public function testReturnNothingWhenInvalidAcceptValue($type, $sub) { - $this->expectException(DomainException::class); - $this->expectExceptionMessage("$type/$sub"); - - new AcceptValue($type, $sub); + $this->assertNull(MediaType::maybe($type, $sub)->match( + static fn($mediaType) => $mediaType, + static fn() => null, + )); } public static function invalids(): array From 8356b74e4c03330212c63c3aaffc78edf37fcfb1 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 11:29:24 +0200 Subject: [PATCH 28/51] make AcceptCharset constructor private --- CHANGELOG.md | 3 + src/Factory/Header/Factories.php | 7 +-- .../Charset.php} | 44 +++++--------- src/Header/AcceptCharset.php | 27 +++++++-- tests/Header/AcceptCharsetTest.php | 13 +++-- tests/Header/AcceptCharsetValueTest.php | 58 +++++++++++++------ 6 files changed, 92 insertions(+), 60 deletions(-) rename src/Header/{AcceptCharsetValue.php => Accept/Charset.php} (51%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3110de8..f7a8efc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - `Innmind\Http\Header\Custom` - `Innmind\Http\Header\Accept\MediaType` +- `Innmind\Http\Header\Accept\Charset` ### Changed @@ -42,6 +43,7 @@ - All custom headers now implements `Innmind\Http\Header\Custom` - `Innmind\Http\Header` is now a final class - `Innmind\Http\Header\Accept` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\AcceptCharset` constructor is now private, use `::of()` named constructor ### Removed @@ -66,6 +68,7 @@ - `Innmind\Http\Header\RangeValue` - `Innmind\Http\Header\ReferrerValue` - `Innmind\Http\Header\AcceptValue` +- `Innmind\Http\Header\AcceptCharsetValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 2008aa0..f72dcd8 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header, Header\AcceptCharset, - Header\AcceptCharsetValue, Header\AcceptEncoding, Header\AcceptEncodingValue, Header\Accept, @@ -148,12 +147,12 @@ public function try(Clock $clock, Str $value): Maybe ->map(static fn($charset) => $charset->toString()); return Maybe::all($charset, $quality)->flatMap( - AcceptCharsetValue::of(...), + Accept\Charset::maybe(...), ); }) - ->sink(self::values(AcceptCharsetValue::class)) + ->sink(self::values(Accept\Charset::class)) ->maybe(static fn($values, $value) => $value->map($values)) - ->map(static fn($values) => new AcceptCharset(...$values->toList())), + ->map(static fn($values) => AcceptCharset::of(...$values->toList())), self::acceptEncoding => $value ->split(',') diff --git a/src/Header/AcceptCharsetValue.php b/src/Header/Accept/Charset.php similarity index 51% rename from src/Header/AcceptCharsetValue.php rename to src/Header/Accept/Charset.php index f72d587..c2746f3 100644 --- a/src/Header/AcceptCharsetValue.php +++ b/src/Header/Accept/Charset.php @@ -1,12 +1,9 @@ toString() !== '*' && - !$charset->matches('~^[a-zA-Z0-9\-_:\(\)]+$~') - ) { - throw new DomainException($charset->toString()); - } - - $this->charset = $charset; - $this->quality = $quality; + private function __construct( + private Str $charset, + private Quality $quality, + ) { } /** @@ -41,14 +25,19 @@ public function __construct(string $charset, ?Quality $quality = null) * * @return Maybe */ - public static function of(string $charset, ?Quality $quality = null): Maybe + public static function maybe(string $charset, ?Quality $quality = null): Maybe { - try { - return Maybe::just(new self($charset, $quality)); - } catch (DomainException $e) { + $charset = Str::of($charset); + + if ( + $charset->toString() !== '*' && + !$charset->matches('~^[a-zA-Z0-9\-_:\(\)]+$~') + ) { /** @var Maybe */ return Maybe::nothing(); } + + return Maybe::just(new self($charset, $quality ?? new Quality(1))); } public function quality(): Quality @@ -56,7 +45,6 @@ public function quality(): Quality return $this->quality; } - #[\Override] public function toString(): string { return $this diff --git a/src/Header/AcceptCharset.php b/src/Header/AcceptCharset.php index 228c3a0..d921ae7 100644 --- a/src/Header/AcceptCharset.php +++ b/src/Header/AcceptCharset.php @@ -3,26 +3,43 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Header\Accept\Charset, +}; +use Innmind\Immutable\Sequence; /** * @psalm-immutable */ final class AcceptCharset implements Custom { - private Header $header; + /** + * @param Sequence $charsets + */ + private function __construct( + private Sequence $charsets, + ) { + } /** + * @psalm-pure * @no-named-arguments */ - public function __construct(AcceptCharsetValue ...$values) + public static function of(Charset ...$charsets): self { - $this->header = new Header('Accept-Charset', ...$values); + return new self(Sequence::of(...$charsets)); } #[\Override] public function normalize(): Header { - return $this->header; + return new Header( + 'Accept-Charset', + ...$this + ->charsets + ->map(static fn($value) => new Value\Value($value->toString())) + ->toList(), + ); } } diff --git a/tests/Header/AcceptCharsetTest.php b/tests/Header/AcceptCharsetTest.php index 78c1f25..987c7b0 100644 --- a/tests/Header/AcceptCharsetTest.php +++ b/tests/Header/AcceptCharsetTest.php @@ -5,8 +5,8 @@ use Innmind\Http\{ Header\AcceptCharset, + Header\Accept\Charset, Header, - Header\AcceptCharsetValue, Header\Parameter\Quality }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -15,9 +15,12 @@ class AcceptCharsetTest extends TestCase { public function testInterface() { - $h = new AcceptCharset( - $v = new AcceptCharsetValue('unicode-1-1', new Quality(0.8)), - ); + $h = Charset::maybe('unicode-1-1', new Quality(0.8)) + ->map(AcceptCharset::of(...)) + ->match( + static fn($header) => $header, + static fn() => null, + ); $this->assertInstanceOf(Header\Custom::class, $h); $this->assertSame('Accept-Charset: unicode-1-1;q=0.8', $h->normalize()->toString()); @@ -25,6 +28,6 @@ public function testInterface() public function testWithoutValues() { - $this->assertSame('Accept-Charset: ', (new AcceptCharset)->normalize()->toString()); + $this->assertSame('Accept-Charset: ', AcceptCharset::of()->normalize()->toString()); } } diff --git a/tests/Header/AcceptCharsetValueTest.php b/tests/Header/AcceptCharsetValueTest.php index 7ee18e1..e8525b6 100644 --- a/tests/Header/AcceptCharsetValueTest.php +++ b/tests/Header/AcceptCharsetValueTest.php @@ -3,11 +3,9 @@ namespace Tests\Innmind\Http\Header; -use Innmind\Http\{ - Header\AcceptCharsetValue, - Header\Value, - Header\Parameter\Quality, - Exception\DomainException, +use Innmind\Http\Header\{ + Accept\Charset, + Parameter\Quality, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -16,34 +14,58 @@ class AcceptCharsetValueTest extends TestCase { public function testInterface() { - $a = new AcceptCharsetValue('unicode-1-1', $q = new Quality(0.8)); + $a = Charset::maybe('unicode-1-1', $q = new Quality(0.8))->match( + static fn($charset) => $charset, + static fn() => null, + ); - $this->assertInstanceOf(Value::class, $a); + $this->assertInstanceOf(Charset::class, $a); $this->assertSame($q, $a->quality()); $this->assertSame('unicode-1-1;q=0.8', $a->toString()); - new AcceptCharsetValue('iso-8859-5', new Quality(1)); - new AcceptCharsetValue('Shift_JIS', new Quality(1)); - new AcceptCharsetValue('ISO_8859-9:1989', new Quality(1)); - new AcceptCharsetValue('NF_Z_62-010_(1973)', new Quality(1)); - new AcceptCharsetValue('*', new Quality(1)); + Charset::maybe('iso-8859-5', new Quality(1))->match( + static fn($charset) => $charset, + static fn() => throw new \Exception, + ); + Charset::maybe('Shift_JIS', new Quality(1))->match( + static fn($charset) => $charset, + static fn() => throw new \Exception, + ); + Charset::maybe('ISO_8859-9:1989', new Quality(1))->match( + static fn($charset) => $charset, + static fn() => throw new \Exception, + ); + Charset::maybe('NF_Z_62-010_(1973)', new Quality(1))->match( + static fn($charset) => $charset, + static fn() => throw new \Exception, + ); + Charset::maybe('*', new Quality(1))->match( + static fn($charset) => $charset, + static fn() => throw new \Exception, + ); } public function testDefaultQuality() { $this->assertSame( '1', - (new AcceptCharsetValue('*'))->quality()->value(), + Charset::maybe('*') + ->match( + static fn($charset) => $charset, + static fn() => null, + ) + ?->quality() + ?->value(), ); } #[DataProvider('invalids')] - public function testThrowWhenInvalidAcceptCharsetValue($value) + public function testReturnNothingWhenInvalidAcceptCharsetValue($value) { - $this->expectException(DomainException::class); - $this->expectExceptionMessage($value); - - new AcceptCharsetValue($value, new Quality(1)); + $this->assertNull(Charset::maybe($value, new Quality(1))->match( + static fn($charset) => $charset, + static fn() => null, + )); } public static function invalids(): array From b2a0c70c84f3c4137516fa78487e12f1c0d3a154 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 11:41:05 +0200 Subject: [PATCH 29/51] make AcceptEncoding constructor private --- CHANGELOG.md | 3 ++ src/Factory/Header/Factories.php | 7 ++- src/Header/AcceptEncoding.php | 27 ++++++++-- src/Header/AcceptEncodingValue.php | 68 ------------------------ tests/Header/AcceptEncodingTest.php | 13 +++-- tests/Header/AcceptEncodingValueTest.php | 49 +++++++++++------ 6 files changed, 70 insertions(+), 97 deletions(-) delete mode 100644 src/Header/AcceptEncodingValue.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f7a8efc..3537ef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - `Innmind\Http\Header\Custom` - `Innmind\Http\Header\Accept\MediaType` - `Innmind\Http\Header\Accept\Charset` +- `Innmind\Http\Header\Accept\Encoding` ### Changed @@ -44,6 +45,7 @@ - `Innmind\Http\Header` is now a final class - `Innmind\Http\Header\Accept` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\AcceptCharset` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\AcceptEncoding` constructor is now private, use `::of()` named constructor ### Removed @@ -69,6 +71,7 @@ - `Innmind\Http\Header\ReferrerValue` - `Innmind\Http\Header\AcceptValue` - `Innmind\Http\Header\AcceptCharsetValue` +- `Innmind\Http\Header\AcceptEncodingValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index f72dcd8..57b3b45 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -7,7 +7,6 @@ Header, Header\AcceptCharset, Header\AcceptEncoding, - Header\AcceptEncodingValue, Header\Accept, Header\AcceptLanguage, Header\AcceptLanguageValue, @@ -170,12 +169,12 @@ public function try(Clock $clock, Str $value): Maybe ->map(static fn($coding) => $coding->toString()); return Maybe::all($coding, $quality)->flatMap( - AcceptEncodingValue::of(...), + Accept\Encoding::maybe(...), ); }) - ->sink(self::values(AcceptEncodingValue::class)) + ->sink(self::values(Accept\Encoding::class)) ->maybe(static fn($values, $value) => $value->map($values)) - ->map(static fn($values) => new AcceptEncoding(...$values->toList())), + ->map(static fn($values) => AcceptEncoding::of(...$values->toList())), self::accept => $value ->split(',') diff --git a/src/Header/AcceptEncoding.php b/src/Header/AcceptEncoding.php index c2b065f..81ef72b 100644 --- a/src/Header/AcceptEncoding.php +++ b/src/Header/AcceptEncoding.php @@ -3,26 +3,43 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Header\Accept\Encoding, +}; +use Innmind\Immutable\Sequence; /** * @psalm-immutable */ final class AcceptEncoding implements Custom { - private Header $header; + /** + * @param Sequence $encodings + */ + private function __construct( + private Sequence $encodings, + ) { + } /** + * @psalm-pure * @no-named-arguments */ - public function __construct(AcceptEncodingValue ...$values) + public static function of(Encoding ...$encodings): self { - $this->header = new Header('Accept-Encoding', ...$values); + return new self(Sequence::of(...$encodings)); } #[\Override] public function normalize(): Header { - return $this->header; + return new Header( + 'Accept-Encoding', + ...$this + ->encodings + ->map(static fn($value) => new Value\Value($value->toString())) + ->toList(), + ); } } diff --git a/src/Header/AcceptEncodingValue.php b/src/Header/AcceptEncodingValue.php deleted file mode 100644 index f63f190..0000000 --- a/src/Header/AcceptEncodingValue.php +++ /dev/null @@ -1,68 +0,0 @@ -toString() !== '*' && - !$coding->matches('~^\w+$~') - ) { - throw new DomainException($coding->toString()); - } - - $this->coding = $coding; - $this->quality = $quality; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(string $coding, ?Quality $quality = null): Maybe - { - try { - return Maybe::just(new self($coding, $quality)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function quality(): Quality - { - return $this->quality; - } - - #[\Override] - public function toString(): string - { - return $this - ->coding - ->append(';') - ->append($this->quality->toString()) - ->toString(); - } -} diff --git a/tests/Header/AcceptEncodingTest.php b/tests/Header/AcceptEncodingTest.php index d3e542d..3d118fa 100644 --- a/tests/Header/AcceptEncodingTest.php +++ b/tests/Header/AcceptEncodingTest.php @@ -6,7 +6,7 @@ use Innmind\Http\{ Header\AcceptEncoding, Header, - Header\AcceptEncodingValue, + Header\Accept\Encoding, Header\Parameter\Quality }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -15,9 +15,12 @@ class AcceptEncodingTest extends TestCase { public function testInterface() { - $h = new AcceptEncoding( - $v = new AcceptEncodingValue('compress', new Quality(1)), - ); + $h = Encoding::maybe('compress', new Quality(1)) + ->map(AcceptEncoding::of(...)) + ->match( + static fn($header) => $header, + static fn() => null, + ); $this->assertInstanceOf(Header\Custom::class, $h); $this->assertSame('Accept-Encoding: compress;q=1', $h->normalize()->toString()); @@ -25,6 +28,6 @@ public function testInterface() public function testWithoutValues() { - $this->assertSame('Accept-Encoding: ', (new AcceptEncoding)->normalize()->toString()); + $this->assertSame('Accept-Encoding: ', AcceptEncoding::of()->normalize()->toString()); } } diff --git a/tests/Header/AcceptEncodingValueTest.php b/tests/Header/AcceptEncodingValueTest.php index 546a4ae..6b05bc6 100644 --- a/tests/Header/AcceptEncodingValueTest.php +++ b/tests/Header/AcceptEncodingValueTest.php @@ -4,10 +4,8 @@ namespace Tests\Innmind\Http\Header; use Innmind\Http\{ - Header\AcceptEncodingValue, - Header\Value, + Header\Accept\Encoding, Header\Parameter\Quality, - Exception\DomainException, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -16,33 +14,54 @@ class AcceptEncodingValueTest extends TestCase { public function testInterface() { - $a = new AcceptEncodingValue('compress', $q = new Quality(1)); + $a = Encoding::maybe('compress', $q = new Quality(1))->match( + static fn($encoding) => $encoding, + static fn() => null, + ); - $this->assertInstanceOf(Value::class, $a); + $this->assertInstanceOf(Encoding::class, $a); $this->assertSame($q, $a->quality()); $this->assertSame('compress;q=1', $a->toString()); - new AcceptEncodingValue('*', new Quality(1)); - new AcceptEncodingValue('compress', new Quality(0.5)); - new AcceptEncodingValue('identity', new Quality(0.5)); - new AcceptEncodingValue('*', new Quality(0)); + Encoding::maybe('*', new Quality(1))->match( + static fn($encoding) => $encoding, + static fn() => throw new \Exception, + ); + Encoding::maybe('compress', new Quality(0.5))->match( + static fn($encoding) => $encoding, + static fn() => throw new \Exception, + ); + Encoding::maybe('identity', new Quality(0.5))->match( + static fn($encoding) => $encoding, + static fn() => throw new \Exception, + ); + Encoding::maybe('*', new Quality(0))->match( + static fn($encoding) => $encoding, + static fn() => throw new \Exception, + ); } public function testDefaultQuality() { $this->assertSame( '1', - (new AcceptEncodingValue('*'))->quality()->value(), + Encoding::maybe('*') + ->match( + static fn($encoding) => $encoding, + static fn() => null, + ) + ?->quality() + ?->value(), ); } #[DataProvider('invalids')] - public function testThrowWhenInvalidAcceptEncodingValue($value) + public function testReturnNothingWhenInvalidAcceptEncodingValue($value) { - $this->expectException(DomainException::class); - $this->expectExceptionMessage($value); - - new AcceptEncodingValue($value, new Quality(1)); + $this->assertNull(Encoding::maybe($value, new Quality(1))->match( + static fn($encoding) => $encoding, + static fn() => null, + )); } public static function invalids(): array From f98fefa8796a179c799e4e63d8cf4de909d88cec Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 11:48:40 +0200 Subject: [PATCH 30/51] make AcceptLanguage constructor private --- CHANGELOG.md | 3 ++ src/Factory/Header/Factories.php | 7 ++- src/Header/AcceptLanguage.php | 27 ++++++++-- src/Header/AcceptLanguageValue.php | 68 ------------------------ tests/Header/AcceptLanguageTest.php | 15 +++--- tests/Header/AcceptLanguageValueTest.php | 53 ++++++++++++------ 6 files changed, 73 insertions(+), 100 deletions(-) delete mode 100644 src/Header/AcceptLanguageValue.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3537ef8..4addc79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - `Innmind\Http\Header\Accept\MediaType` - `Innmind\Http\Header\Accept\Charset` - `Innmind\Http\Header\Accept\Encoding` +- `Innmind\Http\Header\Accept\Language` ### Changed @@ -46,6 +47,7 @@ - `Innmind\Http\Header\Accept` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\AcceptCharset` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\AcceptEncoding` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\AcceptLanguage` constructor is now private, use `::of()` named constructor ### Removed @@ -72,6 +74,7 @@ - `Innmind\Http\Header\AcceptValue` - `Innmind\Http\Header\AcceptCharsetValue` - `Innmind\Http\Header\AcceptEncodingValue` +- `Innmind\Http\Header\AcceptLanguageValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 57b3b45..145605f 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -9,7 +9,6 @@ Header\AcceptEncoding, Header\Accept, Header\AcceptLanguage, - Header\AcceptLanguageValue, Header\AcceptRanges, Header\Age, Header\Allow, @@ -224,12 +223,12 @@ public function try(Clock $clock, Str $value): Maybe ->map(static fn($lang) => $lang->toString()); return Maybe::all($lang, $quality)->flatMap( - AcceptLanguageValue::of(...), + Accept\Language::maybe(...), ); }) - ->sink(self::values(AcceptLanguageValue::class)) + ->sink(self::values(Accept\Language::class)) ->maybe(static fn($values, $value) => $value->map($values)) - ->map(static fn($values) => new AcceptLanguage(...$values->toList())), + ->map(static fn($values) => AcceptLanguage::of(...$values->toList())), self::acceptRanges => AcceptRanges::maybe($value->toString()), diff --git a/src/Header/AcceptLanguage.php b/src/Header/AcceptLanguage.php index d22015a..0e07e31 100644 --- a/src/Header/AcceptLanguage.php +++ b/src/Header/AcceptLanguage.php @@ -3,26 +3,43 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Header\Accept\Language, +}; +use Innmind\Immutable\Sequence; /** * @psalm-immutable */ final class AcceptLanguage implements Custom { - private Header $header; + /** + * @param Sequence $languages + */ + private function __construct( + private Sequence $languages, + ) { + } /** + * @psalm-pure * @no-named-arguments */ - public function __construct(AcceptLanguageValue ...$values) + public static function of(Language ...$languages): self { - $this->header = new Header('Accept-Language', ...$values); + return new self(Sequence::of(...$languages)); } #[\Override] public function normalize(): Header { - return $this->header; + return new Header( + 'Accept-Language', + ...$this + ->languages + ->map(static fn($value) => new Value\Value($value->toString())) + ->toList(), + ); } } diff --git a/src/Header/AcceptLanguageValue.php b/src/Header/AcceptLanguageValue.php deleted file mode 100644 index 604efd8..0000000 --- a/src/Header/AcceptLanguageValue.php +++ /dev/null @@ -1,68 +0,0 @@ -toString() !== '*' && - !$language->matches('~^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$~') - ) { - throw new DomainException($language->toString()); - } - - $this->language = $language; - $this->quality = $quality; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(string $language, ?Quality $quality = null): Maybe - { - try { - return Maybe::just(new self($language, $quality)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function quality(): Quality - { - return $this->quality; - } - - #[\Override] - public function toString(): string - { - return $this - ->language - ->append(';') - ->append($this->quality->toString()) - ->toString(); - } -} diff --git a/tests/Header/AcceptLanguageTest.php b/tests/Header/AcceptLanguageTest.php index d49dab3..b7d7e8b 100644 --- a/tests/Header/AcceptLanguageTest.php +++ b/tests/Header/AcceptLanguageTest.php @@ -6,8 +6,8 @@ use Innmind\Http\{ Header\AcceptLanguage, Header, - Header\AcceptLanguageValue, - Header\Parameter\Quality + Header\Accept\Language, + Header\Parameter\Quality, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -15,9 +15,12 @@ class AcceptLanguageTest extends TestCase { public function testInterface() { - $h = new AcceptLanguage( - $v = new AcceptLanguageValue('fr', new Quality(0.8)), - ); + $h = Language::maybe('fr', new Quality(0.8)) + ->map(AcceptLanguage::of(...)) + ->match( + static fn($header) => $header, + static fn() => null, + ); $this->assertInstanceOf(Header\Custom::class, $h); $this->assertSame('Accept-Language: fr;q=0.8', $h->normalize()->toString()); @@ -25,6 +28,6 @@ public function testInterface() public function testWithoutValues() { - $this->assertSame('Accept-Language: ', (new AcceptLanguage)->normalize()->toString()); + $this->assertSame('Accept-Language: ', AcceptLanguage::of()->normalize()->toString()); } } diff --git a/tests/Header/AcceptLanguageValueTest.php b/tests/Header/AcceptLanguageValueTest.php index 5b3d378..cf5347a 100644 --- a/tests/Header/AcceptLanguageValueTest.php +++ b/tests/Header/AcceptLanguageValueTest.php @@ -3,11 +3,9 @@ namespace Tests\Innmind\Http\Header; -use Innmind\Http\{ - Header\AcceptLanguageValue, - Header\Value, - Header\Parameter\Quality, - Exception\DomainException, +use Innmind\Http\Header\{ + Accept\Language, + Parameter\Quality, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -16,33 +14,54 @@ class AcceptLanguageValueTest extends TestCase { public function testInterface() { - $a = new AcceptLanguageValue('en-gb', $q = new Quality(0.8)); + $a = Language::maybe('en-gb', $q = new Quality(0.8))->match( + static fn($language) => $language, + static fn() => null, + ); - $this->assertInstanceOf(Value::class, $a); + $this->assertInstanceOf(Language::class, $a); $this->assertSame($q, $a->quality()); $this->assertSame('en-gb;q=0.8', $a->toString()); - new AcceptLanguageValue('fr', new Quality(1)); - new AcceptLanguageValue('fr-FR', new Quality(1)); - new AcceptLanguageValue('sgn-CH-DE', new Quality(1)); - new AcceptLanguageValue('*', new Quality(1)); + Language::maybe('fr', new Quality(1))->match( + static fn($language) => $language, + static fn() => throw new \Exception, + ); + Language::maybe('fr-FR', new Quality(1))->match( + static fn($language) => $language, + static fn() => throw new \Exception, + ); + Language::maybe('sgn-CH-DE', new Quality(1))->match( + static fn($language) => $language, + static fn() => throw new \Exception, + ); + Language::maybe('*', new Quality(1))->match( + static fn($language) => $language, + static fn() => throw new \Exception, + ); } public function testDefaultQuality() { $this->assertSame( '1', - (new AcceptLanguageValue('fr'))->quality()->value(), + Language::maybe('fr') + ->match( + static fn($quality) => $quality, + static fn() => null, + ) + ?->quality() + ?->value(), ); } #[DataProvider('invalids')] - public function testThrowWhenInvalidAcceptLanguageValue($value) + public function testReturnNothingWhenInvalidAcceptLanguageValue($value) { - $this->expectException(DomainException::class); - $this->expectExceptionMessage($value); - - new AcceptLanguageValue($value, new Quality(1)); + $this->assertNull(Language::maybe($value, new Quality(1))->match( + static fn($language) => $language, + static fn() => null, + )); } public static function invalids(): array From f7da644f2bbded855aa0b5be1dcaf23451532c53 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 11:55:17 +0200 Subject: [PATCH 31/51] make Allow constructor private --- CHANGELOG.md | 4 ++- src/Factory/Header/Factories.php | 8 +++--- src/Header/Allow.php | 33 ++++++++++++--------- src/Header/AllowValue.php | 38 ------------------------ tests/Header/AllowTest.php | 16 +++-------- tests/Header/AllowValueTest.php | 48 ------------------------------- tests/Response/StringableTest.php | 6 ++-- 7 files changed, 32 insertions(+), 121 deletions(-) delete mode 100644 src/Header/AllowValue.php delete mode 100644 tests/Header/AllowValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4addc79..3c20d1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,7 +47,8 @@ - `Innmind\Http\Header\Accept` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\AcceptCharset` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\AcceptEncoding` constructor is now private, use `::of()` named constructor -- `Innmind\Http\Header\AcceptLanguage` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Allow` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Allow::of()` now expects `Innmind\Http\Method` values ### Removed @@ -75,6 +76,7 @@ - `Innmind\Http\Header\AcceptCharsetValue` - `Innmind\Http\Header\AcceptEncodingValue` - `Innmind\Http\Header\AcceptLanguageValue` +- `Innmind\Http\Header\AllowValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 145605f..96cc279 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -12,7 +12,6 @@ Header\AcceptRanges, Header\Age, Header\Allow, - Header\AllowValue, Header\Authorization, Header\CacheControl, Header\CacheControlValue, @@ -39,6 +38,7 @@ Header\Parameter, Header\Parameter\Quality, TimeContinuum\Format\Http, + Method, }; use Innmind\TimeContinuum\Clock; use Innmind\Validation\Is; @@ -240,10 +240,10 @@ public function try(Clock $clock, Str $value): Maybe self::allow => $value ->split(',') ->map(static fn($allow) => $allow->trim()->toUpper()->toString()) - ->map(AllowValue::of(...)) - ->sink(self::values(AllowValue::class)) + ->map(Method::maybe(...)) + ->sink(self::values(Method::class)) ->maybe(static fn($values, $value) => $value->map($values)) - ->map(static fn($values) => new Allow(...$values->toList())), + ->map(static fn($values) => Allow::of(...$values->toList())), self::authorization => self::authorization($value), diff --git a/src/Header/Allow.php b/src/Header/Allow.php index 51ab7cf..2926f89 100644 --- a/src/Header/Allow.php +++ b/src/Header/Allow.php @@ -3,38 +3,43 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Method, +}; +use Innmind\Immutable\Sequence; /** * @psalm-immutable */ final class Allow implements Custom { - private Header $header; - /** - * @no-named-arguments + * @param Sequence $methods */ - public function __construct(AllowValue ...$values) - { - $this->header = new Header('Allow', ...$values); + private function __construct( + private Sequence $methods, + ) { } /** - * @no-named-arguments * @psalm-pure + * @no-named-arguments */ - public static function of(string ...$values): self + public static function of(Method ...$methods): self { - return new self(...\array_map( - static fn(string $value): AllowValue => new AllowValue($value), - $values, - )); + return new self(Sequence::of(...$methods)); } #[\Override] public function normalize(): Header { - return $this->header; + return new Header( + 'Allow', + ...$this + ->methods + ->map(static fn($method) => new Value\Value($method->toString())) + ->toList(), + ); } } diff --git a/src/Header/AllowValue.php b/src/Header/AllowValue.php deleted file mode 100644 index aa2c65f..0000000 --- a/src/Header/AllowValue.php +++ /dev/null @@ -1,38 +0,0 @@ -value = Method::of($value)->toString(); - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(string $value): Maybe - { - return Method::maybe($value)->map( - static fn($method) => new self($method->toString()), - ); - } - - #[\Override] - public function toString(): string - { - return $this->value; - } -} diff --git a/tests/Header/AllowTest.php b/tests/Header/AllowTest.php index beb1aac..4131fec 100644 --- a/tests/Header/AllowTest.php +++ b/tests/Header/AllowTest.php @@ -6,7 +6,7 @@ use Innmind\Http\{ Header\Allow, Header, - Header\AllowValue + Method, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -14,8 +14,8 @@ class AllowTest extends TestCase { public function testInterface() { - $h = new Allow( - $v = new AllowValue('GET'), + $h = Allow::of( + Method::get, ); $this->assertInstanceOf(Header\Custom::class, $h); @@ -24,14 +24,6 @@ public function testInterface() public function testWithoutValues() { - $this->assertSame('Allow: ', (new Allow)->normalize()->toString()); - } - - public function testOf() - { - $header = Allow::of('GET'); - - $this->assertInstanceOf(Allow::class, $header); - $this->assertSame('Allow: GET', $header->normalize()->toString()); + $this->assertSame('Allow: ', Allow::of()->normalize()->toString()); } } diff --git a/tests/Header/AllowValueTest.php b/tests/Header/AllowValueTest.php deleted file mode 100644 index 6addcad..0000000 --- a/tests/Header/AllowValueTest.php +++ /dev/null @@ -1,48 +0,0 @@ -assertInstanceOf(Value::class, $a); - $this->assertSame('HEAD', $a->toString()); - - new AllowValue('GET'); - new AllowValue('POST'); - new AllowValue('PUT'); - new AllowValue('DELETE'); - new AllowValue('TRACE'); - new AllowValue('CONNECT'); - new AllowValue('OPTIONS'); - new AllowValue('PATCH'); - } - - #[DataProvider('invalids')] - public function testThrowWhenInvalidAllowValue($value) - { - $this->expectException(\UnhandledMatchError::class); - - new AllowValue($value); - } - - public static function invalids(): array - { - return [ - ['42'], - ['get'], - ['FOO'], - ]; - } -} diff --git a/tests/Response/StringableTest.php b/tests/Response/StringableTest.php index 571b844..876aeb7 100644 --- a/tests/Response/StringableTest.php +++ b/tests/Response/StringableTest.php @@ -11,7 +11,7 @@ Headers, Header\ContentType, Header\Allow, - Header\AllowValue + Method, }; use Innmind\Filesystem\File\Content; use Innmind\MediaType\MediaType; @@ -28,9 +28,7 @@ public function testInterface() ContentType::of( MediaType::of('text/plain'), ), - new Allow( - new AllowValue('GET'), - ), + Allow::of(Method::get), ), Content::ofString('{"some":"json", "value":42}'), ); From c983cfaf953cd7079c779515bb6c4375c3405e28 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 11:55:29 +0200 Subject: [PATCH 32/51] add missing models --- src/Header/Accept/Encoding.php | 56 ++++++++++++++++++++++++++++++++++ src/Header/Accept/Language.php | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/Header/Accept/Encoding.php create mode 100644 src/Header/Accept/Language.php diff --git a/src/Header/Accept/Encoding.php b/src/Header/Accept/Encoding.php new file mode 100644 index 0000000..a107b3a --- /dev/null +++ b/src/Header/Accept/Encoding.php @@ -0,0 +1,56 @@ + + */ + public static function maybe(string $coding, ?Quality $quality = null): Maybe + { + $coding = Str::of($coding); + + if ( + $coding->toString() !== '*' && + !$coding->matches('~^\w+$~') + ) { + /** @var Maybe */ + return Maybe::nothing(); + } + + return Maybe::just(new self($coding, $quality ?? new Quality(1))); + } + + public function quality(): Quality + { + return $this->quality; + } + + public function toString(): string + { + return $this + ->coding + ->append(';') + ->append($this->quality->toString()) + ->toString(); + } +} diff --git a/src/Header/Accept/Language.php b/src/Header/Accept/Language.php new file mode 100644 index 0000000..dc1c699 --- /dev/null +++ b/src/Header/Accept/Language.php @@ -0,0 +1,56 @@ + + */ + public static function maybe(string $language, ?Quality $quality = null): Maybe + { + $language = Str::of($language); + + if ( + $language->toString() !== '*' && + !$language->matches('~^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$~') + ) { + /** @var Maybe */ + return Maybe::nothing(); + } + + return Maybe::just(new self($language, $quality ?? new Quality(1))); + } + + public function quality(): Quality + { + return $this->quality; + } + + public function toString(): string + { + return $this + ->language + ->append(';') + ->append($this->quality->toString()) + ->toString(); + } +} From c83a63b0edc0f4e20793277a0297e219c0b5ee91 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 12:03:14 +0200 Subject: [PATCH 33/51] make ContentLanguage constructor private --- CHANGELOG.md | 3 ++ src/Factory/Header/Factories.php | 8 ++-- src/Header/Content/Language.php | 40 +++++++++++++++++++ src/Header/ContentLanguage.php | 31 +++++++++------ src/Header/ContentLanguageValue.php | 48 ----------------------- tests/Header/ContentLanguageTest.php | 21 ++++------ tests/Header/ContentLanguageValueTest.php | 38 +++++++++++------- 7 files changed, 96 insertions(+), 93 deletions(-) create mode 100644 src/Header/Content/Language.php delete mode 100644 src/Header/ContentLanguageValue.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c20d1e..4bf4a28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - `Innmind\Http\Header\Accept\Charset` - `Innmind\Http\Header\Accept\Encoding` - `Innmind\Http\Header\Accept\Language` +- `Innmind\Http\Header\Content\Language` ### Changed @@ -49,6 +50,7 @@ - `Innmind\Http\Header\AcceptEncoding` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Allow` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Allow::of()` now expects `Innmind\Http\Method` values +- `Innmind\Http\Header\ContentLanguage` constructor is now private, use `::of()` named constructor ### Removed @@ -77,6 +79,7 @@ - `Innmind\Http\Header\AcceptEncodingValue` - `Innmind\Http\Header\AcceptLanguageValue` - `Innmind\Http\Header\AllowValue` +- `Innmind\Http\Header\ContentLanguageValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 96cc279..6b16d24 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -15,9 +15,9 @@ Header\Authorization, Header\CacheControl, Header\CacheControlValue, + Header\Content, Header\ContentEncoding, Header\ContentLanguage, - Header\ContentLanguageValue, Header\ContentLength, Header\ContentLocation, Header\ContentRange, @@ -305,10 +305,10 @@ public function try(Clock $clock, Str $value): Maybe self::contentLanguage => $value ->split(',') ->map(static fn($language) => $language->trim()->toString()) - ->map(ContentLanguageValue::of(...)) - ->sink(self::values(ContentLanguageValue::class)) + ->map(Content\Language::maybe(...)) + ->sink(self::values(Content\Language::class)) ->maybe(static fn($values, $value) => $value->map($values)) - ->map(static fn($values) => new ContentLanguage(...$values->toList())), + ->map(static fn($values) => ContentLanguage::of(...$values->toList())), self::contentLength => Maybe::just($value->toString()) ->filter(\is_numeric(...)) diff --git a/src/Header/Content/Language.php b/src/Header/Content/Language.php new file mode 100644 index 0000000..60eb17b --- /dev/null +++ b/src/Header/Content/Language.php @@ -0,0 +1,40 @@ + + */ + public static function maybe(string $language): Maybe + { + if (!Str::of($language)->matches('~^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$~')) { + /** @var Maybe */ + return Maybe::nothing(); + } + + return Maybe::just(new self($language)); + } + + public function toString(): string + { + return $this->language; + } +} diff --git a/src/Header/ContentLanguage.php b/src/Header/ContentLanguage.php index 0eb9040..2f379fa 100644 --- a/src/Header/ContentLanguage.php +++ b/src/Header/ContentLanguage.php @@ -3,38 +3,43 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Header\Content\Language, +}; +use Innmind\Immutable\Sequence; /** * @psalm-immutable */ final class ContentLanguage implements Custom { - private Header $header; - /** - * @no-named-arguments + * @param Sequence $languages */ - public function __construct(ContentLanguageValue ...$values) - { - $this->header = new Header('Content-Language', ...$values); + private function __construct( + private Sequence $languages, + ) { } /** * @no-named-arguments * @psalm-pure */ - public static function of(string ...$values): self + public static function of(Language ...$languages): self { - return new self(...\array_map( - static fn(string $value): ContentLanguageValue => new ContentLanguageValue($value), - $values, - )); + return new self(Sequence::of(...$languages)); } #[\Override] public function normalize(): Header { - return $this->header; + return new Header( + 'Content-Language', + ...$this + ->languages + ->map(static fn($language) => new Value\Value($language->toString())) + ->toList(), + ); } } diff --git a/src/Header/ContentLanguageValue.php b/src/Header/ContentLanguageValue.php deleted file mode 100644 index a871ca9..0000000 --- a/src/Header/ContentLanguageValue.php +++ /dev/null @@ -1,48 +0,0 @@ -matches('~^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$~')) { - throw new DomainException($language); - } - - $this->language = $language; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(string $language): Maybe - { - try { - return Maybe::just(new self($language)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - #[\Override] - public function toString(): string - { - return $this->language; - } -} diff --git a/tests/Header/ContentLanguageTest.php b/tests/Header/ContentLanguageTest.php index 6c3e7d7..07f3d68 100644 --- a/tests/Header/ContentLanguageTest.php +++ b/tests/Header/ContentLanguageTest.php @@ -6,7 +6,7 @@ use Innmind\Http\{ Header\ContentLanguage, Header, - Header\ContentLanguageValue + Header\Content\Language, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -14,24 +14,19 @@ class ContentLanguageTest extends TestCase { public function testInterface() { - $h = new ContentLanguage( - $v = new ContentLanguageValue('fr'), - ); + $h = Language::maybe('fr') + ->map(ContentLanguage::of(...)) + ->match( + static fn($header) => $header, + static fn() => null, + ); $this->assertInstanceOf(Header\Custom::class, $h); $this->assertSame('Content-Language: fr', $h->normalize()->toString()); } - public function test() - { - $header = ContentLanguage::of('fr'); - - $this->assertInstanceOf(ContentLanguage::class, $header); - $this->assertSame('Content-Language: fr', $header->normalize()->toString()); - } - public function testWithoutValues() { - $this->assertSame('Content-Language: ', (new ContentLanguage)->normalize()->toString()); + $this->assertSame('Content-Language: ', ContentLanguage::of()->normalize()->toString()); } } diff --git a/tests/Header/ContentLanguageValueTest.php b/tests/Header/ContentLanguageValueTest.php index 51bcc14..c7208f3 100644 --- a/tests/Header/ContentLanguageValueTest.php +++ b/tests/Header/ContentLanguageValueTest.php @@ -3,11 +3,7 @@ namespace Tests\Innmind\Http\Header; -use Innmind\Http\{ - Header\ContentLanguageValue, - Header\Value, - Exception\DomainException, -}; +use Innmind\Http\Header\Content\Language; use Innmind\BlackBox\PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -15,23 +11,35 @@ class ContentLanguageValueTest extends TestCase { public function testInterface() { - $a = new ContentLanguageValue('en-gb'); + $a = Language::maybe('en-gb')->match( + static fn($language) => $language, + static fn() => null, + ); - $this->assertInstanceOf(Value::class, $a); + $this->assertInstanceOf(Language::class, $a); $this->assertSame('en-gb', $a->toString()); - new ContentLanguageValue('fr'); - new ContentLanguageValue('fr-FR'); - new ContentLanguageValue('sgn-CH-DE'); + Language::maybe('fr')->match( + static fn($language) => $language, + static fn() => throw new \Exception, + ); + Language::maybe('fr-FR')->match( + static fn($language) => $language, + static fn() => throw new \Exception, + ); + Language::maybe('sgn-CH-DE')->match( + static fn($language) => $language, + static fn() => throw new \Exception, + ); } #[DataProvider('invalids')] - public function testThrowWhenInvalidContentLanguageValue($value) + public function testReturnNothingWhenInvalidContentLanguageValue($value) { - $this->expectException(DomainException::class); - $this->expectExceptionMessage($value); - - new ContentLanguageValue($value); + $this->assertNull(Language::maybe($value)->match( + static fn($language) => $language, + static fn() => null, + )); } public static function invalids(): array From 0107c54db157f3fdd029a69a38b25a0ae8edc555 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 12:22:24 +0200 Subject: [PATCH 34/51] make Link constructor private --- CHANGELOG.md | 3 + src/Factory/Header/Factories.php | 40 ++++++------ src/Header/Link.php | 27 ++++++-- .../{LinkValue.php => Link/Relationship.php} | 63 +++++++------------ tests/Header/LinkTest.php | 7 +-- tests/Header/LinkValueTest.php | 26 +++----- 6 files changed, 81 insertions(+), 85 deletions(-) rename src/Header/{LinkValue.php => Link/Relationship.php} (56%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bf4a28..62d145b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - `Innmind\Http\Header\Accept\Encoding` - `Innmind\Http\Header\Accept\Language` - `Innmind\Http\Header\Content\Language` +- `Innmind\Http\Header\Link\Relationship` ### Changed @@ -51,6 +52,7 @@ - `Innmind\Http\Header\Allow` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Allow::of()` now expects `Innmind\Http\Method` values - `Innmind\Http\Header\ContentLanguage` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Link` constructor is now private, use `::of()` named constructor ### Removed @@ -80,6 +82,7 @@ - `Innmind\Http\Header\AcceptLanguageValue` - `Innmind\Http\Header\AllowValue` - `Innmind\Http\Header\ContentLanguageValue` +- `Innmind\Http\Header\LinkValue` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 6b16d24..d7cfeaf 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -30,7 +30,6 @@ Header\IfUnmodifiedSince, Header\LastModified, Header\Link, - Header\LinkValue, Header\Location, Header\Custom, Header\Range, @@ -383,27 +382,32 @@ public function try(Clock $clock, Str $value): Maybe ->get('url') ->flatMap(static fn($url) => Url::maybe($url->toString())); - /** - * @psalm-suppress MixedArgumentTypeCoercion - * @psalm-suppress MixedArgument - */ - return Maybe::all($url, $params)->flatMap( - static fn(Url $url, Map $params) => LinkValue::of( - $url, - $params->get('rel')->match( - static fn(Parameter $rel) => $rel->value(), - static fn() => null, + return $params->flatMap( + static fn($params) => $params + ->get('rel') + ->otherwise(static fn() => Maybe::just(new Parameter\Parameter( + 'rel', + 'related', + ))) + ->map(static fn($rel) => $rel->value()) + ->keep(Is::string()->nonEmpty()->asPredicate()) + ->flatMap( + static fn($rel) => $url->map( + static fn($url) => Link\Relationship::of( + $url, + $rel, + ...$params + ->remove('rel') + ->values() + ->toList(), + ), + ), ), - ...$params - ->remove('rel') - ->values() - ->toList(), - ), ); }) - ->sink(self::values(LinkValue::class)) + ->sink(self::values(Link\Relationship::class)) ->maybe(static fn($values, $value) => $value->map($values)) - ->map(static fn($values) => new Link(...$values->toList())), + ->map(static fn($values) => Link::of(...$values->toList())), self::location => Url::maybe($value->toString())->map( Location::of(...), diff --git a/src/Header/Link.php b/src/Header/Link.php index c2346b8..6b96b93 100644 --- a/src/Header/Link.php +++ b/src/Header/Link.php @@ -3,26 +3,43 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Header\Link\Relationship, +}; +use Innmind\Immutable\Sequence; /** * @psalm-immutable */ final class Link implements Custom { - private Header $header; + /** + * @param Sequence $relationships + */ + private function __construct( + private Sequence $relationships, + ) { + } /** + * @psalm-pure * @no-named-arguments */ - public function __construct(LinkValue ...$values) + public static function of(Relationship ...$relationships): self { - $this->header = new Header('Link', ...$values); + return new self(Sequence::of(...$relationships)); } #[\Override] public function normalize(): Header { - return $this->header; + return new Header( + 'Link', + ...$this + ->relationships + ->map(static fn($relationship) => new Value\Value($relationship->toString())) + ->toList(), + ); } } diff --git a/src/Header/LinkValue.php b/src/Header/Link/Relationship.php similarity index 56% rename from src/Header/LinkValue.php rename to src/Header/Link/Relationship.php index 4a5b4a4..a5bda62 100644 --- a/src/Header/LinkValue.php +++ b/src/Header/Link/Relationship.php @@ -1,66 +1,52 @@ */ - private Map $parameters; - - public function __construct( - Url $url, - ?string $rel = null, - Parameter ...$parameters, + /** + * @param non-empty-string $rel + * @param Map $parameters + */ + private function __construct( + private Url $url, + private string $rel, + private Map $parameters, ) { - $rel = $rel ?? 'related'; - /** @var Map */ - $this->parameters = Map::of(); - - if (Str::of($rel)->empty()) { - throw new DomainException('Relation can\'t be empty'); - } - - foreach ($parameters as $parameter) { - $this->parameters = ($this->parameters)( - $parameter->name(), - $parameter, - ); - } - - $this->url = $url; - $this->rel = $rel; } /** * @psalm-pure * - * @return Maybe + * @param ?non-empty-string $rel */ public static function of( Url $url, ?string $rel = null, Parameter ...$parameters, - ): Maybe { - try { - return Maybe::just(new self($url, $rel, ...$parameters)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); + ): self { + /** @var Map */ + $map = Map::of(); + + foreach ($parameters as $parameter) { + $map = ($map)( + $parameter->name(), + $parameter, + ); } + + return new self($url, $rel ?? 'related', $map); } public function url(): Url @@ -68,7 +54,7 @@ public function url(): Url return $this->url; } - public function relationship(): string + public function kind(): string { return $this->rel; } @@ -81,7 +67,6 @@ public function parameters(): Map return $this->parameters; } - #[\Override] public function toString(): string { $parameters = $this->parameters->values()->map( diff --git a/tests/Header/LinkTest.php b/tests/Header/LinkTest.php index ca2beec..dcba08b 100644 --- a/tests/Header/LinkTest.php +++ b/tests/Header/LinkTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\Link, Header, - Header\LinkValue, Header\Parameter }; use Innmind\Url\Url; @@ -16,8 +15,8 @@ class LinkTest extends TestCase { public function testInterface() { - $h = new Link( - $v = new LinkValue( + $h = Link::of( + Link\Relationship::of( Url::of('/some/resource'), 'some relation', new Parameter\Parameter('title', 'Foo'), @@ -33,6 +32,6 @@ public function testInterface() public function testWithoutValues() { - $this->assertSame('Link: ', (new Link)->normalize()->toString()); + $this->assertSame('Link: ', Link::of()->normalize()->toString()); } } diff --git a/tests/Header/LinkValueTest.php b/tests/Header/LinkValueTest.php index dc5463b..2bf6bf2 100644 --- a/tests/Header/LinkValueTest.php +++ b/tests/Header/LinkValueTest.php @@ -3,11 +3,9 @@ namespace Tests\Innmind\Http\Header; -use Innmind\Http\{ - Header\LinkValue, - Header\Value, - Header\Parameter, - Exception\DomainException, +use Innmind\Http\Header\{ + Link\Relationship, + Parameter, }; use Innmind\Url\Url; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -16,15 +14,15 @@ class LinkValueTest extends TestCase { public function testInterface() { - $l = new LinkValue( + $l = Relationship::of( $url = Url::of('/some/resource'), 'relationship', $p = new Parameter\Parameter('title', 'Foo'), ); - $this->assertInstanceOf(Value::class, $l); + $this->assertInstanceOf(Relationship::class, $l); $this->assertSame($url, $l->url()); - $this->assertSame('relationship', $l->relationship()); + $this->assertSame('relationship', $l->kind()); $this->assertSame($p, $l->parameters()->get('title')->match( static fn($title) => $title, static fn() => null, @@ -39,17 +37,7 @@ public function testDefaultRelationship() { $this->assertSame( 'related', - (new LinkValue(Url::of('/')))->relationship(), - ); - } - - public function testThrowWhenInvalidLinkValue() - { - $this->expectException(DomainException::class); - - new LinkValue( - Url::of('/foo'), - '', + Relationship::of(Url::of('/'))->kind(), ); } } From 179eb5cf33b13b157cc7017ba402a71e0e027e63 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 12:31:03 +0200 Subject: [PATCH 35/51] make WWWAuthenticate constructor private --- CHANGELOG.md | 3 ++ src/Header/WWWAuthenticate.php | 27 +++++++++-- src/Header/WWWAuthenticate/Challenge.php | 58 +++++++++++++++++++++++ src/Header/WWWAuthenticateValue.php | 48 ------------------- tests/Header/WWWAuthenticateTest.php | 12 +++-- tests/Header/WWWAuthenticateValueTest.php | 22 ++++----- 6 files changed, 101 insertions(+), 69 deletions(-) create mode 100644 src/Header/WWWAuthenticate/Challenge.php delete mode 100644 src/Header/WWWAuthenticateValue.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 62d145b..d997f01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - `Innmind\Http\Header\Accept\Language` - `Innmind\Http\Header\Content\Language` - `Innmind\Http\Header\Link\Relationship` +- `Innmind\Http\Header\WWWAuthenticate\Challenge` ### Changed @@ -53,6 +54,7 @@ - `Innmind\Http\Header\Allow::of()` now expects `Innmind\Http\Method` values - `Innmind\Http\Header\ContentLanguage` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Link` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\WWWAuthenticate` constructor is now private, use `::of()` named constructor ### Removed @@ -83,6 +85,7 @@ - `Innmind\Http\Header\AllowValue` - `Innmind\Http\Header\ContentLanguageValue` - `Innmind\Http\Header\LinkValue` +- `Innmind\Http\Header\WWWAuthenticateValue` ### Fixed diff --git a/src/Header/WWWAuthenticate.php b/src/Header/WWWAuthenticate.php index 21763df..e401db7 100644 --- a/src/Header/WWWAuthenticate.php +++ b/src/Header/WWWAuthenticate.php @@ -3,26 +3,43 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Header\WWWAuthenticate\Challenge, +}; +use Innmind\Immutable\Sequence; /** * @psalm-immutable */ final class WWWAuthenticate implements Custom { - private Header $header; + /** + * @param Sequence $challenges + */ + private function __construct( + private Sequence $challenges, + ) { + } /** + * @psalm-pure * @no-named-arguments */ - public function __construct(WWWAuthenticateValue ...$values) + public static function of(Challenge ...$challenges): self { - $this->header = new Header('WWW-Authenticate', ...$values); + return new self(Sequence::of(...$challenges)); } #[\Override] public function normalize(): Header { - return $this->header; + return new Header( + 'WWW-Authenticate', + ...$this + ->challenges + ->map(static fn($challenge) => new Value\Value($challenge->toString())) + ->toList(), + ); } } diff --git a/src/Header/WWWAuthenticate/Challenge.php b/src/Header/WWWAuthenticate/Challenge.php new file mode 100644 index 0000000..073d84b --- /dev/null +++ b/src/Header/WWWAuthenticate/Challenge.php @@ -0,0 +1,58 @@ + + */ + public static function maybe(string $scheme, string $realm): Maybe + { + $scheme = Str::of($scheme); + + if (!$scheme->matches('~^\w+$~')) { + /** @var Maybe */ + return Maybe::nothing(); + } + + return Maybe::just(new self($scheme->toString(), $realm)); + } + + public function scheme(): string + { + return $this->scheme; + } + + public function realm(): string + { + return $this->realm; + } + + public function toString(): string + { + return Str::of($this->scheme) + ->append(' ') + ->append((new Parameter('realm', $this->realm))->toString()) + ->trim() + ->toString(); + } +} diff --git a/src/Header/WWWAuthenticateValue.php b/src/Header/WWWAuthenticateValue.php deleted file mode 100644 index ab23381..0000000 --- a/src/Header/WWWAuthenticateValue.php +++ /dev/null @@ -1,48 +0,0 @@ -matches('~^\w+$~')) { - throw new DomainException($scheme->toString()); - } - - $this->scheme = $scheme->toString(); - $this->realm = $realm; - } - - public function scheme(): string - { - return $this->scheme; - } - - public function realm(): string - { - return $this->realm; - } - - #[\Override] - public function toString(): string - { - return Str::of($this->scheme) - ->append(' ') - ->append((new Parameter\Parameter('realm', $this->realm))->toString()) - ->trim() - ->toString(); - } -} diff --git a/tests/Header/WWWAuthenticateTest.php b/tests/Header/WWWAuthenticateTest.php index 3e1f2f2..fc992e3 100644 --- a/tests/Header/WWWAuthenticateTest.php +++ b/tests/Header/WWWAuthenticateTest.php @@ -5,8 +5,7 @@ use Innmind\Http\{ Header\WWWAuthenticate, - Header\WWWAuthenticateValue, - Header + Header, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -14,9 +13,12 @@ class WWWAuthenticateTest extends TestCase { public function testInterface() { - $header = new WWWAuthenticate( - $value = new WWWAuthenticateValue('Bearer', 'some value'), - ); + $header = WWWAuthenticate\Challenge::maybe('Bearer', 'some value') + ->map(WWWAuthenticate::of(...)) + ->match( + static fn($header) => $header, + static fn() => null, + ); $this->assertInstanceOf(Header\Custom::class, $header); $this->assertSame('WWW-Authenticate: Bearer realm="some value"', $header->normalize()->toString()); diff --git a/tests/Header/WWWAuthenticateValueTest.php b/tests/Header/WWWAuthenticateValueTest.php index 85c76f9..1222e3b 100644 --- a/tests/Header/WWWAuthenticateValueTest.php +++ b/tests/Header/WWWAuthenticateValueTest.php @@ -3,29 +3,29 @@ namespace Tests\Innmind\Http\Header; -use Innmind\Http\{ - Header\WWWAuthenticateValue, - Header\Value, - Exception\DomainException -}; +use Innmind\Http\Header\WWWAuthenticate\Challenge; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class WWWAuthenticateValueTest extends TestCase { public function testInterface() { - $value = new WWWAuthenticateValue('Basic', 'some value'); + $value = Challenge::maybe('Basic', 'some value')->match( + static fn($challenge) => $challenge, + static fn() => null, + ); - $this->assertInstanceOf(Value::class, $value); + $this->assertInstanceOf(Challenge::class, $value); $this->assertSame('Basic', $value->scheme()); $this->assertSame('some value', $value->realm()); $this->assertSame('Basic realm="some value"', $value->toString()); } - public function testThrowWhenInvalidSchemeFormat() + public function testReturnNothingWhenInvalidSchemeFormat() { - $this->expectException(DomainException::class); - - new WWWAuthenticateValue('Foo bar', 'some value'); + $this->assertNull(Challenge::maybe('Foo bar', 'some value')->match( + static fn($challenge) => $challenge, + static fn() => null, + )); } } From d8fa47fbb14c6d938b76085d71d19b57f0756dc0 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 13:45:08 +0200 Subject: [PATCH 36/51] make CacheControl constructor private --- CHANGELOG.md | 1 + src/Factory/Header/Factories.php | 2 +- src/Header/CacheControl.php | 29 ++++++++++++++++++++++++----- tests/Header/CacheControlTest.php | 2 +- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d997f01..2b9b426 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ - `Innmind\Http\Header\ContentLanguage` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Link` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\WWWAuthenticate` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\CacheControl` constructor is now private, use `::of()` named constructor ### Removed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index d7cfeaf..06eaf52 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -294,7 +294,7 @@ public function try(Clock $clock, Str $value): Maybe ->sink(self::values(CacheControlValue::class)) ->maybe(static fn($values, $value) => $value->map($values)) ->map(static fn($values) => $values->match( - static fn($first, $rest) => new CacheControl($first, ...$rest->toList()), + static fn($first, $rest) => CacheControl::of($first, ...$rest->toList()), static fn() => null, )) ->keep(Instance::of(CacheControl::class)), diff --git a/src/Header/CacheControl.php b/src/Header/CacheControl.php index 25bbdf4..bdb7c7d 100644 --- a/src/Header/CacheControl.php +++ b/src/Header/CacheControl.php @@ -4,22 +4,41 @@ namespace Innmind\Http\Header; use Innmind\Http\Header; +use Innmind\Immutable\Sequence; /** * @psalm-immutable */ final class CacheControl implements Custom { - private Header $header; + /** + * @param Sequence $directives + */ + private function __construct( + private Sequence $directives, + ) { + } - public function __construct(CacheControlValue $first, CacheControlValue ...$values) - { - $this->header = new Header('Cache-Control', $first, ...$values); + /** + * @psalm-pure + * @no-named-arguments + */ + public static function of( + CacheControlValue $first, + CacheControlValue ...$values, + ): self { + return new self(Sequence::of($first, ...$values)); } #[\Override] public function normalize(): Header { - return $this->header; + return new Header( + 'Cache-Control', + ...$this + ->directives + ->map(static fn($directive) => new Value\Value($directive->toString())) + ->toList(), + ); } } diff --git a/tests/Header/CacheControlTest.php b/tests/Header/CacheControlTest.php index 0a22e4c..cf3368b 100644 --- a/tests/Header/CacheControlTest.php +++ b/tests/Header/CacheControlTest.php @@ -14,7 +14,7 @@ class CacheControlTest extends TestCase { public function testInterface() { - $h = new CacheControl( + $h = CacheControl::of( $v = new PublicCache, ); From e421000d84cac6cf575c2ad59cb462474f2ccdfb Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 14:28:42 +0200 Subject: [PATCH 37/51] replace CacheControlValue implementations by dedicated classes --- CHANGELOG.md | 14 +++++ src/Factory/Header/Factories.php | 55 +++++++++++++----- src/Header/CacheControl.php | 17 ++++-- src/Header/CacheControl/Directive.php | 32 +++++++++++ src/Header/CacheControl/MaxAge.php | 44 +++++++++++++++ src/Header/CacheControl/MaxStale.php | 44 +++++++++++++++ src/Header/CacheControl/MinimumFresh.php | 44 +++++++++++++++ .../NoCache.php | 29 +++------- .../PrivateCache.php | 29 +++------- src/Header/CacheControl/SharedMaxAge.php | 44 +++++++++++++++ src/Header/CacheControlValue.php | 11 ---- src/Header/CacheControlValue/Immutable.php | 19 ------- src/Header/CacheControlValue/MaxAge.php | 56 ------------------- src/Header/CacheControlValue/MaxStale.php | 56 ------------------- src/Header/CacheControlValue/MinimumFresh.php | 56 ------------------- .../CacheControlValue/MustRevalidate.php | 18 ------ src/Header/CacheControlValue/NoStore.php | 18 ------ src/Header/CacheControlValue/NoTransform.php | 18 ------ src/Header/CacheControlValue/OnlyIfCached.php | 18 ------ .../CacheControlValue/ProxyRevalidate.php | 18 ------ src/Header/CacheControlValue/PublicCache.php | 18 ------ src/Header/CacheControlValue/SharedMaxAge.php | 56 ------------------- tests/Header/CacheControlTest.php | 4 +- .../CacheControlValue/ImmutableTest.php | 10 +--- tests/Header/CacheControlValue/MaxAgeTest.php | 18 +----- .../Header/CacheControlValue/MaxStaleTest.php | 20 ++----- .../CacheControlValue/MinimumFreshTest.php | 18 +----- .../CacheControlValue/MustRevalidateTest.php | 10 +--- .../Header/CacheControlValue/NoCacheTest.php | 28 +++++----- .../Header/CacheControlValue/NoStoreTest.php | 10 +--- .../CacheControlValue/NoTransformTest.php | 10 +--- .../CacheControlValue/OnlyIfCachedTest.php | 10 +--- .../CacheControlValue/PrivateCacheTest.php | 26 +++++---- .../CacheControlValue/ProxyRevalidateTest.php | 10 +--- .../CacheControlValue/PublicCacheTest.php | 10 +--- .../CacheControlValue/SharedMaxAgeTest.php | 18 +----- 36 files changed, 351 insertions(+), 565 deletions(-) create mode 100644 src/Header/CacheControl/Directive.php create mode 100644 src/Header/CacheControl/MaxAge.php create mode 100644 src/Header/CacheControl/MaxStale.php create mode 100644 src/Header/CacheControl/MinimumFresh.php rename src/Header/{CacheControlValue => CacheControl}/NoCache.php (53%) rename src/Header/{CacheControlValue => CacheControl}/PrivateCache.php (52%) create mode 100644 src/Header/CacheControl/SharedMaxAge.php delete mode 100644 src/Header/CacheControlValue.php delete mode 100644 src/Header/CacheControlValue/Immutable.php delete mode 100644 src/Header/CacheControlValue/MaxAge.php delete mode 100644 src/Header/CacheControlValue/MaxStale.php delete mode 100644 src/Header/CacheControlValue/MinimumFresh.php delete mode 100644 src/Header/CacheControlValue/MustRevalidate.php delete mode 100644 src/Header/CacheControlValue/NoStore.php delete mode 100644 src/Header/CacheControlValue/NoTransform.php delete mode 100644 src/Header/CacheControlValue/OnlyIfCached.php delete mode 100644 src/Header/CacheControlValue/ProxyRevalidate.php delete mode 100644 src/Header/CacheControlValue/PublicCache.php delete mode 100644 src/Header/CacheControlValue/SharedMaxAge.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b9b426..0cb24d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,13 @@ - `Innmind\Http\Header\Content\Language` - `Innmind\Http\Header\Link\Relationship` - `Innmind\Http\Header\WWWAuthenticate\Challenge` +- `Innmind\Http\Header\CacheControl\Directive` +- `Innmind\Http\Header\CacheControl\MaxAge` +- `Innmind\Http\Header\CacheControl\MaxStale` +- `Innmind\Http\Header\CacheControl\MinimumFresh` +- `Innmind\Http\Header\CacheControl\NoCache` +- `Innmind\Http\Header\CacheControl\PrivateCache` +- `Innmind\Http\Header\CacheControl\SharedMaxAge` ### Changed @@ -87,6 +94,13 @@ - `Innmind\Http\Header\ContentLanguageValue` - `Innmind\Http\Header\LinkValue` - `Innmind\Http\Header\WWWAuthenticateValue` +- `Innmind\Http\Header\CacheControlValue` +- `Innmind\Http\Header\CacheControlValue\MaxAge` +- `Innmind\Http\Header\CacheControlValue\MaxStale` +- `Innmind\Http\Header\CacheControlValue\MinimumFresh` +- `Innmind\Http\Header\CacheControlValue\NoCache` +- `Innmind\Http\Header\CacheControlValue\PrivateCache` +- `Innmind\Http\Header\CacheControlValue\SharedMaxAge` ### Fixed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 06eaf52..cc7b5e8 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -14,7 +14,6 @@ Header\Allow, Header\Authorization, Header\CacheControl, - Header\CacheControlValue, Header\Content, Header\ContentEncoding, Header\ContentLanguage, @@ -253,45 +252,71 @@ public function try(Clock $clock, Str $value): Maybe $split->matches('~^max-age=\d+$~') => Maybe::just($split->substring(8)->toString()) ->filter(\is_numeric(...)) ->map(static fn($age) => (int) $age) - ->flatMap(static fn($age) => CacheControlValue\MaxAge::of($age)), + ->keep( + Is::int() + ->positive() + ->or(Is::value(0)) + ->asPredicate(), + ) + ->map(CacheControl\MaxAge::of(...)), $split->matches('~^max-stale(=\d+)?$~') => Maybe::just($split) ->filter(static fn($split) => $split->length() > 10) ->map(static fn($split) => $split->substring(10)->toString()) ->filter(\is_numeric(...)) ->map(static fn($age) => (int) $age) ->otherwise(static fn() => Maybe::just(0)) - ->flatMap(CacheControlValue\MaxStale::of(...)), + ->keep( + Is::int() + ->positive() + ->or(Is::value(0)) + ->asPredicate(), + ) + ->map(CacheControl\MaxStale::of(...)), $split->matches('~^min-fresh=\d+$~') => Maybe::just($split->substring(10)->toString()) ->filter(\is_numeric(...)) ->map(static fn($age) => (int) $age) - ->flatMap(CacheControlValue\MinimumFresh::of(...)), - $split->toString() === 'must-revalidate' => Maybe::just(new CacheControlValue\MustRevalidate), + ->keep( + Is::int() + ->positive() + ->or(Is::value(0)) + ->asPredicate(), + ) + ->map(CacheControl\MinimumFresh::of(...)), + $split->toString() === 'must-revalidate' => Maybe::just(CacheControl\Directive::mustRevalidate), $split->matches('~^no-cache(="?\w+"?)?$~') => $split ->capture('~^no-cache(="?(?\w+)"?)?$~') ->get('field') ->map(static fn($field) => $field->toString()) ->otherwise(static fn() => Maybe::just('')) - ->flatMap(CacheControlValue\NoCache::of(...)), - $split->toString() === 'no-store' => Maybe::just(new CacheControlValue\NoStore), - $split->toString() === 'immutable' => Maybe::just(new CacheControlValue\Immutable), - $split->toString() === 'no-transform' => Maybe::just(new CacheControlValue\NoTransform), - $split->toString() === 'only-if-cached' => Maybe::just(new CacheControlValue\OnlyIfCached), + ->flatMap(CacheControl\NoCache::maybe(...)), + $split->toString() === 'no-store' => Maybe::just(CacheControl\Directive::noStore), + $split->toString() === 'immutable' => Maybe::just(CacheControl\Directive::immutable), + $split->toString() === 'no-transform' => Maybe::just(CacheControl\Directive::noTransform), + $split->toString() === 'only-if-cached' => Maybe::just(CacheControl\Directive::onlyIfCached), $split->matches('~^private(="?\w+"?)?$~') => $split ->capture('~^private(="?(?\w+)"?)?$~') ->get('field') ->map(static fn($field) => $field->toString()) ->otherwise(static fn() => Maybe::just('')) - ->flatMap(CacheControlValue\PrivateCache::of(...)), - $split->toString() === 'proxy-revalidate' => Maybe::just(new CacheControlValue\ProxyRevalidate), - $split->toString() === 'public' => Maybe::just(new CacheControlValue\PublicCache), + ->flatMap(CacheControl\PrivateCache::maybe(...)), + $split->toString() === 'proxy-revalidate' => Maybe::just(CacheControl\Directive::proxyRevalidate), + $split->toString() === 'public' => Maybe::just(CacheControl\Directive::public), $split->matches('~^s-maxage=\d+$~') => Maybe::just($split->substring(9)->toString()) ->filter(\is_numeric(...)) ->map(static fn($age) => (int) $age) - ->flatMap(CacheControlValue\SharedMaxAge::of(...)), + ->keep( + Is::int() + ->positive() + ->or(Is::value(0)) + ->asPredicate(), + ) + ->map(CacheControl\SharedMaxAge::of(...)), default => null, }) ->keep(Instance::of(Maybe::class)) - ->sink(self::values(CacheControlValue::class)) + // this is the wrong type but it would be too complex to express + // the correct one, and it doesn't affect the runtime + ->sink(self::values(CacheControl\Directive::class)) ->maybe(static fn($values, $value) => $value->map($values)) ->map(static fn($values) => $values->match( static fn($first, $rest) => CacheControl::of($first, ...$rest->toList()), diff --git a/src/Header/CacheControl.php b/src/Header/CacheControl.php index bdb7c7d..1bf9bd5 100644 --- a/src/Header/CacheControl.php +++ b/src/Header/CacheControl.php @@ -3,7 +3,16 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Header\CacheControl\Directive, + Header\CacheControl\MaxAge, + Header\CacheControl\MaxStale, + Header\CacheControl\MinimumFresh, + Header\CacheControl\NoCache, + Header\CacheControl\PrivateCache, + Header\CacheControl\SharedMaxAge, +}; use Innmind\Immutable\Sequence; /** @@ -12,7 +21,7 @@ final class CacheControl implements Custom { /** - * @param Sequence $directives + * @param Sequence $directives */ private function __construct( private Sequence $directives, @@ -24,8 +33,8 @@ private function __construct( * @no-named-arguments */ public static function of( - CacheControlValue $first, - CacheControlValue ...$values, + Directive|MaxAge|MaxStale|MinimumFresh|NoCache|PrivateCache|SharedMaxAge $first, + Directive|MaxAge|MaxStale|MinimumFresh|NoCache|PrivateCache|SharedMaxAge ...$values, ): self { return new self(Sequence::of($first, ...$values)); } diff --git a/src/Header/CacheControl/Directive.php b/src/Header/CacheControl/Directive.php new file mode 100644 index 0000000..604f792 --- /dev/null +++ b/src/Header/CacheControl/Directive.php @@ -0,0 +1,32 @@ + 'immutable', + self::mustRevalidate => 'must-revalidate', + self::noStore => 'no-store', + self::noTransform => 'no-transform', + self::onlyIfCached => 'only-if-cached', + self::proxyRevalidate => 'proxy-revalidate', + self::public => 'public', + }; + } +} diff --git a/src/Header/CacheControl/MaxAge.php b/src/Header/CacheControl/MaxAge.php new file mode 100644 index 0000000..13840e5 --- /dev/null +++ b/src/Header/CacheControl/MaxAge.php @@ -0,0 +1,44 @@ + $age + */ + private function __construct( + private int $age, + ) { + } + + /** + * @psalm-pure + * + * @param int<0, max> $age + */ + public static function of(int $age): self + { + return new self($age); + } + + /** + * @return int<0, max> + */ + public function age(): int + { + return $this->age; + } + + public function toString(): string + { + return \sprintf( + 'max-age=%s', + $this->age, + ); + } +} diff --git a/src/Header/CacheControl/MaxStale.php b/src/Header/CacheControl/MaxStale.php new file mode 100644 index 0000000..021a2e3 --- /dev/null +++ b/src/Header/CacheControl/MaxStale.php @@ -0,0 +1,44 @@ + $age + */ + private function __construct( + private int $age, + ) { + } + + /** + * @psalm-pure + * + * @param int<0, max> $age + */ + public static function of(int $age): self + { + return new self($age); + } + + /** + * @return int<0, max> + */ + public function age(): int + { + return $this->age; + } + + public function toString(): string + { + return \sprintf( + 'max-stale%s', + $this->age > 0 ? '='.$this->age : '', + ); + } +} diff --git a/src/Header/CacheControl/MinimumFresh.php b/src/Header/CacheControl/MinimumFresh.php new file mode 100644 index 0000000..42bc3b3 --- /dev/null +++ b/src/Header/CacheControl/MinimumFresh.php @@ -0,0 +1,44 @@ + $age + */ + private function __construct( + private int $age, + ) { + } + + /** + * @psalm-pure + * + * @param int<0, max> $age + */ + public static function of(int $age): self + { + return new self($age); + } + + /** + * @return int<0, max> + */ + public function age(): int + { + return $this->age; + } + + public function toString(): string + { + return \sprintf( + 'min-fresh=%s', + $this->age, + ); + } +} diff --git a/src/Header/CacheControlValue/NoCache.php b/src/Header/CacheControl/NoCache.php similarity index 53% rename from src/Header/CacheControlValue/NoCache.php rename to src/Header/CacheControl/NoCache.php index 60a0997..8936cb5 100644 --- a/src/Header/CacheControlValue/NoCache.php +++ b/src/Header/CacheControl/NoCache.php @@ -1,12 +1,8 @@ matches('~^\w*$~')) { - throw new DomainException($field); - } - - $this->field = $field; + private function __construct( + private string $field, + ) { } /** @@ -33,14 +23,14 @@ public function __construct(string $field) * * @return Maybe */ - public static function of(string $field): Maybe + public static function maybe(string $field): Maybe { - try { - return Maybe::just(new self($field)); - } catch (DomainException $e) { + if (!Str::of($field)->matches('~^\w*$~')) { /** @var Maybe */ return Maybe::nothing(); } + + return Maybe::just(new self($field)); } public function field(): string @@ -48,7 +38,6 @@ public function field(): string return $this->field; } - #[\Override] public function toString(): string { return \sprintf( diff --git a/src/Header/CacheControlValue/PrivateCache.php b/src/Header/CacheControl/PrivateCache.php similarity index 52% rename from src/Header/CacheControlValue/PrivateCache.php rename to src/Header/CacheControl/PrivateCache.php index 3d49fb8..3d1a125 100644 --- a/src/Header/CacheControlValue/PrivateCache.php +++ b/src/Header/CacheControl/PrivateCache.php @@ -1,12 +1,8 @@ matches('~^\w*$~')) { - throw new DomainException($field); - } - - $this->field = $field; + private function __construct( + private string $field, + ) { } /** @@ -33,14 +23,14 @@ public function __construct(string $field) * * @return Maybe */ - public static function of(string $field): Maybe + public static function maybe(string $field): Maybe { - try { - return Maybe::just(new self($field)); - } catch (DomainException $e) { + if (!Str::of($field)->matches('~^\w*$~')) { /** @var Maybe */ return Maybe::nothing(); } + + return Maybe::just(new self($field)); } public function field(): string @@ -48,7 +38,6 @@ public function field(): string return $this->field; } - #[\Override] public function toString(): string { return \sprintf( diff --git a/src/Header/CacheControl/SharedMaxAge.php b/src/Header/CacheControl/SharedMaxAge.php new file mode 100644 index 0000000..d132018 --- /dev/null +++ b/src/Header/CacheControl/SharedMaxAge.php @@ -0,0 +1,44 @@ + $age + */ + private function __construct( + private int $age, + ) { + } + + /** + * @psalm-pure + * + * @param int<0, max> $age + */ + public static function of(int $age): self + { + return new self($age); + } + + /** + * @return int<0, max> + */ + public function age(): int + { + return $this->age; + } + + public function toString(): string + { + return \sprintf( + 's-maxage=%s', + $this->age, + ); + } +} diff --git a/src/Header/CacheControlValue.php b/src/Header/CacheControlValue.php deleted file mode 100644 index 042d712..0000000 --- a/src/Header/CacheControlValue.php +++ /dev/null @@ -1,11 +0,0 @@ -age = $age; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(int $age): Maybe - { - try { - return Maybe::just(new self($age)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function age(): int - { - return $this->age; - } - - #[\Override] - public function toString(): string - { - return \sprintf( - 'max-age=%s', - $this->age, - ); - } -} diff --git a/src/Header/CacheControlValue/MaxStale.php b/src/Header/CacheControlValue/MaxStale.php deleted file mode 100644 index c7b9408..0000000 --- a/src/Header/CacheControlValue/MaxStale.php +++ /dev/null @@ -1,56 +0,0 @@ -age = $age; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(int $age): Maybe - { - try { - return Maybe::just(new self($age)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function age(): int - { - return $this->age; - } - - #[\Override] - public function toString(): string - { - return \sprintf( - 'max-stale%s', - $this->age > 0 ? '='.$this->age : '', - ); - } -} diff --git a/src/Header/CacheControlValue/MinimumFresh.php b/src/Header/CacheControlValue/MinimumFresh.php deleted file mode 100644 index 59cf046..0000000 --- a/src/Header/CacheControlValue/MinimumFresh.php +++ /dev/null @@ -1,56 +0,0 @@ -age = $age; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(int $age): Maybe - { - try { - return Maybe::just(new self($age)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function age(): int - { - return $this->age; - } - - #[\Override] - public function toString(): string - { - return \sprintf( - 'min-fresh=%s', - $this->age, - ); - } -} diff --git a/src/Header/CacheControlValue/MustRevalidate.php b/src/Header/CacheControlValue/MustRevalidate.php deleted file mode 100644 index 3048490..0000000 --- a/src/Header/CacheControlValue/MustRevalidate.php +++ /dev/null @@ -1,18 +0,0 @@ -age = $age; - } - - /** - * @psalm-pure - * - * @return Maybe - */ - public static function of(int $age): Maybe - { - try { - return Maybe::just(new self($age)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } - } - - public function age(): int - { - return $this->age; - } - - #[\Override] - public function toString(): string - { - return \sprintf( - 's-maxage=%s', - $this->age, - ); - } -} diff --git a/tests/Header/CacheControlTest.php b/tests/Header/CacheControlTest.php index cf3368b..800c776 100644 --- a/tests/Header/CacheControlTest.php +++ b/tests/Header/CacheControlTest.php @@ -5,8 +5,8 @@ use Innmind\Http\{ Header\CacheControl, + Header\CacheControl\Directive, Header, - Header\CacheControlValue\PublicCache }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -15,7 +15,7 @@ class CacheControlTest extends TestCase public function testInterface() { $h = CacheControl::of( - $v = new PublicCache, + Directive::public, ); $this->assertInstanceOf(Header\Custom::class, $h); diff --git a/tests/Header/CacheControlValue/ImmutableTest.php b/tests/Header/CacheControlValue/ImmutableTest.php index 8a8eefd..aba5576 100644 --- a/tests/Header/CacheControlValue/ImmutableTest.php +++ b/tests/Header/CacheControlValue/ImmutableTest.php @@ -3,19 +3,13 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\Header\{ - CacheControlValue, - CacheControlValue\Immutable -}; +use Innmind\Http\Header\CacheControl\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class ImmutableTest extends TestCase { public function testInterface() { - $h = new Immutable; - - $this->assertInstanceOf(CacheControlValue::class, $h); - $this->assertSame('immutable', $h->toString()); + $this->assertSame('immutable', Directive::immutable->toString()); } } diff --git a/tests/Header/CacheControlValue/MaxAgeTest.php b/tests/Header/CacheControlValue/MaxAgeTest.php index df70497..ec581ba 100644 --- a/tests/Header/CacheControlValue/MaxAgeTest.php +++ b/tests/Header/CacheControlValue/MaxAgeTest.php @@ -3,29 +3,17 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\{ - Header\CacheControlValue, - Header\CacheControlValue\MaxAge, - Exception\DomainException, -}; +use Innmind\Http\Header\CacheControl\MaxAge; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class MaxAgeTest extends TestCase { public function testInterface() { - $h = new MaxAge(42); + $h = MaxAge::of(42); - $this->assertInstanceOf(CacheControlValue::class, $h); + $this->assertInstanceOf(MaxAge::class, $h); $this->assertSame(42, $h->age()); $this->assertSame('max-age=42', $h->toString()); } - - public function testThrowWhenAgeIsNegative() - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage('-42'); - - new MaxAge(-42); - } } diff --git a/tests/Header/CacheControlValue/MaxStaleTest.php b/tests/Header/CacheControlValue/MaxStaleTest.php index 5a068f0..8715a04 100644 --- a/tests/Header/CacheControlValue/MaxStaleTest.php +++ b/tests/Header/CacheControlValue/MaxStaleTest.php @@ -3,30 +3,18 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\{ - Header\CacheControlValue, - Header\CacheControlValue\MaxStale, - Exception\DomainException, -}; +use Innmind\Http\Header\CacheControl\MaxStale; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class MaxStaleTest extends TestCase { public function testInterface() { - $h = new MaxStale(42); + $h = MaxStale::of(42); - $this->assertInstanceOf(CacheControlValue::class, $h); + $this->assertInstanceOf(MaxStale::class, $h); $this->assertSame(42, $h->age()); $this->assertSame('max-stale=42', $h->toString()); - $this->assertSame('max-stale', (new MaxStale(0))->toString()); - } - - public function testThrowWhenAgeIsNegative() - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage('-42'); - - new MaxStale(-42); + $this->assertSame('max-stale', MaxStale::of(0)->toString()); } } diff --git a/tests/Header/CacheControlValue/MinimumFreshTest.php b/tests/Header/CacheControlValue/MinimumFreshTest.php index ecf66a5..4525025 100644 --- a/tests/Header/CacheControlValue/MinimumFreshTest.php +++ b/tests/Header/CacheControlValue/MinimumFreshTest.php @@ -3,29 +3,17 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\{ - Header\CacheControlValue, - Header\CacheControlValue\MinimumFresh, - Exception\DomainException, -}; +use Innmind\Http\Header\CacheControl\MinimumFresh; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class MinimumFreshTest extends TestCase { public function testInterface() { - $h = new MinimumFresh(42); + $h = MinimumFresh::of(42); - $this->assertInstanceOf(CacheControlValue::class, $h); + $this->assertInstanceOf(MinimumFresh::class, $h); $this->assertSame(42, $h->age()); $this->assertSame('min-fresh=42', $h->toString()); } - - public function testThrowWhenAgeIsNegative() - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage('-42'); - - new MinimumFresh(-42); - } } diff --git a/tests/Header/CacheControlValue/MustRevalidateTest.php b/tests/Header/CacheControlValue/MustRevalidateTest.php index e9f50a1..ff4e701 100644 --- a/tests/Header/CacheControlValue/MustRevalidateTest.php +++ b/tests/Header/CacheControlValue/MustRevalidateTest.php @@ -3,19 +3,13 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\Header\{ - CacheControlValue, - CacheControlValue\MustRevalidate -}; +use Innmind\Http\Header\CacheControl\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class MustRevalidateTest extends TestCase { public function testInterface() { - $h = new MustRevalidate; - - $this->assertInstanceOf(CacheControlValue::class, $h); - $this->assertSame('must-revalidate', $h->toString()); + $this->assertSame('must-revalidate', Directive::mustRevalidate->toString()); } } diff --git a/tests/Header/CacheControlValue/NoCacheTest.php b/tests/Header/CacheControlValue/NoCacheTest.php index 62b3eb5..7d7c0f2 100644 --- a/tests/Header/CacheControlValue/NoCacheTest.php +++ b/tests/Header/CacheControlValue/NoCacheTest.php @@ -3,30 +3,32 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\{ - Header\CacheControlValue, - Header\CacheControlValue\NoCache, - Exception\DomainException, -}; +use Innmind\Http\Header\CacheControl\NoCache; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class NoCacheTest extends TestCase { public function testInterface() { - $h = new NoCache('field'); + $h = NoCache::maybe('field')->match( + static fn($value) => $value, + static fn() => null, + ); - $this->assertInstanceOf(CacheControlValue::class, $h); + $this->assertInstanceOf(NoCache::class, $h); $this->assertSame('field', $h->field()); $this->assertSame('no-cache="field"', $h->toString()); - $this->assertSame('no-cache', (new NoCache(''))->toString()); + $this->assertSame('no-cache', NoCache::maybe('')->match( + static fn($value) => $value->toString(), + static fn() => null, + )); } - public function testThrowWhenAgeIsNegative() + public function testReturnNothingWhenAgeIsNegative() { - $this->expectException(DomainException::class); - $this->expectExceptionMessage('foo-bar'); - - new NoCache('foo-bar'); + $this->assertNull(NoCache::maybe('foo-bar')->match( + static fn($value) => $value, + static fn() => null, + )); } } diff --git a/tests/Header/CacheControlValue/NoStoreTest.php b/tests/Header/CacheControlValue/NoStoreTest.php index af6f66a..8856269 100644 --- a/tests/Header/CacheControlValue/NoStoreTest.php +++ b/tests/Header/CacheControlValue/NoStoreTest.php @@ -3,19 +3,13 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\Header\{ - CacheControlValue, - CacheControlValue\NoStore -}; +use Innmind\Http\Header\CacheControl\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class NoStoreTest extends TestCase { public function testInterface() { - $h = new NoStore; - - $this->assertInstanceOf(CacheControlValue::class, $h); - $this->assertSame('no-store', $h->toString()); + $this->assertSame('no-store', Directive::noStore->toString()); } } diff --git a/tests/Header/CacheControlValue/NoTransformTest.php b/tests/Header/CacheControlValue/NoTransformTest.php index f1af561..2ee32a6 100644 --- a/tests/Header/CacheControlValue/NoTransformTest.php +++ b/tests/Header/CacheControlValue/NoTransformTest.php @@ -3,19 +3,13 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\Header\{ - CacheControlValue, - CacheControlValue\NoTransform -}; +use Innmind\Http\Header\CacheControl\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class NoTransformTest extends TestCase { public function testInterface() { - $h = new NoTransform; - - $this->assertInstanceOf(CacheControlValue::class, $h); - $this->assertSame('no-transform', $h->toString()); + $this->assertSame('no-transform', Directive::noTransform->toString()); } } diff --git a/tests/Header/CacheControlValue/OnlyIfCachedTest.php b/tests/Header/CacheControlValue/OnlyIfCachedTest.php index 9aae0b2..b195a2c 100644 --- a/tests/Header/CacheControlValue/OnlyIfCachedTest.php +++ b/tests/Header/CacheControlValue/OnlyIfCachedTest.php @@ -3,19 +3,13 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\Header\{ - CacheControlValue, - CacheControlValue\OnlyIfCached -}; +use Innmind\Http\Header\CacheControl\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class OnlyIfCachedTest extends TestCase { public function testInterface() { - $h = new OnlyIfCached; - - $this->assertInstanceOf(CacheControlValue::class, $h); - $this->assertSame('only-if-cached', $h->toString()); + $this->assertSame('only-if-cached', Directive::onlyIfCached->toString()); } } diff --git a/tests/Header/CacheControlValue/PrivateCacheTest.php b/tests/Header/CacheControlValue/PrivateCacheTest.php index e819bcf..913d63f 100644 --- a/tests/Header/CacheControlValue/PrivateCacheTest.php +++ b/tests/Header/CacheControlValue/PrivateCacheTest.php @@ -3,30 +3,32 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\{ - Header\CacheControlValue, - Header\CacheControlValue\PrivateCache, - Exception\DomainException, -}; +use Innmind\Http\Header\CacheControl\PrivateCache; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class PrivateCacheTest extends TestCase { public function testInterface() { - $h = new PrivateCache('field'); + $h = PrivateCache::maybe('field')->match( + static fn($value) => $value, + static fn() => null, + ); - $this->assertInstanceOf(CacheControlValue::class, $h); + $this->assertInstanceOf(PrivateCache::class, $h); $this->assertSame('field', $h->field()); $this->assertSame('private="field"', $h->toString()); - $this->assertSame('private', (new PrivateCache(''))->toString()); + $this->assertSame('private', PrivateCache::maybe('')->match( + static fn($value) => $value->toString(), + static fn() => null, + )); } public function testThrowWhenAgeIsNegative() { - $this->expectException(DomainException::class); - $this->expectExceptionMessage('foo-bar'); - - new PrivateCache('foo-bar'); + $this->assertNull(PrivateCache::maybe('foo-bar')->match( + static fn($value) => $value, + static fn() => null, + )); } } diff --git a/tests/Header/CacheControlValue/ProxyRevalidateTest.php b/tests/Header/CacheControlValue/ProxyRevalidateTest.php index 57a1cbb..cad31d4 100644 --- a/tests/Header/CacheControlValue/ProxyRevalidateTest.php +++ b/tests/Header/CacheControlValue/ProxyRevalidateTest.php @@ -3,19 +3,13 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\Header\{ - CacheControlValue, - CacheControlValue\ProxyRevalidate -}; +use Innmind\Http\Header\CacheControl\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class ProxyRevalidateTest extends TestCase { public function testInterface() { - $h = new ProxyRevalidate; - - $this->assertInstanceOf(CacheControlValue::class, $h); - $this->assertSame('proxy-revalidate', $h->toString()); + $this->assertSame('proxy-revalidate', Directive::proxyRevalidate->toString()); } } diff --git a/tests/Header/CacheControlValue/PublicCacheTest.php b/tests/Header/CacheControlValue/PublicCacheTest.php index 198852c..195ab46 100644 --- a/tests/Header/CacheControlValue/PublicCacheTest.php +++ b/tests/Header/CacheControlValue/PublicCacheTest.php @@ -3,19 +3,13 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\Header\{ - CacheControlValue, - CacheControlValue\PublicCache -}; +use Innmind\Http\Header\CacheControl\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class PublicCacheTest extends TestCase { public function testInterface() { - $h = new PublicCache; - - $this->assertInstanceOf(CacheControlValue::class, $h); - $this->assertSame('public', $h->toString()); + $this->assertSame('public', Directive::public->toString()); } } diff --git a/tests/Header/CacheControlValue/SharedMaxAgeTest.php b/tests/Header/CacheControlValue/SharedMaxAgeTest.php index 9c8a688..1323eba 100644 --- a/tests/Header/CacheControlValue/SharedMaxAgeTest.php +++ b/tests/Header/CacheControlValue/SharedMaxAgeTest.php @@ -3,29 +3,17 @@ namespace Tests\Innmind\Http\Header\CacheControlValue; -use Innmind\Http\{ - Header\CacheControlValue, - Header\CacheControlValue\SharedMaxAge, - Exception\DomainException, -}; +use Innmind\Http\Header\CacheControl\SharedMaxAge; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class SharedMaxAgeTest extends TestCase { public function testInterface() { - $h = new SharedMaxAge(42); + $h = SharedMaxAge::of(42); - $this->assertInstanceOf(CacheControlValue::class, $h); + $this->assertInstanceOf(SharedMaxAge::class, $h); $this->assertSame(42, $h->age()); $this->assertSame('s-maxage=42', $h->toString()); } - - public function testThrowWhenAgeIsNegative() - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage('-42'); - - new SharedMaxAge(-42); - } } From 63c90a377410d5641c93f7837ba6c50eb74df151 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 14:38:00 +0200 Subject: [PATCH 38/51] make Cookie constructor private --- CHANGELOG.md | 1 + src/Header/Cookie.php | 37 +++++++++++++++++++++++++++++++------ tests/Header/CookieTest.php | 16 ++++------------ 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cb24d4..4fa1293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ - `Innmind\Http\Header\Link` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\WWWAuthenticate` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\CacheControl` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Cookie` constructor is now private, use `::of()` named constructor ### Removed diff --git a/src/Header/Cookie.php b/src/Header/Cookie.php index 7fef46f..1e06eb5 100644 --- a/src/Header/Cookie.php +++ b/src/Header/Cookie.php @@ -4,15 +4,21 @@ namespace Innmind\Http\Header; use Innmind\Http\Header; -use Innmind\Immutable\Map; +use Innmind\Immutable\{ + Map, + Str, +}; /** * @psalm-immutable */ final class Cookie implements Custom { - public function __construct( - private CookieValue $value, + /** + * @param Map $parameters + */ + private function __construct( + private Map $parameters, ) { } @@ -22,7 +28,17 @@ public function __construct( */ public static function of(Parameter ...$parameters): self { - return new self(new CookieValue(...$parameters)); + /** @var Map */ + $map = Map::of(); + + foreach ($parameters as $paramater) { + $map = ($map)( + $paramater->name(), + $paramater, + ); + } + + return new self($map); } /** @@ -30,12 +46,21 @@ public static function of(Parameter ...$parameters): self */ public function parameters(): Map { - return $this->value->parameters(); + return $this->parameters; } #[\Override] public function normalize(): Header { - return new Header('Cookie', $this->value); + $parameters = $this->parameters->values()->map( + static fn($paramater) => $paramater->toString(), + ); + + $value = Str::of('; ')->join($parameters)->toString(); + + return new Header( + 'Cookie', + new Value\Value($value), + ); } } diff --git a/tests/Header/CookieTest.php b/tests/Header/CookieTest.php index 3e254e7..f339efe 100644 --- a/tests/Header/CookieTest.php +++ b/tests/Header/CookieTest.php @@ -6,8 +6,7 @@ use Innmind\Http\{ Header\Cookie, Header, - Header\CookieValue, - Header\Parameter\Parameter + Header\Parameter\Parameter, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -15,19 +14,12 @@ class CookieTest extends TestCase { public function testInterface() { - $cookie = new Cookie( - $value = new CookieValue(new Parameter('foo', 'bar')), + $cookie = Cookie::of( + new Parameter('foo', 'bar'), ); - $this->assertInstanceOf(Header\Custom::class, $cookie); - $this->assertSame('Cookie: foo=bar', $cookie->normalize()->toString()); - } - - public function testOf() - { - $cookie = Cookie::of(new Parameter('foo', 'bar')); - $this->assertInstanceOf(Cookie::class, $cookie); + $this->assertInstanceOf(Header\Custom::class, $cookie); $this->assertSame('Cookie: foo=bar', $cookie->normalize()->toString()); } } From 60b5e2b24e0726b090bf1e1641af324928387d20 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 15:15:44 +0200 Subject: [PATCH 39/51] make SetCookie constructor private --- CHANGELOG.md | 2 + src/Header/CookieValue.php | 52 ---------------------- src/Header/SetCookie.php | 75 +++++++++++++++++++++++++++----- src/ResponseSender.php | 14 ++---- tests/Header/CookieValueTest.php | 36 --------------- tests/Header/SetCookieTest.php | 18 +++----- 6 files changed, 76 insertions(+), 121 deletions(-) delete mode 100644 src/Header/CookieValue.php delete mode 100644 tests/Header/CookieValueTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fa1293..7658b62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ - `Innmind\Http\Header\WWWAuthenticate` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\CacheControl` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Cookie` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\SetCookie` constructor is now private, use `::of()` named constructor ### Removed @@ -102,6 +103,7 @@ - `Innmind\Http\Header\CacheControlValue\NoCache` - `Innmind\Http\Header\CacheControlValue\PrivateCache` - `Innmind\Http\Header\CacheControlValue\SharedMaxAge` +- `Innmind\Http\Header\CookieValue` ### Fixed diff --git a/src/Header/CookieValue.php b/src/Header/CookieValue.php deleted file mode 100644 index 8697afa..0000000 --- a/src/Header/CookieValue.php +++ /dev/null @@ -1,52 +0,0 @@ - */ - private Map $parameters; - - /** - * @no-named-arguments - */ - public function __construct(Parameter ...$parameters) - { - /** @var Map */ - $this->parameters = Map::of(); - - foreach ($parameters as $paramater) { - $this->parameters = ($this->parameters)( - $paramater->name(), - $paramater, - ); - } - } - - /** - * @return Map - */ - public function parameters(): Map - { - return $this->parameters; - } - - #[\Override] - public function toString(): string - { - $parameters = $this->parameters->values()->map( - static fn($paramater) => $paramater->toString(), - ); - - return Str::of('; ')->join($parameters)->toString(); - } -} diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index c7c8d40..b45951b 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -4,44 +4,95 @@ namespace Innmind\Http\Header; use Innmind\Http\Header; -use Innmind\Immutable\Sequence; +use Innmind\Immutable\{ + Sequence, + Str, +}; /** * @psalm-immutable */ final class SetCookie implements Custom { - /** @var Sequence */ - private Sequence $cookies; + /** + * @param Sequence $parameters + * @param Sequence $others + */ + private function __construct( + private Parameter $value, + private Sequence $parameters, + private Sequence $others, + ) { + } /** * @no-named-arguments + * @psalm-pure */ - public function __construct(CookieValue ...$values) + public static function of( + string $name, + string $value, + Parameter ...$parameters, + ): self { + return new self( + new Parameter\Parameter($name, $value), + Sequence::of(...$parameters), + Sequence::of(), + ); + } + + public function and(self $cookie): self + { + return new self( + $this->value, + $this->parameters, + ($this->others)($cookie), + ); + } + + public function name(): string { - $this->cookies = Sequence::of(...$values); + return $this->value->name(); + } + + public function value(): string + { + return $this->value->value(); } /** - * @no-named-arguments - * @psalm-pure + * @return Sequence */ - public static function of(Parameter ...$values): self + public function parameters(): Sequence { - return new self(new CookieValue(...$values)); + return $this->parameters; } /** - * @return Sequence + * @return Sequence */ public function cookies(): Sequence { - return $this->cookies; + return Sequence::of($this)->append($this->others); } #[\Override] public function normalize(): Header { - return new Header('Set-Cookie', ...$this->cookies->toList()); + return new Header( + 'Set-Cookie', + ...$this + ->cookies() + ->map(static fn($self) => new Value\Value( + Str::of('; ') + ->join( + Sequence::of($self->value) + ->append($self->parameters) + ->map(static fn($parameter) => $parameter->toString()), + ) + ->toString(), + )) + ->toList(), + ); } } diff --git a/src/ResponseSender.php b/src/ResponseSender.php index 864e004..6110d09 100644 --- a/src/ResponseSender.php +++ b/src/ResponseSender.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\Date, Header\SetCookie, - Header\CookieValue, Header\Parameter, TimeContinuum\Format\Http, Exception\LogicException, @@ -81,8 +80,8 @@ public function __invoke(Response $response): Attempt private function sendCookie(SetCookie $cookie): void { - $_ = $cookie->cookies()->foreach(static function(CookieValue $value): void { - $parameters = $value->parameters()->values()->reduce( + $_ = $cookie->cookies()->foreach(static function(SetCookie $cookie): void { + $parameters = $cookie->parameters()->reduce( [], static function(array $parameters, Parameter $parameter): array { switch ($parameter->name()) { @@ -123,11 +122,6 @@ static function(array $parameters, Parameter $parameter): array { case 'SameSite': $parameters['samesite'] = $parameter->value(); break; - - default: - $parameters['key'] = $parameter->name(); - $parameters['value'] = $parameter->value(); - break; } return $parameters; @@ -152,8 +146,8 @@ static function(array $parameters, Parameter $parameter): array { * @psalm-suppress InvalidCast */ \setcookie( - $parameters['key'] ?? '', - $parameters['value'] ?? '', + $cookie->name(), + $cookie->value(), $parameters['expire'] ?? 0, $options, ); diff --git a/tests/Header/CookieValueTest.php b/tests/Header/CookieValueTest.php deleted file mode 100644 index 46e7f60..0000000 --- a/tests/Header/CookieValueTest.php +++ /dev/null @@ -1,36 +0,0 @@ -assertInstanceOf(Value::class, $cookie); - $this->assertInstanceOf(Map::class, $cookie->parameters()); - $this->assertCount(2, $cookie->parameters()); - $this->assertSame('bar', $cookie->parameters()->get('foo')->match( - static fn($foo) => $foo->value(), - static fn() => null, - )); - $this->assertSame('baz', $cookie->parameters()->get('bar')->match( - static fn($bar) => $bar->value(), - static fn() => null, - )); - $this->assertSame('foo=bar; bar=baz', $cookie->toString()); - } -} diff --git a/tests/Header/SetCookieTest.php b/tests/Header/SetCookieTest.php index 0cbc22c..4a7abd0 100644 --- a/tests/Header/SetCookieTest.php +++ b/tests/Header/SetCookieTest.php @@ -6,7 +6,6 @@ use Innmind\Http\{ Header\SetCookie, Header, - Header\CookieValue, Header\Parameter\Parameter, Header\CookieParameter\Secure }; @@ -16,15 +15,11 @@ class SetCookieTest extends TestCase { public function testInterface() { - $cookie = new SetCookie( - $value = new CookieValue( - new Parameter('foo', 'bar'), - new Secure, - ), - new CookieValue( - new Parameter('bar', 'baz'), - ), - ); + $cookie = SetCookie::of( + 'foo', + 'bar', + new Secure, + )->and(SetCookie::of('bar', 'baz')); $this->assertInstanceOf(Header\Custom::class, $cookie); $this->assertSame('Set-Cookie: foo=bar; Secure, bar=baz', $cookie->normalize()->toString()); @@ -33,7 +28,8 @@ public function testInterface() public function testOf() { $cookie = SetCookie::of( - new Parameter('foo', 'bar'), + 'foo', + 'bar', new Parameter('bar', 'baz'), ); From c9cc7e88968fcd4ccf7f8cbfb47cc027fb5142e8 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 15:19:56 +0200 Subject: [PATCH 40/51] make Value a final class --- CHANGELOG.md | 1 + src/Factory/Header/Factory.php | 2 +- src/Header/Accept.php | 2 +- src/Header/AcceptCharset.php | 2 +- src/Header/AcceptEncoding.php | 2 +- src/Header/AcceptLanguage.php | 2 +- src/Header/AcceptRanges.php | 2 +- src/Header/Age.php | 2 +- src/Header/Allow.php | 2 +- src/Header/Authorization.php | 2 +- src/Header/CacheControl.php | 2 +- src/Header/ContentEncoding.php | 2 +- src/Header/ContentLanguage.php | 2 +- src/Header/ContentLength.php | 2 +- src/Header/ContentLocation.php | 2 +- src/Header/ContentRange.php | 2 +- src/Header/ContentType.php | 2 +- src/Header/Cookie.php | 2 +- src/Header/Date.php | 2 +- src/Header/Expires.php | 2 +- src/Header/Host.php | 2 +- src/Header/IfModifiedSince.php | 2 +- src/Header/IfUnmodifiedSince.php | 2 +- src/Header/LastModified.php | 2 +- src/Header/Link.php | 2 +- src/Header/Location.php | 2 +- src/Header/Range.php | 2 +- src/Header/Referrer.php | 2 +- src/Header/SetCookie.php | 2 +- src/Header/Value.php | 12 ++++++++++-- src/Header/Value/Value.php | 23 ----------------------- src/Header/WWWAuthenticate.php | 2 +- tests/Header/HeaderTest.php | 4 ++-- tests/Header/HeaderValueTest.php | 2 +- tests/HeadersTest.php | 2 +- 35 files changed, 44 insertions(+), 58 deletions(-) delete mode 100644 src/Header/Value/Value.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 7658b62..637317f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ - `Innmind\Http\Header\Referrer` constructor is now private, use `::of()` named constructor - All custom headers now implements `Innmind\Http\Header\Custom` - `Innmind\Http\Header` is now a final class +- `Innmind\Http\Header\Value` is now a final class - `Innmind\Http\Header\Accept` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\AcceptCharset` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\AcceptEncoding` constructor is now private, use `::of()` named constructor diff --git a/src/Factory/Header/Factory.php b/src/Factory/Header/Factory.php index 386a45e..8b70d04 100644 --- a/src/Factory/Header/Factory.php +++ b/src/Factory/Header/Factory.php @@ -50,7 +50,7 @@ private static function default(Str $name, Str $value): Header $values = $value ->split(',') ->map(static fn($value) => $value->trim()) - ->map(static fn($value) => new Value\Value($value->toString())) + ->map(static fn($value) => new Value($value->toString())) ->toList(); return new Header( diff --git a/src/Header/Accept.php b/src/Header/Accept.php index 5fb2b0b..2e8b05a 100644 --- a/src/Header/Accept.php +++ b/src/Header/Accept.php @@ -37,7 +37,7 @@ public function normalize(): Header 'Accept', ...$this ->values - ->map(static fn($value) => new Value\Value($value->toString())) + ->map(static fn($value) => new Value($value->toString())) ->toList(), ); } diff --git a/src/Header/AcceptCharset.php b/src/Header/AcceptCharset.php index d921ae7..eba2419 100644 --- a/src/Header/AcceptCharset.php +++ b/src/Header/AcceptCharset.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Accept-Charset', ...$this ->charsets - ->map(static fn($value) => new Value\Value($value->toString())) + ->map(static fn($value) => new Value($value->toString())) ->toList(), ); } diff --git a/src/Header/AcceptEncoding.php b/src/Header/AcceptEncoding.php index 81ef72b..106ff03 100644 --- a/src/Header/AcceptEncoding.php +++ b/src/Header/AcceptEncoding.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Accept-Encoding', ...$this ->encodings - ->map(static fn($value) => new Value\Value($value->toString())) + ->map(static fn($value) => new Value($value->toString())) ->toList(), ); } diff --git a/src/Header/AcceptLanguage.php b/src/Header/AcceptLanguage.php index 0e07e31..2333439 100644 --- a/src/Header/AcceptLanguage.php +++ b/src/Header/AcceptLanguage.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Accept-Language', ...$this ->languages - ->map(static fn($value) => new Value\Value($value->toString())) + ->map(static fn($value) => new Value($value->toString())) ->toList(), ); } diff --git a/src/Header/AcceptRanges.php b/src/Header/AcceptRanges.php index 52e6f24..13fa27b 100644 --- a/src/Header/AcceptRanges.php +++ b/src/Header/AcceptRanges.php @@ -53,7 +53,7 @@ public function normalize(): Header { return new Header( 'Accept-Ranges', - new Value\Value($this->ranges), + new Value($this->ranges), ); } } diff --git a/src/Header/Age.php b/src/Header/Age.php index d17a98a..d5b94e7 100644 --- a/src/Header/Age.php +++ b/src/Header/Age.php @@ -53,6 +53,6 @@ public function age(): int #[\Override] public function normalize(): Header { - return new Header('Age', new Value\Value((string) $this->age)); + return new Header('Age', new Value((string) $this->age)); } } diff --git a/src/Header/Allow.php b/src/Header/Allow.php index 2926f89..5a906d1 100644 --- a/src/Header/Allow.php +++ b/src/Header/Allow.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Allow', ...$this ->methods - ->map(static fn($method) => new Value\Value($method->toString())) + ->map(static fn($method) => new Value($method->toString())) ->toList(), ); } diff --git a/src/Header/Authorization.php b/src/Header/Authorization.php index 5c6c4a4..963aaf8 100644 --- a/src/Header/Authorization.php +++ b/src/Header/Authorization.php @@ -62,7 +62,7 @@ public function normalize(): Header { return new Header( 'Authorization', - new Value\Value( + new Value( Str::of($this->scheme) ->append(' ') ->append($this->parameter) diff --git a/src/Header/CacheControl.php b/src/Header/CacheControl.php index 1bf9bd5..bed1cc6 100644 --- a/src/Header/CacheControl.php +++ b/src/Header/CacheControl.php @@ -46,7 +46,7 @@ public function normalize(): Header 'Cache-Control', ...$this ->directives - ->map(static fn($directive) => new Value\Value($directive->toString())) + ->map(static fn($directive) => new Value($directive->toString())) ->toList(), ); } diff --git a/src/Header/ContentEncoding.php b/src/Header/ContentEncoding.php index 721e421..8bd5ee2 100644 --- a/src/Header/ContentEncoding.php +++ b/src/Header/ContentEncoding.php @@ -53,7 +53,7 @@ public function normalize(): Header { return new Header( 'Content-Encoding', - new Value\Value($this->encoding), + new Value($this->encoding), ); } } diff --git a/src/Header/ContentLanguage.php b/src/Header/ContentLanguage.php index 2f379fa..368de1a 100644 --- a/src/Header/ContentLanguage.php +++ b/src/Header/ContentLanguage.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Content-Language', ...$this ->languages - ->map(static fn($language) => new Value\Value($language->toString())) + ->map(static fn($language) => new Value($language->toString())) ->toList(), ); } diff --git a/src/Header/ContentLength.php b/src/Header/ContentLength.php index 7bf74de..4ee685d 100644 --- a/src/Header/ContentLength.php +++ b/src/Header/ContentLength.php @@ -55,7 +55,7 @@ public function normalize(): Header { return new Header( 'Content-Length', - new Value\Value((string) $this->length), + new Value((string) $this->length), ); } } diff --git a/src/Header/ContentLocation.php b/src/Header/ContentLocation.php index b96d8d6..beeae27 100644 --- a/src/Header/ContentLocation.php +++ b/src/Header/ContentLocation.php @@ -34,7 +34,7 @@ public function normalize(): Header { return new Header( 'Content-Location', - new Value\Value($this->url->toString()), + new Value($this->url->toString()), ); } } diff --git a/src/Header/ContentRange.php b/src/Header/ContentRange.php index 60b3198..2b66df5 100644 --- a/src/Header/ContentRange.php +++ b/src/Header/ContentRange.php @@ -110,7 +110,7 @@ public function normalize(): Header { return new Header( 'Content-Range', - new Value\Value(\sprintf( + new Value(\sprintf( '%s %s-%s/%s', $this->unit, $this->firstPosition, diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index ad4bf10..b43b936 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -59,7 +59,7 @@ public function normalize(): Header return new Header( 'Content-Type', - new Value\Value($content), + new Value($content), ); } } diff --git a/src/Header/Cookie.php b/src/Header/Cookie.php index 1e06eb5..8f7aa45 100644 --- a/src/Header/Cookie.php +++ b/src/Header/Cookie.php @@ -60,7 +60,7 @@ public function normalize(): Header return new Header( 'Cookie', - new Value\Value($value), + new Value($value), ); } } diff --git a/src/Header/Date.php b/src/Header/Date.php index 8be8a41..5127ab3 100644 --- a/src/Header/Date.php +++ b/src/Header/Date.php @@ -40,7 +40,7 @@ public function normalize(): Header { return new Header( 'Date', - new Value\Value( + new Value( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/Expires.php b/src/Header/Expires.php index f5d4253..ac51628 100644 --- a/src/Header/Expires.php +++ b/src/Header/Expires.php @@ -40,7 +40,7 @@ public function normalize(): Header { return new Header( 'Expires', - new Value\Value( + new Value( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/Host.php b/src/Header/Host.php index 6b70a12..ad0b946 100644 --- a/src/Header/Host.php +++ b/src/Header/Host.php @@ -43,7 +43,7 @@ public function normalize(): Header { return new Header( 'Host', - new Value\Value( + new Value( $this->host->toString().$this->port->format(), ), ); diff --git a/src/Header/IfModifiedSince.php b/src/Header/IfModifiedSince.php index 35cc7eb..8246a5e 100644 --- a/src/Header/IfModifiedSince.php +++ b/src/Header/IfModifiedSince.php @@ -40,7 +40,7 @@ public function normalize(): Header { return new Header( 'If-Modified-Since', - new Value\Value( + new Value( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/IfUnmodifiedSince.php b/src/Header/IfUnmodifiedSince.php index 53e2caf..614aea4 100644 --- a/src/Header/IfUnmodifiedSince.php +++ b/src/Header/IfUnmodifiedSince.php @@ -40,7 +40,7 @@ public function normalize(): Header { return new Header( 'If-Unmodified-Since', - new Value\Value( + new Value( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/LastModified.php b/src/Header/LastModified.php index 6a7396e..fe8b3c5 100644 --- a/src/Header/LastModified.php +++ b/src/Header/LastModified.php @@ -40,7 +40,7 @@ public function normalize(): Header { return new Header( 'Last-Modified', - new Value\Value( + new Value( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/Link.php b/src/Header/Link.php index 6b96b93..d5507a1 100644 --- a/src/Header/Link.php +++ b/src/Header/Link.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Link', ...$this ->relationships - ->map(static fn($relationship) => new Value\Value($relationship->toString())) + ->map(static fn($relationship) => new Value($relationship->toString())) ->toList(), ); } diff --git a/src/Header/Location.php b/src/Header/Location.php index acac015..cb03fca 100644 --- a/src/Header/Location.php +++ b/src/Header/Location.php @@ -34,7 +34,7 @@ public function normalize(): Header { return new Header( 'Location', - new Value\Value($this->location->toString()), + new Value($this->location->toString()), ); } } diff --git a/src/Header/Range.php b/src/Header/Range.php index c7e0d89..5741f24 100644 --- a/src/Header/Range.php +++ b/src/Header/Range.php @@ -93,7 +93,7 @@ public function normalize(): Header { return new Header( 'Range', - new Value\Value(\sprintf( + new Value(\sprintf( '%s=%s-%s', $this->unit, $this->firstPosition, diff --git a/src/Header/Referrer.php b/src/Header/Referrer.php index cc8c802..be2e11d 100644 --- a/src/Header/Referrer.php +++ b/src/Header/Referrer.php @@ -34,7 +34,7 @@ public function normalize(): Header { return new Header( 'Referer', - new Value\Value($this->referrer->toString()), + new Value($this->referrer->toString()), ); } } diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index b45951b..813a294 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -83,7 +83,7 @@ public function normalize(): Header 'Set-Cookie', ...$this ->cookies() - ->map(static fn($self) => new Value\Value( + ->map(static fn($self) => new Value( Str::of('; ') ->join( Sequence::of($self->value) diff --git a/src/Header/Value.php b/src/Header/Value.php index 5644c68..d45d2a6 100644 --- a/src/Header/Value.php +++ b/src/Header/Value.php @@ -6,7 +6,15 @@ /** * @psalm-immutable */ -interface Value +final class Value { - public function toString(): string; + public function __construct( + private string $value, + ) { + } + + public function toString(): string + { + return $this->value; + } } diff --git a/src/Header/Value/Value.php b/src/Header/Value/Value.php deleted file mode 100644 index 1b51d28..0000000 --- a/src/Header/Value/Value.php +++ /dev/null @@ -1,23 +0,0 @@ -value; - } -} diff --git a/src/Header/WWWAuthenticate.php b/src/Header/WWWAuthenticate.php index e401db7..dbd5d9a 100644 --- a/src/Header/WWWAuthenticate.php +++ b/src/Header/WWWAuthenticate.php @@ -38,7 +38,7 @@ public function normalize(): Header 'WWW-Authenticate', ...$this ->challenges - ->map(static fn($challenge) => new Value\Value($challenge->toString())) + ->map(static fn($challenge) => new Value($challenge->toString())) ->toList(), ); } diff --git a/tests/Header/HeaderTest.php b/tests/Header/HeaderTest.php index ee8f81d..d6cd3f4 100644 --- a/tests/Header/HeaderTest.php +++ b/tests/Header/HeaderTest.php @@ -15,8 +15,8 @@ public function testInterface() { $h = new Header( 'Accept', - $v1 = new Value\Value('application/json'), - $v2 = new Value\Value('*/*'), + $v1 = new Value('application/json'), + $v2 = new Value('*/*'), ); $this->assertInstanceOf(Header::class, $h); diff --git a/tests/Header/HeaderValueTest.php b/tests/Header/HeaderValueTest.php index 373e2b6..8ee05cd 100644 --- a/tests/Header/HeaderValueTest.php +++ b/tests/Header/HeaderValueTest.php @@ -10,7 +10,7 @@ class HeaderValueTest extends TestCase { public function testInterface() { - $hv = new Value\Value('foo'); + $hv = new Value('foo'); $this->assertInstanceOf(Value::class, $hv); $this->assertSame('foo', $hv->toString()); diff --git a/tests/HeadersTest.php b/tests/HeadersTest.php index dd70065..a05df6b 100644 --- a/tests/HeadersTest.php +++ b/tests/HeadersTest.php @@ -8,7 +8,7 @@ Header, Header\Allow, Header\ContentType, - Header\Value\Value, + Header\Value, }; use Innmind\MediaType\MediaType; use Innmind\Immutable\SideEffect; From b3be9c49b752bb02d6fde691e370de27110b7573 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:00:54 +0200 Subject: [PATCH 41/51] enforce the allowed parameters in a SetCookie header --- CHANGELOG.md | 12 +++ src/Header/CookieParameter/Domain.php | 38 -------- src/Header/CookieParameter/Expires.php | 47 ---------- src/Header/CookieParameter/HttpOnly.php | 37 -------- src/Header/CookieParameter/MaxAge.php | 52 ---------- src/Header/CookieParameter/Path.php | 38 -------- src/Header/CookieParameter/SameSite.php | 53 ----------- src/Header/CookieParameter/Secure.php | 37 -------- src/Header/SetCookie.php | 19 +++- src/Header/SetCookie/Directive.php | 27 ++++++ src/Header/SetCookie/Domain.php | 36 +++++++ src/Header/SetCookie/Expires.php | 45 +++++++++ src/Header/SetCookie/MaxAge.php | 51 ++++++++++ src/Header/SetCookie/Path.php | 36 +++++++ src/ResponseSender.php | 94 ++++++------------- tests/Header/CookieParameter/DomainTest.php | 10 +- tests/Header/CookieParameter/ExpiresTest.php | 10 +- tests/Header/CookieParameter/HttpOnlyTest.php | 10 +- tests/Header/CookieParameter/MaxAgeTest.php | 21 +---- tests/Header/CookieParameter/PathTest.php | 10 +- tests/Header/CookieParameter/SameSiteTest.php | 15 +-- tests/Header/CookieParameter/SecureTest.php | 10 +- tests/Header/SetCookieTest.php | 10 +- 23 files changed, 281 insertions(+), 437 deletions(-) delete mode 100644 src/Header/CookieParameter/Domain.php delete mode 100644 src/Header/CookieParameter/Expires.php delete mode 100644 src/Header/CookieParameter/HttpOnly.php delete mode 100644 src/Header/CookieParameter/MaxAge.php delete mode 100644 src/Header/CookieParameter/Path.php delete mode 100644 src/Header/CookieParameter/SameSite.php delete mode 100644 src/Header/CookieParameter/Secure.php create mode 100644 src/Header/SetCookie/Directive.php create mode 100644 src/Header/SetCookie/Domain.php create mode 100644 src/Header/SetCookie/Expires.php create mode 100644 src/Header/SetCookie/MaxAge.php create mode 100644 src/Header/SetCookie/Path.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 637317f..82ecbb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,11 @@ - `Innmind\Http\Header\CacheControl\NoCache` - `Innmind\Http\Header\CacheControl\PrivateCache` - `Innmind\Http\Header\CacheControl\SharedMaxAge` +- `Innmind\Http\Header\SetCookie\Directive` +- `Innmind\Http\Header\SetCookie\Domain` +- `Innmind\Http\Header\SetCookie\Expires` +- `Innmind\Http\Header\SetCookie\MaxAge` +- `Innmind\Http\Header\SetCookie\Path` ### Changed @@ -105,6 +110,13 @@ - `Innmind\Http\Header\CacheControlValue\PrivateCache` - `Innmind\Http\Header\CacheControlValue\SharedMaxAge` - `Innmind\Http\Header\CookieValue` +- `Innmind\Http\Header\CookieParameter\Domain` +- `Innmind\Http\Header\CookieParameter\Expires` +- `Innmind\Http\Header\CookieParameter\HttpOnly` +- `Innmind\Http\Header\CookieParameter\MaxAge` +- `Innmind\Http\Header\CookieParameter\Path` +- `Innmind\Http\Header\CookieParameter\SameSite` +- `Innmind\Http\Header\CookieParameter\Secure` ### Fixed diff --git a/src/Header/CookieParameter/Domain.php b/src/Header/CookieParameter/Domain.php deleted file mode 100644 index 47fd985..0000000 --- a/src/Header/CookieParameter/Domain.php +++ /dev/null @@ -1,38 +0,0 @@ -parameter = new Parameter\Parameter('Domain', $host->toString()); - } - - #[\Override] - public function name(): string - { - return $this->parameter->name(); - } - - #[\Override] - public function value(): string - { - return $this->parameter->value(); - } - - #[\Override] - public function toString(): string - { - return $this->parameter->toString(); - } -} diff --git a/src/Header/CookieParameter/Expires.php b/src/Header/CookieParameter/Expires.php deleted file mode 100644 index 390d16f..0000000 --- a/src/Header/CookieParameter/Expires.php +++ /dev/null @@ -1,47 +0,0 @@ -parameter = new Parameter\Parameter( - 'Expires', - $date->changeOffset(Offset::utc())->format(Http::new()), - ); - } - - #[\Override] - public function name(): string - { - return $this->parameter->name(); - } - - #[\Override] - public function value(): string - { - return $this->parameter->value(); - } - - #[\Override] - public function toString(): string - { - return $this->parameter->toString(); - } -} diff --git a/src/Header/CookieParameter/HttpOnly.php b/src/Header/CookieParameter/HttpOnly.php deleted file mode 100644 index 40759e9..0000000 --- a/src/Header/CookieParameter/HttpOnly.php +++ /dev/null @@ -1,37 +0,0 @@ -parameter = new Parameter\Parameter('HttpOnly', ''); - } - - #[\Override] - public function name(): string - { - return $this->parameter->name(); - } - - #[\Override] - public function value(): string - { - return $this->parameter->value(); - } - - #[\Override] - public function toString(): string - { - return $this->parameter->toString(); - } -} diff --git a/src/Header/CookieParameter/MaxAge.php b/src/Header/CookieParameter/MaxAge.php deleted file mode 100644 index 44d838f..0000000 --- a/src/Header/CookieParameter/MaxAge.php +++ /dev/null @@ -1,52 +0,0 @@ -parameter = new Parameter\Parameter('Max-Age', (string) $number); - } - - /** - * @psalm-pure - */ - public static function expire(): Parameter - { - return new Parameter\Parameter('Max-Age', '-1'); - } - - #[\Override] - public function name(): string - { - return $this->parameter->name(); - } - - #[\Override] - public function value(): string - { - return $this->parameter->value(); - } - - #[\Override] - public function toString(): string - { - return $this->parameter->toString(); - } -} diff --git a/src/Header/CookieParameter/Path.php b/src/Header/CookieParameter/Path.php deleted file mode 100644 index 8bf70b6..0000000 --- a/src/Header/CookieParameter/Path.php +++ /dev/null @@ -1,38 +0,0 @@ -parameter = new Parameter\Parameter('Path', $path->toString()); - } - - #[\Override] - public function name(): string - { - return $this->parameter->name(); - } - - #[\Override] - public function value(): string - { - return $this->parameter->value(); - } - - #[\Override] - public function toString(): string - { - return $this->parameter->toString(); - } -} diff --git a/src/Header/CookieParameter/SameSite.php b/src/Header/CookieParameter/SameSite.php deleted file mode 100644 index 672d98e..0000000 --- a/src/Header/CookieParameter/SameSite.php +++ /dev/null @@ -1,53 +0,0 @@ -parameter = new Parameter\Parameter('SameSite', $value); - } - - /** - * @psalm-pure - */ - public static function strict(): self - { - return new self('Strict'); - } - - /** - * @psalm-pure - */ - public static function lax(): self - { - return new self('Lax'); - } - - #[\Override] - public function name(): string - { - return $this->parameter->name(); - } - - #[\Override] - public function value(): string - { - return $this->parameter->value(); - } - - #[\Override] - public function toString(): string - { - return $this->parameter->toString(); - } -} diff --git a/src/Header/CookieParameter/Secure.php b/src/Header/CookieParameter/Secure.php deleted file mode 100644 index c1f32c9..0000000 --- a/src/Header/CookieParameter/Secure.php +++ /dev/null @@ -1,37 +0,0 @@ -parameter = new Parameter\Parameter('Secure', ''); - } - - #[\Override] - public function name(): string - { - return $this->parameter->name(); - } - - #[\Override] - public function value(): string - { - return $this->parameter->value(); - } - - #[\Override] - public function toString(): string - { - return $this->parameter->toString(); - } -} diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index 813a294..172aae1 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -3,7 +3,14 @@ namespace Innmind\Http\Header; -use Innmind\Http\Header; +use Innmind\Http\{ + Header, + Header\SetCookie\Directive, + Header\SetCookie\Domain, + Header\SetCookie\Expires, + Header\SetCookie\MaxAge, + Header\SetCookie\Path, +}; use Innmind\Immutable\{ Sequence, Str, @@ -15,7 +22,7 @@ final class SetCookie implements Custom { /** - * @param Sequence $parameters + * @param Sequence $parameters * @param Sequence $others */ private function __construct( @@ -32,7 +39,7 @@ private function __construct( public static function of( string $name, string $value, - Parameter ...$parameters, + Directive|Domain|Expires|MaxAge|Path ...$parameters, ): self { return new self( new Parameter\Parameter($name, $value), @@ -61,7 +68,7 @@ public function value(): string } /** - * @return Sequence + * @return Sequence */ public function parameters(): Sequence { @@ -87,7 +94,9 @@ public function normalize(): Header Str::of('; ') ->join( Sequence::of($self->value) - ->append($self->parameters) + ->append($self->parameters->map( + static fn($parameter) => $parameter->toParameter(), + )) ->map(static fn($parameter) => $parameter->toString()), ) ->toString(), diff --git a/src/Header/SetCookie/Directive.php b/src/Header/SetCookie/Directive.php new file mode 100644 index 0000000..92d9597 --- /dev/null +++ b/src/Header/SetCookie/Directive.php @@ -0,0 +1,27 @@ + new Parameter\Parameter('SameSite', 'Lax'), + self::strictSameSite => new Parameter\Parameter('SameSite', 'Strict'), + self::secure => new Parameter\Parameter('Secure', ''), + self::httpOnly => new Parameter\Parameter('HttpOnly', ''), + }; + } +} diff --git a/src/Header/SetCookie/Domain.php b/src/Header/SetCookie/Domain.php new file mode 100644 index 0000000..fb17413 --- /dev/null +++ b/src/Header/SetCookie/Domain.php @@ -0,0 +1,36 @@ +host; + } + + public function toParameter(): Parameter + { + return new Parameter\Parameter('Domain', $this->host->toString()); + } +} diff --git a/src/Header/SetCookie/Expires.php b/src/Header/SetCookie/Expires.php new file mode 100644 index 0000000..a5bf35e --- /dev/null +++ b/src/Header/SetCookie/Expires.php @@ -0,0 +1,45 @@ +changeOffset(Offset::utc())); + } + + public function date(): PointInTime + { + return $this->date; + } + + public function toParameter(): Parameter + { + return new Parameter\Parameter( + 'Expires', + $this->date->format(Http::new()), + ); + } +} diff --git a/src/Header/SetCookie/MaxAge.php b/src/Header/SetCookie/MaxAge.php new file mode 100644 index 0000000..2d5ce92 --- /dev/null +++ b/src/Header/SetCookie/MaxAge.php @@ -0,0 +1,51 @@ + $age + */ + private function __construct( + private ?int $age, + ) { + } + + /** + * @psalm-pure + * + * @param int<1, max> $age + */ + public static function of(int $age): self + { + return new self($age); + } + + /** + * @psalm-pure + */ + public static function expire(): self + { + return new self(null); + } + + public function toInt(): int + { + return match ($this->age) { + null => -1, + default => $this->age, + }; + } + + public function toParameter(): Parameter + { + return new Parameter\Parameter('Max-Age', (string) $this->toInt()); + } +} diff --git a/src/Header/SetCookie/Path.php b/src/Header/SetCookie/Path.php new file mode 100644 index 0000000..b201564 --- /dev/null +++ b/src/Header/SetCookie/Path.php @@ -0,0 +1,36 @@ +path; + } + + public function toParameter(): Parameter + { + return new Parameter\Parameter('Path', $this->path->toString()); + } +} diff --git a/src/ResponseSender.php b/src/ResponseSender.php index 6110d09..d7ae0fb 100644 --- a/src/ResponseSender.php +++ b/src/ResponseSender.php @@ -6,12 +6,14 @@ use Innmind\Http\{ Header\Date, Header\SetCookie, - Header\Parameter, - TimeContinuum\Format\Http, Exception\LogicException, }; -use Innmind\TimeContinuum\Clock; +use Innmind\TimeContinuum\{ + Clock, + Format, +}; use Innmind\Immutable\{ + Map, Attempt, SideEffect, }; @@ -81,74 +83,40 @@ public function __invoke(Response $response): Attempt private function sendCookie(SetCookie $cookie): void { $_ = $cookie->cookies()->foreach(static function(SetCookie $cookie): void { - $parameters = $cookie->parameters()->reduce( - [], - static function(array $parameters, Parameter $parameter): array { - switch ($parameter->name()) { - case 'Domain': - $parameters['domain'] = $parameter->value(); - break; - - case 'Expires': - /** @psalm-suppress PossiblyFalseReference Expires object uses a valid date */ - $timestamp = \DateTimeImmutable::createFromFormat( - Http::new()->toString(), - \substr($parameter->value(), 1, -1), // remove double quotes - )->getTimestamp(); - // MaxAge has precedence - /** @psalm-suppress MixedAssignment */ - $parameters['expire'] = match ($parameters['expire'] ?? 0) { - 0 => $timestamp, - default => $parameters['expire'] ?? 0, - }; - break; - - case 'Max-Age': - $parameters['expire'] = (int) $parameter->value(); - break; - - case 'HttpOnly': - $parameters['httponly'] = true; - break; - - case 'Path': - $parameters['path'] = $parameter->value(); - break; - - case 'Secure': - $parameters['secure'] = true; - break; - - case 'SameSite': - $parameters['samesite'] = $parameter->value(); - break; - } - - return $parameters; + $parameters = $cookie->parameters()->map( + static fn($parameter) => match (true) { + $parameter === SetCookie\Directive::httpOnly => ['httponly', true], + $parameter === SetCookie\Directive::secure => ['secure', true], + $parameter === SetCookie\Directive::laxSameSite => ['samesite', 'Lax'], + $parameter === SetCookie\Directive::strictSameSite => ['samesite', 'Strict'], + $parameter instanceof SetCookie\Domain => ['domain', $parameter->host()->toString()], + $parameter instanceof SetCookie\Expires => [ + 'expires', + (int) $parameter->date()->format(Format::of('U')), + ], + $parameter instanceof SetCookie\MaxAge => ['max-age', $parameter->toInt()], + $parameter instanceof SetCookie\Path => ['path', $parameter->path()->toString()], }, ); - $options = [ - 'path' => $parameters['path'] ?? '', - 'domain' => $parameters['domain'] ?? '', - 'secure' => $parameters['secure'] ?? false, - 'httponly' => $parameters['httponly'] ?? false, - ]; + $parameters = Map::of(...$parameters->toList()); + // Max age has precedence over expire + $parameters = $parameters->get('max-age')->match( + static fn($value) => ($parameters)('expires', $value), + static fn() => $parameters, + ); + $options = $parameters->reduce( + [], + static function(array $options, $key, $value) { + $options[$key] = $value; - if (isset($parameters['samesite'])) { - /** @psalm-suppress MixedAssignment */ - $options['samesite'] = $parameters['samesite']; - } + return $options; + }, + ); - /** - * @psalm-suppress MixedArgument - * @psalm-suppress InvalidArgument - * @psalm-suppress InvalidCast - */ \setcookie( $cookie->name(), $cookie->value(), - $parameters['expire'] ?? 0, $options, ); }); diff --git a/tests/Header/CookieParameter/DomainTest.php b/tests/Header/CookieParameter/DomainTest.php index 1f4ef21..5e9f28a 100644 --- a/tests/Header/CookieParameter/DomainTest.php +++ b/tests/Header/CookieParameter/DomainTest.php @@ -3,10 +3,7 @@ namespace Tests\Innmind\Http\Header\CookieParameter; -use Innmind\Http\Header\{ - CookieParameter\Domain, - Parameter -}; +use Innmind\Http\Header\SetCookie\Domain; use Innmind\Url\Authority\Host; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -14,9 +11,8 @@ class DomainTest extends TestCase { public function testInterface() { - $domain = new Domain(Host::of('localhost')); + $domain = Domain::of(Host::of('localhost')); - $this->assertInstanceOf(Parameter::class, $domain); - $this->assertSame('Domain=localhost', $domain->toString()); + $this->assertSame('Domain=localhost', $domain->toParameter()->toString()); } } diff --git a/tests/Header/CookieParameter/ExpiresTest.php b/tests/Header/CookieParameter/ExpiresTest.php index d6244c5..c6264be 100644 --- a/tests/Header/CookieParameter/ExpiresTest.php +++ b/tests/Header/CookieParameter/ExpiresTest.php @@ -3,10 +3,7 @@ namespace Tests\Innmind\Http\Header\CookieParameter; -use Innmind\Http\Header\{ - CookieParameter\Expires, - Parameter -}; +use Innmind\Http\Header\SetCookie\Expires; use Innmind\TimeContinuum\PointInTime; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -14,11 +11,10 @@ class ExpiresTest extends TestCase { public function testInterface() { - $expires = new Expires(PointInTime::at( + $expires = Expires::at(PointInTime::at( new \DateTimeImmutable('2018-01-01T12:13:14+0200'), )); - $this->assertInstanceOf(Parameter::class, $expires); - $this->assertSame('Expires="Mon, 01 Jan 2018 10:13:14 GMT"', $expires->toString()); + $this->assertSame('Expires="Mon, 01 Jan 2018 10:13:14 GMT"', $expires->toParameter()->toString()); } } diff --git a/tests/Header/CookieParameter/HttpOnlyTest.php b/tests/Header/CookieParameter/HttpOnlyTest.php index 7c084e5..9ea616e 100644 --- a/tests/Header/CookieParameter/HttpOnlyTest.php +++ b/tests/Header/CookieParameter/HttpOnlyTest.php @@ -3,19 +3,15 @@ namespace Tests\Innmind\Http\Header\CookieParameter; -use Innmind\Http\Header\{ - CookieParameter\HttpOnly, - Parameter -}; +use Innmind\Http\Header\SetCookie\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class HttpOnlyTest extends TestCase { public function testInterface() { - $httpOnly = new HttpOnly; + $httpOnly = Directive::httpOnly; - $this->assertInstanceOf(Parameter::class, $httpOnly); - $this->assertSame('HttpOnly', $httpOnly->toString()); + $this->assertSame('HttpOnly', $httpOnly->toParameter()->toString()); } } diff --git a/tests/Header/CookieParameter/MaxAgeTest.php b/tests/Header/CookieParameter/MaxAgeTest.php index fe9f36f..febaaf9 100644 --- a/tests/Header/CookieParameter/MaxAgeTest.php +++ b/tests/Header/CookieParameter/MaxAgeTest.php @@ -3,30 +3,17 @@ namespace Tests\Innmind\Http\Header\CookieParameter; -use Innmind\Http\{ - Header\CookieParameter\MaxAge, - Header\Parameter, - Exception\DomainException -}; +use Innmind\Http\Header\SetCookie\MaxAge; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class MaxAgeTest extends TestCase { public function testInterface() { - $maxAge = new MaxAge(1); + $maxAge = MaxAge::of(1); - $this->assertInstanceOf(Parameter::class, $maxAge); - $this->assertSame('Max-Age=1', $maxAge->toString()); + $this->assertSame('Max-Age=1', $maxAge->toParameter()->toString()); - $this->assertInstanceOf(Parameter::class, MaxAge::expire()); - $this->assertSame('Max-Age=-1', MaxAge::expire()->toString()); - } - - public function testThrowWhenInvalidAge() - { - $this->expectException(DomainException::class); - - new MaxAge(0); + $this->assertSame('Max-Age=-1', MaxAge::expire()->toParameter()->toString()); } } diff --git a/tests/Header/CookieParameter/PathTest.php b/tests/Header/CookieParameter/PathTest.php index 28a576e..f6662aa 100644 --- a/tests/Header/CookieParameter/PathTest.php +++ b/tests/Header/CookieParameter/PathTest.php @@ -3,10 +3,7 @@ namespace Tests\Innmind\Http\Header\CookieParameter; -use Innmind\Http\Header\{ - CookieParameter\Path, - Parameter -}; +use Innmind\Http\Header\SetCookie\Path; use Innmind\Url\Path as UrlPath; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -14,9 +11,8 @@ class PathTest extends TestCase { public function testInterface() { - $path = new Path(UrlPath::of('/foo')); + $path = Path::of(UrlPath::of('/foo')); - $this->assertInstanceOf(Parameter::class, $path); - $this->assertSame('Path=/foo', $path->toString()); + $this->assertSame('Path=/foo', $path->toParameter()->toString()); } } diff --git a/tests/Header/CookieParameter/SameSiteTest.php b/tests/Header/CookieParameter/SameSiteTest.php index dc58d0a..b950289 100644 --- a/tests/Header/CookieParameter/SameSiteTest.php +++ b/tests/Header/CookieParameter/SameSiteTest.php @@ -3,24 +3,19 @@ namespace Tests\Innmind\Http\Header\CookieParameter; -use Innmind\Http\Header\{ - CookieParameter\SameSite, - Parameter -}; +use Innmind\Http\Header\SetCookie\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class SameSiteTest extends TestCase { public function testInterface() { - $sameSite = SameSite::strict(); + $sameSite = Directive::strictSameSite; - $this->assertInstanceOf(Parameter::class, $sameSite); - $this->assertSame('SameSite=Strict', $sameSite->toString()); + $this->assertSame('SameSite=Strict', $sameSite->toParameter()->toString()); - $sameSite = SameSite::lax(); + $sameSite = Directive::laxSameSite; - $this->assertInstanceOf(Parameter::class, $sameSite); - $this->assertSame('SameSite=Lax', $sameSite->toString()); + $this->assertSame('SameSite=Lax', $sameSite->toParameter()->toString()); } } diff --git a/tests/Header/CookieParameter/SecureTest.php b/tests/Header/CookieParameter/SecureTest.php index c8c7b1e..1311f12 100644 --- a/tests/Header/CookieParameter/SecureTest.php +++ b/tests/Header/CookieParameter/SecureTest.php @@ -3,19 +3,15 @@ namespace Tests\Innmind\Http\Header\CookieParameter; -use Innmind\Http\Header\{ - CookieParameter\Secure, - Parameter -}; +use Innmind\Http\Header\SetCookie\Directive; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class SecureTest extends TestCase { public function testInterface() { - $secure = new Secure; + $secure = Directive::secure; - $this->assertInstanceOf(Parameter::class, $secure); - $this->assertSame('Secure', $secure->toString()); + $this->assertSame('Secure', $secure->toParameter()->toString()); } } diff --git a/tests/Header/SetCookieTest.php b/tests/Header/SetCookieTest.php index 4a7abd0..5f44800 100644 --- a/tests/Header/SetCookieTest.php +++ b/tests/Header/SetCookieTest.php @@ -6,8 +6,8 @@ use Innmind\Http\{ Header\SetCookie, Header, - Header\Parameter\Parameter, - Header\CookieParameter\Secure + Header\SetCookie\Directive, + Header\SetCookie\MaxAge, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -18,7 +18,7 @@ public function testInterface() $cookie = SetCookie::of( 'foo', 'bar', - new Secure, + Directive::secure, )->and(SetCookie::of('bar', 'baz')); $this->assertInstanceOf(Header\Custom::class, $cookie); @@ -30,10 +30,10 @@ public function testOf() $cookie = SetCookie::of( 'foo', 'bar', - new Parameter('bar', 'baz'), + MaxAge::expire(), ); $this->assertInstanceOf(SetCookie::class, $cookie); - $this->assertSame('Set-Cookie: foo=bar; bar=baz', $cookie->normalize()->toString()); + $this->assertSame('Set-Cookie: foo=bar; Max-Age=-1', $cookie->normalize()->toString()); } } From 53a8e6b23dead067991da5ef899ff9f4cd4372ed Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:01:59 +0200 Subject: [PATCH 42/51] remove unused class --- CHANGELOG.md | 1 + src/Header/Parameter/NullParameter.php | 30 -------------------- tests/Header/Parameter/NullParameterTest.php | 23 --------------- 3 files changed, 1 insertion(+), 53 deletions(-) delete mode 100644 src/Header/Parameter/NullParameter.php delete mode 100644 tests/Header/Parameter/NullParameterTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 82ecbb8..565e057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -117,6 +117,7 @@ - `Innmind\Http\Header\CookieParameter\Path` - `Innmind\Http\Header\CookieParameter\SameSite` - `Innmind\Http\Header\CookieParameter\Secure` +- `Innmind\Http\Header\Parameter\NullParameter` ### Fixed diff --git a/src/Header/Parameter/NullParameter.php b/src/Header/Parameter/NullParameter.php deleted file mode 100644 index cf890b3..0000000 --- a/src/Header/Parameter/NullParameter.php +++ /dev/null @@ -1,30 +0,0 @@ -assertInstanceOf(Parameter::class, $p); - $this->assertSame('', $p->name()); - $this->assertSame('', $p->value()); - $this->assertSame('', $p->toString()); - } -} From 5f80239700a505327083191ff076e9bd0916e7e1 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:24:09 +0200 Subject: [PATCH 43/51] close down the Quality object --- CHANGELOG.md | 3 ++ src/Factory/Header/Factories.php | 31 +++++++++--- src/Header/Accept/Charset.php | 4 +- src/Header/Accept/Encoding.php | 4 +- src/Header/Accept/Language.php | 4 +- src/Header/Parameter/Quality.php | 62 +++++++++++------------- tests/Header/AcceptCharsetTest.php | 2 +- tests/Header/AcceptCharsetValueTest.php | 15 +++--- tests/Header/AcceptEncodingTest.php | 2 +- tests/Header/AcceptEncodingValueTest.php | 13 ++--- tests/Header/AcceptLanguageTest.php | 2 +- tests/Header/AcceptLanguageValueTest.php | 13 ++--- tests/Header/AcceptTest.php | 2 +- tests/Header/AcceptValueTest.php | 4 +- tests/Header/Parameter/QualityTest.php | 35 +++---------- 15 files changed, 95 insertions(+), 101 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 565e057..0590ea8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,9 @@ - `Innmind\Http\Header\CacheControl` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Cookie` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\SetCookie` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Parameter\Quality` constructor is now private, use `::of()` named constructor +- `Innmind\Http\Header\Parameter\Quality` no longer implements `Innmind\Http\Header\Parameter` +- `Innmind\Http\Header\Parameter\Quality::of()` now returns `self` ### Removed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index cc7b5e8..413925b 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -47,6 +47,7 @@ Maybe, Sequence, Map, + Predicate, Predicate\Instance, }; @@ -133,11 +134,17 @@ public function try(Clock $clock, Str $value): Maybe $matches = $accept->capture( '~(?[a-zA-Z0-9\-_:\(\)]+)(; ?q=(?\d+(\.\d+)?))?~', ); + /** @var Predicate> */ + $range = Is::int() + ->range(0, 100) + ->asPredicate(); $quality = $matches ->get('quality') ->map(static fn($quality) => (float) $quality->toString()) - ->otherwise(static fn() => Maybe::just(1)) - ->flatMap(Quality::of(...)); + ->map(static fn($quality) => (int) ($quality * 100.0)) + ->otherwise(static fn() => Maybe::just(100)) + ->keep($range) + ->map(Quality::of(...)); $charset = $matches ->get('charset') ->map(static fn($charset) => $charset->toString()); @@ -156,11 +163,17 @@ public function try(Clock $clock, Str $value): Maybe $matches = $accept->capture( '~(?(\w+|\*))(; ?q=(?\d+(\.\d+)?))?~', ); + /** @var Predicate> */ + $range = Is::int() + ->range(0, 100) + ->asPredicate(); $quality = $matches ->get('quality') ->map(static fn($quality) => (float) $quality->toString()) - ->otherwise(static fn() => Maybe::just(1)) - ->flatMap(Quality::of(...)); + ->map(static fn($quality) => (int) ($quality * 100.0)) + ->otherwise(static fn() => Maybe::just(100)) + ->keep($range) + ->map(Quality::of(...)); $coding = $matches ->get('coding') ->map(static fn($coding) => $coding->toString()); @@ -211,11 +224,17 @@ public function try(Clock $clock, Str $value): Maybe $matches = $accept->capture( '~(?([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*|\*))(; ?q=(?\d+(\.\d+)?))?~', ); + /** @var Predicate> */ + $range = Is::int() + ->range(0, 100) + ->asPredicate(); $quality = $matches ->get('quality') ->map(static fn($quality) => (float) $quality->toString()) - ->otherwise(static fn() => Maybe::just(1)) - ->flatMap(Quality::of(...)); + ->map(static fn($quality) => (int) ($quality * 100.0)) + ->otherwise(static fn() => Maybe::just(100)) + ->keep($range) + ->map(Quality::of(...)); $lang = $matches ->get('lang') ->map(static fn($lang) => $lang->toString()); diff --git a/src/Header/Accept/Charset.php b/src/Header/Accept/Charset.php index c2746f3..324484d 100644 --- a/src/Header/Accept/Charset.php +++ b/src/Header/Accept/Charset.php @@ -37,7 +37,7 @@ public static function maybe(string $charset, ?Quality $quality = null): Maybe return Maybe::nothing(); } - return Maybe::just(new self($charset, $quality ?? new Quality(1))); + return Maybe::just(new self($charset, $quality ?? Quality::max())); } public function quality(): Quality @@ -50,7 +50,7 @@ public function toString(): string return $this ->charset ->append(';') - ->append($this->quality->toString()) + ->append($this->quality->toParameter()->toString()) ->toString(); } } diff --git a/src/Header/Accept/Encoding.php b/src/Header/Accept/Encoding.php index a107b3a..bb0e085 100644 --- a/src/Header/Accept/Encoding.php +++ b/src/Header/Accept/Encoding.php @@ -37,7 +37,7 @@ public static function maybe(string $coding, ?Quality $quality = null): Maybe return Maybe::nothing(); } - return Maybe::just(new self($coding, $quality ?? new Quality(1))); + return Maybe::just(new self($coding, $quality ?? Quality::max())); } public function quality(): Quality @@ -50,7 +50,7 @@ public function toString(): string return $this ->coding ->append(';') - ->append($this->quality->toString()) + ->append($this->quality->toParameter()->toString()) ->toString(); } } diff --git a/src/Header/Accept/Language.php b/src/Header/Accept/Language.php index dc1c699..3c3aed0 100644 --- a/src/Header/Accept/Language.php +++ b/src/Header/Accept/Language.php @@ -37,7 +37,7 @@ public static function maybe(string $language, ?Quality $quality = null): Maybe return Maybe::nothing(); } - return Maybe::just(new self($language, $quality ?? new Quality(1))); + return Maybe::just(new self($language, $quality ?? Quality::max())); } public function quality(): Quality @@ -50,7 +50,7 @@ public function toString(): string return $this ->language ->append(';') - ->append($this->quality->toString()) + ->append($this->quality->toParameter()->toString()) ->toString(); } } diff --git a/src/Header/Parameter/Quality.php b/src/Header/Parameter/Quality.php index 3e4acaf..7feeebd 100644 --- a/src/Header/Parameter/Quality.php +++ b/src/Header/Parameter/Quality.php @@ -3,58 +3,50 @@ namespace Innmind\Http\Header\Parameter; -use Innmind\Http\{ - Header\Parameter as ParameterInterface, - Exception\DomainException -}; -use Innmind\Immutable\Maybe; +use Innmind\Immutable\Str; /** * @psalm-immutable */ -final class Quality implements ParameterInterface +final class Quality { - private Parameter $parameter; - - public function __construct(float $value) - { - if ($value < 0 || $value > 1) { - throw new DomainException((string) $value); - } - - $this->parameter = new Parameter('q', (string) $value); + /** + * @param int<0, 100> $percent + */ + private function __construct( + private int $percent, + ) { } /** * @psalm-pure * - * @return Maybe + * @param int<0, 100> $percent */ - public static function of(float $value): Maybe + public static function of(int $percent): self { - try { - return Maybe::just(new self($value)); - } catch (DomainException $e) { - /** @var Maybe */ - return Maybe::nothing(); - } + return new self($percent); } - #[\Override] - public function name(): string - { - return $this->parameter->name(); - } - - #[\Override] - public function value(): string + /** + * @psalm-pure + */ + public static function max(): self { - return $this->parameter->value(); + return new self(100); } - #[\Override] - public function toString(): string + public function toParameter(): Parameter { - return $this->parameter->toString(); + $value = Str::of(\sprintf( + '%0.2f', + $this->percent / 100, + )); + + return new Parameter('q', match (true) { + $value->endsWith('.00') => $value->dropEnd(3)->toString(), + $value->endsWith('0') => $value->dropEnd(1)->toString(), + default => $value->toString(), + }); } } diff --git a/tests/Header/AcceptCharsetTest.php b/tests/Header/AcceptCharsetTest.php index 987c7b0..7a01144 100644 --- a/tests/Header/AcceptCharsetTest.php +++ b/tests/Header/AcceptCharsetTest.php @@ -15,7 +15,7 @@ class AcceptCharsetTest extends TestCase { public function testInterface() { - $h = Charset::maybe('unicode-1-1', new Quality(0.8)) + $h = Charset::maybe('unicode-1-1', Quality::of(80)) ->map(AcceptCharset::of(...)) ->match( static fn($header) => $header, diff --git a/tests/Header/AcceptCharsetValueTest.php b/tests/Header/AcceptCharsetValueTest.php index e8525b6..7690f5d 100644 --- a/tests/Header/AcceptCharsetValueTest.php +++ b/tests/Header/AcceptCharsetValueTest.php @@ -14,7 +14,7 @@ class AcceptCharsetValueTest extends TestCase { public function testInterface() { - $a = Charset::maybe('unicode-1-1', $q = new Quality(0.8))->match( + $a = Charset::maybe('unicode-1-1', $q = Quality::of(80))->match( static fn($charset) => $charset, static fn() => null, ); @@ -23,23 +23,23 @@ public function testInterface() $this->assertSame($q, $a->quality()); $this->assertSame('unicode-1-1;q=0.8', $a->toString()); - Charset::maybe('iso-8859-5', new Quality(1))->match( + Charset::maybe('iso-8859-5', Quality::max())->match( static fn($charset) => $charset, static fn() => throw new \Exception, ); - Charset::maybe('Shift_JIS', new Quality(1))->match( + Charset::maybe('Shift_JIS', Quality::max())->match( static fn($charset) => $charset, static fn() => throw new \Exception, ); - Charset::maybe('ISO_8859-9:1989', new Quality(1))->match( + Charset::maybe('ISO_8859-9:1989', Quality::max())->match( static fn($charset) => $charset, static fn() => throw new \Exception, ); - Charset::maybe('NF_Z_62-010_(1973)', new Quality(1))->match( + Charset::maybe('NF_Z_62-010_(1973)', Quality::max())->match( static fn($charset) => $charset, static fn() => throw new \Exception, ); - Charset::maybe('*', new Quality(1))->match( + Charset::maybe('*', Quality::max())->match( static fn($charset) => $charset, static fn() => throw new \Exception, ); @@ -55,6 +55,7 @@ public function testDefaultQuality() static fn() => null, ) ?->quality() + ?->toParameter() ?->value(), ); } @@ -62,7 +63,7 @@ public function testDefaultQuality() #[DataProvider('invalids')] public function testReturnNothingWhenInvalidAcceptCharsetValue($value) { - $this->assertNull(Charset::maybe($value, new Quality(1))->match( + $this->assertNull(Charset::maybe($value, Quality::max())->match( static fn($charset) => $charset, static fn() => null, )); diff --git a/tests/Header/AcceptEncodingTest.php b/tests/Header/AcceptEncodingTest.php index 3d118fa..9a9c183 100644 --- a/tests/Header/AcceptEncodingTest.php +++ b/tests/Header/AcceptEncodingTest.php @@ -15,7 +15,7 @@ class AcceptEncodingTest extends TestCase { public function testInterface() { - $h = Encoding::maybe('compress', new Quality(1)) + $h = Encoding::maybe('compress', Quality::max()) ->map(AcceptEncoding::of(...)) ->match( static fn($header) => $header, diff --git a/tests/Header/AcceptEncodingValueTest.php b/tests/Header/AcceptEncodingValueTest.php index 6b05bc6..37f7a22 100644 --- a/tests/Header/AcceptEncodingValueTest.php +++ b/tests/Header/AcceptEncodingValueTest.php @@ -14,7 +14,7 @@ class AcceptEncodingValueTest extends TestCase { public function testInterface() { - $a = Encoding::maybe('compress', $q = new Quality(1))->match( + $a = Encoding::maybe('compress', $q = Quality::max())->match( static fn($encoding) => $encoding, static fn() => null, ); @@ -23,19 +23,19 @@ public function testInterface() $this->assertSame($q, $a->quality()); $this->assertSame('compress;q=1', $a->toString()); - Encoding::maybe('*', new Quality(1))->match( + Encoding::maybe('*', Quality::max())->match( static fn($encoding) => $encoding, static fn() => throw new \Exception, ); - Encoding::maybe('compress', new Quality(0.5))->match( + Encoding::maybe('compress', Quality::of(50))->match( static fn($encoding) => $encoding, static fn() => throw new \Exception, ); - Encoding::maybe('identity', new Quality(0.5))->match( + Encoding::maybe('identity', Quality::of(50))->match( static fn($encoding) => $encoding, static fn() => throw new \Exception, ); - Encoding::maybe('*', new Quality(0))->match( + Encoding::maybe('*', Quality::of(0))->match( static fn($encoding) => $encoding, static fn() => throw new \Exception, ); @@ -51,6 +51,7 @@ public function testDefaultQuality() static fn() => null, ) ?->quality() + ?->toParameter() ?->value(), ); } @@ -58,7 +59,7 @@ public function testDefaultQuality() #[DataProvider('invalids')] public function testReturnNothingWhenInvalidAcceptEncodingValue($value) { - $this->assertNull(Encoding::maybe($value, new Quality(1))->match( + $this->assertNull(Encoding::maybe($value, Quality::max())->match( static fn($encoding) => $encoding, static fn() => null, )); diff --git a/tests/Header/AcceptLanguageTest.php b/tests/Header/AcceptLanguageTest.php index b7d7e8b..a5dec0e 100644 --- a/tests/Header/AcceptLanguageTest.php +++ b/tests/Header/AcceptLanguageTest.php @@ -15,7 +15,7 @@ class AcceptLanguageTest extends TestCase { public function testInterface() { - $h = Language::maybe('fr', new Quality(0.8)) + $h = Language::maybe('fr', Quality::of(80)) ->map(AcceptLanguage::of(...)) ->match( static fn($header) => $header, diff --git a/tests/Header/AcceptLanguageValueTest.php b/tests/Header/AcceptLanguageValueTest.php index cf5347a..b520580 100644 --- a/tests/Header/AcceptLanguageValueTest.php +++ b/tests/Header/AcceptLanguageValueTest.php @@ -14,7 +14,7 @@ class AcceptLanguageValueTest extends TestCase { public function testInterface() { - $a = Language::maybe('en-gb', $q = new Quality(0.8))->match( + $a = Language::maybe('en-gb', $q = Quality::of(80))->match( static fn($language) => $language, static fn() => null, ); @@ -23,19 +23,19 @@ public function testInterface() $this->assertSame($q, $a->quality()); $this->assertSame('en-gb;q=0.8', $a->toString()); - Language::maybe('fr', new Quality(1))->match( + Language::maybe('fr', Quality::max())->match( static fn($language) => $language, static fn() => throw new \Exception, ); - Language::maybe('fr-FR', new Quality(1))->match( + Language::maybe('fr-FR', Quality::max())->match( static fn($language) => $language, static fn() => throw new \Exception, ); - Language::maybe('sgn-CH-DE', new Quality(1))->match( + Language::maybe('sgn-CH-DE', Quality::max())->match( static fn($language) => $language, static fn() => throw new \Exception, ); - Language::maybe('*', new Quality(1))->match( + Language::maybe('*', Quality::max())->match( static fn($language) => $language, static fn() => throw new \Exception, ); @@ -51,6 +51,7 @@ public function testDefaultQuality() static fn() => null, ) ?->quality() + ?->toParameter() ?->value(), ); } @@ -58,7 +59,7 @@ public function testDefaultQuality() #[DataProvider('invalids')] public function testReturnNothingWhenInvalidAcceptLanguageValue($value) { - $this->assertNull(Language::maybe($value, new Quality(1))->match( + $this->assertNull(Language::maybe($value, Quality::max())->match( static fn($language) => $language, static fn() => null, )); diff --git a/tests/Header/AcceptTest.php b/tests/Header/AcceptTest.php index 5ede356..ace92bc 100644 --- a/tests/Header/AcceptTest.php +++ b/tests/Header/AcceptTest.php @@ -17,7 +17,7 @@ public function testInterface() $h = Accept\MediaType::maybe( 'text', 'html', - new Quality(0.8), + Quality::of(80)->toParameter(), ) ->map(Accept::of(...)) ->match( diff --git a/tests/Header/AcceptValueTest.php b/tests/Header/AcceptValueTest.php index 6cc25a5..5733907 100644 --- a/tests/Header/AcceptValueTest.php +++ b/tests/Header/AcceptValueTest.php @@ -18,7 +18,7 @@ public function testInterface() $a = MediaType::maybe( 'text', 'x-c', - $q = new Quality(0.8), + $q = Quality::of(80)->toParameter(), )->match( static fn($mediaType) => $mediaType, static fn() => null, @@ -57,7 +57,7 @@ public function testInterface() MediaType::maybe( 'application', 'octet-stream', - new Quality(0.4), + Quality::of(40)->toParameter(), new Parameter\Parameter('level', '1'), )->match( static fn($mediaType) => $mediaType, diff --git a/tests/Header/Parameter/QualityTest.php b/tests/Header/Parameter/QualityTest.php index d1dbc5b..766a6ef 100644 --- a/tests/Header/Parameter/QualityTest.php +++ b/tests/Header/Parameter/QualityTest.php @@ -3,42 +3,19 @@ namespace Tests\Innmind\Http\Header\Parameter; -use Innmind\Http\{ - Header\Parameter\Quality, - Header\Parameter, - Exception\DomainException, -}; +use Innmind\Http\Header\Parameter\Quality; use Innmind\BlackBox\PHPUnit\Framework\TestCase; -use PHPUnit\Framework\Attributes\DataProvider; class QualityTest extends TestCase { public function testInterface() { - $p = new Quality(0.8); + $p = Quality::of(80); - $this->assertInstanceOf(Parameter::class, $p); - $this->assertSame('q', $p->name()); - $this->assertSame('0.8', $p->value()); - $this->assertSame('q=0.8', $p->toString()); + $this->assertSame('q', $p->toParameter()->name()); + $this->assertSame('0.8', $p->toParameter()->value()); + $this->assertSame('q=0.8', $p->toParameter()->toString()); - $this->assertSame('q=0', (new Quality(0))->toString()); - } - - #[DataProvider('invalids')] - public function testThrowWhenInvalidQualityValue($v) - { - $this->expectException(DomainException::class); - $this->expectExceptionMessage((string) $v); - - new Quality($v); - } - - public static function invalids() - { - return [ - [-1], - [2], - ]; + $this->assertSame('q=0', Quality::of(0)->toParameter()->toString()); } } From 35f852fff5d18eb954420c9592abcb07c083c555 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:30:37 +0200 Subject: [PATCH 44/51] make Boundary no longer implement Parameter --- CHANGELOG.md | 1 + src/Header/ContentType/Boundary.php | 17 +++-------------- tests/Header/ContentType/BoundaryTest.php | 8 +------- 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0590ea8..c761862 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ - `Innmind\Http\Header\Parameter\Quality` constructor is now private, use `::of()` named constructor - `Innmind\Http\Header\Parameter\Quality` no longer implements `Innmind\Http\Header\Parameter` - `Innmind\Http\Header\Parameter\Quality::of()` now returns `self` +- `Innmind\Http\Header\ContentType\Boundary` no longer implements `Innmind\Http\Header\Parameter` ### Removed diff --git a/src/Header/ContentType/Boundary.php b/src/Header/ContentType/Boundary.php index 685b11d..2f119f0 100644 --- a/src/Header/ContentType/Boundary.php +++ b/src/Header/ContentType/Boundary.php @@ -16,7 +16,7 @@ /** * @psalm-immutable */ -final class Boundary implements Parameter +final class Boundary { private function __construct( private string $value, @@ -58,24 +58,13 @@ public static function uuid(): self return self::of(Uuid::uuid4()->toString()); } - #[\Override] - public function name(): string - { - return 'boundary'; - } - - #[\Override] public function value(): string { return $this->value; } - #[\Override] - public function toString(): string + public function toParameter(): Parameter { - return \sprintf( - 'boundary="%s"', - $this->value, - ); + return new Parameter\Parameter('boundary', $this->value); } } diff --git a/tests/Header/ContentType/BoundaryTest.php b/tests/Header/ContentType/BoundaryTest.php index a32fc10..ed817b1 100644 --- a/tests/Header/ContentType/BoundaryTest.php +++ b/tests/Header/ContentType/BoundaryTest.php @@ -5,7 +5,6 @@ use Innmind\Http\{ Header\ContentType\Boundary, - Header\Parameter, Exception\DomainException, }; use Innmind\BlackBox\{ @@ -18,18 +17,13 @@ class BoundaryTest extends TestCase { use BlackBox; - public function testInterface() - { - $this->assertInstanceOf(Parameter::class, Boundary::uuid()); - } - public function testOf() { $id = \uniqid(); $boundary = Boundary::of($id); $this->assertSame($id, $boundary->value()); - $this->assertSame("boundary=\"$id\"", $boundary->toString()); + $this->assertSame("boundary=$id", $boundary->toParameter()->toString()); } public function testThrowWhenRandomString() From 399eafd58f9bb8b5dd244cf3802ce7c489480fbb Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:34:32 +0200 Subject: [PATCH 45/51] make Parameter a final class --- CHANGELOG.md | 1 + src/Factory/Header/Factories.php | 12 ++--- src/Header/ContentType.php | 2 +- src/Header/ContentType/Boundary.php | 2 +- src/Header/Parameter.php | 46 +++++++++++++++++-- src/Header/Parameter/Parameter.php | 56 ------------------------ src/Header/Parameter/Quality.php | 1 + src/Header/SetCookie.php | 2 +- src/Header/SetCookie/Directive.php | 8 ++-- src/Header/SetCookie/Domain.php | 2 +- src/Header/SetCookie/Expires.php | 2 +- src/Header/SetCookie/MaxAge.php | 2 +- src/Header/SetCookie/Path.php | 2 +- src/Header/WWWAuthenticate/Challenge.php | 2 +- tests/Header/AcceptValueTest.php | 2 +- tests/Header/CookieTest.php | 2 +- tests/Header/LinkTest.php | 2 +- tests/Header/LinkValueTest.php | 2 +- tests/Header/Parameter/ParameterTest.php | 6 +-- 19 files changed, 67 insertions(+), 87 deletions(-) delete mode 100644 src/Header/Parameter/Parameter.php diff --git a/CHANGELOG.md b/CHANGELOG.md index c761862..706eb7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ - `Innmind\Http\Header\Parameter\Quality` no longer implements `Innmind\Http\Header\Parameter` - `Innmind\Http\Header\Parameter\Quality::of()` now returns `self` - `Innmind\Http\Header\ContentType\Boundary` no longer implements `Innmind\Http\Header\Parameter` +- `Innmind\Http\Header\Parameter` is now a final class ### Removed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 413925b..4ef736f 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -429,7 +429,7 @@ public function try(Clock $clock, Str $value): Maybe return $params->flatMap( static fn($params) => $params ->get('rel') - ->otherwise(static fn() => Maybe::just(new Parameter\Parameter( + ->otherwise(static fn() => Maybe::just(new Parameter( 'rel', 'related', ))) @@ -493,7 +493,7 @@ private static function buildAcceptParams(Str $params): Maybe $matches = $value->capture('~(?\w+)=\"?(?[\w\-.]+)\"?~'); return Maybe::all($matches->get('key'), $matches->get('value')) - ->map(static fn(Str $key, Str $value) => new Parameter\Parameter( + ->map(static fn(Str $key, Str $value) => new Parameter( $key->toString(), $value->toString(), )); @@ -504,11 +504,11 @@ private static function buildAcceptParams(Str $params): Maybe } /** - * @return Maybe> + * @return Maybe> */ private static function buildLinkParams(Str $params): Maybe { - /** @var Sequence */ + /** @var Sequence */ $values = Sequence::of(); return $params @@ -518,7 +518,7 @@ private static function buildLinkParams(Str $params): Maybe $matches = $value->capture('~(?\w+)=\"?(?[ \t!#$%&\\\'()*+\-.\/\d:<=>?@A-z{|}\~]+)\"?~'); return Maybe::all($matches->get('key'), $matches->get('value')) - ->map(static fn(Str $key, Str $value) => new Parameter\Parameter( + ->map(static fn(Str $key, Str $value) => new Parameter( $key->toString(), $value->toString(), )) @@ -542,7 +542,7 @@ private static function buildCookieParams(Str $params): Sequence $matches = $value->capture('~^(?\w+)=\"?(?[\w\-.]*)\"?$~'); return Maybe::all($matches->get('key'), $matches->get('value')) - ->map(static fn(Str $key, Str $value) => new Parameter\Parameter( + ->map(static fn(Str $key, Str $value) => new Parameter( $key->toString(), $value->toString(), )); diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index b43b936..f259415 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -42,7 +42,7 @@ public function normalize(): Header $this ->content ->parameters() - ->map(static fn($parameter) => new Parameter\Parameter( // to make sure it's of the HTTP format + ->map(static fn($parameter) => new Parameter( // to make sure it's of the HTTP format $parameter->name(), $parameter->value(), )) diff --git a/src/Header/ContentType/Boundary.php b/src/Header/ContentType/Boundary.php index 2f119f0..a3da517 100644 --- a/src/Header/ContentType/Boundary.php +++ b/src/Header/ContentType/Boundary.php @@ -65,6 +65,6 @@ public function value(): string public function toParameter(): Parameter { - return new Parameter\Parameter('boundary', $this->value); + return new Parameter('boundary', $this->value); } } diff --git a/src/Header/Parameter.php b/src/Header/Parameter.php index 666c040..a727100 100644 --- a/src/Header/Parameter.php +++ b/src/Header/Parameter.php @@ -3,12 +3,50 @@ namespace Innmind\Http\Header; +use Innmind\Immutable\Str; + /** * @psalm-immutable */ -interface Parameter +final class Parameter { - public function name(): string; - public function value(): string; - public function toString(): string; + private string $name; + private string $value; + private string $string; + + public function __construct(string $name, string $value) + { + $value = Str::of($value)->trim(); + + if ($value->matches("/[ \t]/")) { + $value = $value + ->trim('"') + ->append('"') + ->prepend('"'); + } + + $this->name = $name; + $this->value = $value->toString(); + $this->string = \sprintf( + '%s%s%s', + $this->name, + \strlen($this->value) > 0 ? '=' : '', + \strlen($this->value) > 0 ? $this->value : '', + ); + } + + public function name(): string + { + return $this->name; + } + + public function value(): string + { + return $this->value; + } + + public function toString(): string + { + return $this->string; + } } diff --git a/src/Header/Parameter/Parameter.php b/src/Header/Parameter/Parameter.php deleted file mode 100644 index 7b5040c..0000000 --- a/src/Header/Parameter/Parameter.php +++ /dev/null @@ -1,56 +0,0 @@ -trim(); - - if ($value->matches("/[ \t]/")) { - $value = $value - ->trim('"') - ->append('"') - ->prepend('"'); - } - - $this->name = $name; - $this->value = $value->toString(); - $this->string = \sprintf( - '%s%s%s', - $this->name, - \strlen($this->value) > 0 ? '=' : '', - \strlen($this->value) > 0 ? $this->value : '', - ); - } - - #[\Override] - public function name(): string - { - return $this->name; - } - - #[\Override] - public function value(): string - { - return $this->value; - } - - #[\Override] - public function toString(): string - { - return $this->string; - } -} diff --git a/src/Header/Parameter/Quality.php b/src/Header/Parameter/Quality.php index 7feeebd..d7ff8e1 100644 --- a/src/Header/Parameter/Quality.php +++ b/src/Header/Parameter/Quality.php @@ -3,6 +3,7 @@ namespace Innmind\Http\Header\Parameter; +use Innmind\Http\Header\Parameter; use Innmind\Immutable\Str; /** diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index 172aae1..c7ea0c2 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -42,7 +42,7 @@ public static function of( Directive|Domain|Expires|MaxAge|Path ...$parameters, ): self { return new self( - new Parameter\Parameter($name, $value), + new Parameter($name, $value), Sequence::of(...$parameters), Sequence::of(), ); diff --git a/src/Header/SetCookie/Directive.php b/src/Header/SetCookie/Directive.php index 92d9597..debad9e 100644 --- a/src/Header/SetCookie/Directive.php +++ b/src/Header/SetCookie/Directive.php @@ -18,10 +18,10 @@ enum Directive public function toParameter(): Parameter { return match ($this) { - self::laxSameSite => new Parameter\Parameter('SameSite', 'Lax'), - self::strictSameSite => new Parameter\Parameter('SameSite', 'Strict'), - self::secure => new Parameter\Parameter('Secure', ''), - self::httpOnly => new Parameter\Parameter('HttpOnly', ''), + self::laxSameSite => new Parameter('SameSite', 'Lax'), + self::strictSameSite => new Parameter('SameSite', 'Strict'), + self::secure => new Parameter('Secure', ''), + self::httpOnly => new Parameter('HttpOnly', ''), }; } } diff --git a/src/Header/SetCookie/Domain.php b/src/Header/SetCookie/Domain.php index fb17413..056432f 100644 --- a/src/Header/SetCookie/Domain.php +++ b/src/Header/SetCookie/Domain.php @@ -31,6 +31,6 @@ public function host(): Host public function toParameter(): Parameter { - return new Parameter\Parameter('Domain', $this->host->toString()); + return new Parameter('Domain', $this->host->toString()); } } diff --git a/src/Header/SetCookie/Expires.php b/src/Header/SetCookie/Expires.php index a5bf35e..96e1f3c 100644 --- a/src/Header/SetCookie/Expires.php +++ b/src/Header/SetCookie/Expires.php @@ -37,7 +37,7 @@ public function date(): PointInTime public function toParameter(): Parameter { - return new Parameter\Parameter( + return new Parameter( 'Expires', $this->date->format(Http::new()), ); diff --git a/src/Header/SetCookie/MaxAge.php b/src/Header/SetCookie/MaxAge.php index 2d5ce92..926daa8 100644 --- a/src/Header/SetCookie/MaxAge.php +++ b/src/Header/SetCookie/MaxAge.php @@ -46,6 +46,6 @@ public function toInt(): int public function toParameter(): Parameter { - return new Parameter\Parameter('Max-Age', (string) $this->toInt()); + return new Parameter('Max-Age', (string) $this->toInt()); } } diff --git a/src/Header/SetCookie/Path.php b/src/Header/SetCookie/Path.php index b201564..250defd 100644 --- a/src/Header/SetCookie/Path.php +++ b/src/Header/SetCookie/Path.php @@ -31,6 +31,6 @@ public function path(): UrlPath public function toParameter(): Parameter { - return new Parameter\Parameter('Path', $this->path->toString()); + return new Parameter('Path', $this->path->toString()); } } diff --git a/src/Header/WWWAuthenticate/Challenge.php b/src/Header/WWWAuthenticate/Challenge.php index 073d84b..4808089 100644 --- a/src/Header/WWWAuthenticate/Challenge.php +++ b/src/Header/WWWAuthenticate/Challenge.php @@ -3,7 +3,7 @@ namespace Innmind\Http\Header\WWWAuthenticate; -use Innmind\Http\Header\Parameter\Parameter; +use Innmind\Http\Header\Parameter; use Innmind\Immutable\{ Str, Maybe, diff --git a/tests/Header/AcceptValueTest.php b/tests/Header/AcceptValueTest.php index 5733907..19e4abc 100644 --- a/tests/Header/AcceptValueTest.php +++ b/tests/Header/AcceptValueTest.php @@ -58,7 +58,7 @@ public function testInterface() 'application', 'octet-stream', Quality::of(40)->toParameter(), - new Parameter\Parameter('level', '1'), + new Parameter('level', '1'), )->match( static fn($mediaType) => $mediaType, static fn() => throw new \Exception, diff --git a/tests/Header/CookieTest.php b/tests/Header/CookieTest.php index f339efe..ab26362 100644 --- a/tests/Header/CookieTest.php +++ b/tests/Header/CookieTest.php @@ -6,7 +6,7 @@ use Innmind\Http\{ Header\Cookie, Header, - Header\Parameter\Parameter, + Header\Parameter, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; diff --git a/tests/Header/LinkTest.php b/tests/Header/LinkTest.php index dcba08b..6d259bd 100644 --- a/tests/Header/LinkTest.php +++ b/tests/Header/LinkTest.php @@ -19,7 +19,7 @@ public function testInterface() Link\Relationship::of( Url::of('/some/resource'), 'some relation', - new Parameter\Parameter('title', 'Foo'), + new Parameter('title', 'Foo'), ), ); diff --git a/tests/Header/LinkValueTest.php b/tests/Header/LinkValueTest.php index 2bf6bf2..942d7a6 100644 --- a/tests/Header/LinkValueTest.php +++ b/tests/Header/LinkValueTest.php @@ -17,7 +17,7 @@ public function testInterface() $l = Relationship::of( $url = Url::of('/some/resource'), 'relationship', - $p = new Parameter\Parameter('title', 'Foo'), + $p = new Parameter('title', 'Foo'), ); $this->assertInstanceOf(Relationship::class, $l); diff --git a/tests/Header/Parameter/ParameterTest.php b/tests/Header/Parameter/ParameterTest.php index 6970678..27eb8d2 100644 --- a/tests/Header/Parameter/ParameterTest.php +++ b/tests/Header/Parameter/ParameterTest.php @@ -3,10 +3,7 @@ namespace Tests\Innmind\Http\Header\Parameter; -use Innmind\Http\Header\{ - Parameter\Parameter, - Parameter as ParameterInterface -}; +use Innmind\Http\Header\Parameter; use Innmind\BlackBox\PHPUnit\Framework\TestCase; class ParameterTest extends TestCase @@ -15,7 +12,6 @@ public function testInterface() { $p = new Parameter('q', 'foo'); - $this->assertInstanceOf(ParameterInterface::class, $p); $this->assertSame('q', $p->name()); $this->assertSame('foo', $p->value()); $this->assertSame('q=foo', $p->toString()); From e117dd053baabb262775dcf4d1398f8039efd16a Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:35:31 +0200 Subject: [PATCH 46/51] fix public constructor --- src/Header/Authorization.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Header/Authorization.php b/src/Header/Authorization.php index 963aaf8..24c3cfb 100644 --- a/src/Header/Authorization.php +++ b/src/Header/Authorization.php @@ -17,7 +17,7 @@ */ final class Authorization implements Custom { - public function __construct( + private function __construct( private string $scheme, private string $parameter, ) { From f5c1b88f18e642d56350c25e7b01b79ada91b455 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:42:16 +0200 Subject: [PATCH 47/51] make Header constructor private --- CHANGELOG.md | 1 + src/Factory/Header/Factory.php | 2 +- src/Header.php | 17 +++++++++++------ src/Header/Accept.php | 2 +- src/Header/AcceptCharset.php | 2 +- src/Header/AcceptEncoding.php | 2 +- src/Header/AcceptLanguage.php | 2 +- src/Header/AcceptRanges.php | 2 +- src/Header/Age.php | 2 +- src/Header/Allow.php | 2 +- src/Header/Authorization.php | 2 +- src/Header/CacheControl.php | 2 +- src/Header/ContentEncoding.php | 2 +- src/Header/ContentLanguage.php | 2 +- src/Header/ContentLength.php | 2 +- src/Header/ContentLocation.php | 2 +- src/Header/ContentRange.php | 2 +- src/Header/ContentType.php | 2 +- src/Header/Cookie.php | 2 +- src/Header/Date.php | 2 +- src/Header/Expires.php | 2 +- src/Header/Host.php | 2 +- src/Header/IfModifiedSince.php | 2 +- src/Header/IfUnmodifiedSince.php | 2 +- src/Header/LastModified.php | 2 +- src/Header/Link.php | 2 +- src/Header/Location.php | 2 +- src/Header/Range.php | 2 +- src/Header/Referrer.php | 2 +- src/Header/SetCookie.php | 2 +- src/Header/WWWAuthenticate.php | 2 +- tests/Header/HeaderTest.php | 4 ++-- tests/HeadersTest.php | 12 ++++++------ 33 files changed, 49 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 706eb7a..c351b8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ - `Innmind\Http\Header\Parameter\Quality::of()` now returns `self` - `Innmind\Http\Header\ContentType\Boundary` no longer implements `Innmind\Http\Header\Parameter` - `Innmind\Http\Header\Parameter` is now a final class +- `Innmind\Http\Header` constructor is now private, use `::of` named constructor ### Removed diff --git a/src/Factory/Header/Factory.php b/src/Factory/Header/Factory.php index 8b70d04..941ee89 100644 --- a/src/Factory/Header/Factory.php +++ b/src/Factory/Header/Factory.php @@ -53,7 +53,7 @@ private static function default(Str $name, Str $value): Header ->map(static fn($value) => new Value($value->toString())) ->toList(); - return new Header( + return Header::of( $name->toString(), ...$values, ); diff --git a/src/Header.php b/src/Header.php index c8e16f2..c594eb6 100644 --- a/src/Header.php +++ b/src/Header.php @@ -14,17 +14,22 @@ */ final class Header { - private string $name; - /** @var Sequence */ - private Sequence $values; + /** + * @param Sequence $values + */ + private function __construct( + private string $name, + private Sequence $values, + ) { + } /** + * @psalm-pure * @no-named-arguments */ - public function __construct(string $name, Value ...$values) + public static function of(string $name, Value ...$values): self { - $this->name = $name; - $this->values = Sequence::of(...$values); + return new self($name, Sequence::of(...$values)); } public function name(): string diff --git a/src/Header/Accept.php b/src/Header/Accept.php index 2e8b05a..d7d05be 100644 --- a/src/Header/Accept.php +++ b/src/Header/Accept.php @@ -33,7 +33,7 @@ public static function of(MediaType $first, MediaType ...$values): self #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Accept', ...$this ->values diff --git a/src/Header/AcceptCharset.php b/src/Header/AcceptCharset.php index eba2419..dd2c7f4 100644 --- a/src/Header/AcceptCharset.php +++ b/src/Header/AcceptCharset.php @@ -34,7 +34,7 @@ public static function of(Charset ...$charsets): self #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Accept-Charset', ...$this ->charsets diff --git a/src/Header/AcceptEncoding.php b/src/Header/AcceptEncoding.php index 106ff03..ab7a5a6 100644 --- a/src/Header/AcceptEncoding.php +++ b/src/Header/AcceptEncoding.php @@ -34,7 +34,7 @@ public static function of(Encoding ...$encodings): self #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Accept-Encoding', ...$this ->encodings diff --git a/src/Header/AcceptLanguage.php b/src/Header/AcceptLanguage.php index 2333439..a216b77 100644 --- a/src/Header/AcceptLanguage.php +++ b/src/Header/AcceptLanguage.php @@ -34,7 +34,7 @@ public static function of(Language ...$languages): self #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Accept-Language', ...$this ->languages diff --git a/src/Header/AcceptRanges.php b/src/Header/AcceptRanges.php index 13fa27b..80a9b91 100644 --- a/src/Header/AcceptRanges.php +++ b/src/Header/AcceptRanges.php @@ -51,7 +51,7 @@ public static function maybe(string $range): Maybe #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Accept-Ranges', new Value($this->ranges), ); diff --git a/src/Header/Age.php b/src/Header/Age.php index d5b94e7..d88848b 100644 --- a/src/Header/Age.php +++ b/src/Header/Age.php @@ -53,6 +53,6 @@ public function age(): int #[\Override] public function normalize(): Header { - return new Header('Age', new Value((string) $this->age)); + return Header::of('Age', new Value((string) $this->age)); } } diff --git a/src/Header/Allow.php b/src/Header/Allow.php index 5a906d1..b19c400 100644 --- a/src/Header/Allow.php +++ b/src/Header/Allow.php @@ -34,7 +34,7 @@ public static function of(Method ...$methods): self #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Allow', ...$this ->methods diff --git a/src/Header/Authorization.php b/src/Header/Authorization.php index 24c3cfb..2109283 100644 --- a/src/Header/Authorization.php +++ b/src/Header/Authorization.php @@ -60,7 +60,7 @@ public function parameter(): string #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Authorization', new Value( Str::of($this->scheme) diff --git a/src/Header/CacheControl.php b/src/Header/CacheControl.php index bed1cc6..35707ca 100644 --- a/src/Header/CacheControl.php +++ b/src/Header/CacheControl.php @@ -42,7 +42,7 @@ public static function of( #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Cache-Control', ...$this ->directives diff --git a/src/Header/ContentEncoding.php b/src/Header/ContentEncoding.php index 8bd5ee2..9aa5b2c 100644 --- a/src/Header/ContentEncoding.php +++ b/src/Header/ContentEncoding.php @@ -51,7 +51,7 @@ public static function maybe(string $encoding): Maybe #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Content-Encoding', new Value($this->encoding), ); diff --git a/src/Header/ContentLanguage.php b/src/Header/ContentLanguage.php index 368de1a..fa718bd 100644 --- a/src/Header/ContentLanguage.php +++ b/src/Header/ContentLanguage.php @@ -34,7 +34,7 @@ public static function of(Language ...$languages): self #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Content-Language', ...$this ->languages diff --git a/src/Header/ContentLength.php b/src/Header/ContentLength.php index 4ee685d..e193f16 100644 --- a/src/Header/ContentLength.php +++ b/src/Header/ContentLength.php @@ -53,7 +53,7 @@ public function length(): int #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Content-Length', new Value((string) $this->length), ); diff --git a/src/Header/ContentLocation.php b/src/Header/ContentLocation.php index beeae27..cfe3a29 100644 --- a/src/Header/ContentLocation.php +++ b/src/Header/ContentLocation.php @@ -32,7 +32,7 @@ public function url(): Url #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Content-Location', new Value($this->url->toString()), ); diff --git a/src/Header/ContentRange.php b/src/Header/ContentRange.php index 2b66df5..9610282 100644 --- a/src/Header/ContentRange.php +++ b/src/Header/ContentRange.php @@ -108,7 +108,7 @@ public function length(): Maybe #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Content-Range', new Value(\sprintf( '%s %s-%s/%s', diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index f259415..3de4068 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -57,7 +57,7 @@ public function normalize(): Header $content .= $parameters->toString(); - return new Header( + return Header::of( 'Content-Type', new Value($content), ); diff --git a/src/Header/Cookie.php b/src/Header/Cookie.php index 8f7aa45..3c1db30 100644 --- a/src/Header/Cookie.php +++ b/src/Header/Cookie.php @@ -58,7 +58,7 @@ public function normalize(): Header $value = Str::of('; ')->join($parameters)->toString(); - return new Header( + return Header::of( 'Cookie', new Value($value), ); diff --git a/src/Header/Date.php b/src/Header/Date.php index 5127ab3..fd9a7c0 100644 --- a/src/Header/Date.php +++ b/src/Header/Date.php @@ -38,7 +38,7 @@ public function date(): PointInTime #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Date', new Value( $this diff --git a/src/Header/Expires.php b/src/Header/Expires.php index ac51628..1934b50 100644 --- a/src/Header/Expires.php +++ b/src/Header/Expires.php @@ -38,7 +38,7 @@ public function date(): PointInTime #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Expires', new Value( $this diff --git a/src/Header/Host.php b/src/Header/Host.php index ad0b946..5147ee1 100644 --- a/src/Header/Host.php +++ b/src/Header/Host.php @@ -41,7 +41,7 @@ public function port(): Port #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Host', new Value( $this->host->toString().$this->port->format(), diff --git a/src/Header/IfModifiedSince.php b/src/Header/IfModifiedSince.php index 8246a5e..65bc291 100644 --- a/src/Header/IfModifiedSince.php +++ b/src/Header/IfModifiedSince.php @@ -38,7 +38,7 @@ public function date(): PointInTime #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'If-Modified-Since', new Value( $this diff --git a/src/Header/IfUnmodifiedSince.php b/src/Header/IfUnmodifiedSince.php index 614aea4..2c9782b 100644 --- a/src/Header/IfUnmodifiedSince.php +++ b/src/Header/IfUnmodifiedSince.php @@ -38,7 +38,7 @@ public function date(): PointInTime #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'If-Unmodified-Since', new Value( $this diff --git a/src/Header/LastModified.php b/src/Header/LastModified.php index fe8b3c5..a4117a4 100644 --- a/src/Header/LastModified.php +++ b/src/Header/LastModified.php @@ -38,7 +38,7 @@ public function date(): PointInTime #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Last-Modified', new Value( $this diff --git a/src/Header/Link.php b/src/Header/Link.php index d5507a1..0d8f7bd 100644 --- a/src/Header/Link.php +++ b/src/Header/Link.php @@ -34,7 +34,7 @@ public static function of(Relationship ...$relationships): self #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Link', ...$this ->relationships diff --git a/src/Header/Location.php b/src/Header/Location.php index cb03fca..17ae84b 100644 --- a/src/Header/Location.php +++ b/src/Header/Location.php @@ -32,7 +32,7 @@ public function url(): Url #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Location', new Value($this->location->toString()), ); diff --git a/src/Header/Range.php b/src/Header/Range.php index 5741f24..f4b5419 100644 --- a/src/Header/Range.php +++ b/src/Header/Range.php @@ -91,7 +91,7 @@ public function lastPosition(): int #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Range', new Value(\sprintf( '%s=%s-%s', diff --git a/src/Header/Referrer.php b/src/Header/Referrer.php index be2e11d..8778427 100644 --- a/src/Header/Referrer.php +++ b/src/Header/Referrer.php @@ -32,7 +32,7 @@ public function referrer(): Url #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Referer', new Value($this->referrer->toString()), ); diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index c7ea0c2..f6dfe4f 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -86,7 +86,7 @@ public function cookies(): Sequence #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'Set-Cookie', ...$this ->cookies() diff --git a/src/Header/WWWAuthenticate.php b/src/Header/WWWAuthenticate.php index dbd5d9a..af52c69 100644 --- a/src/Header/WWWAuthenticate.php +++ b/src/Header/WWWAuthenticate.php @@ -34,7 +34,7 @@ public static function of(Challenge ...$challenges): self #[\Override] public function normalize(): Header { - return new Header( + return Header::of( 'WWW-Authenticate', ...$this ->challenges diff --git a/tests/Header/HeaderTest.php b/tests/Header/HeaderTest.php index d6cd3f4..d0514ce 100644 --- a/tests/Header/HeaderTest.php +++ b/tests/Header/HeaderTest.php @@ -13,7 +13,7 @@ class HeaderTest extends TestCase { public function testInterface() { - $h = new Header( + $h = Header::of( 'Accept', $v1 = new Value('application/json'), $v2 = new Value('*/*'), @@ -28,6 +28,6 @@ public function testInterface() public function testWithoutValues() { - $this->assertSame('X-Foo: ', (new Header('X-Foo'))->toString()); + $this->assertSame('X-Foo: ', Header::of('X-Foo')->toString()); } } diff --git a/tests/HeadersTest.php b/tests/HeadersTest.php index a05df6b..e6ab718 100644 --- a/tests/HeadersTest.php +++ b/tests/HeadersTest.php @@ -88,7 +88,7 @@ public function testForeach() ContentType::of( MediaType::of('application/json'), ), - new Header('x-foo'), + Header::of('x-foo'), ); $called = 0; @@ -107,7 +107,7 @@ public function testReduce() ContentType::of( MediaType::of('application/json'), ), - new Header('x-foo'), + Header::of('x-foo'), ); $reduced = $headers->reduce( @@ -128,7 +128,7 @@ public function testFind() ContentType::of( MediaType::of('application/json'), ), - new Header('Allow'), + Header::of('Allow'), ); $this->assertTrue($headers->find(ContentType::class)->match( @@ -141,7 +141,7 @@ public function testFind() )); $headers = Headers::of( - new Header('Content-Type', new Value('application/json')), + Header::of('Content-Type', new Value('application/json')), ); $this->assertFalse($headers->find(ContentType::class)->match( @@ -156,7 +156,7 @@ public function testFilter() ContentType::of( MediaType::of('application/json'), ), - new Header('x-foo'), + Header::of('x-foo'), ); $this->assertCount( @@ -179,7 +179,7 @@ public function testAll() $contentType = ContentType::of( MediaType::of('application/json'), ), - $foo = new Header('x-foo'), + $foo = Header::of('x-foo'), ); $this->assertEquals( From 1e1092416be32f69f12e70989a05f5d2cdeb6160 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:44:27 +0200 Subject: [PATCH 48/51] make Value constructor private --- CHANGELOG.md | 1 + src/Factory/Header/Factory.php | 2 +- src/Header/Accept.php | 2 +- src/Header/AcceptCharset.php | 2 +- src/Header/AcceptEncoding.php | 2 +- src/Header/AcceptLanguage.php | 2 +- src/Header/AcceptRanges.php | 2 +- src/Header/Age.php | 2 +- src/Header/Allow.php | 2 +- src/Header/Authorization.php | 2 +- src/Header/CacheControl.php | 2 +- src/Header/ContentEncoding.php | 2 +- src/Header/ContentLanguage.php | 2 +- src/Header/ContentLength.php | 2 +- src/Header/ContentLocation.php | 2 +- src/Header/ContentRange.php | 2 +- src/Header/ContentType.php | 2 +- src/Header/Cookie.php | 2 +- src/Header/Date.php | 2 +- src/Header/Expires.php | 2 +- src/Header/Host.php | 2 +- src/Header/IfModifiedSince.php | 2 +- src/Header/IfUnmodifiedSince.php | 2 +- src/Header/LastModified.php | 2 +- src/Header/Link.php | 2 +- src/Header/Location.php | 2 +- src/Header/Range.php | 2 +- src/Header/Referrer.php | 2 +- src/Header/SetCookie.php | 2 +- src/Header/Value.php | 10 +++++++++- src/Header/WWWAuthenticate.php | 2 +- tests/Header/HeaderTest.php | 4 ++-- tests/Header/HeaderValueTest.php | 2 +- tests/HeadersTest.php | 2 +- 34 files changed, 43 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c351b8f..c2addb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ - `Innmind\Http\Header\ContentType\Boundary` no longer implements `Innmind\Http\Header\Parameter` - `Innmind\Http\Header\Parameter` is now a final class - `Innmind\Http\Header` constructor is now private, use `::of` named constructor +- `Innmind\Http\Header\Value` constructor is now private, use `::of` named constructor ### Removed diff --git a/src/Factory/Header/Factory.php b/src/Factory/Header/Factory.php index 941ee89..23c3788 100644 --- a/src/Factory/Header/Factory.php +++ b/src/Factory/Header/Factory.php @@ -50,7 +50,7 @@ private static function default(Str $name, Str $value): Header $values = $value ->split(',') ->map(static fn($value) => $value->trim()) - ->map(static fn($value) => new Value($value->toString())) + ->map(static fn($value) => Value::of($value->toString())) ->toList(); return Header::of( diff --git a/src/Header/Accept.php b/src/Header/Accept.php index d7d05be..eee0eaf 100644 --- a/src/Header/Accept.php +++ b/src/Header/Accept.php @@ -37,7 +37,7 @@ public function normalize(): Header 'Accept', ...$this ->values - ->map(static fn($value) => new Value($value->toString())) + ->map(static fn($value) => Value::of($value->toString())) ->toList(), ); } diff --git a/src/Header/AcceptCharset.php b/src/Header/AcceptCharset.php index dd2c7f4..f5ffa96 100644 --- a/src/Header/AcceptCharset.php +++ b/src/Header/AcceptCharset.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Accept-Charset', ...$this ->charsets - ->map(static fn($value) => new Value($value->toString())) + ->map(static fn($value) => Value::of($value->toString())) ->toList(), ); } diff --git a/src/Header/AcceptEncoding.php b/src/Header/AcceptEncoding.php index ab7a5a6..bf102f9 100644 --- a/src/Header/AcceptEncoding.php +++ b/src/Header/AcceptEncoding.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Accept-Encoding', ...$this ->encodings - ->map(static fn($value) => new Value($value->toString())) + ->map(static fn($value) => Value::of($value->toString())) ->toList(), ); } diff --git a/src/Header/AcceptLanguage.php b/src/Header/AcceptLanguage.php index a216b77..96f2bcf 100644 --- a/src/Header/AcceptLanguage.php +++ b/src/Header/AcceptLanguage.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Accept-Language', ...$this ->languages - ->map(static fn($value) => new Value($value->toString())) + ->map(static fn($value) => Value::of($value->toString())) ->toList(), ); } diff --git a/src/Header/AcceptRanges.php b/src/Header/AcceptRanges.php index 80a9b91..80123d4 100644 --- a/src/Header/AcceptRanges.php +++ b/src/Header/AcceptRanges.php @@ -53,7 +53,7 @@ public function normalize(): Header { return Header::of( 'Accept-Ranges', - new Value($this->ranges), + Value::of($this->ranges), ); } } diff --git a/src/Header/Age.php b/src/Header/Age.php index d88848b..6a81773 100644 --- a/src/Header/Age.php +++ b/src/Header/Age.php @@ -53,6 +53,6 @@ public function age(): int #[\Override] public function normalize(): Header { - return Header::of('Age', new Value((string) $this->age)); + return Header::of('Age', Value::of((string) $this->age)); } } diff --git a/src/Header/Allow.php b/src/Header/Allow.php index b19c400..3e177bd 100644 --- a/src/Header/Allow.php +++ b/src/Header/Allow.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Allow', ...$this ->methods - ->map(static fn($method) => new Value($method->toString())) + ->map(static fn($method) => Value::of($method->toString())) ->toList(), ); } diff --git a/src/Header/Authorization.php b/src/Header/Authorization.php index 2109283..f84996c 100644 --- a/src/Header/Authorization.php +++ b/src/Header/Authorization.php @@ -62,7 +62,7 @@ public function normalize(): Header { return Header::of( 'Authorization', - new Value( + Value::of( Str::of($this->scheme) ->append(' ') ->append($this->parameter) diff --git a/src/Header/CacheControl.php b/src/Header/CacheControl.php index 35707ca..02a9183 100644 --- a/src/Header/CacheControl.php +++ b/src/Header/CacheControl.php @@ -46,7 +46,7 @@ public function normalize(): Header 'Cache-Control', ...$this ->directives - ->map(static fn($directive) => new Value($directive->toString())) + ->map(static fn($directive) => Value::of($directive->toString())) ->toList(), ); } diff --git a/src/Header/ContentEncoding.php b/src/Header/ContentEncoding.php index 9aa5b2c..8adbf85 100644 --- a/src/Header/ContentEncoding.php +++ b/src/Header/ContentEncoding.php @@ -53,7 +53,7 @@ public function normalize(): Header { return Header::of( 'Content-Encoding', - new Value($this->encoding), + Value::of($this->encoding), ); } } diff --git a/src/Header/ContentLanguage.php b/src/Header/ContentLanguage.php index fa718bd..75cd28a 100644 --- a/src/Header/ContentLanguage.php +++ b/src/Header/ContentLanguage.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Content-Language', ...$this ->languages - ->map(static fn($language) => new Value($language->toString())) + ->map(static fn($language) => Value::of($language->toString())) ->toList(), ); } diff --git a/src/Header/ContentLength.php b/src/Header/ContentLength.php index e193f16..131bc46 100644 --- a/src/Header/ContentLength.php +++ b/src/Header/ContentLength.php @@ -55,7 +55,7 @@ public function normalize(): Header { return Header::of( 'Content-Length', - new Value((string) $this->length), + Value::of((string) $this->length), ); } } diff --git a/src/Header/ContentLocation.php b/src/Header/ContentLocation.php index cfe3a29..a4f65c5 100644 --- a/src/Header/ContentLocation.php +++ b/src/Header/ContentLocation.php @@ -34,7 +34,7 @@ public function normalize(): Header { return Header::of( 'Content-Location', - new Value($this->url->toString()), + Value::of($this->url->toString()), ); } } diff --git a/src/Header/ContentRange.php b/src/Header/ContentRange.php index 9610282..a4a2b68 100644 --- a/src/Header/ContentRange.php +++ b/src/Header/ContentRange.php @@ -110,7 +110,7 @@ public function normalize(): Header { return Header::of( 'Content-Range', - new Value(\sprintf( + Value::of(\sprintf( '%s %s-%s/%s', $this->unit, $this->firstPosition, diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index 3de4068..7e6a836 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -59,7 +59,7 @@ public function normalize(): Header return Header::of( 'Content-Type', - new Value($content), + Value::of($content), ); } } diff --git a/src/Header/Cookie.php b/src/Header/Cookie.php index 3c1db30..f42e43d 100644 --- a/src/Header/Cookie.php +++ b/src/Header/Cookie.php @@ -60,7 +60,7 @@ public function normalize(): Header return Header::of( 'Cookie', - new Value($value), + Value::of($value), ); } } diff --git a/src/Header/Date.php b/src/Header/Date.php index fd9a7c0..3973f33 100644 --- a/src/Header/Date.php +++ b/src/Header/Date.php @@ -40,7 +40,7 @@ public function normalize(): Header { return Header::of( 'Date', - new Value( + Value::of( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/Expires.php b/src/Header/Expires.php index 1934b50..d9f5f13 100644 --- a/src/Header/Expires.php +++ b/src/Header/Expires.php @@ -40,7 +40,7 @@ public function normalize(): Header { return Header::of( 'Expires', - new Value( + Value::of( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/Host.php b/src/Header/Host.php index 5147ee1..740216e 100644 --- a/src/Header/Host.php +++ b/src/Header/Host.php @@ -43,7 +43,7 @@ public function normalize(): Header { return Header::of( 'Host', - new Value( + Value::of( $this->host->toString().$this->port->format(), ), ); diff --git a/src/Header/IfModifiedSince.php b/src/Header/IfModifiedSince.php index 65bc291..63c0c57 100644 --- a/src/Header/IfModifiedSince.php +++ b/src/Header/IfModifiedSince.php @@ -40,7 +40,7 @@ public function normalize(): Header { return Header::of( 'If-Modified-Since', - new Value( + Value::of( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/IfUnmodifiedSince.php b/src/Header/IfUnmodifiedSince.php index 2c9782b..1c57a8f 100644 --- a/src/Header/IfUnmodifiedSince.php +++ b/src/Header/IfUnmodifiedSince.php @@ -40,7 +40,7 @@ public function normalize(): Header { return Header::of( 'If-Unmodified-Since', - new Value( + Value::of( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/LastModified.php b/src/Header/LastModified.php index a4117a4..9d6abdc 100644 --- a/src/Header/LastModified.php +++ b/src/Header/LastModified.php @@ -40,7 +40,7 @@ public function normalize(): Header { return Header::of( 'Last-Modified', - new Value( + Value::of( $this ->point ->changeOffset(Offset::utc()) diff --git a/src/Header/Link.php b/src/Header/Link.php index 0d8f7bd..0de9a5a 100644 --- a/src/Header/Link.php +++ b/src/Header/Link.php @@ -38,7 +38,7 @@ public function normalize(): Header 'Link', ...$this ->relationships - ->map(static fn($relationship) => new Value($relationship->toString())) + ->map(static fn($relationship) => Value::of($relationship->toString())) ->toList(), ); } diff --git a/src/Header/Location.php b/src/Header/Location.php index 17ae84b..c4ff2d7 100644 --- a/src/Header/Location.php +++ b/src/Header/Location.php @@ -34,7 +34,7 @@ public function normalize(): Header { return Header::of( 'Location', - new Value($this->location->toString()), + Value::of($this->location->toString()), ); } } diff --git a/src/Header/Range.php b/src/Header/Range.php index f4b5419..14041df 100644 --- a/src/Header/Range.php +++ b/src/Header/Range.php @@ -93,7 +93,7 @@ public function normalize(): Header { return Header::of( 'Range', - new Value(\sprintf( + Value::of(\sprintf( '%s=%s-%s', $this->unit, $this->firstPosition, diff --git a/src/Header/Referrer.php b/src/Header/Referrer.php index 8778427..207f025 100644 --- a/src/Header/Referrer.php +++ b/src/Header/Referrer.php @@ -34,7 +34,7 @@ public function normalize(): Header { return Header::of( 'Referer', - new Value($this->referrer->toString()), + Value::of($this->referrer->toString()), ); } } diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index f6dfe4f..e5b0755 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -90,7 +90,7 @@ public function normalize(): Header 'Set-Cookie', ...$this ->cookies() - ->map(static fn($self) => new Value( + ->map(static fn($self) => Value::of( Str::of('; ') ->join( Sequence::of($self->value) diff --git a/src/Header/Value.php b/src/Header/Value.php index d45d2a6..13f9832 100644 --- a/src/Header/Value.php +++ b/src/Header/Value.php @@ -8,11 +8,19 @@ */ final class Value { - public function __construct( + private function __construct( private string $value, ) { } + /** + * @psalm-pure + */ + public static function of(string $value): self + { + return new self($value); + } + public function toString(): string { return $this->value; diff --git a/src/Header/WWWAuthenticate.php b/src/Header/WWWAuthenticate.php index af52c69..c688cd2 100644 --- a/src/Header/WWWAuthenticate.php +++ b/src/Header/WWWAuthenticate.php @@ -38,7 +38,7 @@ public function normalize(): Header 'WWW-Authenticate', ...$this ->challenges - ->map(static fn($challenge) => new Value($challenge->toString())) + ->map(static fn($challenge) => Value::of($challenge->toString())) ->toList(), ); } diff --git a/tests/Header/HeaderTest.php b/tests/Header/HeaderTest.php index d0514ce..50b1a4b 100644 --- a/tests/Header/HeaderTest.php +++ b/tests/Header/HeaderTest.php @@ -15,8 +15,8 @@ public function testInterface() { $h = Header::of( 'Accept', - $v1 = new Value('application/json'), - $v2 = new Value('*/*'), + $v1 = Value::of('application/json'), + $v2 = Value::of('*/*'), ); $this->assertInstanceOf(Header::class, $h); diff --git a/tests/Header/HeaderValueTest.php b/tests/Header/HeaderValueTest.php index 8ee05cd..b8b2e24 100644 --- a/tests/Header/HeaderValueTest.php +++ b/tests/Header/HeaderValueTest.php @@ -10,7 +10,7 @@ class HeaderValueTest extends TestCase { public function testInterface() { - $hv = new Value('foo'); + $hv = Value::of('foo'); $this->assertInstanceOf(Value::class, $hv); $this->assertSame('foo', $hv->toString()); diff --git a/tests/HeadersTest.php b/tests/HeadersTest.php index e6ab718..2f2fdbf 100644 --- a/tests/HeadersTest.php +++ b/tests/HeadersTest.php @@ -141,7 +141,7 @@ public function testFind() )); $headers = Headers::of( - Header::of('Content-Type', new Value('application/json')), + Header::of('Content-Type', Value::of('application/json')), ); $this->assertFalse($headers->find(ContentType::class)->match( From e2d3d5b9c51b69031024e055418c817f5443d1f0 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:47:35 +0200 Subject: [PATCH 49/51] make Parameter constructor private --- CHANGELOG.md | 1 + src/Factory/Header/Factories.php | 8 ++++---- src/Header/ContentType.php | 2 +- src/Header/ContentType/Boundary.php | 2 +- src/Header/Parameter.php | 10 +++++++++- src/Header/Parameter/Quality.php | 2 +- src/Header/SetCookie.php | 2 +- src/Header/SetCookie/Directive.php | 8 ++++---- src/Header/SetCookie/Domain.php | 2 +- src/Header/SetCookie/Expires.php | 2 +- src/Header/SetCookie/MaxAge.php | 2 +- src/Header/SetCookie/Path.php | 2 +- src/Header/WWWAuthenticate/Challenge.php | 2 +- tests/Header/AcceptValueTest.php | 2 +- tests/Header/CookieTest.php | 2 +- tests/Header/LinkTest.php | 2 +- tests/Header/LinkValueTest.php | 2 +- tests/Header/Parameter/ParameterTest.php | 12 ++++++------ 18 files changed, 37 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2addb4..11245d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ - `Innmind\Http\Header\Parameter` is now a final class - `Innmind\Http\Header` constructor is now private, use `::of` named constructor - `Innmind\Http\Header\Value` constructor is now private, use `::of` named constructor +- `Innmind\Http\Header\Parameter` constructor is now private, use `::of` named constructor ### Removed diff --git a/src/Factory/Header/Factories.php b/src/Factory/Header/Factories.php index 4ef736f..8ffe227 100644 --- a/src/Factory/Header/Factories.php +++ b/src/Factory/Header/Factories.php @@ -429,7 +429,7 @@ public function try(Clock $clock, Str $value): Maybe return $params->flatMap( static fn($params) => $params ->get('rel') - ->otherwise(static fn() => Maybe::just(new Parameter( + ->otherwise(static fn() => Maybe::just(Parameter::of( 'rel', 'related', ))) @@ -493,7 +493,7 @@ private static function buildAcceptParams(Str $params): Maybe $matches = $value->capture('~(?\w+)=\"?(?[\w\-.]+)\"?~'); return Maybe::all($matches->get('key'), $matches->get('value')) - ->map(static fn(Str $key, Str $value) => new Parameter( + ->map(static fn(Str $key, Str $value) => Parameter::of( $key->toString(), $value->toString(), )); @@ -518,7 +518,7 @@ private static function buildLinkParams(Str $params): Maybe $matches = $value->capture('~(?\w+)=\"?(?[ \t!#$%&\\\'()*+\-.\/\d:<=>?@A-z{|}\~]+)\"?~'); return Maybe::all($matches->get('key'), $matches->get('value')) - ->map(static fn(Str $key, Str $value) => new Parameter( + ->map(static fn(Str $key, Str $value) => Parameter::of( $key->toString(), $value->toString(), )) @@ -542,7 +542,7 @@ private static function buildCookieParams(Str $params): Sequence $matches = $value->capture('~^(?\w+)=\"?(?[\w\-.]*)\"?$~'); return Maybe::all($matches->get('key'), $matches->get('value')) - ->map(static fn(Str $key, Str $value) => new Parameter( + ->map(static fn(Str $key, Str $value) => Parameter::of( $key->toString(), $value->toString(), )); diff --git a/src/Header/ContentType.php b/src/Header/ContentType.php index 7e6a836..402cbe9 100644 --- a/src/Header/ContentType.php +++ b/src/Header/ContentType.php @@ -42,7 +42,7 @@ public function normalize(): Header $this ->content ->parameters() - ->map(static fn($parameter) => new Parameter( // to make sure it's of the HTTP format + ->map(static fn($parameter) => Parameter::of( // to make sure it's of the HTTP format $parameter->name(), $parameter->value(), )) diff --git a/src/Header/ContentType/Boundary.php b/src/Header/ContentType/Boundary.php index a3da517..d12f581 100644 --- a/src/Header/ContentType/Boundary.php +++ b/src/Header/ContentType/Boundary.php @@ -65,6 +65,6 @@ public function value(): string public function toParameter(): Parameter { - return new Parameter('boundary', $this->value); + return Parameter::of('boundary', $this->value); } } diff --git a/src/Header/Parameter.php b/src/Header/Parameter.php index a727100..dc33498 100644 --- a/src/Header/Parameter.php +++ b/src/Header/Parameter.php @@ -14,7 +14,7 @@ final class Parameter private string $value; private string $string; - public function __construct(string $name, string $value) + private function __construct(string $name, string $value) { $value = Str::of($value)->trim(); @@ -35,6 +35,14 @@ public function __construct(string $name, string $value) ); } + /** + * @psalm-pure + */ + public static function of(string $name, string $value): self + { + return new self($name, $value); + } + public function name(): string { return $this->name; diff --git a/src/Header/Parameter/Quality.php b/src/Header/Parameter/Quality.php index d7ff8e1..33c6ae5 100644 --- a/src/Header/Parameter/Quality.php +++ b/src/Header/Parameter/Quality.php @@ -44,7 +44,7 @@ public function toParameter(): Parameter $this->percent / 100, )); - return new Parameter('q', match (true) { + return Parameter::of('q', match (true) { $value->endsWith('.00') => $value->dropEnd(3)->toString(), $value->endsWith('0') => $value->dropEnd(1)->toString(), default => $value->toString(), diff --git a/src/Header/SetCookie.php b/src/Header/SetCookie.php index e5b0755..fd7397f 100644 --- a/src/Header/SetCookie.php +++ b/src/Header/SetCookie.php @@ -42,7 +42,7 @@ public static function of( Directive|Domain|Expires|MaxAge|Path ...$parameters, ): self { return new self( - new Parameter($name, $value), + Parameter::of($name, $value), Sequence::of(...$parameters), Sequence::of(), ); diff --git a/src/Header/SetCookie/Directive.php b/src/Header/SetCookie/Directive.php index debad9e..84fa5e2 100644 --- a/src/Header/SetCookie/Directive.php +++ b/src/Header/SetCookie/Directive.php @@ -18,10 +18,10 @@ enum Directive public function toParameter(): Parameter { return match ($this) { - self::laxSameSite => new Parameter('SameSite', 'Lax'), - self::strictSameSite => new Parameter('SameSite', 'Strict'), - self::secure => new Parameter('Secure', ''), - self::httpOnly => new Parameter('HttpOnly', ''), + self::laxSameSite => Parameter::of('SameSite', 'Lax'), + self::strictSameSite => Parameter::of('SameSite', 'Strict'), + self::secure => Parameter::of('Secure', ''), + self::httpOnly => Parameter::of('HttpOnly', ''), }; } } diff --git a/src/Header/SetCookie/Domain.php b/src/Header/SetCookie/Domain.php index 056432f..8516a9c 100644 --- a/src/Header/SetCookie/Domain.php +++ b/src/Header/SetCookie/Domain.php @@ -31,6 +31,6 @@ public function host(): Host public function toParameter(): Parameter { - return new Parameter('Domain', $this->host->toString()); + return Parameter::of('Domain', $this->host->toString()); } } diff --git a/src/Header/SetCookie/Expires.php b/src/Header/SetCookie/Expires.php index 96e1f3c..9dd0710 100644 --- a/src/Header/SetCookie/Expires.php +++ b/src/Header/SetCookie/Expires.php @@ -37,7 +37,7 @@ public function date(): PointInTime public function toParameter(): Parameter { - return new Parameter( + return Parameter::of( 'Expires', $this->date->format(Http::new()), ); diff --git a/src/Header/SetCookie/MaxAge.php b/src/Header/SetCookie/MaxAge.php index 926daa8..bf1af28 100644 --- a/src/Header/SetCookie/MaxAge.php +++ b/src/Header/SetCookie/MaxAge.php @@ -46,6 +46,6 @@ public function toInt(): int public function toParameter(): Parameter { - return new Parameter('Max-Age', (string) $this->toInt()); + return Parameter::of('Max-Age', (string) $this->toInt()); } } diff --git a/src/Header/SetCookie/Path.php b/src/Header/SetCookie/Path.php index 250defd..b5eabb9 100644 --- a/src/Header/SetCookie/Path.php +++ b/src/Header/SetCookie/Path.php @@ -31,6 +31,6 @@ public function path(): UrlPath public function toParameter(): Parameter { - return new Parameter('Path', $this->path->toString()); + return Parameter::of('Path', $this->path->toString()); } } diff --git a/src/Header/WWWAuthenticate/Challenge.php b/src/Header/WWWAuthenticate/Challenge.php index 4808089..991dd59 100644 --- a/src/Header/WWWAuthenticate/Challenge.php +++ b/src/Header/WWWAuthenticate/Challenge.php @@ -51,7 +51,7 @@ public function toString(): string { return Str::of($this->scheme) ->append(' ') - ->append((new Parameter('realm', $this->realm))->toString()) + ->append((Parameter::of('realm', $this->realm))->toString()) ->trim() ->toString(); } diff --git a/tests/Header/AcceptValueTest.php b/tests/Header/AcceptValueTest.php index 19e4abc..6da5899 100644 --- a/tests/Header/AcceptValueTest.php +++ b/tests/Header/AcceptValueTest.php @@ -58,7 +58,7 @@ public function testInterface() 'application', 'octet-stream', Quality::of(40)->toParameter(), - new Parameter('level', '1'), + Parameter::of('level', '1'), )->match( static fn($mediaType) => $mediaType, static fn() => throw new \Exception, diff --git a/tests/Header/CookieTest.php b/tests/Header/CookieTest.php index ab26362..d8401b7 100644 --- a/tests/Header/CookieTest.php +++ b/tests/Header/CookieTest.php @@ -15,7 +15,7 @@ class CookieTest extends TestCase public function testInterface() { $cookie = Cookie::of( - new Parameter('foo', 'bar'), + Parameter::of('foo', 'bar'), ); $this->assertInstanceOf(Cookie::class, $cookie); diff --git a/tests/Header/LinkTest.php b/tests/Header/LinkTest.php index 6d259bd..9efb1ab 100644 --- a/tests/Header/LinkTest.php +++ b/tests/Header/LinkTest.php @@ -19,7 +19,7 @@ public function testInterface() Link\Relationship::of( Url::of('/some/resource'), 'some relation', - new Parameter('title', 'Foo'), + Parameter::of('title', 'Foo'), ), ); diff --git a/tests/Header/LinkValueTest.php b/tests/Header/LinkValueTest.php index 942d7a6..bd132f5 100644 --- a/tests/Header/LinkValueTest.php +++ b/tests/Header/LinkValueTest.php @@ -17,7 +17,7 @@ public function testInterface() $l = Relationship::of( $url = Url::of('/some/resource'), 'relationship', - $p = new Parameter('title', 'Foo'), + $p = Parameter::of('title', 'Foo'), ); $this->assertInstanceOf(Relationship::class, $l); diff --git a/tests/Header/Parameter/ParameterTest.php b/tests/Header/Parameter/ParameterTest.php index 27eb8d2..7d4e070 100644 --- a/tests/Header/Parameter/ParameterTest.php +++ b/tests/Header/Parameter/ParameterTest.php @@ -10,20 +10,20 @@ class ParameterTest extends TestCase { public function testInterface() { - $p = new Parameter('q', 'foo'); + $p = Parameter::of('q', 'foo'); $this->assertSame('q', $p->name()); $this->assertSame('foo', $p->value()); $this->assertSame('q=foo', $p->toString()); - $this->assertSame('level', (new Parameter('level', ''))->toString()); + $this->assertSame('level', (Parameter::of('level', ''))->toString()); } public function testQuoteWhenThereIsAWithespace() { $this->assertSame( 'foo="bar baz"', - (new Parameter('foo', 'bar baz'))->toString(), + (Parameter::of('foo', 'bar baz'))->toString(), ); } @@ -31,7 +31,7 @@ public function testQuoteWhenThereIsATab() { $this->assertSame( "foo=\"bar\tbaz\"", - (new Parameter('foo', "bar\tbaz"))->toString(), + (Parameter::of('foo', "bar\tbaz"))->toString(), ); } @@ -39,7 +39,7 @@ public function testDoesntDuplicateQuotes() { $this->assertSame( 'foo="bar baz"', - (new Parameter('foo', '"bar baz"'))->toString(), + (Parameter::of('foo', '"bar baz"'))->toString(), ); } @@ -47,7 +47,7 @@ public function testDoesntChangeIfAlreadyQuotedEvenIfNotNeeded() { $this->assertSame( 'foo="bar"', - (new Parameter('foo', '"bar"'))->toString(), + (Parameter::of('foo', '"bar"'))->toString(), ); } } From 470f96b0768efc4f5ad4d5291a00347d98bade2b Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:50:24 +0200 Subject: [PATCH 50/51] do not keep parameter string representation in memory --- src/Header/Parameter.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Header/Parameter.php b/src/Header/Parameter.php index dc33498..ce9adb6 100644 --- a/src/Header/Parameter.php +++ b/src/Header/Parameter.php @@ -12,7 +12,6 @@ final class Parameter { private string $name; private string $value; - private string $string; private function __construct(string $name, string $value) { @@ -27,12 +26,6 @@ private function __construct(string $name, string $value) $this->name = $name; $this->value = $value->toString(); - $this->string = \sprintf( - '%s%s%s', - $this->name, - \strlen($this->value) > 0 ? '=' : '', - \strlen($this->value) > 0 ? $this->value : '', - ); } /** @@ -55,6 +48,11 @@ public function value(): string public function toString(): string { - return $this->string; + return \sprintf( + '%s%s%s', + $this->name, + \strlen($this->value) > 0 ? '=' : '', + \strlen($this->value) > 0 ? $this->value : '', + ); } } From 2ce7c3921b9ae22df7e7255a7ee824088712de48 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 20 Apr 2025 16:55:01 +0200 Subject: [PATCH 51/51] fix sending boundary --- tests/Content/MultipartTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Content/MultipartTest.php b/tests/Content/MultipartTest.php index 8603073..8a1f3cf 100644 --- a/tests/Content/MultipartTest.php +++ b/tests/Content/MultipartTest.php @@ -135,7 +135,7 @@ public function testFunctional() \curl_setopt($handle, \CURLOPT_HEADER, false); \curl_setopt($handle, \CURLOPT_RETURNTRANSFER, true); \curl_setopt($handle, \CURLOPT_HTTPHEADER, [ - 'Content-Type: multipart/form-data; '.$boundary->toString(), + 'Content-Type: multipart/form-data; '.$boundary->toParameter()->toString(), ]); \curl_setopt($handle, \CURLOPT_CUSTOMREQUEST, 'POST'); \curl_setopt($handle, \CURLOPT_UPLOAD, true);