Skip to content

Commit 83f214f

Browse files
committed
Adding tests for lazy attribute
1 parent 738964c commit 83f214f

File tree

6 files changed

+147
-28
lines changed

6 files changed

+147
-28
lines changed

src/Attributes/Class/Lazy.php

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Nuxtifyts\PhpDto\Attributes\Class;
4+
5+
use Attribute;
6+
7+
#[Attribute(Attribute::TARGET_CLASS)]
8+
class Lazy
9+
{
10+
}

src/Concerns/BaseData.php

+30-18
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,20 @@ final public static function create(mixed ...$args): static
3131
throw DataCreationException::invalidParamsPassed(static::class);
3232
}
3333

34-
$data = DeserializePipeline::createFromArray()
35-
->sendThenReturn(new DeserializePipelinePassable(
36-
classContext: $context,
37-
data: $value
38-
))
39-
->data;
40-
41-
return $context->constructFromArray($data);
34+
$dataCreationClosure = static function () use ($context, $value): static {
35+
$data = DeserializePipeline::createFromArray()
36+
->sendThenReturn(new DeserializePipelinePassable(
37+
classContext: $context,
38+
data: $value
39+
))
40+
->data;
41+
42+
return $context->constructFromArray($data);
43+
};
44+
45+
return $context->isLazy
46+
? $context->newLazyProxy($dataCreationClosure)
47+
: $dataCreationClosure();
4248
} catch (Throwable $e) {
4349
throw DataCreationException::unableToCreateInstance(static::class, $e);
4450
}
@@ -59,16 +65,22 @@ final public static function from(mixed $value): static
5965
throw DeserializeException::invalidValue();
6066
}
6167

62-
$data = DeserializePipeline::hydrateFromArray()
63-
->sendThenReturn(new DeserializePipelinePassable(
64-
classContext: $context,
65-
data: $value
66-
))
67-
->data;
68-
69-
return $context->hasComputedProperties
70-
? $context->constructFromArray($data)
71-
: static::instanceWithoutConstructorFrom($context, $data);
68+
$dataCreationClosure = static function () use ($context, $value): static {
69+
$data = DeserializePipeline::hydrateFromArray()
70+
->sendThenReturn(new DeserializePipelinePassable(
71+
classContext: $context,
72+
data: $value
73+
))
74+
->data;
75+
76+
return $context->hasComputedProperties
77+
? $context->constructFromArray($data)
78+
: static::instanceWithoutConstructorFrom($context, $data);
79+
};
80+
81+
return $context->isLazy
82+
? $context->newLazyProxy($dataCreationClosure)
83+
: $dataCreationClosure();
7284
} catch (Throwable $e) {
7385
throw DeserializeException::generic($e);
7486
}

src/Concerns/CloneableData.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@ public function with(mixed ...$args): static
3232
throw DataCreationException::invalidParamsPassed(static::class);
3333
}
3434

35-
return $context->hasComputedProperties
35+
$cloneDataClosure = fn (): static => $context->hasComputedProperties
3636
? $this->cloneInstanceWithConstructorCall($context, $value)
3737
: $this->cloneInstanceWithoutConstructorCall($context, $value);
38+
39+
return $context->isLazy
40+
? $context->newLazyProxy($cloneDataClosure)
41+
: $cloneDataClosure();
3842
} catch (Throwable $t) {
3943
throw DataCreationException::unableToCloneInstanceWithNewData(static::class, $t);
4044
}

src/Contexts/ClassContext.php

+20-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Nuxtifyts\PhpDto\Contexts;
44

55
use Exception;
6+
use Nuxtifyts\PhpDto\Attributes\Class\Lazy;
67
use Nuxtifyts\PhpDto\Attributes\Class\MapName;
78
use Nuxtifyts\PhpDto\Attributes\Class\WithNormalizer;
89
use Nuxtifyts\PhpDto\Contexts\ClassContext\NameMapperConfig;
@@ -41,6 +42,8 @@ class ClassContext
4142

4243
private(set) ?NameMapperConfig $nameMapperConfig = null;
4344

