10
10
` bakame/http-structured-fields ` is a framework-agnostic PHP library that allows you to parse, serialize
11
11
build and update HTTP Structured Fields in PHP according to the [ RFC8941] ( https://www.rfc-editor.org/rfc/rfc8941.html ) .
12
12
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
+
13
51
## System Requirements
14
52
15
53
** PHP >= 8.1** is required but the latest stable version of PHP is recommended.
@@ -26,8 +64,8 @@ composer require bakame/http-structured-fields
26
64
27
65
### Parsing and Serializing Structured Fields
28
66
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:
31
69
32
70
``` php
33
71
declare(strict_types=1);
@@ -47,12 +85,10 @@ $field->parameter('baz'); // returns 42; the value of the parameter or null if t
47
85
```
48
86
49
87
The ` 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 .
52
90
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.
56
92
57
93
```` php
58
94
use Bakame\Http\StructuredFields\Item;
@@ -69,8 +105,8 @@ $newResponse = $response->headers->set('foo', $bar->toHttpValue());
69
105
$newResponse = $response->headers->set('foo', $bar);
70
106
````
71
107
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
74
110
` StructuredField ` interface and expose a ` fromHttpValue ` named constructor:
75
111
76
112
- ` Item `
@@ -100,9 +136,9 @@ The table below summarizes the item value type.
100
136
| Byte Sequence | class ` ByteSequence ` | ` Type::ByteSequence ` |
101
137
| Date | class ` DateTimeImmutable ` | ` Type::Date ` |
102
138
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.
106
142
107
143
``` php
108
144
use Bakame\Http\StructuredFields\Token;
@@ -139,7 +175,7 @@ from a string or a string like object**
139
175
140
176
#### Item
141
177
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
143
179
are accessible using the following methods:
144
180
145
181
``` php
@@ -155,8 +191,8 @@ Type::Date->equals($item); // returns true
155
191
156
192
#### Containers
157
193
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
160
196
161
197
``` php
162
198
$container->keys(): array<string >;
@@ -166,7 +202,7 @@ $container->hasMembers(): bool;
166
202
$container->hasNoMembers(): bool;
167
203
```
168
204
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 `
170
206
if you try to use them on any container object:
171
207
172
208
``` php
@@ -180,8 +216,7 @@ $value['a'] = 23 // triggers a ForbiddenOperation exception
180
216
unset($value['a']); // triggers a ForbiddenOperation exception
181
217
```
182
218
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:
185
220
186
221
``` php
187
222
$container->hasPair(int ...$offsets): bool;
@@ -191,25 +226,31 @@ $container->toPairs(): iterable<array{0:string, 1:StructuredField}>;
191
226
192
227
#### Accessing the parameters values
193
228
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:
196
231
197
232
``` php
233
+ use Bakame\Http\StructuredFields\InnerList;
234
+ use Bakame\Http\StructuredFields\Item;
198
235
use Bakame\Http\StructuredFields\Parameters;
199
236
200
237
$field->parameter(string $key): ByteSequence|Token|DateTimeImmutable|Stringable|string|int|float|bool|null;
201
238
$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}>};
202
241
```
203
242
204
243
** Of note: the ` parameter ` method will return ` null ` if no value is found for the given index.**
205
244
206
245
### Building and Updating Structured Fields Values
207
246
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.
209
250
210
251
#### Items value
211
252
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
213
254
bare items (ie: item without parameters attached to them).
214
255
215
256
``` php
@@ -232,12 +273,12 @@ Item::true(): self;
232
273
Item::false(): self;
233
274
```
234
275
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:
236
277
237
278
``` php
238
279
use Bakame\Http\StructuredFields\Item;
239
280
240
- Item::withValue(mixed $value): static
281
+ Item::withValue(DateTimeInterface|ByteSequence|Token|string|int|float|bool $value): static
241
282
```
242
283
243
284
#### Dictionaries
@@ -248,7 +289,7 @@ The `Dictionary` and `Parameters` instances can be build with an associative ite
248
289
use Bakame\Http\StructuredFields\Dictionary;
249
290
250
291
$value = Dictionary::fromAssociative([
251
- 'b' => false,
292
+ 'b' => Item:: false() ,
252
293
'a' => Item::fromToken('bar'),
253
294
'c' => new DateTimeImmutable('2022-12-23 13:00:23'),
254
295
]);
@@ -257,25 +298,37 @@ echo $value->toHttpValue(); //"b=?0, a=bar, c=@1671800423"
257
298
echo $value; //"b=?0, a=bar, c=@1671800423"
258
299
```
259
300
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:
261
302
262
303
``` php
263
304
use Bakame\Http\StructuredFields\Parameters;
305
+ use Bakame\Http\StructuredFields\Item;
264
306
265
- $value = Parameters::fromPairs([
266
- ['b', false],
307
+ $value = Parameters::fromPairs(new ArrayIterator( [
308
+ ['b', Item:: false() ],
267
309
['a', Item::fromToken('bar')],
268
310
['c', new DateTime('2022-12-23 13:00:23')]
269
- ]);
311
+ ])) ;
270
312
271
313
echo $value->toHttpValue(); //;b=?0;a=bar;c=@1671800423
272
314
echo $value; //;b=?0;a=bar;c=@1671800423
273
315
```
274
316
275
317
If 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.
278
321
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
+ `
279
332
``` php
280
333
use Bakame\Http\StructuredFields\Dictionary;
281
334
use Bakame\Http\StructuredFields\Item;
@@ -291,30 +344,38 @@ echo $value->toHttpValue(); //"b=?0, a=bar, c=@1671800423"
291
344
echo $value; //"b=?0, a=bar, c=@1671800423"
292
345
```
293
346
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.**
296
350
297
- ` Dictionary ` and ` Parameters ` exhibit the following modifying methods :
351
+ This means that the previous example can be rewritten like this :
298
352
299
353
``` 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"
306
366
```
307
367
308
368
#### Lists
309
369
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:
311
372
312
373
``` php
313
374
use Bakame\Http\StructuredFields\InnerList;
314
- use Bakame\Http\StructuredFields\Item ;
375
+ use Bakame\Http\StructuredFields\ByteSequence ;
315
376
316
377
$list = InnerList::new(
317
- Item::fromDecodedByteSequence ('Hello World'),
378
+ ByteSequence::fromDecoded ('Hello World'),
318
379
42.0,
319
380
42
320
381
);
@@ -323,38 +384,38 @@ echo $list->toHttpValue(); //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
323
384
echo $list; //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
324
385
```
325
386
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
327
400
328
401
``` php
329
402
use Bakame\Http\StructuredFields\ByteSequence;
330
403
use Bakame\Http\StructuredFields\InnerList;
331
- use Bakame\Http\StructuredFields\Item;
332
404
333
405
$list = InnerList::new()
334
406
->unshift('42')
335
407
->push(42)
336
408
->insert(1, 42.0)
337
- ->replace(0, Item::new( ByteSequence::fromDecoded('Hello World') ));
409
+ ->replace(0, ByteSequence::fromDecoded('Hello World'));
338
410
339
411
echo $list->toHttpValue(); //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
340
412
echo $list; //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
341
413
```
342
414
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
-
353
415
#### Adding and updating parameters
354
416
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:
358
419
359
420
``` php
360
421
use Bakame\Http\StructuredFields\ByteSequence;
@@ -390,19 +451,8 @@ echo Item::fromPair([
390
451
//both methods return `bar;baz=42`
391
452
```
392
453
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
-
404
454
Both 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.
406
456
407
457
``` php
408
458
use Bakame\Http\StructuredFields\Parameters;
@@ -415,6 +465,22 @@ $field->withoutAnyParameter(): static;
415
465
$field->withParameters(Parameters $parameters): static;
416
466
```
417
467
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
+
418
484
## Contributing
419
485
420
486
Contributions 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