Skip to content

Commit 3349ded

Browse files
committed
refactor: adapt to orm changes and support normal tables
1 parent 1b45354 commit 3349ded

File tree

10 files changed

+133
-241
lines changed

10 files changed

+133
-241
lines changed

packages/database/src/Builder/QueryBuilders/QueryBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public function new(mixed ...$params): object
152152
*
153153
* @return TModel
154154
*/
155-
public function findById(string|int|PrimaryKey $id): object
155+
public function findById(string|int|PrimaryKey $id): ?object
156156
{
157157
if (! inspect($this->model)->hasPrimaryKey()) {
158158
throw ModelDidNotHavePrimaryColumn::neededForMethod($this->model, 'findById');

packages/validation/src/Rules/Exists.php

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,59 @@
66

77
use Attribute;
88
use InvalidArgumentException;
9-
use Tempest\Database\Id;
9+
use Tempest\Database\PrimaryKey;
10+
use Tempest\Validation\HasTranslationVariables;
1011
use Tempest\Validation\Rule;
1112

13+
use function Tempest\Database\inspect;
1214
use function Tempest\Database\query;
1315

16+
/**
17+
* Ensures that for the given model, the primary key value associated to this rule exists in the database.
18+
*/
1419
#[Attribute(Attribute::TARGET_PROPERTY)]
15-
final readonly class Exists implements Rule
20+
final readonly class Exists implements Rule, HasTranslationVariables
1621
{
22+
/**
23+
* @param class-string|non-empty-string $table
24+
*/
1725
public function __construct(
18-
private string $model,
26+
private string $table,
27+
private ?string $column = null,
1928
) {
20-
if (! class_exists($this->model)) {
21-
throw new InvalidArgumentException("Model {$this->model} does not exist");
29+
if (! class_exists($table) && $column === null) {
30+
throw new InvalidArgumentException('A column must be specified when the table is not a model class.');
2231
}
2332
}
2433

2534
public function isValid(mixed $value): bool
2635
{
27-
if ((! is_numeric($value) || is_float($value)) && ! is_object($value)) {
36+
if (! is_object($value) && ! is_numeric($value) && ! is_string($value)) {
2837
return false;
2938
}
3039

31-
$id = is_object($value) ? $value : new Id($value);
32-
33-
if ($id->id >= PHP_INT_MAX) {
40+
if (is_float($value)) {
3441
return false;
3542
}
3643

37-
$model = query($this->model)
38-
->select()
39-
->get(id: $id);
44+
$column = match (is_null($this->column)) {
45+
false => $this->column,
46+
true => match ($key = inspect($this->table)->getPrimaryKey()) {
47+
null => throw new InvalidArgumentException("Model `{$this->table}` does not have a primary key, and a column was not specified."),
48+
default => $key,
49+
},
50+
};
4051

41-
return $model !== null;
52+
return query($this->table)
53+
->count()
54+
->whereField($column, $value)
55+
->execute() > 0;
4256
}
4357

44-
public function message(): string
58+
public function getTranslationVariables(): array
4559
{
46-
return sprintf('Record for model %1$s does not exist', $this->model);
60+
return [
61+
'model' => $this->table,
62+
];
4763
}
4864
}

packages/validation/src/localization.en.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ validation_error:
7979
.input {$field :string}
8080
.input {$needle :string}
8181
{$field} must end with "{$needle}"
82+
exists: |
83+
.input {$field :string}
84+
{$field} could not be found
8285
is_even_number: |
8386
.input {$field :string}
8487
{$field} must be even

packages/validation/tests/Fixtures/ValidateExistsModel.php

Lines changed: 0 additions & 16 deletions
This file was deleted.

packages/validation/tests/Rules/ExistsTest.php

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,47 @@
77
use InvalidArgumentException;
88
use PHPUnit\Framework\Attributes\Test;
99
use PHPUnit\Framework\TestCase;
10+
use Tempest\Database\PrimaryKey;
1011
use Tempest\Validation\Rules\Exists;
11-
use Tempest\Validation\Tests\Fixtures\ValidateExistsModel;
1212

1313
/**
1414
* @internal
1515
*/
1616
final class ExistsTest extends TestCase
1717
{
1818
#[Test]
19-
public function throws_exception_for_invalid_model_class(): void
19+
public function throws_exception_for_table_without_column(): void
2020
{
2121
$this->expectException(InvalidArgumentException::class);
22-
$this->expectExceptionMessage('Model NonExistentModel does not exist');
22+
$this->expectExceptionMessage('A column must be specified when the table is not a model class.');
2323

24-
new Exists('NonExistentModel');
24+
new Exists('random-table');
2525
}
2626

2727
#[Test]
2828
public function returns_false_for_null_or_non_integer_values(): void
2929
{
3030
$rule = new Exists(ValidateExistsModel::class);
3131

32-
$this->assertFalse($rule->isValid('string'));
3332
$this->assertFalse($rule->isValid(1.5));
3433
$this->assertFalse($rule->isValid([]));
3534
$this->assertFalse($rule->isValid(true));
35+
$this->assertFalse($rule->isValid(false));
3636
$this->assertFalse($rule->isValid(null));
3737
}
3838

39-
#[Test]
40-
public function returns_correct_error_message(): void
41-
{
42-
$rule = new Exists(ValidateExistsModel::class);
43-
44-
$expectedMessage = sprintf('Record for model %s does not exist', ValidateExistsModel::class);
45-
$this->assertSame($expectedMessage, $rule->message());
46-
}
47-
4839
#[Test]
4940
public function can_be_constructed_with_valid_model_class(): void
5041
{
51-
$rule = new Exists(ValidateExistsModel::class);
52-
53-
$this->assertInstanceOf(Exists::class, $rule);
54-
$this->assertStringContainsString(ValidateExistsModel::class, $rule->message());
42+
$this->assertInstanceOf(Exists::class, new Exists(ValidateExistsModel::class));
5543
}
5644
}
45+
46+
/** @internal */
47+
final class ValidateExistsModel
48+
{
49+
public function __construct(
50+
public PrimaryKey $id,
51+
public string $name,
52+
) {}
53+
}

tests/Fixtures/Requests/BookRequest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Tempest\Database\HasOne;
88
use Tempest\Http\IsRequest;
99
use Tempest\Http\Request;
10+
use Tempest\Validation\Rules\Exists;
1011
use Tempest\Validation\Rules\HasLength;
1112
use Tests\Tempest\Fixtures\Modules\Books\Models\Author;
1213
use Tests\Tempest\Fixtures\Modules\Books\Models\Isbn;

tests/Fixtures/Rules/ValidateExistsModel.php

Lines changed: 0 additions & 16 deletions
This file was deleted.

tests/Integration/Http/Rules/ExistsRuleTest.php

Lines changed: 0 additions & 175 deletions
This file was deleted.

0 commit comments

Comments
 (0)