Skip to content

Commit 963abd5

Browse files
committed
SDK-766: Immutable document images
1 parent d5ed053 commit 963abd5

File tree

4 files changed

+223
-7
lines changed

4 files changed

+223
-7
lines changed

src/Yoti/Entity/MultiValue.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ class MultiValue extends \ArrayObject
88
*/
99
private $originalItems = [];
1010

11+
/**
12+
* @var boolean Flag to make MultiValue immutable.
13+
*/
14+
private $isImmutable = false;
15+
1116
/**
1217
* @var callable[] Filter callbacks.
1318
*/
@@ -32,6 +37,7 @@ public function __construct($items)
3237
*/
3338
public function filter($callback)
3439
{
40+
$this->assertMutable('Attempting to filter immutable array');
3541
$this->filters[] = $callback;
3642
$this->applyFilters();
3743
return $this;
@@ -42,6 +48,11 @@ public function filter($callback)
4248
*/
4349
private function applyFilters()
4450
{
51+
// Only apply filters if this is mutable.
52+
if ($this->isImmutable) {
53+
return;
54+
}
55+
4556
// Reset to original items before filtering.
4657
$this->exchangeArray($this->originalItems);
4758

@@ -116,8 +127,79 @@ public function filterType($type)
116127
*/
117128
public function resetFilters()
118129
{
130+
$this->assertMutable('Attempting to reset filters on immutable array');
119131
$this->filters = [];
120132
$this->applyFilters();
121133
return $this;
122134
}
135+
136+
137+
/**
138+
* Make this MultiValue Immutable.
139+
*
140+
* @return MultiValue
141+
*/
142+
public function immutable()
143+
{
144+
$this->isImmutable = true;
145+
146+
// Lock nested items.
147+
foreach ($this->getArrayCopy() as $item) {
148+
if ($item instanceof MultiValue) {
149+
$item->immutable();
150+
}
151+
}
152+
return $this;
153+
}
154+
155+
/**
156+
* @inheritDoc
157+
*/
158+
public function append($value)
159+
{
160+
$this->assertMutable('Attempting to append to immutable array');
161+
parent::append($value);
162+
}
163+
164+
/**
165+
* @inheritDoc
166+
*/
167+
public function exchangeArray($input)
168+
{
169+
$this->assertMutable('Attempting to change immutable array');
170+
parent::exchangeArray($input);
171+
}
172+
173+
/**
174+
* @inheritDoc
175+
*/
176+
public function offsetSet($index, $newval)
177+
{
178+
$this->assertMutable('Attempting to add to immutable array');
179+
parent::offsetSet($index, $newval);
180+
}
181+
182+
/**
183+
* @inheritDoc
184+
*/
185+
public function offsetUnset($index)
186+
{
187+
$this->assertMutable('Attempting to remove from immutable array');
188+
parent::offsetUnset($index);
189+
}
190+
191+
/**
192+
* Asserts that this MultiValue is mutable.
193+
*
194+
* @param string $message
195+
* Used as Exception message when immutable.
196+
*
197+
* @throws \LogicException
198+
*/
199+
private function assertMutable($message)
200+
{
201+
if ($this->isImmutable) {
202+
throw new \LogicException($message);
203+
}
204+
}
123205
}

src/Yoti/Util/Profile/AttributeConverter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ private static function convertValueBasedOnAttributeName($value, $attrName)
4141
}
4242
return $value
4343
->filterInstance(Image::class)
44-
->getArrayCopy();
44+
->immutable();
4545

4646
default:
4747
return $value;