45+
private(set) bool $isLazy = false;
46+
4447
/**
4548
* @param ReflectionClass<T> $reflection
4649
*
@@ -135,6 +138,8 @@ private function syncClassAttributes(): void
135138
to: $instance->to
136139
);
137140
}
141+
142+
$this->isLazy = !empty($this->reflection->getAttributes(Lazy::class));
138143
}
139144

140145
/**
@@ -204,19 +209,25 @@ public function newLazyProxy(callable $lazyProxyCallable): mixed
204209
*/
205210
public function emptyValue(): mixed
206211
{
207-
/** @var array<string, mixed> $args */
208-
$args = [];
212+
$emptyValueCreationClosure = function () {
213+
/** @var array<string, mixed> $args */
214+
$args = [];
209215

210-
foreach ($this->constructorParams as $paramName) {
211-
$propertyContext = $this->properties[$paramName] ?? null;
216+
foreach ($this->constructorParams as $paramName) {
217+
$propertyContext = $this->properties[$paramName] ?? null;
212218

213-
if (!$propertyContext) {
214-
throw DataCreationException::invalidProperty();
219+
if (!$propertyContext) {
220+
throw DataCreationException::invalidProperty();
221+
}
222+
223+
$args[$paramName] = $propertyContext->emptyValue();
215224
}
216225

217-
$args[$paramName] = $propertyContext->emptyValue();
218-
}
226+
return $this->newInstanceWithConstructorCall(...$args);
227+
};
219228

220-
return $this->newInstanceWithConstructorCall(...$args);
229+
return $this->isLazy
230+
? $this->newLazyProxy($emptyValueCreationClosure)
231+
: $emptyValueCreationClosure();
221232
}
222233
}

tests/Dummies/LazyDummyData.php

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Nuxtifyts\PhpDto\Tests\Dummies;
4+
5+
use Nuxtifyts\PhpDto\Attributes\Class\Lazy;
6+
use Nuxtifyts\PhpDto\Data;
7+
8+
#[Lazy]
9+
final readonly class LazyDummyData extends Data
10+
{
11+
public function __construct(
12+
public string $propertyA,
13+
public string $propertyB,
14+
) {
15+
}
16+
}

tests/Unit/Attributes/LazyTest.php

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Nuxtifyts\PhpDto\Tests\Unit\Attributes;
4+
5+
use Nuxtifyts\PhpDto\Attributes\Class\Lazy;
6+
use Nuxtifyts\PhpDto\Contexts\ClassContext;
7+
use Nuxtifyts\PhpDto\Data;
8+
use Nuxtifyts\PhpDto\Tests\Dummies\LazyDummyData;
9+
use Nuxtifyts\PhpDto\Tests\Unit\UnitCase;
10+
use PHPUnit\Framework\Attributes\CoversClass;
11+
use PHPUnit\Framework\Attributes\Test;
12+
use PHPUnit\Framework\Attributes\UsesClass;
13+
use Throwable;
14+
15+
#[CoversClass(Lazy::class)]
16+
#[CoversClass(Data::class)]
17+
#[CoversClass(ClassContext::class)]
18+
#[UsesClass(LazyDummyData::class)]
19+
final class LazyTest extends UnitCase
20+
{
21+
/**
22+
* @throws Throwable
23+
*/
24+
#[Test]
25+
public function will_be_able_to_detect_lazy_data_and_create_it_using_attribute(): void
26+
{
27+
$context = ClassContext::getInstance(LazyDummyData::class);
28+
29+
self::assertTrue($context->isLazy);
30+
31+
$lazyDummyData = LazyDummyData::create(propertyA: 'a', propertyB: 'b');
32+
33+
self::assertEquals('a', $lazyDummyData->propertyA);
34+
self::assertEquals('b', $lazyDummyData->propertyB);
35+
36+
$lazyDummyData = LazyDummyData::from(['propertyA' => 'a', 'propertyB' => 'b']);
37+
self::assertEquals('a', $lazyDummyData->propertyA);
38+
self::assertEquals('b', $lazyDummyData->propertyB);
39+
}
40+
41+
/**
42+
* @throws Throwable
43+
*/
44+
#[Test]
45+
public function will_be_able_to_create_empty_instance_of_lazy_data(): void
46+
{
47+
$lazyDummyData = LazyDummyData::empty();
48+
49+
self::assertInstanceOf(LazyDummyData::class, $lazyDummyData);
50+
self::assertEquals('', $lazyDummyData->propertyA);
51+
self::assertEquals('', $lazyDummyData->propertyB);
52+
}
53+
54+
/**
55+
* @throws Throwable
56+
*/
57+
#[Test]
58+
public function will_be_able_to_clone_instance_of_lazy_data(): void
59+
{
60+
$lazyDummyData = LazyDummyData::create(propertyA: 'a', propertyB: 'b');
61+
$clonedLazyDummyData = $lazyDummyData->with(propertyA: 'c', propertyB: 'd');
62+
63+
self::assertEquals('c', $clonedLazyDummyData->propertyA);
64+
self::assertEquals('d', $clonedLazyDummyData->propertyB);
65+
}
66+
}

0 commit comments

Comments
 (0)