Skip to content

Commit c17a734

Browse files
committed
Improve internal codebase
1 parent a8b8df3 commit c17a734

19 files changed

+248
-412
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ All Notable changes to `bakame/http-strucured-fields` will be documented in this
5050
- `Dictionary::toPairs` and `Parameters::toPairs`
5151
- `ByteSequence` class replaced by `Bytes` class
5252
- `DataType::create` method use a specific DataType class instead.
53+
- `Value` internal class.
5354

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

phpstan.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ parameters:
1111
ignoreErrors:
1212
- message: '#it_fails_to_create_an_item_from_an_array_of_pairs\(\)#'
1313
path: tests/ItemTest.php
14-
- message: '#Method Bakame\\Http\\StructuredFields\\DataType::(serialize|build|create|toRfc9651|toRfc8941)\(\) has parameter \$data with no value type specified in iterable type iterable.#'
14+
- message: '#Method Bakame\\Http\\StructuredFields\\DataType::(serialize|parse)\(\) has parameter \$data with no value type specified in iterable type iterable.#'
1515
path: src/DataType.php
1616
excludePaths:
1717
- tests/Record.php

src/DataType.php

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ enum DataType: string
1818
/**
1919
* @throws SyntaxError|Exception
2020
*/
21-
public function parse(Stringable|string $httpValue, ?Ietf $rfc = Ietf::Rfc9651): OuterList|InnerList|Parameters|Dictionary|Item
21+
public function parse(Stringable|string $httpValue, Ietf $rfc = Ietf::Rfc9651): OuterList|InnerList|Parameters|Dictionary|Item
2222
{
2323
return match ($this) {
2424
self::List => OuterList::fromHttpValue($httpValue, $rfc),
@@ -32,7 +32,7 @@ public function parse(Stringable|string $httpValue, ?Ietf $rfc = Ietf::Rfc9651):
3232
/**
3333
* @throws SyntaxError|Exception
3434
*/
35-
public function serialize(iterable $data, ?Ietf $rfc = Ietf::Rfc9651): string
35+
public function serialize(iterable $data, Ietf $rfc = Ietf::Rfc9651): string
3636
{
3737
return (match ($this) {
3838
self::List => OuterList::fromPairs($data),
@@ -42,36 +42,4 @@ public function serialize(iterable $data, ?Ietf $rfc = Ietf::Rfc9651): string
4242
self::Parameters => Parameters::fromPairs($data),
4343
})->toHttpValue($rfc);
4444
}
45-
46-
/**
47-
* @throws SyntaxError|Exception
48-
*/
49-
public function fromRfc9651(Stringable|string $httpValue): OuterList|InnerList|Parameters|Dictionary|Item
50-
{
51-
return $this->parse($httpValue, Ietf::Rfc9651);
52-
}
53-
54-
/**
55-
* @throws SyntaxError|Exception
56-
*/
57-
public function toRfc9651(iterable $data): string
58-
{
59-
return $this->serialize($data, Ietf::Rfc9651);
60-
}
61-
62-
/**
63-
* @throws SyntaxError|Exception
64-
*/
65-
public function fromRfc8941(Stringable|string $httpValue): OuterList|InnerList|Parameters|Dictionary|Item
66-
{
67-
return $this->parse($httpValue, Ietf::Rfc8941);
68-
}
69-
70-
/**
71-
* @throws SyntaxError|Exception
72-
*/
73-
public function toRfc8941(iterable $data): string
74-
{
75-
return $this->serialize($data, Ietf::Rfc8941);
76-
}
7745
}

src/Dictionary.php

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@
1414
use Stringable;
1515
use Throwable;
1616

17+
use function array_is_list;
1718
use function array_key_exists;
1819
use function array_keys;
20+
use function array_map;
1921
use function count;
2022
use function implode;
2123
use function is_array;
24+
use function is_bool;
2225
use function is_int;
2326
use function is_iterable;
2427
use function is_string;
28+
use function uasort;
2529

2630
/**
2731
* @see https://www.rfc-editor.org/rfc/rfc9651.html#section-3.2
@@ -56,14 +60,16 @@ private static function filterMember(mixed $member): InnerList|Item
5660
{
5761
if ($member instanceof StructuredFieldProvider) {
5862
$member = $member->toStructuredField();
63+
if ($member instanceof Item || $member instanceof InnerList) {
64+
return $member;
65+
}
66+
67+
throw new InvalidArgument('The '.StructuredFieldProvider::class.' must provide a '.Item::class.' or an '.InnerList::class.'; '.$member::class.' given.');
5968
}
6069

6170
return match (true) {
6271
$member instanceof InnerList,
6372
$member instanceof Item => $member,
64-
$member instanceof OuterList,
65-
$member instanceof Dictionary,
66-
$member instanceof Parameters => throw new InvalidArgument('An instance of "'.$member::class.'" can not be a member of "'.self::class.'".'),
6773
is_iterable($member) => InnerList::new(...$member),
6874
default => Item::new($member),
6975
};
@@ -122,6 +128,11 @@ public static function fromPairs(StructuredFieldProvider|Dictionary|Parameters|i
122128
$converter = function (mixed $pair): InnerList|Item {
123129
if ($pair instanceof StructuredFieldProvider) {
124130
$pair = $pair->toStructuredField();
131+
if ($pair instanceof Item || $pair instanceof InnerList) {
132+
return $pair;
133+
}
134+
135+
throw new InvalidArgument('The '.StructuredFieldProvider::class.' must provide a '.Item::class.' or an '.InnerList::class.'; '.$pair::class.' given.');
125136
}
126137

127138
if ($pair instanceof InnerList || $pair instanceof Item) {
@@ -140,13 +151,11 @@ public static function fromPairs(StructuredFieldProvider|Dictionary|Parameters|i
140151
return InnerList::new();
141152
}
142153

143-
[$member, $parameters] = match (count($pair)) {
144-
2 => $pair,
145-
1 => [$pair[0], []],
146-
default => throw new SyntaxError('The pair first member is the item value; its second member is the item parameters.'),
147-
};
154+
if (!in_array(count($pair), [1, 2], true)) {
155+
throw new SyntaxError('The pair first member is the item value; its second member is the item parameters.');
156+
}
148157

149-
return is_iterable($member) ? InnerList::fromPair([$member, $parameters]) : Item::fromPair([$member, $parameters]);
158+
return is_iterable($pair[0]) ? InnerList::fromPair($pair) : Item::fromPair($pair);
150159
};
151160

152161
return match (true) {
@@ -191,9 +200,9 @@ public static function fromRfc8941(Stringable|string $httpValue): self
191200
*
192201
* @throws StructuredFieldError|Throwable If the string is not a valid
193202
*/
194-
public static function fromHttpValue(Stringable|string $httpValue, ?Ietf $rfc = Ietf::Rfc9651): self
203+
public static function fromHttpValue(Stringable|string $httpValue, Ietf $rfc = Ietf::Rfc9651): self
195204
{
196-
return self::fromPairs(Parser::new($rfc)->parseDictionary($httpValue)); /* @phpstan-ignore-line */
205+
return self::fromPairs((new Parser($rfc))->parseDictionary($httpValue)); /* @phpstan-ignore-line */
197206
}
198207

199208
public function toRfc9651(): string
@@ -206,18 +215,14 @@ public function toRfc8941(): string
206215
return $this->toHttpValue(Ietf::Rfc8941);
207216
}
208217

