Skip to content

Commit 5c57ef4

Browse files
committed
Added Arr and Collection classes from closed PR
1 parent 7de89b5 commit 5c57ef4

File tree

6 files changed

+924
-7
lines changed

6 files changed

+924
-7
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
}
2929
},
3030
"scripts": {
31-
"ci-test": "XDEBUG_MODE=coverage vendor/bin/phpunit --testsuite=ci --configuration phpunit.xml",
31+
"ci-test": "XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --testsuite=ci --configuration phpunit.xml",
32+
"unit-test": "XDEBUG_MODE=coverage vendor/bin/phpunit --testsuite=unit --configuration phpunit.xml",
3233
"phpstan": "vendor/bin/phpstan analyse --configuration phpstan.neon --memory-limit=256M"
3334
}
3435
}

src/Concerns/BaseData.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use Nuxtifyts\PhpDto\Normalizers\Concerns\HasNormalizers;
1010
use Nuxtifyts\PhpDto\Pipelines\DeserializePipeline\DeserializePipeline;
1111
use Nuxtifyts\PhpDto\Pipelines\DeserializePipeline\DeserializePipelinePassable;
12-
use ReflectionClass;
1312
use Throwable;
1413

1514
trait BaseData

src/Support/Arr.php

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
namespace Nuxtifyts\PhpDto\Support;
44

5+
use BackedEnum;
6+
use InvalidArgumentException;
7+
58
final readonly class Arr
69
{
710
/**
811
* @param array<array-key, mixed> $array
9-
* @param string $key
1012
* @param array<array-key, mixed> $default
1113
*
1214
* @return array<array-key, mixed>
@@ -30,4 +32,165 @@ public static function isArrayOfClassStrings(array $array, string $classString):
3032
&& is_subclass_of($value, $classString)
3133
);
3234
}
35+
36+
/**
37+
* @param array<array-key, mixed> $array
38+
*/
39+
public static function getStringOrNull(array $array, string $key): ?string
40+
{
41+
$value = $array[$key] ?? null;
42+
43+
return is_string($value) ? $value : null;
44+
}
45+
46+
/**
47+
* @param array<array-key, mixed> $array
48+
*/
49+
public static function getString(array $array, string $key, string $default = ''): string
50+
{
51+
return self::getStringOrNull($array, $key) ?? $default;
52+
}
53+
54+
/**
55+
* @param array<array-key, mixed> $array
56+
*/
57+
public static function getIntegerOrNull(array $array, string $key): ?int
58+
{
59+
$value = $array[$key] ?? null;
60+
61+
return is_int($value) ? $value : null;
62+
}
63+
64+
/**
65+
* @param array<array-key, mixed> $array
66+
*/
67+
public static function getInteger(array $array, string $key, int $default = 0): int
68+
{
69+
return self::getIntegerOrNull($array, $key) ?? $default;
70+
}
71+
72+
/**
73+
* @param array<array-key, mixed> $array
74+
*/
75+
public static function getFloatOrNull(array $array, string $key): ?float
76+
{
77+
$value = $array[$key] ?? null;
78+
79+
return is_float($value) ? $value : null;
80+
}
81+
82+
/**
83+
* @param array<array-key, mixed> $array
84+
*/
85+
public static function getFloat(array $array, string $key, float $default = 0.0): float
86+
{
87+
return self::getFloatOrNull($array, $key) ?? $default;
88+
}
89+
90+
/**
91+
* @param array<array-key, mixed> $array
92+
*/
93+
public static function getBooleanOrNull(array $array, string $key): ?bool
94+
{
95+
$value = $array[$key] ?? null;
96+
97+
return is_bool($value) ? $value : null;
98+
}
99+
100+
/**
101+
* @param array<array-key, mixed> $array
102+
*/
103+
public static function getBoolean(array $array, string $key, bool $default = false): bool
104+
{
105+
return self::getBooleanOrNull($array, $key) ?? $default;
106+
}
107+
108+
/**
109+
* @template T of BackedEnum
110+
*
111+
* @param array<array-key, mixed> $array
112+
* @param class-string<T> $enumClass
113+
* @param ?T $default
114+
*
115+
* @return ?T
116+
*/
117+
public static function getBackedEnumOrNull(
118+
array $array,
119+
string $key,
120+
string $enumClass,
121+
?BackedEnum $default = null
122+
): ?BackedEnum {
123+
$value = $array[$key] ?? null;
124+
125+
if ($value instanceof $enumClass) {
126+
return $value;
127+
} else if (
128+
(is_string($value) || is_integer($value))
129+
&& $resolvedValue = $enumClass::tryFrom($value)
130+
) {
131+
return $resolvedValue;
132+
}
133+
134+
return is_null($default)
135+
? null
136+
: ($default instanceof $enumClass
137+
? $default
138+
: throw new InvalidArgumentException('Default value must be an instance of ' . $enumClass)
139+
);
140+
}
141+
142+
/**
143+
* @template T of BackedEnum
144+
*
145+
* @param array<array-key, mixed> $array
146+
* @param class-string<T> $enumClass
147+
* @param T $default
148+
*
149+
* @return T
150+
*/
151+
public static function getBackedEnum(
152+
array $array,
153+
string $key,
154+
string $enumClass,
155+
BackedEnum $default
156+
): BackedEnum {
157+
return self::getBackedEnumOrNull($array, $key, $enumClass, $default) ?? $default;
158+
}
159+
160+
161+
/**
162+
* @param array<array-key, mixed> $array
163+
*
164+
* @return ($preserveKeys is true ? array<array-key, mixed> : list<mixed>)
165+
*/
166+
public static function flatten(array $array, float $depth = INF, bool $preserveKeys = true): array
167+
{
168+
$result = [];
169+
170+
foreach ($array as $key => $item) {
171+
$item = $item instanceof Collection ? $item->all() : $item;
172+
173+
if (! is_array($item)) {
174+
if ($preserveKeys) {
175+
$result[$key] = $item;
176+
} else {
177+
$result[] = $item;
178+
}
179+
} else {
180+
$values = $depth === 1.0
181+
? $item
182+
: self::flatten($item, $depth - 1, $preserveKeys);
183+
184+
foreach ($values as $subKey => $value) {
185+
if ($preserveKeys) {
186+
$result[$subKey] = $value;
187+
} else {
188+
$result[] = $value;
189+
}
190+
}
191+
}
192+
}
193+
194+
return $result;
195+
}
33196
}

src/Support/Collection.php

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
namespace Nuxtifyts\PhpDto\Support;
4+
5+
/**
6+
* @template TKey of array-key
7+
* @template TValue of mixed
8+
*/
9+
class Collection
10+
{
11+
/** @var array<TKey, TValue> */
12+
protected array $items = [];
13+
14+
/**
15+
* @param array<TKey, TValue> $items
16+
*/
17+
public function __construct(array $items = [])
18+
{
19+
$this->items = $items;
20+
}
21+
22+
/**
23+
* @param TValue $item
24+
*
25+
* @return self<TKey, TValue>
26+
*/
27+
public function push(mixed $item): self
28+
{
29+
$this->items[] = $item;
30+
return $this;
31+
}
32+
33+
/**
34+
* @param TKey $key
35+
* @param TValue $value
36+
*
37+
* @return self<TKey, TValue>
38+
*/
39+
public function put(mixed $key, mixed $value): self
40+
{
41+
$this->items[$key] = $value;
42+
return $this;
43+
}
44+
45+
/**
46+
* @param ?callable(TValue $item): bool $callable
47+
*
48+
* @return ?TValue
49+
*/
50+
public function first(?callable $callable = null): mixed
51+
{
52+
return is_null($callable)
53+
? reset($this->items) ?: null
54+
: array_find($this->items, $callable);
55+
}
56+
57+
/**
58+
* @template TNewValue of mixed
59+
* @param callable(TValue $item): TNewValue $callable
60+
*
61+
* @return self<TKey, TNewValue>
62+
*/
63+
public function map(callable $callable): self
64+
{
65+
return new self(array_map($callable, $this->items));
66+
}
67+
68+
/**
69+
* @return ($preserveKeys is true ? Collection<array-key, mixed> : Collection<int, mixed>)
70+
*/
71+
public function collapse(bool $preserveKeys = false): self
72+
{
73+
return $this->flatten(1, $preserveKeys);
74+
}
75+
76+
/**
77+
* @return ($preserveKeys is true ? Collection<array-key, mixed> : Collection<int, mixed>)
78+
*/
79+
public function flatten(float $depth = INF, bool $preserveKeys = true): self
80+
{
81+
return new self(Arr::flatten($this->items, $depth, $preserveKeys));
82+
}
83+
84+
public function isNotEmpty(): bool
85+
{
86+
return !empty($this->items);
87+
}
88+
89+
public function isEmpty(): bool
90+
{
91+
return !$this->isNotEmpty();
92+
}
93+
94+
/**
95+
* @param callable(TValue $item): bool $callable
96+
*/
97+
public function every(callable $callable): bool
98+
{
99+
return array_all($this->items, $callable);
100+
}
101+
102+
/**
103+
* @param callable(TValue $item): bool $callable
104+
*/
105+
public function some(callable $callable): bool
106+
{
107+
return array_any($this->items, $callable);
108+
}
109+
110+
/**
111+
* @return array<TKey, TValue>
112+
*/
113+
public function all(): array
114+
{
115+
return $this->items;
116+
}
117+
}

0 commit comments

Comments
 (0)