Skip to content

Commit 328d3ad

Browse files
authored
Merge pull request #123 from Grazulex/fix-validation
Enhance validation rule handling in ValidatorRuleBuilder and add inte…
2 parents 562b679 + fa98984 commit 328d3ad

File tree

5 files changed

+188
-5
lines changed

5 files changed

+188
-5
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@ package-lock.json
2828
/.phpunit.cache
2929
cache.sqlite
3030
/build
31+
/workbench/
32+
33+
# Test files temporaires
34+
test-validation.yaml
35+
test-dto-generation.php

composer.json

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@
3939
},
4040
"autoload-dev": {
4141
"psr-4": {
42-
"Tests\\": "tests/"
42+
"Tests\\": "tests/",
43+
"Workbench\\App\\": "workbench/app/",
44+
"Workbench\\Database\\Factories\\": "workbench/database/factories/",
45+
"Workbench\\Database\\Seeders\\": "workbench/database/seeders/"
4346
}
4447
},
4548
"extra": {
@@ -80,6 +83,22 @@
8083
"composer run-script phpstan",
8184
"composer run-script rector",
8285
"composer run-script test"
86+
],
87+
"post-autoload-dump": [
88+
"@clear",
89+
"@prepare"
90+
],
91+
"clear": "@php vendor/bin/testbench package:purge-skeleton --ansi",
92+
"prepare": "@php vendor/bin/testbench package:discover --ansi",
93+
"build": "@php vendor/bin/testbench workbench:build --ansi",
94+
"serve": [
95+
"Composer\\Config::disableProcessTimeout",
96+
"@build",
97+
"@php vendor/bin/testbench serve --ansi"
98+
],
99+
"lint": [
100+
"@php vendor/bin/pint --ansi",
101+
"@php vendor/bin/phpstan analyse --verbose --ansi"
83102
]
84103
},
85104
"config": {

src/Support/ValidatorRuleBuilder.php

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ final class ValidatorRuleBuilder
88
{
99
/**
1010
* @param string[] $defaultRules
11-
* @param array $definition YAML field definition (with optional 'rules' and 'required')
11+
* @param array $definition YAML field definition (with optional 'rules', 'validation' and 'required')
1212
* @return string[]
1313
*/
1414
public static function build(array $defaultRules, array $definition): array
@@ -24,9 +24,20 @@ public static function build(array $defaultRules, array $definition): array
2424
$rules[] = 'nullable';
2525
}
2626

27-
// Merge user-defined rules
28-
if (! empty($definition['rules']) && is_array($definition['rules'])) {
29-
foreach ($definition['rules'] as $rule) {
27+
// Merge user-defined rules from 'validation' field (YAML format)
28+
$validationRules = $definition['validation'] ?? [];
29+
if (! empty($validationRules) && is_array($validationRules)) {
30+
foreach ($validationRules as $rule) {
31+
if (! in_array($rule, $rules, true)) {
32+
$rules[] = $rule;
33+
}
34+
}
35+
}
36+
37+
// Merge user-defined rules from 'rules' field (legacy support)
38+
$legacyRules = $definition['rules'] ?? [];
39+
if (! empty($legacyRules) && is_array($legacyRules)) {
40+
foreach ($legacyRules as $rule) {
3041
if (! in_array($rule, $rules, true)) {
3142
$rules[] = $rule;
3243
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Integration;
6+
7+
use Grazulex\LaravelArc\Generator\DtoGenerator;
8+
use Tests\TestCase;
9+
10+
final class ValidationRulesGenerationTest extends TestCase
11+
{
12+
/** @test */
13+
public function it_generates_validation_rules_from_yaml_validation_field()
14+
{
15+
$yamlDefinition = [
16+
'name' => 'TestUser',
17+
'table' => 'test_users',
18+
'relationships' => [],
19+
'traits' => [],
20+
'fields' => [
21+
'email' => [
22+
'type' => 'string',
23+
'required' => true,
24+
'validation' => ['email', 'unique:users'],
25+
],
26+
'age' => [
27+
'type' => 'integer',
28+
'required' => false,
29+
'validation' => ['min:18', 'max:120'],
30+
],
31+
'status' => [
32+
'type' => 'string',
33+
'required' => false,
34+
'validation' => ['in:active,inactive,pending'],
35+
],
36+
],
37+
];
38+
39+
$generator = DtoGenerator::make();
40+
$generatedCode = $generator->generateFromDefinition($yamlDefinition);
41+
42+
// Vérifier que les règles de validation personnalisées sont présentes
43+
$this->assertStringContainsString("'email' => ['string', 'required', 'email', 'unique:users']", $generatedCode);
44+
$this->assertStringContainsString("'age' => ['integer', 'nullable', 'min:18', 'max:120']", $generatedCode);
45+
$this->assertStringContainsString("'status' => ['string', 'nullable', 'in:active,inactive,pending']", $generatedCode);
46+
}
47+
48+
/** @test */
49+
public function it_supports_legacy_rules_field_format()
50+
{
51+
$yamlDefinition = [
52+
'name' => 'TestUser',
53+
'table' => 'test_users',
54+
'relationships' => [],
55+
'traits' => [],
56+
'fields' => [
57+
'email' => [
58+
'type' => 'string',
59+
'required' => true,
60+
'rules' => ['email', 'max:255'],
61+
],
62+
],
63+
];
64+
65+
$generator = DtoGenerator::make();
66+
$generatedCode = $generator->generateFromDefinition($yamlDefinition);
67+
68+
// Vérifier que les règles du champ 'rules' sont aussi prises en compte
69+
$this->assertStringContainsString("'email' => ['string', 'required', 'email', 'max:255']", $generatedCode);
70+
}
71+
72+
/** @test */
73+
public function it_merges_validation_and_rules_fields()
74+
{
75+
$yamlDefinition = [
76+
'name' => 'TestUser',
77+
'table' => 'test_users',
78+
'relationships' => [],
79+
'traits' => [],
80+
'fields' => [
81+
'email' => [
82+
'type' => 'string',
83+
'required' => true,
84+
'validation' => ['email'],
85+
'rules' => ['unique:users'],
86+
],
87+
],
88+
];
89+
90+
$generator = DtoGenerator::make();
91+
$generatedCode = $generator->generateFromDefinition($yamlDefinition);
92+
93+
// Vérifier que les deux champs sont fusionnés
94+
$this->assertStringContainsString("'email' => ['string', 'required', 'email', 'unique:users']", $generatedCode);
95+
}
96+
}

tests/Unit/Support/ValidatorRuleBuilderTest.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,56 @@
4848

4949
expect($rules)->toBe(['string', 'required', 'max:255']);
5050
});
51+
52+
it('merges validation field rules from yaml definition', function () {
53+
$definition = [
54+
'validation' => ['email', 'unique:users'],
55+
];
56+
57+
$rules = ValidatorRuleBuilder::build(['string'], $definition);
58+
59+
expect($rules)->toBe(['string', 'required', 'email', 'unique:users']);
60+
});
61+
62+
it('handles both validation and rules fields together', function () {
63+
$definition = [
64+
'validation' => ['email'],
65+
'rules' => ['unique:users'],
66+
];
67+
68+
$rules = ValidatorRuleBuilder::build(['string'], $definition);
69+
70+
expect($rules)->toBe(['string', 'required', 'email', 'unique:users']);
71+
});
72+
73+
it('handles nullable with validation rules', function () {
74+
$definition = [
75+
'required' => false,
76+
'validation' => ['min:18', 'max:120'],
77+
];
78+
79+
$rules = ValidatorRuleBuilder::build(['integer'], $definition);
80+
81+
expect($rules)->toBe(['integer', 'nullable', 'min:18', 'max:120']);
82+
});
83+
84+
it('does not duplicate rules from validation field', function () {
85+
$definition = [
86+
'validation' => ['required', 'email'],
87+
];
88+
89+
$rules = ValidatorRuleBuilder::build(['string', 'required'], $definition);
90+
91+
expect($rules)->toBe(['string', 'required', 'email']);
92+
});
93+
94+
it('handles empty validation array', function () {
95+
$definition = [
96+
'validation' => [],
97+
];
98+
99+
$rules = ValidatorRuleBuilder::build(['string'], $definition);
100+
101+
expect($rules)->toBe(['string', 'required']);
102+
});
51103
});

0 commit comments

Comments
 (0)