Skip to content

Commit c95b889

Browse files
authored
Merge pull request #56 from Astrotomic/ft-rule-value-formatter
rule value formatter
2 parents cce61b3 + d0d86fa commit c95b889

File tree

4 files changed

+252
-6
lines changed

4 files changed

+252
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ vendor/
22
composer.lock
33
coverage/
44
.phpunit.result.cache
5+
build/

phpunit.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
</testsuites>
1717
<filter>
1818
<whitelist processUncoveredFilesFromWhitelist="false">
19-
<file>./src/Translatable/Translatable.php</file>
19+
<directory suffix=".php">src/Translatable</directory>
2020
</whitelist>
2121
</filter>
2222
</phpunit>

src/Translatable/Validation/RuleFactory.php

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public function __construct(Repository $config, ?int $format = null, ?string $pr
4040

4141
public static function make(array $rules, ?int $format = null, ?string $prefix = null, ?string $suffix = null, ?array $locales = null): array
4242
{
43-
$factory = app()->make(static::class, compact('format', 'prefix', 'suffix'));
43+
/** @var RuleFactory $factory */
44+
$factory = app(static::class, compact('format', 'prefix', 'suffix'));
4445

4546
$factory->setLocales($locales);
4647

@@ -80,20 +81,56 @@ public function parse(array $input): array
8081
}
8182

8283
foreach ($this->locales as $locale) {
83-
$rules[$this->formatKey($locale, $key)] = $value;
84+
$rules[$this->formatKey($locale, $key)] = $this->formatRule($locale, $value);
8485
}
8586
}
8687

8788
return $rules;
8889
}
8990

9091
protected function formatKey(string $locale, string $key): string
92+
{
93+
return $this->replacePlaceholder($locale, $key);
94+
}
95+
96+
/**
97+
* @param string $locale
98+
* @param string|string[]|mixed $rule
99+
*
100+
* @return string|string[]|mixed
101+
*/
102+
protected function formatRule(string $locale, $rule)
103+
{
104+
if (is_string($rule)) {
105+
if (strpos($rule, '|')) {
106+
return implode('|', array_map(function (string $rule) use ($locale) {
107+
return $this->replacePlaceholder($locale, $rule);
108+
}, explode('|', $rule)));
109+
}
110+
111+
return $this->replacePlaceholder($locale, $rule);
112+
} elseif (is_array($rule)) {
113+
return array_map(function ($rule) use ($locale) {
114+
return $this->formatRule($locale, $rule);
115+
}, $rule);
116+
}
117+
118+
return $rule;
119+
}
120+
121+
protected function replacePlaceholder(string $locale, string $value): string
122+
{
123+
return preg_replace($this->getPattern(), $this->getReplacement($locale), $value);
124+
}
125+
126+
protected function getReplacement(string $locale): string
91127
{
92128
switch ($this->format) {
93-
case self::FORMAT_ARRAY:
94-
return preg_replace($this->getPattern(), $locale.'.$1', $key);
95129
case self::FORMAT_KEY:
96-
return preg_replace($this->getPattern(), '$1:'.$locale, $key);
130+
return '$1:'.$locale;
131+
default:
132+
case self::FORMAT_ARRAY:
133+
return $locale.'.$1';
97134
}
98135
}
99136

tests/ValidationTest.php

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?php
22

3+
use Illuminate\Validation\Rule;
34
use Astrotomic\Translatable\Locales;
5+
use Illuminate\Validation\Rules\RequiredIf;
46
use Astrotomic\Translatable\Validation\RuleFactory;
57

68
final class ValidationTest extends TestsBase
@@ -259,6 +261,212 @@ public function test_it_throws_exception_with_undefined_locales()
259261
]);
260262
}
261263

