@@ -50,7 +50,186 @@ echo $list[-1]->value(); // returns '/member/*/comments'
50
50
51
51
## Documentation
52
52
53
- Full documentation can be found in the [ docs] ( /docs ) .
53
+ ### Parsing and Serializing Structured Fields
54
+
55
+ To parse an HTTP field you may use the ` fromHttpValue ` named constructor provided by all the
56
+ immutable value objects:
57
+
58
+ ``` php
59
+ use Bakame\Http\StructuredFields\Dictionary;
60
+
61
+ $dictionary = Dictionary::fromHttpValue("a=?0, b, c=?1; foo=bar");
62
+ ```
63
+
64
+ The ` fromHttpValue ` named constructor returns an instance of the ` Bakame\Http\StructuredFields\StructuredField ` interface
65
+ which provides a way to serialize back the object into a normalized RFC compliant HTTP field using the ` toHttpValue ` method.
66
+
67
+ To ease integration with current PHP frameworks and packages working with HTTP headers and trailers, each value object
68
+ also exposes the ` Stringable ` interface method ` __toString ` which is an alias of the ` toHttpValue ` method.
69
+
70
+ ```` php
71
+ use Bakame\Http\StructuredFields\OuterList;
72
+
73
+ $list = OuterList::fromHttpValue('("foo"; a=1;b=2);lvl=5, ("bar" "baz");lvl=1');
74
+ echo $list->toHttpValue(); // '("foo";a=1;b=2);lvl=5, ("bar" "baz");lvl=1'
75
+ echo $list; // '("foo";a=1;b=2);lvl=5, ("bar" "baz");lvl=1'
76
+ ````
77
+
78
+ The library provides currently five (5) immutable value objects define inside the ` Bakame\Http\StructuredFields ` namespace:
79
+
80
+ - an [ Item] ( item.md ) ;
81
+ - a [ 2 Ordered Map Containers] ( ordered-maps.md ) ` Dictionary ` and ` Parameters ` ;
82
+ - a [ 2 List Containers] ( lists.md ) ` OuterList ` and ` InnerList ` ;
83
+
84
+ All five of them implement the ` StructuredField ` interface and expose a ` fromHttpValue ` named constructor.
85
+
86
+ ### Building and Updating Structured Fields
87
+
88
+ Creating or updating an HTTP field value can be achieved using any of our immutable value object as a starting point.
89
+
90
+ For instance Ordered Map Containers can be build with an associative iterable as shown below
91
+
92
+ ``` php
93
+ use Bakame\Http\StructuredFields\Dictionary;
94
+
95
+ $value = Dictionary::fromAssociative([
96
+ 'b' => false,
97
+ 'a' => Item::fromToken('bar', ['baz' => 42]),
98
+ 'c' => new DateTimeImmutable('2022-12-23 13:00:23'),
99
+ ]);
100
+
101
+ echo $value->toHttpValue(); //"b=?0, a=bar;baz=42, c=@1671800423"
102
+ echo $value; //"b=?0, a=bar;baz=42, c=@1671800423"
103
+ ```
104
+
105
+ Or with an iterable of pairs as described in the RFC:
106
+
107
+ ``` php
108
+ use Bakame\Http\StructuredFields\Parameters;
109
+
110
+ $value = Parameters::fromPairs([
111
+ ['b', false],
112
+ ['a', Item::fromPair([Token::fromString('bar')])],
113
+ ['c', new DateTime('2022-12-23 13:00:23')]
114
+ ]);
115
+
116
+ echo $value->toHttpValue(); //;b=?0;a=bar;c=@1671800423
117
+ echo $value; //;b=?0;a=bar;c=@1671800423
118
+ ```
119
+
120
+ If builder methods are preferred, the same result can be achieved with the following steps:
121
+
122
+ ``` php
123
+ use Bakame\Http\StructuredFields\Dictionary;
124
+ use Bakame\Http\StructuredFields\Item;
125
+ use Bakame\Http\StructuredFields\Token;
126
+
127
+ $bar = Item::fromToken('bar')
128
+ ->addParameter('baz', Item::from(42));
129
+ $dictBuilder = Dictionary::create()
130
+ ->add('a', $bar)
131
+ ->prepend('b', Item::from(false))
132
+ ->append('c', Item::from(new DateTimeImmutable('2022-12-23 13:00:23')))
133
+ ;
134
+
135
+ echo $value->toHttpValue(); //"b=?0, a=bar;baz=42, c=@1671800423"
136
+ echo $value; //"b=?0, a=bar;baz=42, c=@1671800423"
137
+ ```
138
+
139
+ Because we are using immutable value object any change to the value object will return a new instance with
140
+ the changes implemented and leave the original instance unchanged.
141
+
142
+ The same changes can be applied to List Containers but with adapted methods around list handling:
143
+
144
+ ``` php
145
+ use Bakame\Http\StructuredFields\InnerList;
146
+ use Bakame\Http\StructuredFields\Item;
147
+
148
+ $list = InnerList::from()
149
+ ->unshift('42')
150
+ ->push(42)
151
+ ->insert(1, 42.0)
152
+ ->replace(0, Item::fromDecodedByteSequence('Hello World'));
153
+
154
+ echo $list->toHttpValue(); //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
155
+ echo $list; //'(:SGVsbG8gV29ybGQ=: 42.0 42)'
156
+ ```
157
+
158
+ ### Item and RFC Data Types
159
+
160
+ To handle an item, the package provide a specific ` Item ` value obhject with additional named constructors
161
+ Items can have different types that are translated to PHP using:
162
+
163
+ - native type where possible
164
+ - specific classes defined in the package namespace to represent non-native type
165
+
166
+ The table below summarizes the item value type.
167
+
168
+ | HTTP DataType | Package Data Type | Package Enum Type |
169
+ | ---------------| ---------------------------| ----------------------|
170
+ | Integer | ` int ` | ` Type::Integer ` |
171
+ | Decimal | ` float ` | ` Type::Decimal ` |
172
+ | String | ` string ` | ` Tyoe::String ` |
173
+ | Boolean | ` bool ` | ` Type::Boolean ` |
174
+ | Token | class ` Token ` | ` Type::Token ` |
175
+ | Byte Sequence | class ` ByteSequence ` | ` Type::ByteSequence ` |
176
+ | Date | class ` DateTimeImmutable ` | ` Type::Date ` |
177
+
178
+ ``` php
179
+ use Bakame\Http\StructuredFields\ByteSequence;
180
+ use Bakame\Http\StructuredFields\Item;
181
+
182
+ $item = Item::fromPair([
183
+ "hello world", [
184
+ ["a", ByteSequence::fromDecoded("Hello World")],
185
+ ]
186
+ ]);
187
+ $item->value(); // returns "hello world"
188
+ $item->type(); // returns Type::String
189
+ $item->parameters()["a"]->type(); // returns Type::ByteSequence
190
+ $item->parameters()["a"]->value(); // returns StructuredFields\ByteSequence::fromDecoded('Hello World');
191
+ echo $item->toHttpValue(); // returns "hello world";a=:SGVsbG8gV29ybGQ=:
192
+ ```
193
+
194
+ Once again it is possible to simplify this code using the following technique:
195
+
196
+ ``` php
197
+ use Bakame\Http\StructuredFields\ByteSequence;
198
+ use Bakame\Http\StructuredFields\Item;
199
+
200
+ $item = Item::from("hello world", [
201
+ "a" => Item::fromDecodedByteSequence("Hello World")
202
+ ]);
203
+ $item->value(); // returns "hello world"
204
+ $item->type(); // returns Type::String
205
+ $item->parameters()["a"]->value(); // returns StructuredFields\ByteSequence::fromDecoded('Hello World');
206
+ $item->parameters()["a"]->type(); // returns Type::ByteSequence
207
+ echo $item->toHttpValue(); // returns "hello world";a=:SGVsbG8gV29ybGQ=:
208
+ ```
209
+
210
+ The RFC define two (2) specific data types that can not be represented by PHP default type system, for them, we define
211
+ two classes ` Token ` and ` ByteSequence ` to help representing them in our code.
212
+
213
+ ``` php
214
+ use Bakame\Http\StructuredFields\Token;
215
+ use Bakame\Http\StructuredFields\ByteSequence;
216
+
217
+ Token::fromString(string|Stringable $value): self; // from a value and an associate iterable of parameters
218
+ ByteSequence::fromDecoded(string|Stringable $value): self; // a string to convert to a Token and an associate iterable of parameters
219
+ ByteSequence::fromEncoded(string|Stringable $value): self; // a string to convert to a Byte Sequence and an associate iterable of parameters
220
+ ```
221
+
222
+ ** Of note: to instantiate a decimal number type a float MUST be used as the first argument of ` Item::from ` .**
223
+
224
+ ``` php
225
+ use Bakame\Http\StructuredFields\Item;
226
+
227
+ $decimal = Item::from(42.0);
228
+ $decimal->type(); //Type::Decimal
229
+
230
+ $integer = Item::fromPair([42]);
231
+ $integer->type(); //return Type::Integer
232
+ ```
54
233
55
234
## Contributing
56
235
0 commit comments