tests/Entity/MultiValueTest.php

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,138 @@ public function testMultiValueResetFilters()
170170
$this->assertCount(3, $this->multiValue[6]);
171171
$this->assertInstanceOf(Image::class, $this->multiValue[6][2]);
172172
}
173+
174+
/**
175+
* @covers ::immutable
176+
* @covers ::filter
177+
*
178+
* @expectedException \LogicException
179+
* @expectedExceptionMessage Attempting to filter immutable array
180+
*/
181+
public function testImmutableFilter()
182+
{
183+
$this->multiValue->immutable()->filter(function ($item) {
184+
return $item instanceof MultiValue;
185+
});
186+
}
187+
188+
/**
189+
* @covers ::immutable
190+
* @covers ::filterType
191+
*
192+
* @expectedException \LogicException
193+
* @expectedExceptionMessage Attempting to filter immutable array
194+
*/
195+
public function testImmutableFilterType()
196+
{
197+
$this->multiValue->immutable()->filterType('string');
198+
}
199+
200+
/**
201+
* @covers ::immutable
202+
* @covers ::filterInstance
203+
*
204+
* @expectedException \LogicException
205+
* @expectedExceptionMessage Attempting to filter immutable array
206+
*/
207+
public function testImmutableFilterInstance()
208+
{
209+
$this->multiValue->immutable()->filterInstance(Image::class);
210+
}
211+
212+
/**
213+
* @covers ::immutable
214+
* @covers ::resetFilters
215+
*
216+
* @expectedException \LogicException
217+
* @expectedExceptionMessage Attempting to reset filters on immutable array
218+
*/
219+
public function testImmutableResetFilters()
220+
{
221+
// Apply image filter.
222+
$this->multiValue
223+
->filterInstance(Image::class);
224+
$this->assertCount(2, $this->multiValue);
225+
226+
// Reset filters.
227+
$this->multiValue->resetFilters();
228+
$this->assertCount(8, $this->multiValue);
229+
230+
// Make immutable.
231+
$this->multiValue->immutable();
232+
233+
// Filters cannot be reset.
234+
$this->multiValue->resetFilters();
235+
}
236+
237+
/**
238+
* @covers ::append
239+
* @covers ::immutable
240+
*
241+
* @expectedException \LogicException
242+
* @expectedExceptionMessage Attempting to append to immutable array
243+
*/
244+
public function testImmutableAppend()
245+
{
246+
$this->multiValue->append('allowed');
247+
$this->assertEquals('allowed', $this->multiValue[8]);
248+
249+
$this->multiValue->immutable()->append('not allowed');
250+
}
251+
252+
/**
253+
* @covers ::exchangeArray
254+
* @covers ::immutable
255+
*
256+
* @expectedException \LogicException
257+
* @expectedExceptionMessage Attempting to change immutable array
258+
*/
259+
public function testImmutableExchangeArray()
260+
{
261+
$this->multiValue->exchangeArray([]);
262+
$this->assertEquals([], $this->multiValue->getArrayCopy());
263+
264+
$this->multiValue->immutable()->exchangeArray([]);
265+
}
266+
/**
267+
* @covers ::offsetSet
268+
* @covers ::immutable
269+
*
270+
* @expectedException \LogicException
271+
* @expectedExceptionMessage Attempting to add to immutable array
272+
*/
273+
public function testImmutableOffsetSet()
274+
{
275+
$this->multiValue[0] = 'allowed';
276+
$this->assertEquals('allowed', $this->multiValue[0]);
277+
278+
$this->multiValue->immutable()[0] = 'not allowed';
279+
}
280+
281+
/**
282+
* @covers ::offsetUnset
283+
* @covers ::immutable
284+
*
285+
* @expectedException \LogicException
286+
* @expectedExceptionMessage Attempting to remove from immutable array
287+
*/
288+
public function testImmutableOffsetUnset()
289+
{
290+
unset($this->multiValue[0]);
291+
$this->assertFalse(isset($this->multiValue[0]));
292+
293+
unset($this->multiValue->immutable()[0]);
294+
}
295+
296+
/**
297+
* @covers ::offsetUnset
298+
* @covers ::immutable
299+
*
300+
* @expectedException \LogicException
301+
* @expectedExceptionMessage Attempting to remove from immutable array
302+
*/
303+
public function testImmutableOffsetUnsetNested()
304+
{
305+
unset($this->multiValue->immutable()[6][0]);
306+
}
173307
}

tests/Util/Profile/AttributeConverterTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,12 @@ public function testConvertToYotiAttributeDocumentImages()
100100
$protobufAttribute = new \Attrpubapi\Attribute();
101101
$protobufAttribute->mergeFromString(base64_decode(MULTI_VALUE_ATTRIBUTE));
102102

103-
$multiValue = AttributeConverter::convertToYotiAttribute($protobufAttribute);
104-
$this->assertEquals(2, count($multiValue->getValue()));
105-
$this->assertTrue(is_array($multiValue->getValue()));
103+
$attr = AttributeConverter::convertToYotiAttribute($protobufAttribute);
104+
$this->assertEquals(2, count($attr->getValue()));
105+
$this->assertInstanceOf(MultiValue::class, $attr->getValue());
106106

107-
$this->assertIsExpectedImage($multiValue->getValue()[0], 'image/jpeg', 'vWgD//2Q==');
108-
$this->assertIsExpectedImage($multiValue->getValue()[1], 'image/jpeg', '38TVEH/9k=');
107+
$this->assertIsExpectedImage($attr->getValue()[0], 'image/jpeg', 'vWgD//2Q==');
108+
$this->assertIsExpectedImage($attr->getValue()[1], 'image/jpeg', '38TVEH/9k=');
109109
}
110110

111111
/**
@@ -145,7 +145,7 @@ public function testConvertToYotiAttributeDocumentImagesFiltered()
145145
$multiValue = $attr->getValue();
146146

147147
$this->assertEquals(2, count($multiValue));
148-
$this->assertTrue(is_array($multiValue));
148+
$this->assertInstanceOf(MultiValue::class, $multiValue);
149149

150150
$this->assertInstanceOf(Image::class, $multiValue[0]);
151151
$this->assertEquals('image/jpeg', $multiValue[0]->getMimeType());

0 commit comments

Comments
 (0)