-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChoices.php
More file actions
146 lines (136 loc) · 4.22 KB
/
Choices.php
File metadata and controls
146 lines (136 loc) · 4.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<?php
namespace Bdf\Form\Attribute\Element;
use Attribute;
use Bdf\Form\AbstractElementBuilder;
use Bdf\Form\Attribute\AttributeForm;
use Bdf\Form\Attribute\ChildBuilderAttributeInterface;
use Bdf\Form\Attribute\Processor\CodeGenerator\AttributesProcessorGenerator;
use Bdf\Form\Attribute\Processor\GenerateConfiguratorStrategy;
use Bdf\Form\Child\ChildBuilderInterface;
use Bdf\Form\Choice\ArrayChoice;
use Bdf\Form\Choice\Choiceable;
use Bdf\Form\Choice\ChoiceBuilderTrait;
use Bdf\Form\Choice\ChoiceInterface;
use Bdf\Form\Choice\LazyChoice;
use Bdf\Form\ElementBuilderInterface;
use Bdf\Form\Leaf\StringElementBuilder;
use Nette\PhpGenerator\Literal;
/**
* Define available values choice for the element
*
* The choices can be :
* - a simple array of values (without labels)
* - an associative array for provide a label (in key), and inner value (in value)
* - a method name for resolving choices in lazy way
*
* Note: this attribute is not repeatable
*
* This attribute is equivalent to call :
* <code>
* $builder->string('foo')->choices(['bar', 'baz']);
* </code>
*
* Usage:
* <code>
* class MyForm extends AttributeForm
* {
* #[Choices(['bar', 'rab'])]
* private StringElement $foo;
*
* #[Choices(['My label' => 'v1', 'Other label' => 'v2'])]
* private StringElement $bar;
*
* #[Choices('loadBazValues', 'Invalid value')]
* private StringElement $baz;
*
* // For dynamic choices, or with complex logic
* public function loadBazValues(): array
* {
* $values = [];
*
* foreach (BazEntity::all() as $baz) {
* $values[$baz->label()] = $baz->id();
* }
*
* return $values;
* }
* }
* </code>
*
* @implements ChildBuilderAttributeInterface<\Bdf\Form\ElementBuilderInterface>
*
* @see ChoiceBuilderTrait::choices() The called method
* @see Choiceable Supported element type
* @see ArrayChoice Used when an array is given as parameter
* @see LazyChoice Used when a method name is given as parameter
*
* @api
*/
#[Attribute(Attribute::TARGET_PROPERTY)]
final class Choices implements ChildBuilderAttributeInterface
{
public function __construct(
/**
* Choice provider
*
* Can be a method name for load choices. The method must be public and declared on the form class,
* with the prototype `public function (): array`
*
* If the value is an array, the key will be used as label (displayed value), and the value as real value
* The label is not required.
*
* @var literal-string|array
* @readonly
*/
private string|array $choices,
/**
* The error message
* If not provided, a default message will be used
*
* @var string|null
* @readonly
*/
private ?string $message = null,
/**
* Extra constraint options
*
* @var array
* @readonly
*/
private array $options = [],
) {
}
/**
* {@inheritdoc}
*/
public function applyOnChildBuilder(AttributeForm $form, ChildBuilderInterface $builder): void
{
$options = $this->options;
if ($this->message !== null) {
$options['message'] = $options['multipleMessage'] = $this->message;
}
// Q&D fix for psalm because it does not recognize trait as type
/** @var StringElementBuilder $builder */
$builder->choices(
is_string($this->choices) ? new LazyChoice([$form, $this->choices]) : $this->choices,
$options
);
}
/**
* {@inheritdoc}
*/
public function generateCodeForChildBuilder(string $name, AttributesProcessorGenerator $generator, AttributeForm $form): void
{
$options = $this->options;
if ($this->message !== null) {
$options['message'] = $options['multipleMessage'] = $this->message;
}
if (is_string($this->choices)) {
$generator->use(LazyChoice::class);
$choices = new Literal('new LazyChoice([$form, ?])', [$this->choices]);
} else {
$choices = $this->choices;
}
$generator->line('$?->choices(?, ?);', [$name, $choices, $options]);
}
}