1010` bakame/http-structured-fields ` is a framework-agnostic PHP library that allows you to parse, serialize
1111build and update HTTP Structured Fields in PHP according to the [ RFC8941] ( https://www.rfc-editor.org/rfc/rfc8941.html ) .
1212
13+ Once installed you will be able to do the following:
14+
15+ ``` php
16+ use Bakame\Http\StructuredFields\InnerList;
17+ use Bakame\Http\StructuredFields\Item;
18+ use Bakame\Http\StructuredFields\OuterList;
19+ use Bakame\Http\StructuredFields\Token;
20+
21+ echo OuterList::new()
22+ ->push(
23+ InnerList::new(Item::fromString('foo'), Item::fromString('bar'))
24+ ->addParameter('expire', Item::fromDateString('+30 minutes'))
25+ ->addParameter('path', '/')
26+ ->addParameter('max-age', 2500)
27+ ->addParameter('secure', true)
28+ ->addParameter('httponly', false)
29+ ->addParameter('samesite', Token::fromString('lax'))
30+ )
31+ ->toHttpValue();
32+
33+ // or
34+
35+ echo OuterList::new(
36+ InnerList::fromAssociative(['foo', 'bar'], [
37+ 'expire' => new DateTimeImmutable('+30 minutes'),
38+ 'path' => '/',
39+ 'max-age' => 2500,
40+ 'secure' => true,
41+ 'httponly' => true,
42+ 'samesite' => Token::fromString('lax'),
43+ ])
44+ );
45+
46+ // Both code snippet return
47+ // ("foo" "bar");expire=@1681504328;path="/";max-age=2500;secure;httponly=?0;samesite=lax
48+ // the retrofit representation of the cookie header
49+ ```
50+
1351## System Requirements
1452
1553** PHP >= 8.1** is required but the latest stable version of PHP is recommended.
@@ -26,8 +64,8 @@ composer require bakame/http-structured-fields
2664
2765### Parsing and Serializing Structured Fields
2866
29- Once the library is installed parsing the header value is done via the normalized ` fromHttpValue ` named
30- constructor attached to library's structured fields representation as shown below:
67+ Parsing the header value is done via the ` fromHttpValue ` named constructor
68+ attached to each library's structured fields representation as shown below:
3169
3270``` php
3371declare(strict_types=1);
@@ -47,12 +85,10 @@ $field->parameter('baz'); // returns 42; the value of the parameter or null if t
4785```
4886
4987The ` fromHttpValue ` method returns an instance which implements the` StructuredField ` interface.
50- The interface provides a way to serialize the object into a normalized RFC compliant HTTP
51- field string value using the ` StructuredField::toHttpValue ` method .
88+ The interface provides the ` toHttpValue ` method that serializes it into a normalized
89+ RFC compliant HTTP field string value .
5290
53- To ease integration with current PHP frameworks and packages working with HTTP headers and trailers,
54- each value object also exposes the ` Stringable ` interface method ` __toString ` as an alias to
55- the ` toHttpValue ` method.
91+ To ease integration, the ` __toString ` method is implemented as an alias to the ` toHttpValue ` method.
5692
5793```` php
5894use Bakame\Http\StructuredFields\Item;
@@ -69,8 +105,8 @@ $newResponse = $response->headers->set('foo', $bar->toHttpValue());
69105$newResponse = $response->headers->set('foo', $bar);
70106````
71107
72- The library provides all five (5) structured data type as defined in the RFC inside the
73- ` Bakame\Http\StructuredFields ` namespace. As mentioned, they all implement the
108+ All five (5) structured data type as defined in the RFC are provided inside the
109+ ` Bakame\Http\StructuredFields ` namespace. They all implement the
74110` StructuredField ` interface and expose a ` fromHttpValue ` named constructor:
75111
76112- ` Item `
@@ -100,9 +136,9 @@ The table below summarizes the item value type.
100136| Byte Sequence | class ` ByteSequence ` | ` Type::ByteSequence ` |
101137| Date | class ` DateTimeImmutable ` | ` Type::Date ` |
102138
103- As shown in the table, the RFC define two (2) specific data types that can not be represented by
104- PHP default type system, for them, we have defined two classes ` Token ` and ` ByteSequence ` to help
105- with representation.
139+ The RFC define two (2) specific data types that can not be represented by
140+ PHP default type system, for them, we have defined two classes ` Token `
141+ and ` ByteSequence ` to help with their representation.
106142
107143``` php
108144use Bakame\Http\StructuredFields\Token;
@@ -139,7 +175,7 @@ from a string or a string like object**
139175
140176#### Item
141177
142- The defined types are all attached to the ` Item ` object where there values and types
178+ The defined types are all attached to the ` Item ` object where their values and types
143179are accessible using the following methods:
144180
145181``` php
@@ -155,8 +191,8 @@ Type::Date->equals($item); // returns true
155191
156192#### Containers
157193
158- All containers objects implement PHP ` IteratorAggregate ` , ` Countable ` and ` ArrayAccess ` interfaces for
159- easy usage in your codebase. You also can access container members via the following shared methods
194+ All containers objects implement PHP ` IteratorAggregate ` , ` Countable ` and ` ArrayAccess `
195+ interfaces. Their members can be accessed using the following shared methods
160196
161197``` php
162198$container->keys(): array<string >;
@@ -166,7 +202,7 @@ $container->hasMembers(): bool;
166202$container->hasNoMembers(): bool;
167203```
168204
169- To avoid invalid states, the modifying methods from PHP ` ArrayAccess ` will throw a ` ForbiddenOperation `
205+ To avoid invalid states, ` ArrayAccess ` modifying methods throw a ` ForbiddenOperation `
170206if you try to use them on any container object:
171207
172208``` php
@@ -180,8 +216,7 @@ $value['a'] = 23 // triggers a ForbiddenOperation exception
180216unset($value['a']); // triggers a ForbiddenOperation exception
181217```
182218
183- Apart from the PHP interfaces, the ` Dictionary ` and ` Parameters ` classes allow accessing its members
184- as pairs:
219+ The ` Dictionary ` and ` Parameters ` classes also allow accessing its members as pairs:
185220
186221``` php
187222$container->hasPair(int ...$offsets): bool;
@@ -191,25 +226,31 @@ $container->toPairs(): iterable<array{0:string, 1:StructuredField}>;
191226
192227#### Accessing the parameters values
193228
194- You can also read the associated ` Parameters ` instance attached to an ` InnerList ` or a ` Item ` instances
195- using the following methods:
229+ Accessing the associated ` Parameters ` instance attached to an ` InnerList ` or a ` Item ` instances
230+ is done using the following methods:
196231
197232``` php
233+ use Bakame\Http\StructuredFields\InnerList;
234+ use Bakame\Http\StructuredFields\Item;
198235use Bakame\Http\StructuredFields\Parameters;
199236
200237$field->parameter(string $key): ByteSequence|Token|DateTimeImmutable|Stringable|string|int|float|bool|null;
201238$field->parameters(): Parameters;
239+ InnerList::toPair(): array{0:list<Item >, 1:Parameters}>};
240+ Item::toPair(): array{0:ByteSequence|Token|DateTimeImmutable|Stringable|string|int|float|bool, 1:Parameters}>};
202241```
203242
204243** Of note: the ` parameter ` method will return ` null ` if no value is found for the given index.**
205244
206245### Building and Updating Structured Fields Values
207246
208- Every value object can be used as a builder to create an HTTP field value.
247+ Every value object can be used as a builder to create an HTTP field value. Because we are
248+ using immutable value objects any change to the value object will return a new instance
249+ with the changes applied and leave the original instance unchanged.
209250
210251#### Items value
211252
212- The ` Item ` value object exposes a number of named constructors to construct
253+ The ` Item ` value object exposes the following named constructors to instantiate
213254bare items (ie: item without parameters attached to them).
214255
215256``` php
@@ -232,12 +273,12 @@ Item::true(): self;
232273Item::false(): self;
233274```
234275
235- To update an ` Item ` object value, the ` Item:: withValue` method should be use :
276+ To update the ` Item ` instance value, use the ` withValue ` method:
236277
237278``` php
238279use Bakame\Http\StructuredFields\Item;
239280
240- Item::withValue(mixed $value): static
281+ Item::withValue(DateTimeInterface|ByteSequence|Token|string|int|float|bool $value): static
241282```
242283
243284#### Dictionaries
@@ -248,7 +289,7 @@ The `Dictionary` and `Parameters` instances can be build with an associative ite
248289use Bakame\Http\StructuredFields\Dictionary;
249290
250291$value = Dictionary::fromAssociative([
251- 'b' => false,
292+ 'b' => Item:: false() ,
252293 'a' => Item::fromToken('bar'),
253294 'c' => new DateTimeImmutable('2022-12-23 13:00:23'),
254295]);
@@ -257,25 +298,37 @@ echo $value->toHttpValue(); //"b=?0, a=bar, c=@1671800423"
257298echo $value; //"b=?0, a=bar, c=@1671800423"
258299```
259300
260- Or with an iterable structure of pairs as per defined in the RFC:
301+ or with an iterable structure of pairs (tuple) as defined in the RFC:
261302
262303``` php
263304use Bakame\Http\StructuredFields\Parameters;
305+ use Bakame\Http\StructuredFields\Item;
264306
265- $value = Parameters::fromPairs([
266- ['b', false],
307+ $value = Parameters::fromPairs(new ArrayIterator( [
308+ ['b', Item:: false() ],
267309 ['a', Item::fromToken('bar')],
268310 ['c', new DateTime('2022-12-23 13:00:23')]
269- ]);
311+ ])) ;
270312
271313echo $value->toHttpValue(); //;b=?0;a=bar;c=@1671800423
272314echo $value; //;b=?0;a=bar;c=@1671800423
273315```
274316
275317If the preference is to use the builder pattern, the same result can be achieved with the following steps.
276- We start building a ` Parameters ` or a ` Dictionary ` instance using the ` new ` named constructor which
277- returns a new instance with no members.
318+ First create a ` Parameters ` or a ` Dictionary ` instance using the ` new ` named constructor which
319+ returns a new instance with no members. And then, use any of the following modifying methods
320+ to populate it.
278321
322+ ``` php
323+ $map->add(string $key, $value): static;
324+ $map->append(string $key, $value): static;
325+ $map->prepend(string $key, $value): static;
326+ $map->mergeAssociative(...$others): static;
327+ $map->mergePairs(...$others): static;
328+ $map->remove(string ...$key): static;
329+ ```
330+ As shown below:
331+ `
279332``` php
280333use Bakame\Http\StructuredFields\Dictionary;
281334use Bakame\Http\StructuredFields\Item;
@@ -291,30 +344,38 @@ echo $value->toHttpValue(); //"b=?0, a=bar, c=@1671800423"
291344echo $value; //"b=?0, a=bar, c=@1671800423"
292345```
293346
294- Because we are using immutable value objects any change to the value object will return a new instance with
295- the changes applied and leave the original instance unchanged.
347+ ** Of note: For all containers, if the submitted type is not a ` StructuredField `
348+ implementing object, it will be passed to ` Item::new ` to convert it into a
349+ bare ` Item ` instances.**
296350
297- ` Dictionary ` and ` Parameters ` exhibit the following modifying methods :
351+ This means that the previous example can be rewritten like this :
298352
299353``` php
300- $map->add(string $key, $value): static;
301- $map->append(string $key, $value): static;
302- $map->prepend(string $key, $value): static;
303- $map->mergeAssociative(...$others): static;
304- $map->mergePairs(...$others): static;
305- $map->remove(string ...$key): static;
354+ use Bakame\Http\StructuredFields\Dictionary;
355+ use Bakame\Http\StructuredFields\Item;
356+ use Bakame\Http\StructuredFields\Token;
357+
358+ $value = Dictionary::new()
359+ ->add('a', 'bar')
360+ ->prepend('b', false)
361+ ->append('c', new DateTimeImmutable('2022-12-23 13:00:23'))
362+ ;
363+
364+ echo $value->toHttpValue(); //"b=?0, a=bar, c=@1671800423"
365+ echo $value; //"b=?0, a=bar, c=@1671800423"
306366```
307367
308368#### Lists
309369
310- To Create ` OuterList ` and ` InnerList ` instances you can use the ` new ` named constructor:
370+ To Create ` OuterList ` and ` InnerList ` instances you can use the ` new ` named constructor
371+ which takes fron 0 to n members:
311372
312373``` php
313374use Bakame\Http\StructuredFields\InnerList;
314- use Bakame\Http\StructuredFields\Item ;
375+ use Bakame\Http\StructuredFields\ByteSequence ;
315376
316377$list = InnerList::new(
317- Item::fromDecodedByteSequence ('Hello World'),
378+ ByteSequence::fromDecoded ('Hello World'),
318379 42.0,
319380 42
320381);
@@ -323,38 +384,38 @@ echo $list->toHttpValue(); //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
323384echo $list; //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
324385```
325386
326- Once again, builder methods exist on both classes to ease container construction.
387+ Once again, the builder pattern can be achieved with a combinason of
388+ using the ` new ` named constructor and the using any of the following
389+ modifying methods.
390+
391+ ``` php
392+ $list->unshift(...$members): static;
393+ $list->push(...$members): static;
394+ $list->insert(int $key, ...$members): static;
395+ $list->replace(int $key, $member): static;
396+ $list->remove(int ...$key): static;
397+ ```
398+
399+ as shown below
327400
328401``` php
329402use Bakame\Http\StructuredFields\ByteSequence;
330403use Bakame\Http\StructuredFields\InnerList;
331- use Bakame\Http\StructuredFields\Item;
332404
333405$list = InnerList::new()
334406 ->unshift('42')
335407 ->push(42)
336408 ->insert(1, 42.0)
337- ->replace(0, Item::new( ByteSequence::fromDecoded('Hello World') ));
409+ ->replace(0, ByteSequence::fromDecoded('Hello World'));
338410
339411echo $list->toHttpValue(); //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
340412echo $list; //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
341413```
342414
343- ` OuterList ` and ` InnerList ` exhibit the following modifying methods:
344-
345- ``` php
346- $list->unshift(...$members): static;
347- $list->push(...$members): static;
348- $list->insert(int $key, ...$members): static;
349- $list->replace(int $key, $member): static;
350- $list->remove(int ...$key): static;
351- ```
352-
353415#### Adding and updating parameters
354416
355- To ease working with instance that have a ` Parameters ` object attached to, the following
356- public API is added. It is also possible to instantiate an ` InnerList ` or an ` Item `
357- instance with included parameters using one of these named constructors:
417+ To ease working with instances that have a ` Parameters ` object attached to, the following
418+ methods are added:
358419
359420``` php
360421use Bakame\Http\StructuredFields\ByteSequence;
@@ -390,19 +451,8 @@ echo Item::fromPair([
390451//both methods return `bar;baz=42`
391452```
392453
393- Both classes allow return their respective pair representation via the ` toPair ` method.
394-
395- ``` php
396- use Bakame\Http\StructuredFields\InnerList;
397- use Bakame\Http\StructuredFields\Item;
398- use Bakame\Http\StructuredFields\Parameters;
399-
400- InnerList::toPair(): array{0:list<Item >, 1:Parameters}>};
401- Item::toPair(): array{0:mixed, 1:Parameters}>};
402- ```
403-
404454Both objects provide additional modifying methods to help deal with parameters.
405- You can attach and update the associated ` Parameters ` instance using the following methods:
455+ You can attach and update the associated ` Parameters ` instance using the following methods.
406456
407457``` php
408458use Bakame\Http\StructuredFields\Parameters;
@@ -415,6 +465,22 @@ $field->withoutAnyParameter(): static;
415465$field->withParameters(Parameters $parameters): static;
416466```
417467
468+ ** The return value will be the parent class an NOT a ` Parameters ` instance**
469+
470+ ``` php
471+ use Bakame\Http\StructuredFields\InnerList;
472+ use Bakame\Http\StructuredFields\Item;
473+
474+ echo InnerList::new('foo', 'bar')
475+ ->addParameter('expire', Item::fromDateString('+30 minutes'))
476+ ->addParameter('path', '/')
477+ ->addParameter('max-age', 2500)
478+ ->toHttpValue();
479+
480+ // return the InnerList HTTP value
481+ // ("foo" "bar");expire=@1681538756;path="/";max-age=2500
482+ ```
483+
418484## Contributing
419485
420486Contributions 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