Skip to content

Commit 607077f

Browse files
authored
Merge pull request #63 from phpgt/59-typed-array
feature: getTypedArray closes #59
2 parents 31bdb17 + b65640b commit 607077f

File tree

3 files changed

+221
-4
lines changed

3 files changed

+221
-4
lines changed

src/Cache.php

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,112 @@ public function getDateTime(string $name, callable $callback):DateTimeInterface
6767
public function getArray(string $name, callable $callback):array {
6868
$value = $this->get($name, $callback);
6969
if(!is_array($value)) {
70-
throw new TypeError("Value with key '$name' is not an array");
70+
throw new TypeError("Data '$name' is not an array");
7171
}
7272

7373
return $value;
7474
}
7575

76+
/**
77+
* @template T
78+
* @param class-string<T> $className
79+
* @return array<T>
80+
*/
81+
public function getTypedArray(string $name, string $className, callable $callback):array {
82+
$array = $this->get($name, $callback);
83+
if(!is_array($array)) {
84+
throw new TypeError("Data '$name' is not an array");
85+
}
86+
87+
foreach($array as $key => $value) {
88+
$array[$key] = $this->validateAndConvertValue($value, $className, $key);
89+
}
90+
91+
return $array;
92+
}
93+
94+
/**
95+
* @template T
96+
* @param mixed $value
97+
* @param class-string<T> $className
98+
* @param string|int $key
99+
* @return T
100+
*/
101+
private function validateAndConvertValue(mixed $value, string $className, string|int $key): mixed {
102+
return match(strtolower($className)) {
103+
"int", "integer" => $this->validateAndConvertInt($value, $key),
104+
"float", "double" => $this->validateAndConvertFloat($value, $key),
105+
"string" => $this->convertToString($value),
106+
"bool", "boolean" => $this->convertToBool($value),
107+
default => $this->validateInstance($value, $className, $key),
108+
};
109+
}
110+
111+
/**
112+
* @param mixed $value
113+
* @param string|int $key
114+
* @return int
115+
*/
116+
private function validateAndConvertInt(mixed $value, string|int $key): int {
117+
if(is_int($value)) {
118+
return $value;
119+
}
120+
121+
if(is_numeric($value)) {
122+
return (int)$value;
123+
}
124+
125+
throw new TypeError("Array value at key '$key' is not an integer");
126+
}
127+
128+
/**
129+
* @param mixed $value
130+
* @param string|int $key
131+
* @return float
132+
*/
133+
private function validateAndConvertFloat(mixed $value, string|int $key): float {
134+
if(is_float($value)) {
135+
return $value;
136+
}
137+
138+
if(is_numeric($value)) {
139+
return (float)$value;
140+
}
141+
142+
throw new TypeError("Array value at key '$key' is not a float");
143+
}
144+
145+
/**
146+
* @param mixed $value
147+
* @return string
148+
*/
149+
private function convertToString(mixed $value): string {
150+
return (string)$value;
151+
}
152+
153+
/**
154+
* @param mixed $value
155+
* @return bool
156+
*/
157+
private function convertToBool(mixed $value): bool {
158+
return (bool)$value;
159+
}
160+
161+
/**
162+
* @template T
163+
* @param mixed $value
164+
* @param class-string<T> $className
165+
* @param string|int $key
166+
* @return T
167+
*/
168+
private function validateInstance(mixed $value, string $className, string|int $key): object {
169+
if($value instanceof $className) {
170+
return $value;
171+
}
172+
173+
throw new TypeError("Array value at key '$key' is not an instance of $className");
174+
}
175+
76176
/**
77177
* @template T
78178
* @param class-string<T> $className
@@ -81,7 +181,7 @@ public function getArray(string $name, callable $callback):array {
81181
public function getInstance(string $name, string $className, callable $callback):object {
82182
$value = $this->get($name, $callback);
83183
if(get_class($value) !== $className) {
84-
throw new TypeError("Value is not of type $className");
184+
throw new TypeError("Value is not an instance of $className");
85185
}
86186

87187
return $value;

src/FileAccess.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,13 @@ public function checkValidity(string $name, int $secondsValidity):void {
3535
throw new CacheInvalidException($filePath);
3636
}
3737
}
38+
39+
public function invalidate(string $name):void {
40+
$filePath = "$this->dirPath/$name";
41+
if(!is_file($filePath)) {
42+
return;
43+
}
44+
45+
unlink($filePath);
46+
}
3847
}

test/phpunit/CacheTest.php

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
use Gt\FileCache\Cache;
55
use Gt\FileCache\FileAccess;
66
use PHPUnit\Framework\TestCase;
7+
use SplFileInfo;
8+
use SplFixedArray;
79
use stdClass;
10+
use TypeError;
811

912
class CacheTest extends TestCase {
1013
public function tearDown():void {
@@ -97,6 +100,18 @@ public function testGetInstance():void {
97100
self::assertSame($value->name, $class->name);
98101
}
99102

103+
public function testGetInstance_error():void {
104+
$value = new StdClass();
105+
$value->name = uniqid();
106+
107+
$sut = $this->getSut([
108+
"test" => $value,
109+
]);
110+
self::expectException(TypeError::class);
111+
self::expectExceptionMessage("Value is not an instance of SplFileInfo");
112+
$sut->getInstance("test", SplFileInfo::class, fn() => false);
113+
}
114+
100115
public function testGetArray():void {
101116
$value = [1, 2, 3];
102117
$sut = $this->getSut([
@@ -110,11 +125,104 @@ public function testGetArray_notArray():void {
110125
$sut = $this->getSut([
111126
"numbers" => $value,
112127
]);
113-
self::expectException(\TypeError::class);
114-
self::expectExceptionMessage("Value with key 'numbers' is not an array");
128+
self::expectException(TypeError::class);
129+
self::expectExceptionMessage("Data 'numbers' is not an array");
115130
$sut->getArray("numbers", fn() => []);
116131
}
117132

133+
public function testGetTypedArray_notArray():void {
134+
$value = (object)[1, 2, 3];
135+
$sut = $this->getSut([
136+
"numbers" => $value,
137+
]);
138+
self::expectException(TypeError::class);
139+
self::expectExceptionMessage("Data 'numbers' is not an array");
140+
$sut->getTypedArray("numbers", "int", fn() => []);
141+
}
142+
143+
public function testGetTypedArray_int():void {
144+
$value = [1, "2", 3.000];
145+
$sut = $this->getSut([
146+
"numbers" => $value,
147+
]);
148+
$typedArray = $sut->getTypedArray("numbers", "int", fn() => []);
149+
foreach($typedArray as $value) {
150+
self::assertIsInt($value);
151+
}
152+
}
153+
154+
public function testGetTypedArray_intFailure():void {
155+
$value = [1, "2", 3.000, "four"];
156+
$sut = $this->getSut([
157+
"numbers" => $value,
158+
]);
159+
self::expectException(TypeError::class);
160+
$sut->getTypedArray("numbers", "int", fn() => []);
161+
}
162+
163+
public function testGetTypedArray_float():void {
164+
$value = [1, "2", 3.000];
165+
$sut = $this->getSut([
166+
"numbers" => $value,
167+
]);
168+
$typedArray = $sut->getTypedArray("numbers", "float", fn() => []);
169+
foreach($typedArray as $value) {
170+
self::assertIsFloat($value);
171+
}
172+
}
173+
174+
public function testGetTypedArray_floatFailure():void {
175+
$value = [1, "2", 3.000, "four"];
176+
$sut = $this->getSut([
177+
"numbers" => $value,
178+
]);
179+
self::expectException(TypeError::class);
180+
$sut->getTypedArray("numbers", "float", fn() => []);
181+
}
182+
183+
public function testGetTypedArray_string():void {
184+
$value = [1, "2", 3.000, "four"];
185+
$sut = $this->getSut([
186+
"numbers" => $value,
187+
]);
188+
$typedArray= $sut->getTypedArray("numbers", "string", fn() => []);
189+
foreach($typedArray as $value) {
190+
self::assertIsString($value);
191+
}
192+
}
193+
194+
public function testGetTypedArray_bool():void {
195+
$value = [0, "1", false, true, [], new StdClass()];
196+
$sut = $this->getSut([
197+
"booleans" => $value,
198+
]);
199+
$typedArray= $sut->getTypedArray("booleans", "bool", fn() => []);
200+
foreach($typedArray as $i => $value) {
201+
self::assertSame((bool)($i % 2), $value, $i);
202+
}
203+
}
204+
205+
public function testGetTypedArray_class():void {
206+
$value = [new SplFileInfo(__FILE__), new SplFileInfo(__DIR__)];
207+
$sut = $this->getSut([
208+
"files" => $value,
209+
]);
210+
$typedArray= $sut->getTypedArray("files", SplFileInfo::class, fn() => []);
211+
foreach($typedArray as $value) {
212+
self::assertInstanceOf(SplFileInfo::class, $value);
213+
}
214+
}
215+
216+
public function testGetTypedArray_classError():void {
217+
$value = [new SplFileInfo(__FILE__), new SplFixedArray(), new SplFileInfo(__DIR__)];
218+
$sut = $this->getSut([
219+
"files" => $value,
220+
]);
221+
self::expectExceptionMessage("Array value at key '1' is not an instance of SplFileInfo");
222+
self::expectException(TypeError::class);
223+
$sut->getTypedArray("files", SplFileInfo::class, fn() => []);
224+
}
225+
118226
private function getSut(array $mockFiles = []):Cache {
119227
$mockFileAccess = null;
120228
if(!empty($mockFiles)) {

0 commit comments

Comments
 (0)