1: <?php
2:
3: namespace Charcoal\Ui\Form;
4:
5: use \Exception;
6: use \InvalidArgumentException;
7:
8:
9: use \Charcoal\Factory\FactoryInterface;
10:
11:
12: use \Charcoal\Ui\Form\FormInterface;
13: use \Charcoal\Ui\FormGroup\FormGroupInterface;
14:
15: 16: 17:
18: trait FormTrait
19: {
20: 21: 22: 23: 24:
25: private $action = '';
26:
27: 28: 29: 30: 31:
32: private $method = 'post';
33:
34: 35: 36: 37: 38:
39: private $l10nMode = 'loop_inputs';
40:
41: 42: 43: 44: 45:
46: protected $groupDisplayMode;
47:
48: 49: 50: 51: 52:
53: protected $groups = [];
54:
55: 56: 57: 58: 59:
60: private $formData = [];
61:
62: 63: 64: 65: 66:
67: private $metadata;
68:
69: 70: 71: 72: 73:
74: protected $formGroupFactory;
75:
76: 77: 78: 79: 80:
81: private $groupCallback;
82:
83: 84: 85: 86:
87: public function setFormGroupFactory(FactoryInterface $factory)
88: {
89: $this->formGroupFactory = $factory;
90:
91: return $this;
92: }
93:
94: 95: 96: 97:
98: protected function formGroupFactory()
99: {
100: if ($this->formGroupFactory === null) {
101: throw new Exception(
102: 'Form group factory was not set.'
103: );
104: }
105:
106: return $this->formGroupFactory;
107: }
108:
109: 110: 111: 112:
113: public function setGroupCallback(callable $cb)
114: {
115: $this->groupCallback = $cb;
116:
117: return $this;
118: }
119:
120: 121: 122: 123: 124:
125: public function setAction($action)
126: {
127: if (!is_string($action)) {
128: throw new InvalidArgumentException(
129: 'Action must be a string'
130: );
131: }
132: $this->action = $action;
133:
134: return $this;
135: }
136:
137: 138: 139:
140: public function action()
141: {
142: return $this->action;
143: }
144:
145: 146: 147: 148: 149: 150: 151:
152: public function setMethod($method)
153: {
154: $method = strtolower($method);
155: if (!in_array($method, ['post', 'get'])) {
156: throw new InvalidArgumentException(
157: 'Method must be "post" or "get"'
158: );
159: }
160: $this->method = $method;
161:
162: return $this;
163: }
164:
165: 166: 167:
168: public function method()
169: {
170: return $this->method;
171: }
172:
173: 174: 175: 176:
177: public function setL10nMode($mode)
178: {
179: $this->l10nMode = $mode;
180:
181: return $this;
182: }
183:
184: 185: 186:
187: public function l10nMode()
188: {
189: return $this->l10nMode;
190: }
191:
192: 193: 194: 195: 196: 197:
198: public function setGroups(array $groups)
199: {
200: $this->groups = [];
201:
202: foreach ($groups as $groupIdent => $group) {
203: $this->addGroup($groupIdent, $group);
204: }
205:
206: return $this;
207: }
208:
209: 210: 211: 212: 213: 214: 215: 216:
217: public function addGroup($groupIdent, $group)
218: {
219: if ($group === false || $group === null) {
220: return $this;
221: }
222:
223: if (!is_string($groupIdent)) {
224: throw new InvalidArgumentException(
225: 'Group identifier must be a string'
226: );
227: }
228:
229: if ($group instanceof FormGroupInterface) {
230: $group = $this->updateFormGroup($group, null, $groupIdent);
231: } elseif (is_array($group)) {
232: $data = $group;
233:
234: if (isset($data['ident'])) {
235: $groupIdent = $data['ident'];
236: } else {
237: $data['ident'] = $groupIdent;
238: }
239:
240: $group = $this->createFormGroup($data);
241: } else {
242: throw new InvalidArgumentException(sprintf(
243: 'Group must be an instance of %s or an array of form group options, received %s',
244: 'FormGroupInterface',
245: (is_object($group) ? get_class($group) : gettype($group))
246: ));
247: }
248:
249: $this->groups[$groupIdent] = $group;
250:
251: return $this;
252: }
253:
254: 255: 256: 257: 258: 259:
260: protected function createFormGroup(array $data = null)
261: {
262: if (isset($data['type'])) {
263: $type = $data['type'];
264: } else {
265: $type = $this->defaultGroupType();
266: }
267:
268: $group = $this->formGroupFactory()->create($type);
269: $group->setForm($this);
270:
271: if ($data !== null) {
272: $group->setData($data);
273: }
274:
275: return $group;
276: }
277:
278: 279: 280: 281: 282: 283: 284: 285:
286: protected function updateFormGroup(
287: FormGroupInterface $group,
288: array $groupData = null,
289: $groupIdent = null
290: ) {
291: $group->setForm($this);
292:
293: if ($groupData !== null) {
294: $group->setData($groupData);
295: }
296:
297: if ($groupIdent !== null) {
298: $group->setIdent($groupIdent);
299: }
300:
301: return $group;
302: }
303:
304: 305: 306: 307: 308:
309: public function defaultGroupType()
310: {
311: return 'charcoal/ui/form-group/generic';
312: }
313:
314: 315: 316: 317: 318: 319:
320: public function groups(callable $groupCallback = null)
321: {
322: $groups = $this->groups;
323: uasort($groups, [$this, 'sortGroupsByPriority']);
324:
325: $groupCallback = (isset($groupCallback) ? $groupCallback : $this->groupCallback);
326:
327: $i = 1;
328: foreach ($groups as $group) {
329: if (!$group->active()) {
330: continue;
331: }
332:
333:
334: if ($group->isAuthorized() === false) {
335: continue;
336: }
337:
338: if (!$group->l10nMode()) {
339: $group->setL10nMode($this->l10nMode());
340: }
341:
342: if ($groupCallback) {
343: $groupCallback($group);
344: }
345:
346: $GLOBALS['widget_template'] = $group->template();
347:
348: if ($this->isTabbable() && $i > 1) {
349: $group->isHidden = true;
350: }
351: $i++;
352:
353: yield $group;
354:
355: $GLOBALS['widget_template'] = '';
356: }
357: }
358:
359: 360: 361: 362: 363:
364: public function hasGroups()
365: {
366: return (count($this->groups) > 0);
367: }
368:
369: 370: 371: 372: 373: 374: 375:
376: public function hasGroup($groupIdent)
377: {
378: if (!is_string($groupIdent)) {
379: throw new InvalidArgumentException(
380: 'Group identifier must be a string'
381: );
382: }
383:
384: return isset($this->groups[$groupIdent]);
385: }
386:
387: 388: 389: 390: 391:
392: public function numGroups()
393: {
394: return count($this->groups);
395: }
396:
397: 398: 399: 400: 401: 402: 403: 404: 405:
406: public function setGroupDisplayMode($mode)
407: {
408: if (!is_string($mode)) {
409: throw new InvalidArgumentException(
410: 'Display mode must be a string'
411: );
412: }
413:
414: if ($mode === 'tabs') {
415: $mode = 'tab';
416: }
417:
418: $this->groupDisplayMode = $mode;
419:
420: return $this;
421: }
422:
423: 424: 425: 426: 427:
428: public function groupDisplayMode()
429: {
430: return $this->groupDisplayMode;
431: }
432:
433: 434: 435: 436: 437:
438: public function isTabbable()
439: {
440: return ($this->groupDisplayMode() === 'tab');
441: }
442:
443: 444: 445: 446:
447: public function setFormData(array $formData)
448: {
449: $this->formData = $formData;
450:
451: return $this;
452: }
453:
454: 455: 456: 457: 458: 459:
460: public function addFormData($key, $val)
461: {
462: if (!is_string($key)) {
463: throw new InvalidArgumentException(
464: 'Can not add form data: Data key must be a string'
465: );
466: }
467: $this->formData[$key] = $val;
468:
469: return $this;
470: }
471:
472: 473: 474:
475: public function formData()
476: {
477: return $this->formData;
478: }
479:
480: 481: 482: 483: 484: 485: 486:
487: protected static function sortGroupsByPriority(
488: FormGroupInterface $a,
489: FormGroupInterface $b
490: ) {
491: $a = $a->priority();
492: $b = $b->priority();
493:
494: return ($a < $b) ? (-1) : 1;
495: }
496: }
497: