Skip to content

Commit d9129ff

Browse files
committed
#3 implementing ArrayAccess for list containers
1 parent 0427906 commit d9129ff

File tree

6 files changed

+221
-3
lines changed

6 files changed

+221
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ All Notable changes to `bakame/http-strucured-fields` will be documented in this
99
- `Item::fromPair` named constructor to create a new instance from a pair expressed as an array list with two values.
1010
- `Parameters::sanitize` ensure the container always contains only Bare Items.
1111
- `autoload.php` script to allow non composer application to load the package
12+
- `OrderedList` and `InnerList` now implements the PHP `ArrayAccess` interface.
1213

1314
### Fixed
1415

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,32 @@ setter methods
367367
- `replace` to replace an element at a given position in the list;
368368
- `remove` to remove elements based on their position;
369369

370+
Additionally, both classes implements PHP `ArrayAccess` interface as syntactic sugar methods
371+
around the `get`, `has`, `push`, `remove` and `replace` methods.
372+
373+
```php
374+
use Bakame\Http\StructuredFields;
375+
376+
$innerList = StructuredFields\InnerList::fromList([42, 42.0, "42"], ["a" => true]);
377+
isset($innerList[2]); //return true
378+
isset($innerList[42]); //return false
379+
$innerList[] = StructuredFields\Token::fromString('forty-two');
380+
unset($innerList[0]);
381+
unset($innerList[1]); //<-- we use `1` instead of 2 because of re-indexation !!!
382+
echo $innerList->toHttpValue(); //returns '(42.0 forty-two);a'
383+
```
384+
385+
**if you try to set a key which does not exist an exception will be thrown as both
386+
classes must remain valid lists with no empty keys.
387+
Be aware that re-indexation behaviour may affect your logic**
388+
389+
```php
390+
use Bakame\Http\StructuredFields;
391+
392+
$innerList = StructuredFields\OrderedList::fromList([42, 42.0, "42"], ["a" => true]);
393+
$innerList[2] = StructuredFields\Token::fromString('forty-two'); // will throw
394+
```
395+
370396
A `Parameters` instance can be associated to an `InnerList` using the same API as for the `Item` value object.
371397

