Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
48.48% covered (danger)
48.48%
16 / 33
54.55% covered (warning)
54.55%
6 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
FormName
48.48% covered (danger)
48.48%
16 / 33
54.55% covered (warning)
54.55%
6 / 11
56.51
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fromNative
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 hasChildFormFieldName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getChildFormFieldName
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 createChildForm
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toNative
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toValidationErrorKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPrototypeName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createTranslationString
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 __toString
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 createSchema
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2namespace Apie\HtmlBuilders\ValueObjects;
3
4use Apie\Core\Attributes\Description;
5use Apie\Core\Attributes\SchemaMethod;
6use Apie\Core\BoundedContext\BoundedContextId;
7use Apie\Core\Exceptions\InvalidTypeException;
8use Apie\Core\Identifiers\SnakeCaseSlug;
9use Apie\Core\Translator\ValueObjects\TranslationString;
10use Apie\Core\ValueObjects\Interfaces\ValueObjectInterface;
11use Apie\HtmlBuilders\Exceptions\EmptyFormNameException;
12use ReflectionClass;
13use Stringable;
14
15#[Description('Represents a form name field, for example form[a][b]')]
16#[SchemaMethod('createSchema')]
17final class FormName implements ValueObjectInterface, Stringable
18{
19    /** @var array<int, string> */
20    private array $internal = [];
21
22    public function __construct(string... $parts)
23    {
24        $this->internal = $parts;
25    }
26
27    /**
28     * @return static
29     */
30    public static function fromNative(mixed $input): self
31    {
32        if (is_string($input) && str_starts_with($input, 'form[')) {
33            // remove 'form['
34            $input = preg_replace('/^form\[/', '', $input);
35            // remove trailing ']'
36            $input = preg_replace('/\]$/', '', $input);
37            $input = str_replace('][', ',', $input);
38            return new static(...explode(',', $input));
39        }
40        if (is_iterable($input)) {
41            return new static(...$input);
42        }
43        throw new InvalidTypeException($input, 'string|array');
44    }
45
46    public function hasChildFormFieldName(): bool
47    {
48        return !empty($this->internal);
49    }
50
51    public function getChildFormFieldName(): string
52    {
53        if (empty($this->internal)) {
54            throw new EmptyFormNameException();
55        }
56        return end($this->internal);
57    }
58
59    public function createChildForm(string $formFieldName): self
60    {
61        return new self(...[...$this->internal, $formFieldName]);
62    }
63
64    /**
65     * @return array<string|int, string>
66     */
67    public function toNative(): array
68    {
69        return $this->internal;
70    }
71
72    public function toValidationErrorKey(): string
73    {
74        return implode('.', $this->internal);
75    }
76
77    public function getPrototypeName(): string
78    {
79        return '__' . end($this->internal);
80    }
81
82    /**
83     * @param ReflectionClass<object> $class
84     */
85    public function createTranslationString(ReflectionClass $class, ?BoundedContextId $boundedContextId = null): TranslationString
86    {
87        $suffix = '.'
88            . SnakeCaseSlug::fromClass($class)
89            . '.properties.'
90            . strtolower(implode('.', $this->internal));
91        if ($boundedContextId === null) {
92            return new TranslationString('apie.resource' . $suffix);
93        }
94        return new TranslationString('apie.bounded.' .  $boundedContextId . $suffix);
95    }
96
97    public function __toString(): string
98    {
99        if (empty($this->internal)) {
100            return 'form';
101        }
102        return 'form[' . implode('][', $this->internal) . ']';
103    }
104
105    /**
106     * @return array<string, mixed>
107     */
108    public static function createSchema(): array
109    {
110        return [
111            'type' => 'array',
112            'items' => [
113                'type' => 'string',
114            ]
115        ];
116    }
117}