Skip to content

Commit 46570b3

Browse files
committed
Improve documentation
1 parent c406d6c commit 46570b3

File tree

1 file changed

+137
-71
lines changed

1 file changed

+137
-71
lines changed

README.md

Lines changed: 137 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,44 @@
1010
`bakame/http-structured-fields` is a framework-agnostic PHP library that allows you to parse, serialize
1111
build 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
3371
declare(strict_types=1);
@@ -47,12 +85,10 @@ $field->parameter('baz'); // returns 42; the value of the parameter or null if t
4785
```
4886

4987
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.
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
5894
use 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
108144
use 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
143179
are 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`
170206
if you try to use them on any container object:
171207

172208
```php
@@ -180,8 +216,7 @@ $value['a'] = 23 // triggers a ForbiddenOperation exception
180216
unset($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;
198235
use 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
213254
bare items (ie: item without parameters attached to them).
214255

215256
```php
@@ -232,12 +273,12 @@ Item::true(): self;
232273
Item::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
238279
use 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
248289
use 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"
257298
echo $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
263304
use 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

271313
echo $value->toHttpValue(); //;b=?0;a=bar;c=@1671800423
272314
echo $value; //;b=?0;a=bar;c=@1671800423
273315
```
274316

275317
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.
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
280333
use Bakame\Http\StructuredFields\Dictionary;
281334
use Bakame\Http\StructuredFields\Item;
@@ -291,30 +344,38 @@ echo $value->toHttpValue(); //"b=?0, a=bar, c=@1671800423"
291344
echo $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
313374
use 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)'
323384
echo $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
329402
use Bakame\Http\StructuredFields\ByteSequence;
330403
use 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

339411
echo $list->toHttpValue(); //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
340412
echo $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
360421
use 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-
404454
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.
406456

407457
```php
408458
use 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

420486
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

Comments
 (0)