88[ ![ Sponsor development of this project] ( https://img.shields.io/badge/sponsor%20this%20package-%E2%9D%A4-ff69b4.svg?style=flat-square )] ( https://github.com/sponsors/nyamsprod )
99
1010` bakame/http-structured-fields ` is a framework-agnostic PHP library that allows you to parse, serialize
11- build and update HTTP Structured Fields in PHP according to the [ RFC8941] ( https://www.rfc-editor.org/rfc/rfc8941.html ) .
11+ create and update HTTP Structured Fields in PHP according to the [ RFC8941] ( https://www.rfc-editor.org/rfc/rfc8941.html ) .
1212
1313Once installed you will be able to do the following:
1414
@@ -24,20 +24,20 @@ $field[2]->parameter('q'); // returns (float) 0.9
2424$field[0]->value()->toString(); // returns 'text/html'
2525$field[0]->parameter('q'); // returns null
2626
27- //2 - building a Retrofit Cookie Header
28- echo DataType::List->build ([
27+ //2 - building a retrofit Cookie Header
28+ echo DataType::List->serialize ([
2929 [
3030 ['foo', 'bar'],
3131 [
32- ['expire', $expire ],
32+ ['expire', new DateTimeImmutable('2023-04-14 20:32:08') ],
3333 ['path', '/'],
3434 [ 'max-age', 2500],
3535 ['secure', true],
3636 ['httponly', true],
3737 ['samesite', Token::fromString('lax')],
3838 ]
3939 ],
40- ]),
40+ ]);
4141// returns ("foo" "bar");expire=@1681504328;path="/";max-age=2500;secure;httponly=?0;samesite=lax
4242```
4343
@@ -58,9 +58,11 @@ composer require bakame/http-structured-fields
5858### Foreword
5959
6060> [ !CAUTION]
61- > While this package parses and serializes the header value, it does not validate its content.
62- It is still required to validate the parsed data against the constraints of the corresponding
63- header. Content validation is out of scope for this library.
61+ > While this package parses and serializes the HTTP value, it does not validate its content
62+ > against any conformance rule. You are still required to perform a compliance check
63+ > against the constraints of the corresponding field. Content validation is
64+ > out of scope for this library even though you can leverage some of its feature to
65+ > ease the required validation.
6466
6567### Parsing and Serializing Structured Fields
6668
@@ -69,7 +71,7 @@ header. Content validation is out of scope for this library.
6971> [ !NOTE]
7072> New in version 1.2.0
7173
72- To quickly parse or build one of the five (5) available data type according to the RFC, you can use the ` DataType ` enum.
74+ To quickly parse or serialize one of the five (5) available data type according to the RFC, you can use the ` DataType ` enum.
7375Apart from listing the data types (` List ` , ` InnerList ` , ` Parameters ` , ` Dictionary ` and ` Item ` ) you can give to
7476its ` parse ` method a string or a stringable object representing a field text representation. On success,
7577it will return an object representing the structured field otherwise an exception will be thrown.
@@ -81,14 +83,36 @@ $field->value(); // returns Token::fromString('bar); the found token va
8183$field->parameter('baz'); // returns 42; the value of the parameter or null if the parameter is not defined.
8284```
8385
84- On the other hand, ` build ` method expects an iterable structure composed of pair values
85- that matches any structured field data type and returns its text representation.
86+ To complement the behaviour, you can use its ` serialize ` method to turn an iterable structure
87+ composed of pair values that matches any structured field data type and returns its
88+ text representation.
89+
90+ ``` php
91+ use Bakame\Http\StructuredFields\Item;
92+ use Bakame\Http\StructuredFields\DataType;
93+
94+ echo DataType::List->serialize([
95+ [
96+ 'dumela lefatshe',
97+ [['a', false]]
98+ ],
99+ [
100+ ['a', 'b', Item::fromDateString('+30 minutes')],
101+ [['a', true]]
102+ ],
103+ ]);
104+ // display "dumela lefatshe";a=?0, ("a" "b" @1703319068);a
105+ ```
106+
107+ The ` serialize ` method is a shortcut to converting the iterable structure into a ` StructuredField ` via
108+ the ` create ` method and calling on the newly created object its ` toHttpValue ` method. With that
109+ in mind, it is possible to rewrite The last example:
86110
87111``` php
88112use Bakame\Http\StructuredFields\Item;
89113use Bakame\Http\StructuredFields\DataType;
90114
91- echo DataType::List->build ([
115+ $list = DataType::List->create ([
92116 [
93117 'dumela lefatshe',
94118 [['a', false]]
@@ -98,18 +122,20 @@ echo DataType::List->build([
98122 [['a', true]]
99123 ],
100124]);
125+
126+ echo $list->toHttpValue();
101127// display "dumela lefatshe";a=?0, ("a" "b" @1703319068);a
102128```
103129
104130> [ !TIP]
105131> While the format can be overwhelming at first, you will come to understand it while reading
106132> the rest of the documentation. Under the hood, the ` DataType ` enum uses the mechanism discussed hereafter.
107133
108- #### Using specific named constructor
134+ #### Using specific data type classes
109135
110- The package provides specific classes for each data type. Parsing the structured field value is done
111- via the ` fromHttpValue ` named constructor. The method is attached to each library's structured
112- field representation as shown below :
136+ The package provides specific classes for each data type. Parsing is done their respective
137+ ` fromHttpValue ` named constructor. A example of how the method works can be seen below
138+ using the ` Item ` class :
113139
114140``` php
115141declare(strict_types=1);
@@ -127,9 +153,13 @@ $field->value(); // returns Token::fromString('bar); the found token va
127153$field->parameter('baz'); // returns 42; the value of the parameter or null if the parameter is not defined.
128154```
129155
156+ > [ !TIP]
157+ > The ` DataType::parse ` method uses the ` fromHttpValue ` named constructor for
158+ > each specific class to generate the structured field PHP representation.
159+
130160The ` fromHttpValue ` method returns an instance which implements the ` StructuredField ` interface.
131161The interface provides the ` toHttpValue ` method that serializes it into a normalized RFC
132- compliant HTTP field string value. To ease integration, the ` __toString ` method is
162+ compliant HTTP field string value. To ease integration, the ` __toString ` method is
133163implemented as an alias to the ` toHttpValue ` method.
134164
135165```` php
@@ -145,6 +175,10 @@ header('foo: '. $field->toHttpValue());
145175header('foo: '. $field);
146176````
147177
178+ > [ !TIP]
179+ > This is the mechanism used by the ` DataType::serialize ` method. Once the Structured
180+ > field has been created, the method calls its ` toHttpValue ` method.
181+
148182All five (5) structured data type as defined in the RFC are provided inside the
149183` Bakame\Http\StructuredFields ` namespace. They all implement the
150184` StructuredField ` interface and expose a ` fromHttpValue ` named constructor:
@@ -155,65 +189,13 @@ All five (5) structured data type as defined in the RFC are provided inside the
155189- ` OuterList ` (named ` List ` in the RFC but renamed in the package because ` list ` is a reserved word in PHP.)
156190- ` InnerList `
157191
158- #### Advance parsing usage
159-
160- Starting with version ` 1.1 ` the internal parser has been made public in order to allow:
161-
162- - clearer decoupling between parsing and objet building
163- - different parsers implementations
164- - improve the package usage in testing.
165-
166- Each ` fromHttpValue ` method signature has been updated to take a second optional argument
167- that represents the parser interface to use in order to allow parsing of the HTTP string
168- representation value.
169-
170- By default, if no parser is provided, the package will default to use the package ` Parser ` class,
171-
172- ``` php
173- Item::fromHttpValue(Stringable|string $httpValue, ItemParser $parser = new Parser()): Item;
174- InnerList::fromHttpValue(Stringable|string $httpValue, InnerListParser $parser = new Parser()): InnerList;
175- Dictionary::fromHttpValue(Stringable|string $httpValue, DictionaryParser $parser = new Parser()): Dictionary;
176- OuterList::fromHttpValue(Stringable|string $httpValue, ListParser $parser = new Parser()): OuterList;
177- Parameters::fromHttpValue(Stringable|string $httpValue, ParametersParser $parser = new Parser()): Parameters;
178- ```
179-
180- The ` Parser ` class exposes the following method each belonging to a different contract or interface.
181-
182- ``` php
183- Parser::parseValue(Stringable|string $httpValue): ByteSequence|Token|DateTimeImmutable|string|int|float|bool;
184- Parser::parseItem(Stringable|string $httpValue): array;
185- Parser::parseParameters(Stringable|string $httpValue): array;
186- Parser::parseInnerList(Stringable|string $httpValue): array;
187- Parser::parseList(Stringable|string $httpValue): array;
188- Parser::parseDictionary(Stringable|string $httpValue): array;
189- ```
190-
191- Once instantiated, calling one of the above listed method is straightforward:
192-
193- ``` php
194- use Bakame\Http\StructuredFields\Parser;
195-
196- $parser = new Parser();
197- $parser->parseValue('text/csv'); //returns Token::fromString('text/csv')
198- $parser->parseItem('@1234567890;file=24');
199- //returns an array
200- // [
201- // new DateTimeImmutable('@1234567890'),
202- // ['file' => 24],
203- // ]
204- ```
205-
206- > [ !NOTE]
207- > While the provided default ` Parser ` class implements all these methods you are free to only implement
208- the methods you need.
209-
210192### Accessing Structured Fields Values
211193
212194#### RFC Value type
213195
214- Per the RFC, items can have different types that are translated to PHP using:
196+ Per the RFC, items value can have different types that are translated to PHP using:
215197
216- - native type where possible
198+ - native type or classes where possible;
217199- specific classes defined in the package namespace to represent non-native type
218200
219201The table below summarizes the item value type.
@@ -231,13 +213,13 @@ The table below summarizes the item value type.
231213
232214> [ !NOTE]
233215> The ` Date ` and ` DisplayString ` type are not yet part of any accepted
234- > RFC. But they are already added as new types in the superseeding
216+ > RFC. But they are already added as new types in the super-seeding
235217> RFC proposal.
236218>
237219> See https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-sfbis
238220> for more information.
239221
240- The Enum ` Type ` which list all available types can be used to determine the RFC type
222+ The Enum ` Type ` list all available types and can be used to determine the RFC type
241223corresponding to a PHP structure using the ` Type::fromVariable ` static method.
242224The method will throw if the structure is not recognized. Alternatively
243225it is possible to use the ` Type::tryFromVariable ` which will instead
@@ -311,8 +293,8 @@ $displayString->type(); // returns Type::DisplayString
311293```
312294
313295> [ !WARNING]
314- > The classes DO NOT expose the ` Stringable ` interface to distinguish them
315- > from a regular string or a string like object
296+ > The classes DO NOT expose the ` Stringable ` interface to help distinguish
297+ > them from a string or a stringable object
316298
317299#### Item
318300
@@ -406,7 +388,7 @@ use Bakame\Http\StructuredFields\ByteSequence;
406388use Bakame\Http\StructuredFields\Item;
407389use Bakame\Http\StructuredFields\Token;
408390
409- Item:new(DateTimeInterface|ByteSequence|Token|DisplayString|string|int|float|bool $value): self
391+ Item:new(DateTimeInterface|ByteSequence|Token|DisplayString|string|int|array| float|bool $value): self
410392Item::fromDecodedByteSequence(Stringable|string $value): self;
411393Item::fromEncodedDisplayString(Stringable|string $value): self;
412394Item::fromDecodedDisplayString(Stringable|string $value): self;
@@ -674,7 +656,7 @@ $list = OuterList::fromPairs([
674656 [
675657 ['foo', 'bar'],
676658 [
677- ['expire', $expire ],
659+ ['expire', new DateTime('2024-01-01 12:33:45') ],
678660 ['path', '/'],
679661 [ 'max-age', 2500],
680662 ['secure', true],
@@ -784,6 +766,58 @@ echo InnerList::new('foo', 'bar')
784766// ("foo" "bar");expire=@1681538756;path="/";max-age=2500
785767```
786768
769+ ### Advance parsing usage
770+
771+ Starting with version ` 1.1 ` the internal parser has been made public in order to allow:
772+
773+ - clearer decoupling between parsing and objet building
774+ - different parsers implementations
775+ - improve the package usage in testing.
776+
777+ Each ` fromHttpValue ` method signature has been updated to take a second optional argument
778+ that represents the parser interface to use in order to allow parsing of the HTTP string
779+ representation value.
780+
781+ By default, if no parser is provided, the package will default to use the package ` Parser ` class,
782+
783+ ``` php
784+ Item::fromHttpValue(Stringable|string $httpValue, ItemParser $parser = new Parser()): Item;
785+ InnerList::fromHttpValue(Stringable|string $httpValue, InnerListParser $parser = new Parser()): InnerList;
786+ Dictionary::fromHttpValue(Stringable|string $httpValue, DictionaryParser $parser = new Parser()): Dictionary;
787+ OuterList::fromHttpValue(Stringable|string $httpValue, ListParser $parser = new Parser()): OuterList;
788+ Parameters::fromHttpValue(Stringable|string $httpValue, ParametersParser $parser = new Parser()): Parameters;
789+ ```
790+
791+ The ` Parser ` class exposes the following method each belonging to a different contract or interface.
792+
793+ ``` php
794+ Parser::parseValue(Stringable|string $httpValue): ByteSequence|Token|DateTimeImmutable|string|int|float|bool;
795+ Parser::parseItem(Stringable|string $httpValue): array;
796+ Parser::parseParameters(Stringable|string $httpValue): array;
797+ Parser::parseInnerList(Stringable|string $httpValue): array;
798+ Parser::parseList(Stringable|string $httpValue): array;
799+ Parser::parseDictionary(Stringable|string $httpValue): array;
800+ ```
801+
802+ Once instantiated, calling one of the above listed method is straightforward:
803+
804+ ``` php
805+ use Bakame\Http\StructuredFields\Parser;
806+
807+ $parser = new Parser();
808+ $parser->parseValue('text/csv'); //returns Token::fromString('text/csv')
809+ $parser->parseItem('@1234567890;file=24');
810+ //returns an array
811+ // [
812+ // new DateTimeImmutable('@1234567890'),
813+ // ['file' => 24],
814+ // ]
815+ ```
816+
817+ > [ !NOTE]
818+ > While the provided default ` Parser ` class implements all these methods you are free to only implement
819+ the methods you need.
820+
787821## Contributing
788822
789823Contributions are welcome and will be fully credited. Please see [ CONTRIBUTING] ( .github/CONTRIBUTING.md ) and [ CODE OF CONDUCT] ( .github/CODE_OF_CONDUCT.md ) for details.
0 commit comments