Skip to content

Commit b4703fb

Browse files
viducbrambaud
authored andcommitted
feat!: throw exception when trying to set unknown properties
1 parent 7a3935c commit b4703fb

File tree

4 files changed

+96
-2
lines changed

4 files changed

+96
-2
lines changed

src/BuildableWithArgUnpacking.php

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

55
namespace Buildotter\Core;
66

7+
use Buildotter\Core\Exception\UnknownPropertyException;
8+
79
trait BuildableWithArgUnpacking
810
{
911
/**
@@ -12,10 +14,17 @@ trait BuildableWithArgUnpacking
1214
public function with(...$values): static
1315
{
1416
$r = new \ReflectionClass(static::class);
17+
$properties = $r->getProperties();
18+
19+
$propertyNames = \array_map(static fn($p) => $p->getName(), $properties);
20+
$invalidArguments = \array_diff(\array_keys($values), $propertyNames);
21+
if ([] !== $invalidArguments) {
22+
throw UnknownPropertyException::new($invalidArguments, static::class);
23+
}
1524

1625
$clone = $r->newInstanceWithoutConstructor();
1726

18-
foreach ($r->getProperties() as $property) {
27+
foreach ($properties as $property) {
1928
$field = $property->name;
2029
$clone->$field = match (\array_key_exists($field, $values)) {
2130
true => (static function () use ($values, $field) {

src/BuildableWithArray.php

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

55
namespace Buildotter\Core;
66

7+
use Buildotter\Core\Exception\UnknownPropertyException;
8+
79
trait BuildableWithArray
810
{
911
/**
@@ -12,10 +14,17 @@ trait BuildableWithArray
1214
public function with(array $values): static
1315
{
1416
$r = new \ReflectionClass(static::class);
17+
$properties = $r->getProperties();
18+
19+
$propertyNames = \array_map(static fn($p) => $p->getName(), $properties);
20+
$invalidArguments = \array_diff(\array_keys($values), $propertyNames);
21+
if ([] !== $invalidArguments) {
22+
throw UnknownPropertyException::new($invalidArguments, static::class);
23+
}
1524

1625
$clone = $r->newInstanceWithoutConstructor();
1726

18-
foreach ($r->getProperties() as $property) {
27+
foreach ($properties as $property) {
1928
$field = $property->name;
2029
$clone->$field = match (\array_key_exists($field, $values)) {
2130
true => (static function () use ($values, $field) {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Buildotter\Core\Exception;
6+
7+
final class UnknownPropertyException extends \InvalidArgumentException
8+
{
9+
/**
10+
* @param array<string|int> $properties
11+
*/
12+
public static function new(array $properties, string $class): self
13+
{
14+
return new self(
15+
\sprintf(
16+
'The following properties do not exist in "%s": "%s".',
17+
$class,
18+
\implode('", "', $properties),
19+
),
20+
);
21+
}
22+
}

tests/BuildatableTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Buildotter\Core\BuildableWithArgUnpacking;
88
use Buildotter\Core\BuildableWithArray;
99
use Buildotter\Core\Buildatable;
10+
use Buildotter\Core\Exception\UnknownPropertyException;
1011
use PHPUnit\Framework\TestCase;
1112
use function PHPUnit\Framework\assertEquals;
1213

@@ -39,6 +40,59 @@ public function test_it_is_buildatable_with_arg_unpacking(): void
3940
$fooBuiltWithArgsUnpacking,
4041
);
4142
}
43+
44+
public function test_it_is_not_buildatable_with_bad_arg_unpacking(): void
45+
{
46+
$this->expectException(UnknownPropertyException::class);
47+
$this->expectExceptionMessage('The following properties do not exist in "Buildotter\Tests\Core\FooBuilderWithArgUnpacking": "0", "doesNotExist", "doesNotExistEither".');
48+
49+
FooBuilderWithArgUnpacking::new()
50+
->with(
51+
random()->word(),
52+
doesNotExist: random()->word(),
53+
number: random()->randomNumber(),
54+
doesNotExistEither: random()->word(),
55+
)
56+
->build();
57+
}
58+
59+
public function test_it_is_not_buildatable_with_bad_arg_unpacking_2(): void
60+
{
61+
$this->expectException(UnknownPropertyException::class);
62+
$this->expectExceptionMessage('The following properties do not exist in "Buildotter\Tests\Core\FooBuilderWithArgUnpacking": "doesNotExist".');
63+
64+
FooBuilderWithArgUnpacking::new()
65+
->named(random()->name())
66+
->with(doesNotExist: random()->word())
67+
->with(doesNotExistEither: random()->word())
68+
->build();
69+
}
70+
71+
public function test_it_is_not_buildatable_with_bad_arg_array(): void
72+
{
73+
$this->expectException(UnknownPropertyException::class);
74+
$this->expectExceptionMessage('The following properties do not exist in "Buildotter\Tests\Core\FooBuilderWithArray": "doesNotExist", "doesNotExistEither".');
75+
76+
FooBuilderWithArray::new()
77+
->with([
78+
'doesNotExist' => random()->word(),
79+
'number' => random()->randomNumber(),
80+
'doesNotExistEither' => random()->word(),
81+
])
82+
->build();
83+
}
84+
85+
public function test_it_is_not_buildatable_with_bad_arg_array_2(): void
86+
{
87+
$this->expectException(UnknownPropertyException::class);
88+
$this->expectExceptionMessage('The following properties do not exist in "Buildotter\Tests\Core\FooBuilderWithArray": "doesNotExist".');
89+
90+
FooBuilderWithArray::new()
91+
->named(random()->name())
92+
->with(['doesNotExist' => random()->word()])
93+
->with(['doesNotExistEither' => random()->word()])
94+
->build();
95+
}
4296
}
4397

4498
final class Foo

0 commit comments

Comments
 (0)