209-
public function toHttpValue(?Ietf $rfc = Ietf::Rfc9651): string
218+
public function toHttpValue(Ietf $rfc = Ietf::Rfc9651): string
210219
{
211-
$rfc ??= Ietf::Rfc9651;
212-
$members = [];
213-
foreach ($this->members as $key => $member) {
214-
$members[] = match (true) {
215-
$member instanceof Item && true === $member->value() => $key.$member->parameters()->toHttpValue($rfc),
216-
default => $key.'='.$member->toHttpValue($rfc),
217-
};
218-
}
220+
$formatter = static fn (Item|InnerList $member, string $offset): string => match (true) {
221+
$member instanceof Item && true === $member->value() => $offset.$member->parameters()->toHttpValue($rfc),
222+
default => $offset.'='.$member->toHttpValue($rfc),
223+
};
219224

220-
return implode(', ', $members);
225+
return implode(', ', array_map($formatter, $this->members, array_keys($this->members)));
221226
}
222227

223228
public function __toString(): string
@@ -506,7 +511,7 @@ public function last(): array
506511
*/
507512
public function add(
508513
string $key,
509-
iterable|StructuredFieldProvider|OuterList|Dictionary|InnerList|Parameters|Item|Token|Bytes|DisplayString|DateTimeInterface|string|int|float|bool|null $member
514+
iterable|StructuredFieldProvider|Dictionary|Parameters|Item|Token|Bytes|DisplayString|DateTimeInterface|string|int|float|bool|null $member
510515
): self {
511516
if (null === $member) {
512517
return $this;
@@ -596,7 +601,7 @@ public function removeByKeys(string ...$keys): self
596601
*/
597602
public function append(
598603
string $key,
599-
iterable|StructuredFieldProvider|OuterList|Dictionary|InnerList|Parameters|Item|Token|Bytes|DisplayString|DateTimeInterface|string|int|float|bool $member
604+
iterable|StructuredFieldProvider|Dictionary|Parameters|Item|Token|Bytes|DisplayString|DateTimeInterface|string|int|float|bool $member
600605
): self {
601606
$members = $this->members;
602607
unset($members[$key]);
@@ -616,7 +621,7 @@ public function append(
616621
*/
617622
public function prepend(
618623
string $key,
619-
iterable|StructuredFieldProvider|OuterList|Dictionary|InnerList|Parameters|Item|Token|Bytes|DisplayString|DateTimeInterface|string|int|float|bool $member
624+
iterable|StructuredFieldProvider|Dictionary|Parameters|Item|Token|Bytes|DisplayString|DateTimeInterface|string|int|float|bool $member
620625
): self {
621626
$members = $this->members;
622627
unset($members[$key]);
@@ -840,7 +845,7 @@ public function filter(callable $callback): self
840845
public function sort(callable $callback): self
841846
{
842847
$members = iterator_to_array($this);
843-
usort($members, $callback);
848+
uasort($members, $callback);
844849

845850
return self::fromPairs($members);
846851
}

src/DisplayString.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use function preg_replace_callback;
1212
use function rawurldecode;
1313
use function rawurlencode;
14+
use function str_contains;
1415

1516
/**
1617
* @see https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-sfbis#section-4.2.10

src/InnerList.php

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use function array_values;
2121
use function count;
2222
use function implode;
23+
use function uasort;
2324

2425
use const ARRAY_FILTER_USE_BOTH;
2526
use const ARRAY_FILTER_USE_KEY;
@@ -46,10 +47,10 @@ final class InnerList implements ArrayAccess, Countable, IteratorAggregate
4647
/**
4748
* @param iterable<SfItemInput> $members
4849
*/
49-
private function __construct(iterable $members, Parameters $parameters)
50+
private function __construct(iterable $members, ?Parameters $parameters = null)
5051
{
5152
$this->members = array_map($this->filterMember(...), array_values([...$members]));
52-
$this->parameters = $parameters;
53+
$this->parameters = $parameters ?? Parameters::new();
5354
}
5455

5556
/**
@@ -59,22 +60,28 @@ private function filterMember(mixed $member): Item
5960
{
6061
if ($member instanceof StructuredFieldProvider) {
6162
$member = $member->toStructuredField();
63+
if (!$member instanceof Item) {
64+
throw new InvalidArgument('The '.StructuredFieldProvider::class.' must provide a '.Item::class.'; '.$member::class.' given.');
65+
}
66+
67+
return $member;
6268
}
6369

64-
return match (true) {
65-
$member instanceof Item => $member,
66-
default => Item::new($member),
67-
};
70+
if (!$member instanceof Item) {
71+
return Item::new($member);
72+
}
73+
74+
return $member;
6875
}
6976

7077
/**
7178
* Returns an instance from an HTTP textual representation.
7279
*
7380
* @see https://www.rfc-editor.org/rfc/rfc9651.html#section-3.1
7481
*/
75-
public static function fromHttpValue(Stringable|string $httpValue, ?Ietf $rfc = Ietf::Rfc9651): self
82+
public static function fromHttpValue(Stringable|string $httpValue, Ietf $rfc = Ietf::Rfc9651): self
7683
{
77-
return self::fromPair(Parser::new($rfc)->parseInnerList($httpValue));
84+
return self::fromPair((new Parser($rfc))->parseInnerList($httpValue));
7885
}
7986

8087
/**
@@ -95,7 +102,7 @@ public static function fromAssociative(
95102
}
96103

97104
if (!$parameters instanceof Parameters) {
98-
$parameters = Parameters::fromAssociative($parameters);
105+
return new self($value, Parameters::fromAssociative($parameters));
99106
}
100107

101108
return new self($value, $parameters);
@@ -115,7 +122,7 @@ public static function fromPair(array $pair): self
115122
}
116123

117124
if (1 === count($pair)) {
118-
return new self($pair[0], Parameters::new());
125+
return new self($pair[0]);
119126
}
120127

121128
if ($pair[1] instanceof StructuredFieldProvider) {
@@ -126,7 +133,7 @@ public static function fromPair(array $pair): self
126133
}
127134

128135
if (!$pair[1] instanceof Parameters) {
129-
$pair[1] = Parameters::fromPairs($pair[1]);
136+
return new self($pair[0], Parameters::fromPairs($pair[1]));
130137
}
131138

132139
return new self($pair[0], $pair[1]);
@@ -138,7 +145,7 @@ public static function fromPair(array $pair): self
138145
public static function new(
139146
StructuredFieldProvider|OuterList|Dictionary|InnerList|Parameters|Item|Token|Bytes|DisplayString|DateTimeInterface|string|int|float|bool ...$members
140147
): self {
141-
return new self($members, Parameters::new());
148+
return new self($members);
142149
}
143150

144151
public static function fromRfc9651(Stringable|string $httpValue): self
@@ -151,10 +158,8 @@ public static function fromRfc8941(Stringable|string $httpValue): self
151158
return self::fromHttpValue($httpValue, Ietf::Rfc8941);
152159
}
153160

154-
public function toHttpValue(?Ietf $rfc = Ietf::Rfc9651): string
161+
public function toHttpValue(Ietf $rfc = Ietf::Rfc9651): string
155162
{
156-
$rfc ??= Ietf::Rfc9651;
157-
158163
return '('.implode(' ', array_map(fn (Item $value): string => $value->toHttpValue($rfc), $this->members)).')'.$this->parameters->toHttpValue($rfc);
159164
}
160165

@@ -483,7 +488,7 @@ public function filter(callable $callback): self
483488
public function sort(callable $callback): self
484489
{
485490
$members = $this->members;
486-
usort($members, $callback);
491+
uasort($members, $callback);
487492

488493
return new self($members, $this->parameters);
489494
}

0 commit comments

Comments
 (0)