264+
public function test_format_array_it_replaces_single_rule()
265+
{
266+
$rules = [
267+
'%title%' => 'sometimes|string',
268+
'%content%' => 'required_with:%title%',
269+
];
270+
271+
$this->assertEquals([
272+
'en.title' => 'sometimes|string',
273+
'de.title' => 'sometimes|string',
274+
'de-DE.title' => 'sometimes|string',
275+
'de-AT.title' => 'sometimes|string',
276+
277+
'en.content' => 'required_with:en.title',
278+
'de.content' => 'required_with:de.title',
279+
'de-DE.content' => 'required_with:de-DE.title',
280+
'de-AT.content' => 'required_with:de-AT.title',
281+
], RuleFactory::make($rules, RuleFactory::FORMAT_ARRAY));
282+
}
283+
284+
public function test_format_array_it_replaces_imploded_rules()
285+
{
286+
$rules = [
287+
'%title%' => 'sometimes|string',
288+
'%content%' => 'required_with:%title%|string',
289+
];
290+
291+
$this->assertEquals([
292+
'en.title' => 'sometimes|string',
293+
'de.title' => 'sometimes|string',
294+
'de-DE.title' => 'sometimes|string',
295+
'de-AT.title' => 'sometimes|string',
296+
297+
'en.content' => 'required_with:en.title|string',
298+
'de.content' => 'required_with:de.title|string',
299+
'de-DE.content' => 'required_with:de-DE.title|string',
300+
'de-AT.content' => 'required_with:de-AT.title|string',
301+
], RuleFactory::make($rules, RuleFactory::FORMAT_ARRAY));
302+
}
303+
304+
public function test_format_array_it_replaces_array_of_rules()
305+
{
306+
$rules = [
307+
'%title%' => 'sometimes|string',
308+
'%content%' => ['required_with:%title%', 'string'],
309+
];
310+
311+
$this->assertEquals([
312+
'en.title' => 'sometimes|string',
313+
'de.title' => 'sometimes|string',
314+
'de-DE.title' => 'sometimes|string',
315+
'de-AT.title' => 'sometimes|string',
316+
317+
'en.content' => ['required_with:en.title', 'string'],
318+
'de.content' => ['required_with:de.title', 'string'],
319+
'de-DE.content' => ['required_with:de-DE.title', 'string'],
320+
'de-AT.content' => ['required_with:de-AT.title', 'string'],
321+
], RuleFactory::make($rules, RuleFactory::FORMAT_ARRAY));
322+
}
323+
324+
public function test_format_array_it_does_not_touch_non_string_rule()
325+
{
326+
$rules = [
327+
'title' => 'required',
328+
'%content%' => Rule::requiredIf(function () {
329+
return true;
330+
}),
331+
];
332+
333+
$formattedRules = RuleFactory::make($rules, RuleFactory::FORMAT_ARRAY);
334+
335+
$this->assertEquals('required', $formattedRules['title']);
336+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['en.content']);
337+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['de.content']);
338+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['de-DE.content']);
339+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['de-AT.content']);
340+
}
341+
342+
public function test_format_array_it_does_not_touch_non_string_rule_in_array()
343+
{
344+
$rules = [
345+
'title' => 'required',
346+
'%content%' => [
347+
'required_with:%title%',
348+
Rule::requiredIf(function () {
349+
return true;
350+
}),
351+
],
352+
];
353+
354+
$formattedRules = RuleFactory::make($rules, RuleFactory::FORMAT_ARRAY);
355+
356+
$this->assertEquals('required', $formattedRules['title']);
357+
$this->assertEquals('required_with:en.title', $formattedRules['en.content'][0]);
358+
$this->assertEquals('required_with:de.title', $formattedRules['de.content'][0]);
359+
$this->assertEquals('required_with:de-DE.title', $formattedRules['de-DE.content'][0]);
360+
$this->assertEquals('required_with:de-AT.title', $formattedRules['de-AT.content'][0]);
361+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['en.content'][1]);
362+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['de.content'][1]);
363+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['de-DE.content'][1]);
364+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['de-AT.content'][1]);
365+
}
366+
367+
public function test_format_key_it_replaces_single_rule()
368+
{
369+
$rules = [
370+
'%title%' => 'sometimes|string',
371+
'%content%' => 'required_with:"%title%"',
372+
];
373+
374+
$this->assertEquals([
375+
'title:en' => 'sometimes|string',
376+
'title:de' => 'sometimes|string',
377+
'title:de-DE' => 'sometimes|string',
378+
'title:de-AT' => 'sometimes|string',
379+
380+
'content:en' => 'required_with:"title:en"',
381+
'content:de' => 'required_with:"title:de"',
382+
'content:de-DE' => 'required_with:"title:de-DE"',
383+
'content:de-AT' => 'required_with:"title:de-AT"',
384+
], RuleFactory::make($rules, RuleFactory::FORMAT_KEY));
385+
}
386+
387+
public function test_format_key_it_replaces_imploded_rules()
388+
{
389+
$rules = [
390+
'%title%' => 'sometimes|string',
391+
'%content%' => 'required_with:"%title%"|string',
392+
];
393+
394+
$this->assertEquals([
395+
'title:en' => 'sometimes|string',
396+
'title:de' => 'sometimes|string',
397+
'title:de-DE' => 'sometimes|string',
398+
'title:de-AT' => 'sometimes|string',
399+
400+
'content:en' => 'required_with:"title:en"|string',
401+
'content:de' => 'required_with:"title:de"|string',
402+
'content:de-DE' => 'required_with:"title:de-DE"|string',
403+
'content:de-AT' => 'required_with:"title:de-AT"|string',
404+
], RuleFactory::make($rules, RuleFactory::FORMAT_KEY));
405+
}
406+
407+
public function test_format_key_it_replaces_array_of_rules()
408+
{
409+
$rules = [
410+
'%title%' => 'sometimes|string',
411+
'%content%' => ['required_with:"%title%"', 'string'],
412+
];
413+
414+
$this->assertEquals([
415+
'title:en' => 'sometimes|string',
416+
'title:de' => 'sometimes|string',
417+
'title:de-DE' => 'sometimes|string',
418+
'title:de-AT' => 'sometimes|string',
419+
420+
'content:en' => ['required_with:"title:en"', 'string'],
421+
'content:de' => ['required_with:"title:de"', 'string'],
422+
'content:de-DE' => ['required_with:"title:de-DE"', 'string'],
423+
'content:de-AT' => ['required_with:"title:de-AT"', 'string'],
424+
], RuleFactory::make($rules, RuleFactory::FORMAT_KEY));
425+
}
426+
427+
public function test_format_key_it_does_not_touch_non_string_rule()
428+
{
429+
$rules = [
430+
'title' => 'required',
431+
'%content%' => Rule::requiredIf(function () {
432+
return true;
433+
}),
434+
];
435+
436+
$formattedRules = RuleFactory::make($rules, RuleFactory::FORMAT_KEY);
437+
438+
$this->assertEquals('required', $formattedRules['title']);
439+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['content:en']);
440+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['content:de']);
441+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['content:de-DE']);
442+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['content:de-AT']);
443+
}
444+
445+
public function test_format_key_it_does_not_touch_non_string_rule_in_array()
446+
{
447+
$rules = [
448+
'title' => 'required',
449+
'%content%' => [
450+
'required_with:"%title%"',
451+
Rule::requiredIf(function () {
452+
return true;
453+
}),
454+
],
455+
];
456+
457+
$formattedRules = RuleFactory::make($rules, RuleFactory::FORMAT_KEY);
458+
459+
$this->assertEquals('required', $formattedRules['title']);
460+
$this->assertEquals('required_with:"title:en"', $formattedRules['content:en'][0]);
461+
$this->assertEquals('required_with:"title:de"', $formattedRules['content:de'][0]);
462+
$this->assertEquals('required_with:"title:de-DE"', $formattedRules['content:de-DE'][0]);
463+
$this->assertEquals('required_with:"title:de-AT"', $formattedRules['content:de-AT'][0]);
464+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['content:en'][1]);
465+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['content:de'][1]);
466+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['content:de-DE'][1]);
467+
$this->assertInstanceOf(RequiredIf::class, $formattedRules['content:de-AT'][1]);
468+
}
469+
262470
protected function setUp(): void
263471
{
264472
$this->setUpTheTestEnvironment();

0 commit comments

Comments
 (0)