Skip to content

Commit 43216f6

Browse files
committed
Adding Parameters::sanitize method
1 parent 29ca09e commit 43216f6

File tree

4 files changed

+104
-28
lines changed

4 files changed

+104
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ All Notable changes to `bakame/http-strucured-fields` will be documented in this
77
### Added
88

99
- `Item::fromPair` named constructor to create a new instance from a pair expressed as an array list with two values.
10+
- `Parameters::sanitize` ensure the container always contains only Bare Items.
1011

1112
### Fixed
1213

README.md

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ Structured Field Values for PHP
88
[![Total Downloads](https://img.shields.io/packagist/dt/bakame/http-structured-fields.svg?style=flat-square)](https://packagist.org/packages/bakame/http-structured-fields)
99
[![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)
1010

11-
The package uses pragmatic value objects to parse and serialize [HTTP Structured Fields][1] in PHP.
11+
The package uses value objects to parse, serialize and buikd [HTTP Structured Fields][1] in PHP.
1212

1313
HTTP Structured fields are intended for use by specifications of new HTTP fields that wish to
14-
use a common syntax that is more restrictive than traditional HTTP field values or could be
15-
used to [retrofit current headers](https://www.ietf.org/id/draft-ietf-httpbis-retrofit-00.html) to have them compliant with the new syntax.
14+
use a common syntax that is more restrictive than traditional HTTP field values or could
15+
be used to [retrofit current headers][2] to have them compliant with the new syntax.
1616

1717
The package can be used to:
1818

@@ -73,19 +73,19 @@ $item = StructuredFields\Item::fromHttpValue('"foo";a=1;b=2"');
7373
echo $item->toHttpValue(); // "foo";a=1;b=2
7474
```
7575

76-
## Manipulating Structured Fields Data Types
76+
## Structured Fields Data Types
7777

7878
The RFC defines different data types to handle structured fields values.
7979

8080
### Items
8181

82-
The Item is the minimal building block for structured fields the following explains how to build
82+
Items are the minimal building block for structured fields the following explains how to build
8383
and interact with them.
8484

8585
#### Bare Items
8686

87-
Item have different types [defined in the RFC](https://www.rfc-editor.org/rfc/rfc8941.html#section-3.3).
88-
They are translated to PHP native type when possible. Two additional classes
87+
Items can have different types [defined in the RFC][3]. They are translated to PHP native type
88+
when possible. Two additional classes
8989

9090
- `Bakame\Http\StructuredFields\Token` and
9191
- `Bakame\Http\StructuredFields\ByteSequence`
@@ -101,10 +101,10 @@ are used to represent non-native types as shown in the table below:
101101
| Token | class `Token` | `Item::isToken` |
102102
| Byte Sequence | class `ByteSequence` | `Item::isByteSequence` |
103103

104-
#### Extending Items
104+
#### Extended Items
105105

106-
As explain in the RFC, Item can be associated with `Parameters` that are ordered maps of key-value pairs, where the
107-
keys are string and the value are bare items. Their public API will be cover in subsequent paragraphs.
106+
Item can be associated with `Parameters` that are ordered maps of key-value pairs, where the
107+
keys is a string and the value are bare items. Their public API will be cover in subsequent paragraphs.
108108

109109
#### Usage
110110

@@ -123,6 +123,21 @@ $item->isToken(); //return false
123123
$item->parameters->value("a"); //returns 1
124124
```
125125

126+
Conversely, the `Item::fromPair` is an alternative to the `Item::from`
127+
which expects a tuple composed by an array as w list where:
128+
129+
- The first member on index `0` represents one of the six (6) item type value;
130+
- The second optional member, on index `1`, MUST be an iterable construct where its index represents the parameter key and its value an item or a item type value;
131+
132+
```php
133+
use Bakame\Http\StructuredFields;
134+
135+
$item = StructuredFields\Item::fromPair(["hello world", ["a" => 1]]);
136+
$item->value; //returns "hello world"
137+
$item->isString(); //return true
138+
$item->isToken(); //return false
139+
$item->parameters->value("a"); //returns 1
140+
```
126141

127142
Once instantiated, accessing `Item` properties is done via two (2) readonly properties:
128143

@@ -138,7 +153,7 @@ $decimal = StructuredFields\Item::from(42.0);
138153
$decimal->isDecimal(); //return true
139154
$decimal->isInteger(); //return false
140155

141-
$item = StructuredFields\Item::from(42);
156+
$item = StructuredFields\Item::fromPair([42]);
142157
$item->isDecimal(); //return false
143158
$item->isInteger(); //return true
144159
```
@@ -155,7 +170,7 @@ package exposes those containers via the following value objects:
155170

156171
At any given time it is possible with each of these objects to:
157172

158-
- iterate over each contained member and its optional associated key via the `IteratorAggregate` interface;
173+
- iterate over its members using the `IteratorAggregate` interface;
159174
- tell whether the container is empty via an `isEmpty` method;
160175
- know the number of members contained in the container via the `Countable` interface;
161176
- clear the container using the `clear` method;
@@ -172,51 +187,60 @@ $parameters->toHttpValue(); // return ";a=1;b=2"
172187
#### Ordered Maps
173188

174189
The `Parameters` and the `Dictionary` classes allow associating a string
175-
key to its members as such they expose the following methods:
190+
key to its members as such they expose
191+
192+
the following getter methods:
176193

177194
- `fromAssociative` a named constructor to instantiate the container with an associative array;
178195
- `fromPairs` a named constructor to instantiate the container with a list of key-value pairs;
196+
- `toPairs` returns an iterator to iterate over the container pairs;
197+
- `keys` to list all existing keys of the ordered maps as an array list;
179198
- `has` tell whether a specific element is associated to a given `key`;
180-
- `get` returns the element associated to a specific `key`;
181199
- `hasPair` tell whether a `key-value` association exists at a given `index` (negative indexes are supported);
200+
- `get` returns the element associated to a specific `key`;
182201
- `pair` returns the key-pair association present at a specific `index` (negative indexes are supported);
183-
- `pairs` returns an iterator to iterate over the container pairs;
202+
203+
the following setter methods:
204+
184205
- `set` add an element at the end of the container if the key is new otherwise only the value is updated;
185206
- `append` always add an element at the end of the container, if already present the previous value is removed;
186207
- `prepend` always add an element at the beginning of the container, if already present the previous value is removed;
187208
- `delete` to remove elements based on their associated keys;
188-
- `keys` to list all existing keys for the ordered maps as an array list;
189209
- `mergeAssociative` merge multiple instances of iterable structure as associative constructs;
190210
- `mergePairs` merge multiple instances of iterable structure as pairs constructs;
191211

212+
**All setter methods are chainable.**
213+
192214
```php
193215
use Bakame\Http\StructuredFields;
194216

195217
$dictionary = StructuredFields\Dictionary::fromPairs([['b', true]]);
196-
$dictionary->append('c', StructuredFields\Item::from(true, ['foo' => StructuredFields\Token::fromString('bar')]));
197-
$dictionary->prepend('a', false);
198-
$dictionary->toHttpValue(); //returns "a=?0, b, c;foo=bar"
218+
$dictionary
219+
->append('c', StructuredFields\Item::from(true, ['foo' => StructuredFields\Token::fromString('bar')]))
220+
->prepend('a', false)
221+
->toHttpValue(); //returns "a=?0, b, c;foo=bar"
222+
199223
$dictionary->has('a'); //return true
200224
$dictionary->has('foo'); //return false
201225
$dictionary->pair(1); //return ['b', Item::fromBoolean(true)]
202226
$dictionary->hasPair(-1); //return true
203-
$dictionary->append('z', 42.0);
204-
$dictionary->delete('b', 'c');
205-
echo $dictionary->toHttpValue(); //returns "a=?0, z=42.0"
227+
228+
echo $dictionary
229+
->append('z', 42.0)
230+
->delete('b', 'c')
231+
->toHttpValue(); //returns "a=?0, z=42.0"
206232
```
207233

208234
**Item types are inferred using `Item::from` if a `Item` object is not submitted.**
209235

210-
**EVERY CHANGE IN THE ORDERED MAP WILL RE-INDEX THE PAIRS AS TO NOT EXPOSE MISSING INDEXES**
211-
212236
- `Parameters` can only contains `Item` instances
213237
- `Dictionary` instance can contain `Item` and `InnerList` instances.
214238

215-
The `Parameters` instance exposes the following methods:
239+
The `Parameters` instance exposes the following additional methods:
216240

217-
- `Parameters::values` to list all existing Bare Items value as an array list;
241+
- `Parameters::values()` to list all existing Bare Items value as an array list;
218242
- `Parameters::value(string $key)` to return the value of the Bare Item associated to the `$key` or `null` if the key is unknown or invalid;
219-
- `Parameters::merge` also accepts iterable as associative key-value as part of the variadic signature.
243+
- `Parameters::sanitize()` to return an instance where all Items present in the container are Bare Items. Any non Bared Item instance will see its parameters getting clear up.
220244

221245
```php
222246
use Bakame\Http\StructuredFields;
@@ -239,12 +263,17 @@ $parameters->value('unknown'); // returns null
239263
#### Lists
240264

241265
The `OrderedList` and the `InnerList` classes are list of members
242-
that act as containers and also expose the following methods
266+
that act as containers and also expose the following
267+
268+
getter methods:
243269

244270
- `fromList` a named constructor to instantiate the container with a list of members in an iterable construct;
245271
- `from` a named constructor to instantiate the container with a list of members as variadic;
246272
- `get` to access an element at a given index (negative indexes are supported)
247273
- `has` tell whether an element is attached to the container using its `index`;
274+
275+
setter methods (**All setter methods are chainable.**)
276+
248277
- `push` to add elements at the end of the list;
249278
- `unshift` to add elements at the beginning of the list;
250279
- `insert` to add elements at a given position in the list;
@@ -332,3 +361,5 @@ License
332361
The MIT License (MIT). Please see [License File](LICENSE) for more information.
333362

334363
[1]: https://www.rfc-editor.org/rfc/rfc8941.html
364+
[2]: https://www.ietf.org/id/draft-ietf-httpbis-retrofit-00.html
365+
[3]: https://www.rfc-editor.org/rfc/rfc8941.html#section-3.3

src/Parameters.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,4 +395,21 @@ public function mergePairs(Parameters|iterable ...$others): self
395395

396396
return $this;
397397
}
398+
399+
/**
400+
* Ensure the container always contains only Bare Items.
401+
*
402+
* If Item with parameters exists they will be strip from the object
403+
* before returning the parent instance
404+
*/
405+
public function sanitize(): self
406+
{
407+
$this->members = array_map(function (Item $item): Item {
408+
$item->parameters->clear();
409+
410+
return $item;
411+
}, $this->members);
412+
413+
return $this;
414+
}
398415
}

src/ParametersTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,4 +332,31 @@ public function it_successfully_parse_a_parameter_value_with_optional_white_spac
332332
Parameters::fromHttpValue(' ;foo=bar')
333333
);
334334
}
335+
336+
/**
337+
* @test
338+
*/
339+
public function it_fails_creating_an_object_with_an_already_defined_parameter_configuration(): void
340+
{
341+
$this->expectException(StructuredFieldError::class);
342+
343+
$parameters = Parameters::fromAssociative(['a' => false]);
344+
$item = $parameters->get('a');
345+
$item->parameters->set('b', true);
346+
self::assertSame('?0;b', $item->toHttpValue());
347+
348+
$parameters->toHttpValue();
349+
}
350+
351+
/**
352+
* @test
353+
*/
354+
public function it_can_serialize_after_sanitizing_the_parameters(): void
355+
{
356+
$parameters = Parameters::fromAssociative(['a' => false]);
357+
$item = $parameters->get('a');
358+
$item->parameters->set('b', true);
359+
360+
self::assertSame(';a=?0', $parameters->sanitize()->toHttpValue());
361+
}
335362
}

0 commit comments

Comments
 (0)