CallbackArrayConstraint   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 59
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 11
dl 0
loc 59
ccs 14
cts 14
cp 1
rs 10
c 1
b 0
f 0
wmc 5

3 Methods

Rating   Name   Duplication   Size   Complexity  
A applyOnChildBuilder() 0 9 2
A __construct() 0 27 1
A generateCodeForChildBuilder() 0 10 2
1
<?php
2
3
namespace Bdf\Form\Attribute\Aggregate;
4
5
use Attribute;
6
use Bdf\Form\Aggregate\ArrayElementBuilder;
7
use Bdf\Form\Attribute\AttributeForm;
8
use Bdf\Form\Attribute\ChildBuilderAttributeInterface;
9
use Bdf\Form\Attribute\Processor\CodeGenerator\AttributesProcessorGenerator;
10
use Bdf\Form\Attribute\Processor\GenerateConfiguratorStrategy;
11
use Bdf\Form\Child\ChildBuilderInterface;
12
use Bdf\Form\Constraint\Closure;
13
use Bdf\Form\ElementBuilderInterface;
14
use Nette\PhpGenerator\Literal;
15
use Symfony\Component\Validator\Constraint;
16
17
/**
18
 * Define a custom constraint for an array element, using a validation method
19
 *
20
 * This attribute is equivalent to call :
21
 * <code>
22
 * $builder->array('foo')->arrayConstraint([$this, 'validateFoo'], 'Foo is invalid');
23
 * </code>
24
 *
25
 * Usage:
26
 * <code>
27
 * class MyForm extends AttributeForm
28
 * {
29
 *     #[CustomConstraint('validateFoo', message: 'Foo is invalid')]
30
 *     private ArrayElement $foo;
31
 *
32
 *     public function validateFoo(array $value, ElementInterface $input): bool
33
 *     {
34
 *         return count($value) % 5 > 2;
35
 *     }
36
 * }
37
 * </code>
38
 *
39
 * @see ArrayElementBuilder::arrayConstraint() The called method
40
 * @see Constraint
41
 * @see Closure The used constraint
42
 * @see ArrayConstraint Use for a class constraint
43
 *
44
 * @implements ChildBuilderAttributeInterface<ArrayElementBuilder>
45
 */
46
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
47
final class CallbackArrayConstraint implements ChildBuilderAttributeInterface
48
{
49 3
    public function __construct(
50
        /**
51
         * The method name to use as validator
52
         * Must be a public method declared on the form class
53
         *
54
         * Its prototype should be :
55
         * `public function (array $value, ElementInterface $input): bool|string|array{code: string message: string}|null`
56
         *
57
         * - Return true, or null (nothing) for a valid input
58
         * - Return false for invalid input, with the default error message (or the declared one)
59
         * - Return string for a custom error message
60
         * - Return array with error message and code
61
         *
62
         * @var literal-string
63
         * @readonly
64
         */
65
        private string $methodName,
66
        /**
67
         * The error message to use
68
         * This option is used only if the validator return false, in other cases,
69
         * the message returned by the validator will be used
70
         *
71
         * @var string|null
72
         * @readonly
73
         */
74
        private ?string $message = null,
75
    ) {
76 3
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81 1
    public function applyOnChildBuilder(AttributeForm $form, ChildBuilderInterface $builder): void
82
    {
83 1
        $constraint = new Closure(['callback' => [$form, $this->methodName]]);
84
85 1
        if ($this->message) {
86 1
            $constraint->message = $this->message;
87
        }
88
89 1
        $builder->arrayConstraint($constraint);
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95 2
    public function generateCodeForChildBuilder(string $name, AttributesProcessorGenerator $generator, AttributeForm $form): void
96
    {
97 2
        $generator->use(Closure::class, 'ClosureConstraint');
98
99 2
        $parameters = $this->message
100 2
            ? new Literal("['callback' => [\$form, ?], 'message' => ?]", [$this->methodName, $this->message])
101 2
            : new Literal('[$form, ?]', [$this->methodName])
102 2
        ;
103
104 2
        $generator->line('$?->arrayConstraint(new ClosureConstraint(?));', [$name, $parameters]);
105
    }
106
}
107