Skip to content

Commit c223ebb

Browse files
committed
Re-introducing the DataType enum
1 parent 074afd2 commit c223ebb

File tree

9 files changed

+160
-108
lines changed

9 files changed

+160
-108
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ All Notable changes to `bakame/http-strucured-fields` will be documented in this
1010
- `ByteSequence::tryFromEncoded`
1111
- `Token::tryFromString`
1212
- `OuterList::fromPairs`
13-
- Adding functional API via `http_parse_sf` and `http_build_sf`
13+
- `DataType` is now part of the public API
1414

1515
### Fixed
1616

README.md

Lines changed: 95 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,31 @@ build and update HTTP Structured Fields in PHP according to the [RFC8941](https:
1313
Once installed you will be able to do the following:
1414

1515
```php
16-
use Bakame\Http\StructuredFields\InnerList;
17-
use Bakame\Http\StructuredFields\OuterList;
16+
use Bakame\Http\StructuredFields\DataType;
1817
use Bakame\Http\StructuredFields\Token;
1918

2019
//1 - parsing an Accept Header
2120
$headerValue = 'text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8';
22-
$field = http_parse_structured_field('list', $headerValue);
21+
$field = DataType::List->parse($headerValue);
2322
$field[2]->value()->toString(); // returns 'application/xml'
2423
$field[2]->parameter('q'); // returns (float) 0.9
2524
$field[0]->value()->toString(); // returns 'text/html'
2625
$field[0]->parameter('q'); // returns null
2726

2827
//2 - building a Retrofit Cookie Header
29-
echo http_build_structured_field('list', [
28+
echo DataType::List->build[
3029
[
3130
['foo', 'bar'],
3231
[
33-
'expire' => $expire,
34-
'path' => '/',
35-
'max-age' => 2500,
36-
'secure' => true,
37-
'httponly' => true,
38-
'samesite' => Token::fromString('lax'),
32+
['expire', $expire],
33+
['path', '/'],
34+
[ 'max-age', 2500],
35+
['secure', true],
36+
['httponly', true],
37+
['samesite', Token::fromString('lax')],
3938
]
40-
]
41-
]);
39+
],
40+
]),
4241
// returns ("foo" "bar");expire=@1681504328;path="/";max-age=2500;secure;httponly=?0;samesite=lax
4342
```
4443

@@ -65,22 +64,66 @@ header. Content validation is out of scope for this library.
6564

6665
### Parsing and Serializing Structured Fields
6766

68-
#### Basic usage
67+
#### Basic Usage
68+
69+
> [!NOTE]
70+
> New in version 1.2.0
71+
72+
The `DataType` enum serves as a factory class to quickly parse and build a structured field.
73+
The enum list all available data type according to the RFC. To parse a header you need to
74+
give the `parse` method a string or a stringable object. On success, it will return a
75+
`Bakame\Http\StruncturedFields\StruncturedField` implementing object otherwise an
76+
exception will be thrown.
77+
78+
```php
79+
$headerLine = 'bar;baz=42'; //the raw header line is a structured field item
80+
$field = DataType::Item->parse($headerLine);
81+
$field->value(); // returns Token::fromString('bar); the found token value
82+
$field->parameter('baz'); // returns 42; the value of the parameter or null if the parameter is not defined.
83+
```
84+
85+
On the other hand, `build` method expects an iterable structure composed
86+
of pair values that matches each data type and returns the structured field text representation
87+
of the header.
88+
89+
```php
90+
use Bakame\Http\StructuredFields\Item;
91+
use Bakame\Http\StructuredFields\DataType;
92+
93+
echo DataType::List->build([
94+
[
95+
'dumela lefatshe',
96+
[['a', false]]
97+
],
98+
[
99+
['a', 'b', Item::fromDateString('+30 minutes')],
100+
[['a', true]]
101+
],
102+
]);
103+
// display "dumela lefatshe";a=?0, ("a" "b" @1703319068);a
104+
```
105+
106+
The data type can be given as a string or using the `DataType` enum.
69107

70-
Parsing the header value is done via the `fromHttpValue` named constructor.
71-
The method is attached to each library's structured fields representation
72-
as shown below:
108+
#### Using specific named constructor
109+
110+
The package provides specific classes for each data type. if you do not wish to
111+
use the `DataType` factoring, parsing the header value is done via the
112+
`fromHttpValue` named constructor. The method is attached to each library's
113+
structured fields representation as shown below:
73114

74115
```php
75116
declare(strict_types=1);
76117

118+
use Bakame\Http\StructuredFields\DataType;
119+
77120
require 'vendor/autoload.php';
78121

79122
// the raw HTTP field value is given by your application
80123
// via any given framework, package or super global.
81124

82125
$headerLine = 'bar;baz=42'; //the raw header line is a structured field item
83-
$field = parse($headerLine, 'item');
126+
$field = Item::fromHttpValue($headerLine);
84127
$field->value(); // returns Token::fromString('bar); the found token value
85128
$field->parameter('baz'); // returns 42; the value of the parameter or null if the parameter is not defined.
86129
```
@@ -91,10 +134,7 @@ compliant HTTP field string value. To ease integration, the `__toString` method
91134
implemented as an alias to the `toHttpValue` method.
92135

93136
````php
94-
use function Bakame\Http\StructuredFields\http_sf_parse;
95-
use function Bakame\Http\StructuredFields\http_sf_build;
96-
97-
$field = http_sf_parse('bar; baz=42; secure=?1', 'item');
137+
$field = Item::fromHttpValue('bar; baz=42; secure=?1');
98138
echo $field->toHttpValue(); // return 'bar;baz=42;secure'
99139
// on serialization the field has been normalized
100140

@@ -104,8 +144,6 @@ echo $field->toHttpValue(); // return 'bar;baz=42;secure'
104144
header('foo: '. $field->toHttpValue());
105145
//or
106146
header('foo: '. $field);
107-
//or
108-
header('foo: '. http_sf_build($field));
109147
````
110148

111149
All five (5) structured data type as defined in the RFC are provided inside the
@@ -211,9 +249,10 @@ To ease validation a `Type::equals` method is exposed to check if the `Item` has
211249
the expected type. It can also be used to compare types.
212250

213251
```php
252+
use Bakame\Http\StructuredFields\DataType;
214253
use Bakame\Http\StructuredFields\Type;
215254

216-
$field = Item::fromHttpValue('"foo"');
255+
$field = DataType::Item->parse('"foo"');
217256
Type::Date->equals($field); // returns false
218257
Type::String->equals($field); // returns true;
219258
Type::Boolean->equals(Type::String); // returns false
@@ -302,7 +341,7 @@ if you try to use them on any container object:
302341
```php
303342
use Bakame\Http\StructuredFields\Parameters;
304343

305-
$value = Parameters::fromHttpValue(';a=foobar']);
344+
$value = Parameters::fromHttpValue(';a=foobar');
306345
$value->has('b'); // return false
307346
$value['a']->value(); // return 'foobar'
308347
$value['b']; // triggers a InvalidOffset exception, the index does not exist
@@ -613,6 +652,37 @@ echo $list->toHttpValue(); //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
613652
echo $list; //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
614653
```
615654

655+
> [!NOTE]
656+
> New in version 1.2.0
657+
658+
It is also possible to create an `OuterList` based on an iterable structure
659+
of pairs.
660+
661+
```php
662+
use Bakame\Http\StructuredFields\OuterList;
663+
664+
$list = OuterList::fromPairs([
665+
[
666+
['foo', 'bar'],
667+
[
668+
['expire', $expire],
669+
['path', '/'],
670+
[ 'max-age', 2500],
671+
['secure', true],
672+
['httponly', true],
673+
['samesite', Token::fromString('lax')],
674+
]
675+
],
676+
[
677+
'coucoulesamis',
678+
[['a', false]],
679+
]
680+
]);
681+
```
682+
683+
The pairs definitions are the same as for creating either a `InnerList` or an `Item` using
684+
their respective `fromPair` method.
685+
616686
#### Adding and updating parameters
617687

618688
To ease working with instances that have a `Parameters` object attached to, the following

composer.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@
3939
"symfony/var-dumper": "^6.4.0"
4040
},
4141
"autoload": {
42-
"files": [
43-
"src/functions.php"
44-
],
4542
"psr-4": {
4643
"Bakame\\Http\\StructuredFields\\": "src/"
4744
}

phpstan.neon

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ parameters:
1111
ignoreErrors:
1212
- message: '#it_fails_to_create_an_item_from_an_array_of_pairs\(\)#'
1313
path: tests/ItemTest.php
14-
- message: '#Function http_build_structured_field\(\) has parameter \$data with no value type specified in iterable type iterable.#'
15-
path: src/functions.php
14+
- message: '#Method Bakame\\Http\\StructuredFields\\DataType::build\(\) has parameter \$data with no value type specified in iterable type iterable.#'
15+
path: src/DataType.php
1616
reportUnmatchedIgnoredErrors: true

src/DataType.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Bakame\Http\StructuredFields;
6+
7+
use Stringable;
8+
9+
enum DataType: string
10+
{
11+
case Item = 'item';
12+
case Parameters = 'parameters';
13+
case InnerList = 'innerlist';
14+
case List = 'list';
15+
case Dictionary = 'dictionary';
16+
17+
/**
18+
* @throws StructuredFieldError
19+
*/
20+
public function parse(Stringable|string $httpValue): StructuredField
21+
{
22+
return match ($this) {
23+
self::Dictionary => Dictionary::fromHttpValue($httpValue),
24+
self::Parameters => Parameters::fromHttpValue($httpValue),
25+
self::List => OuterList::fromHttpValue($httpValue),
26+
self::InnerList => InnerList::fromHttpValue($httpValue),
27+
self::Item => Item::fromHttpValue($httpValue),
28+
};
29+
}
30+
31+
/**
32+
* @throws StructuredFieldError
33+
*/
34+
public function build(iterable $data): string
35+
{
36+
return match ($this) {
37+
self::Dictionary => Dictionary::fromPairs($data)->toHttpValue(),
38+
self::Parameters => Parameters::fromPairs($data)->toHttpValue(),
39+
self::List => OuterList::fromPairs($data)->toHttpValue(),
40+
self::InnerList => InnerList::fromPair([...$data])->toHttpValue(), /* @phpstan-ignore-line */
41+
self::Item => Item::fromPair([...$data])->toHttpValue(), /* @phpstan-ignore-line */
42+
};
43+
}
44+
}

src/Type.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@
99
/**
1010
* @see https://www.rfc-editor.org/rfc/rfc8941.html#section-3.3
1111
*/
12-
enum Type
12+
enum Type: string
1313
{
14-
case Integer;
15-
case Decimal;
16-
case String;
17-
case Token;
18-
case ByteSequence;
19-
case DisplayString;
20-
case Boolean;
21-
case Date;
14+
case Integer = 'integer';
15+
case Decimal = 'decimal';
16+
case String = 'string';
17+
case Token = 'token';
18+
case ByteSequence = 'bytesequence';
19+
case DisplayString = 'displaystring';
20+
case Boolean = 'boolean';
21+
case Date = 'date';
2222

2323
public function equals(mixed $other): bool
2424
{
@@ -48,9 +48,9 @@ public static function tryFromValue(mixed $value): self|null
4848
is_float($value) => Type::Decimal,
4949
is_bool($value) => Type::Boolean,
5050
is_string($value) => match (true) {
51-
1 === preg_match('/[^\x20-\x7f]/', $value) => Type::DisplayString,
52-
1 === preg_match("/^([a-z*][a-z\d:\/!#\$%&'*+\-.^_`|~]*)$/i", $value) => Type::Token,
51+
null !== Token::tryFromString($value) => Type::Token,
5352
null !== ByteSequence::tryFromEncoded($value) => Type::ByteSequence,
53+
1 === preg_match('/[^\x20-\x7f]/', $value) => Type::DisplayString,
5454
default => Type::String,
5555
},
5656
default => null,

src/functions.php

Lines changed: 0 additions & 59 deletions
This file was deleted.

0 commit comments

Comments
 (0)