372398
```php

src/InnerList.php

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Bakame\Http\StructuredFields;
66

7+
use ArrayAccess;
78
use Countable;
89
use Iterator;
910
use IteratorAggregate;
@@ -14,9 +15,10 @@
1415
use function count;
1516

1617
/**
17-
* @implements IteratorAggregate<array-key, Item>
18+
* @implements IteratorAggregate<int, Item>
19+
* @implements ArrayAccess<int, Item>
1820
*/
19-
final class InnerList implements Countable, IteratorAggregate, StructuredField
21+
final class InnerList implements ArrayAccess, Countable, IteratorAggregate, StructuredField
2022
{
2123
/** @var array<Item> */
2224
private array $members;
@@ -201,4 +203,56 @@ public function clear(): self
201203

202204
return $this;
203205
}
206+
207+
/**
208+
* @param int $offset the integer index of the member to validate.
209+
*
210+
* @see ::has
211+
*/
212+
public function offsetExists($offset): bool
213+
{
214+
return $this->has($offset);
215+
}
216+
217+
/**
218+
*
219+
* @param int $offset the integer index of the member to retrieve.
220+
*
221+
* @see ::get
222+
*/
223+
public function offsetGet($offset): Item
224+
{
225+
return $this->get($offset);
226+
}
227+
228+
/**
229+
*
230+
* @param int $offset the integer index of the member to remove
231+
*
232+
* @see ::remove
233+
*
234+
*/
235+
public function offsetUnset($offset): void
236+
{
237+
$this->remove($offset);
238+
}
239+
240+
/**
241+
*
242+
* @param int|null $offset the integer index of member to add or update
243+
* @param Item|ByteSequence|Token|bool|int|float|string $value the member to add
244+
*
245+
* @see ::push
246+
* @see ::insert
247+
*/
248+
public function offsetSet($offset, $value): void
249+
{
250+
if (null !== $offset) {
251+
$this->replace($offset, $value);
252+
253+
return;
254+
}
255+
256+
$this->push($value);
257+
}
204258
}

src/InnerListTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,45 @@ public function it_successfully_parse_a_http_field_with_optional_white_spaces_in
173173
InnerList::fromHttpValue(' ("hello)world" 42 42.0;john=doe);foo="bar("')
174174
);
175175
}
176+
177+
/**
178+
* @test
179+
*/
180+
public function it_implements_the_array_access_interface(): void
181+
{
182+
$sequence = InnerList::fromList();
183+
$sequence[] = 42;
184+
185+
self::assertTrue(isset($sequence[0]));
186+
self::assertEquals(42, $sequence[0]->value);
187+
188+
$sequence[0] = false;
189+
190+
self::assertNotEquals(42, $sequence[0]->value);
191+
unset($sequence[0]);
192+
193+
self::assertCount(0, $sequence);
194+
}
195+
196+
/**
197+
* @test
198+
*/
199+
public function it_fails_to_insert_unknown_index_via_the_array_access_interface(): void
200+
{
201+
$this->expectException(StructuredFieldError::class);
202+
203+
$sequence = InnerList::fromList();
204+
$sequence[0] = Item::from(42.0);
205+
}
206+
207+
/**
208+
* @test
209+
*/
210+
public function testArrayAccessThrowsInvalidIndex2(): void
211+
{
212+
$sequence = InnerList::from();
213+
unset($sequence[0]);
214+
215+
self::assertCount(0, $sequence);
216+
}
176217
}

src/OrderedList.php

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Bakame\Http\StructuredFields;
66

7+
use ArrayAccess;
78
use Countable;
89
use Iterator;
910
use IteratorAggregate;
@@ -16,8 +17,9 @@
1617

1718
/**
1819
* @implements IteratorAggregate<array-key, Item|InnerList>
20+
* @implements ArrayAccess<int, Item|InnerList>
1921
*/
20-
final class OrderedList implements Countable, IteratorAggregate, StructuredField
22+
final class OrderedList implements ArrayAccess, Countable, IteratorAggregate, StructuredField
2123
{
2224
/** @var array<Item|InnerList> */
2325
private array $members;
@@ -211,4 +213,56 @@ public function clear(): self
211213

212214
return $this;
213215
}
216+
217+
/**
218+
* @param int $offset the integer index of the member to validate.
219+
*
220+
* @see ::has
221+
*/
222+
public function offsetExists($offset): bool
223+
{
224+
return $this->has($offset);
225+
}
226+
227+
/**
228+
*
229+
* @param int $offset the integer index of the member to retrieve.
230+
*
231+
* @see ::get
232+
*/
233+
public function offsetGet($offset): Item|InnerList
234+
{
235+
return $this->get($offset);
236+
}
237+
238+
/**
239+
*
240+
* @param int $offset the integer index of the member to remove
241+
*
242+
* @see ::remove
243+
*
244+
*/
245+
public function offsetUnset($offset): void
246+
{
247+
$this->remove($offset);
248+
}
249+
250+
/**
251+
*
252+
* @param int|null $offset the integer index of member to add or update
253+
* @param InnerList|Item|ByteSequence|Token|bool|int|float|string $value the member to add
254+
*
255+
* @see ::push
256+
* @see ::insert
257+
*/
258+
public function offsetSet($offset, $value): void
259+
{
260+
if (null !== $offset) {
261+
$this->replace($offset, $value);
262+
263+
return;
264+
}
265+
266+
$this->push($value);
267+
}
214268
}

src/OrderedListTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,46 @@ public function test_it_can_generate_the_same_value(): void
144144

145145
self::assertSame($res->toHttpValue(), $list->toHttpValue());
146146
}
147+
148+
/**
149+
* @test
150+
*/
151+
public function it_implements_the_array_access_interface(): void
152+
{
153+
$sequence = OrderedList::fromList();
154+
$sequence[] = InnerList::from(42, 69);
155+
156+
self::assertTrue(isset($sequence[0]));
157+
self::assertInstanceOf(InnerList::class, $sequence[0]);
158+
self::assertEquals(42, $sequence[0]->get(0)->value);
159+
160+
$sequence[0] = false;
161+
162+
self::assertEquals(Item::from(false), $sequence[0]);
163+
unset($sequence[0]);
164+
165+
self::assertFalse(isset($sequence[0]));
166+
}
167+
168+
/**
169+
* @test
170+
*/
171+
public function it_fails_to_insert_unknown_index_via_the_array_access_interface(): void
172+
{
173+
$this->expectException(StructuredFieldError::class);
174+
175+
$sequence = OrderedList::fromList();
176+
$sequence[0] = Item::from(42.0);
177+
}
178+
179+
/**
180+
* @test
181+
*/
182+
public function testArrayAccessThrowsInvalidIndex2(): void
183+
{
184+
$sequence = OrderedList::from();
185+
unset($sequence[0]);
186+
187+
self::assertCount(0, $sequence);
188+
}
147189
}

0 commit comments

Comments
 (0)