1: <?php
2:
3: namespace Charcoal\Ui\FormGroup;
4:
5: use \InvalidArgumentException;
6:
7: // Intra-module (`charcoal-ui`) dependencies
8: use \Charcoal\Ui\Form\FormInterface;
9: use \Charcoal\Ui\FormInput\FormInputBuilder;
10: use \Charcoal\Ui\FormInput\FormInputInterface;
11:
12: /**
13: * Provides an implementation of {@see \Charcoal\Ui\FormGroup\FormGroupInterface}.
14: */
15: trait FormGroupTrait
16: {
17: /**
18: * Store a reference to the parent form widget.
19: *
20: * @var FormInterface
21: */
22: protected $form;
23:
24: /**
25: * The group's collection of fields.
26: *
27: * @var FormInputInterface[]
28: */
29: private $inputs;
30:
31: /**
32: * The input callback; called on every input.
33: *
34: * Callable signature: `function(FormInputInterface $input)`
35: *
36: * @var callable
37: */
38: private $inputCallback;
39:
40: /**
41: * Store the builder instance for the current class.
42: *
43: * @var FormInputBuilder
44: */
45: protected $formInputBuilder;
46:
47: /**
48: * The L10N display mode.
49: *
50: * @var string
51: */
52: private $l10nMode;
53:
54: /**
55: * The group's identifier.
56: *
57: * @var string
58: */
59: private $ident;
60:
61: /**
62: * The group's priority.
63: *
64: * @var integer
65: */
66: private $priority;
67:
68: /**
69: * The required Acl permissions fetch from form group.
70: *
71: * @var string[] $requiredAclPermissions
72: */
73: private $requiredAclPermissions = [];
74:
75: /**
76: * Class or Classes for tab form group.
77: *
78: * @var string|string[]
79: */
80: private $tabCssClasses;
81:
82: /**
83: * @param FormInputBuilder $builder The builder, to create customized form input objects.
84: * @return FormGroupInterface Chainable
85: */
86: protected function setFormInputBuilder(FormInputBuilder $builder)
87: {
88: $this->formInputBuilder = $builder;
89:
90: return $this;
91: }
92:
93: /**
94: * @param callable $cb The input callback.
95: * @return FormGroupInterface Chainable
96: */
97: public function setInputCallback(callable $cb)
98: {
99: $this->inputCallback = $cb;
100:
101: return $this;
102: }
103:
104: /**
105: * @param FormInterface $form The parent form object.
106: * @return FormGroupInterface Chainable
107: */
108: public function setForm(FormInterface $form)
109: {
110: $this->form = $form;
111:
112: return $this;
113: }
114:
115: /**
116: * @return FormInterface
117: */
118: public function form()
119: {
120: return $this->form;
121: }
122:
123: /**
124: * @param string $mode The l10n mode.
125: * @return FormGroupInterface Chainable
126: */
127: public function setL10nMode($mode)
128: {
129: $this->l10nMode = $mode;
130:
131: return $this;
132: }
133:
134: /**
135: * @return string
136: */
137: public function l10nMode()
138: {
139: return $this->l10nMode;
140: }
141:
142: /**
143: * @param array $inputs The group inputs.
144: * @return FormGroupInterface Chainable
145: */
146: public function setInputs(array $inputs)
147: {
148: $this->inputs = [];
149: foreach ($inputs as $inputIdent => $input) {
150: $this->addInput($inputIdent, $input);
151: }
152:
153: return $this;
154: }
155:
156: /**
157: * @param string $inputIdent The input identifier.
158: * @param array|FormInputInterface $input The input object or structure.
159: * @throws InvalidArgumentException If the ident argument is not a string or if the input is not valid.
160: * @return FormGroupInterface Chainable
161: */
162: public function addInput($inputIdent, $input)
163: {
164: if (!is_string($inputIdent)) {
165: throw new InvalidArgumentException(
166: 'Group ident must be a string'
167: );
168: }
169:
170: if (($input instanceof FormInputInterface)) {
171: $input->setForm($this->form);
172: $input->setFormGroup($this);
173: $this->inputs[$inputIdent] = $input;
174: } elseif (is_array($input)) {
175: $g = $this->formInputBuilder->build($input);
176: $this->inputs[$inputIdent] = $g;
177: } else {
178: throw new InvalidArgumentException(
179: 'Group must be a Form Group object or an array of form group options'
180: );
181: }
182:
183: return $this;
184: }
185:
186: /**
187: * Form Input generator.
188: *
189: * @param callable $inputCallback Optional. Input callback.
190: * @return FormGroupInterface[]|Generator
191: */
192: public function inputs(callable $inputCallback = null)
193: {
194: $groups = $this->groups;
195: uasort($groups, ['self', 'sortInputsByPriority']);
196:
197: $inputCallback = isset($inputCallback) ? $inputCallback : $this->inputCallback;
198: foreach ($inputs as $input) {
199: if (!$input->l10nMode()) {
200: $input->setL10nMode($this->l10nMode());
201: }
202: if ($inputCallback) {
203: $inputCallback($input);
204: }
205: $GLOBALS['widget_template'] = $input->template();
206: yield $input->ident() => $input;
207: $GLOBALS['widget_template'] = '';
208: }
209: }
210:
211: /**
212: * Wether this group contains any inputs.
213: *
214: * @return boolean
215: */
216: public function hasInputs()
217: {
218: return (count($this->inputs) > 0);
219: }
220:
221: /**
222: * Get the number of inputs in this group.
223: *
224: * @return integer
225: */
226: public function numInputs()
227: {
228: return count($this->inputs);
229: }
230:
231: /**
232: * Set the identifier of the group.
233: *
234: * @param string $ident The group identifier.
235: * @return self
236: */
237: public function setIdent($ident)
238: {
239: $this->ident = $ident;
240:
241: return $this;
242: }
243:
244: /**
245: * Retrieve the idenfitier of the group.
246: *
247: * @return string
248: */
249: public function ident()
250: {
251: return $this->ident;
252: }
253:
254: /**
255: * Set the group's priority or sorting index.
256: *
257: * @param integer $priority An index, for sorting.
258: * @throws InvalidArgumentException If the priority is not an integer.
259: * @return self
260: */
261: public function setPriority($priority)
262: {
263: if (!is_numeric($priority)) {
264: throw new InvalidArgumentException(
265: 'Priority must be an integer'
266: );
267: }
268:
269: $this->priority = intval($priority);
270:
271: return $this;
272: }
273:
274: /**
275: * Retrieve the group's priority or sorting index.
276: *
277: * @return integer
278: */
279: public function priority()
280: {
281: return $this->priority;
282: }
283:
284: /**
285: * @param string|\string[] $classes Class or Classes for tab form group.
286: * @return self
287: */
288: public function setTabCssClasses($classes)
289: {
290: if (is_string($classes)) {
291: $this->tabCssClasses = $classes;
292: }
293:
294: if (is_array($classes)) {
295: $this->tabCssClasses = implode(' ', $classes);
296: }
297:
298: return $this;
299: }
300:
301: /**
302: * @return string|\string[]
303: */
304: public function tabCssClasses()
305: {
306: return $this->tabCssClasses;
307: }
308: }
309: