Completed
Branch develop (ab1b2a)
by Steve
07:43
created

FieldsBuilder::setGroupConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
nc 1
cc 1
eloc 3
nop 2
1
<?php
2
3
namespace StoutLogic\AcfBuilder;
4
5
/**
6
 * Builds configurations for ACF Field Groups
7
 */
8
class FieldsBuilder extends Builder implements NamedBuilder
9
{
10
    /**
11
     * Field Group Configuration
12
     * @var array
13
     */
14
    protected $config = [];
15
16
    /**
17
     * Manages the Field Configurations
18
     * @var FieldManager
19
     */
20
    protected $fieldManager;
21
22
    /**
23
     * Location configuration for Field Group
24
     * @var LocationBuilder
25
     */
26
    protected $location = null;
27
28
    /**
29
     * Field Group Name
30
     * @var string
31
     */
32
    protected $name;
33
34
    /**
35
     * @param string $name Field Group name
36
     * @param array $groupConfig Field Group configuration
37
     */
38
    public function __construct($name, $groupConfig = [])
39
    {
40
        $this->fieldManager = new FieldManager();
41
        $this->name = $name;
42
        $this->setGroupConfig('key', $name);
43
        $this->setGroupConfig('title', $this->generateLabel($name));
44
45
        $this->config = array_merge($this->config, $groupConfig);
46
    }
47
48
    /**
49
     * Set a value for a particular key in the group config
50
     * @param string $key
51
     * @param mixed $value
52
     */
53
    public function setGroupConfig($key, $value)
54
    {
55
        $this->config[$key] = $value;
56
57
        return $this;
58
    }
59
60
    /**
61
     * @return string
62
     */
63
    public function getName()
64
    {
65
        return $this->name;
66
    }
67
68
    /**
69
     * Namespace a group key
70
     * Append the namespace 'group' before the set key.
71
     *
72
     * @param  string $key Field Key
73
     * @return string      Field Key
74
     */
75
    private function namespaceGroupKey($key)
76
    {
77
        if (strpos($key, 'group_') !== 0) {
78
            $key = 'group_'.$key;
79
        }
80
        return $key;
81
    }
82
83
    /**
84
     * Build the final config array. Build any other builders that may exist
85
     * in the config.
86
     * @return array    final field config
87
     */
88
    public function build()
89
    {
90
        return array_merge($this->config, [
91
            'fields' => $this->buildFields(),
92
            'location' => $this->buildLocation(),
93
            'key' => $this->namespaceGroupKey($this->config['key']),
94
        ]);
95
    }
96
97
    /**
98
     * Return a fields config array
99
     * @return array
100
     */
101
    private function buildFields()
102
    {
103
        $fields = array_map(function ($field) {
104
            return ($field instanceof Builder) ? $field->build() : $field;
105
        }, $this->getFields());
106
107
        return $this->transformFields($fields);
108
    }
109
110
    /**
111
     * Apply field transforms
112
     * @param  array $fields
113
     * @return array Transformed fields config
114
     */
115
    private function transformFields($fields)
116
    {
117
        $conditionalTransform = new Transform\ConditionalLogic($this);
118
        $namespaceFieldKeyTransform = new Transform\NamespaceFieldKey($this);
119
120
        return
121
            $namespaceFieldKeyTransform->transform(
122
                $conditionalTransform->transform($fields)
123
            );
124
    }
125
126
    /**
127
     * Return a locations config array
128
     * @return array
129
     */
130
    private function buildLocation()
131
    {
132
        $location = $this->getLocation();
133
        return ($location instanceof Builder) ? $location->build() : $location;
134
    }
135
136
    /**
137
     * Add multiple fields either via an array or from another builder
138
     * @param mixed $fields array of fields or a FieldBuilder
139
     * @return $this
140
     */
141
    public function addFields($fields)
142
    {
143
        if ($fields instanceof FieldsBuilder) {
144
            $builder = clone $fields;
145
            $fields = $builder->getFields();
146
        }
147
148
        foreach ($fields as $field) {
149
            $this->getFieldManager()->pushField($field);
150
        }
151
152
        return $this;
153
    }
154
155
    /**
156
     * Add field to field group
157
     * @param string $name field name
158
     * @param array $args field options
159
     * @throws FieldNameCollisionException if name already exists.
160
     * @return $this
161
     */
162
    public function addField($name, $args = [])
163
    {
164
        $field = array_merge([
165
            'key' => $name,
166
            'name' => $name,
167
            'label' => $this->generateLabel($name),
168
        ], $args);
169
170
        $this->getFieldManager()->pushField($field);
171
        return $this;
172
    }
173
174
    /**
175
     * Add a field of a specific type
176
     * @param string $name
177
     * @param string $type
178
     * @param array $args field configuration
179
     * @return $this
180
     */
181
    protected function addFieldType($name, $type, $args = [])
182
    {
183
        return $this->addField($name, array_merge([
184
            'type' => $type,
185
        ], $args));
186
    }
187
188
    /**
189
     * @param string $name
190
     * @param array $args field configuration
191
     * @return $this
192
     */
193
    public function addText($name, $args = [])
194
    {
195
        return $this->addFieldType($name, 'text', $args);
196
    }
197
198
    /**
199
     * @param string $name
200
     * @param array $args field configuration
201
     * @return $this
202
     */
203
    public function addTextarea($name, $args = [])
204
    {
205
        return $this->addFieldType($name, 'textarea', $args);
206
    }
207
208
    /**
209
     * @param string $name
210
     * @param array $args field configuration
211
     * @return $this
212
     */
213
    public function addNumber($name, $args = [])
214
    {
215
        return $this->addFieldType($name, 'number', $args);
216
    }
217
218
    /**
219
     * @param string $name
220
     * @param array $args field configuration
221
     * @return $this
222
     */
223
    public function addEmail($name, $args = [])
224
    {
225
        return $this->addFieldType($name, 'email', $args);
226
    }
227
228
    /**
229
     * @param string $name
230
     * @param array $args field configuration
231
     * @return $this
232
     */
233
    public function addUrl($name, $args = [])
234
    {
235
        return $this->addFieldType($name, 'url', $args);
236
    }
237
238
    /**
239
     * @param string $name
240
     * @param array $args field configuration
241
     * @return $this
242
     */
243
    public function addPassword($name, $args = [])
244
    {
245
        return $this->addFieldType($name, 'password', $args);
246
    }
247
248
    /**
249
     * @param string $name
250
     * @param array $args field configuration
251
     * @return $this
252
     */
253
    public function addWysiwyg($name, $args = [])
254
    {
255
        return $this->addFieldType($name, 'wysiwyg', $args);
256
    }
257
258
    /**
259
     * @param string $name
260
     * @param array $args field configuration
261
     * @return $this
262
     */
263
    public function addOembed($name, $args = [])
264
    {
265
        return $this->addFieldType($name, 'oembed', $args);
266
    }
267
268
    /**
269
     * @param string $name
270
     * @param array $args field configuration
271
     * @return $this
272
     */
273
    public function addImage($name, $args = [])
274
    {
275
        return $this->addFieldType($name, 'image', $args);
276
    }
277
278
    /**
279
     * @param string $name
280
     * @param array $args field configuration
281
     * @return $this
282
     */
283
    public function addFile($name, $args = [])
284
    {
285
        return $this->addFieldType($name, 'file', $args);
286
    }
287
288
    /**
289
     * @param string $name
290
     * @param array $args field configuration
291
     * @return $this
292
     */
293
    public function addGallery($name, $args = [])
294
    {
295
        return $this->addFieldType($name, 'gallery', $args);
296
    }
297
298
    /**
299
     * @param string $name
300
     * @param array $args field configuration
301
     * @return $this
302
     */
303
    public function addTrueFalse($name, $args = [])
304
    {
305
        return $this->addFieldType($name, 'true_false', $args);
306
    }
307
308
    /**
309
     * @param string $name
310
     * @param array $args field configuration
311
     * @return $this
312
     */
313
    public function addSelect($name, $args = [])
314
    {
315
        return $this->addFieldType($name, 'select', $args);
316
    }
317
318
    /**
319
     * @param string $name
320
     * @param array $args field configuration
321
     * @return $this
322
     */
323
    public function addRadio($name, $args = [])
324
    {
325
        return $this->addFieldType($name, 'radio', $args);
326
    }
327
328
    /**
329
     * @param string $name
330
     * @param array $args field configuration
331
     * @return $this
332
     */
333
    public function addCheckbox($name, $args = [])
334
    {
335
        return $this->addFieldType($name, 'checkbox', $args);
336
    }
337
338
    /**
339
     * @param string $name
340
     * @param array $args field configuration
341
     * @return $this
342
     */
343
    public function addPostObject($name, $args = [])
344
    {
345
        return $this->addFieldType($name, 'post_object', $args);
346
    }
347
348
    /**
349
     * @param string $name
350
     * @param array $args field configuration
351
     * @return $this
352
     */
353
    public function addPostLink($name, $args = [])
354
    {
355
        return $this->addFieldType($name, 'post_link', $args);
356
    }
357
358
    /**
359
     * @param string $name
360
     * @param array $args field configuration
361
     * @return $this
362
     */
363
    public function addRelationship($name, $args = [])
364
    {
365
        return $this->addFieldType($name, 'relationship', $args);
366
    }
367
368
    /**
369
     * @param string $name
370
     * @param array $args field configuration
371
     * @return $this
372
     */
373
    public function addTaxonomy($name, $args = [])
374
    {
375
        return $this->addFieldType($name, 'taxonomy', $args);
376
    }
377
378
    /**
379
     * @param string $name
380
     * @param array $args field configuration
381
     * @return $this
382
     */
383
    public function addUser($name, $args = [])
384
    {
385
        return $this->addFieldType($name, 'user', $args);
386
    }
387
388
    /**
389
     * @param string $name
390
     * @param array $args field configuration
391
     * @return $this
392
     */
393
    public function addDatePicker($name, $args = [])
394
    {
395
        return $this->addFieldType($name, 'date_picker', $args);
396
    }
397
398
    /**
399
     * @param string $name
400
     * @param array $args field configuration
401
     * @return $this
402
     */
403
    public function addTimePicker($name, $args = [])
404
    {
405
        return $this->addFieldType($name, 'time_picker', $args);
406
    }
407
408
    /**
409
     * @param string $name
410
     * @param array $args field configuration
411
     * @return $this
412
     */
413
    public function addDateTimePicker($name, $args = [])
414
    {
415
        return $this->addFieldType($name, 'date_time_picker', $args);
416
    }
417
418
    /**
419
     * @param string $name
420
     * @param array $args field configuration
421
     * @return $this
422
     */
423
    public function addColorPicker($name, $args = [])
424
    {
425
        return $this->addFieldType($name, 'color_picker', $args);
426
    }
427
428
    /**
429
     * All fields added after will appear under this tab, until another tab
430
     * is added.
431
     * @param string $label Tab label
432
     * @param array $args field configuration
433
     * @return $this
434
     */
435 View Code Duplication
    public function addTab($label, $args = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
436
    {
437
        $name = $this->generateName($label).'_tab';
438
        $args = array_merge([
439
            'label' => $label,
440
        ], $args);
441
442
        return $this->addFieldType($name, 'tab', $args);
443
    }
444
445
    /**
446
     * Configs the tab as an endpoint tab. New tabs will start on another row.
447
     * @param  int $value boolean 1 or 0
448
     * @return $this
449
     */
450
    public function endpoint($value = 1)
451
    {
452
        return $this->setConfig('endpoint', $value);
453
    }
454
455
    /**
456
     * Addes a message field
457
     * @param string $label
458
     * @param string $message
459
     * @param array $args field configuration
460
     * @return $this
461
     */
462 View Code Duplication
    public function addMessage($label, $message, $args = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
463
    {
464
        $name = $this->generateName($label).'_message';
465
        $args = array_merge([
466
            'label' => $label,
467
            'message' => $message,
468
        ], $args);
469
470
        return $this->addFieldType($name, 'message', $args);
471
    }
472
473
    /**
474
     * Add a repeater field. Any fields added after will be added to the repeater
475
     * until `endRepeater` is called.
476
     * @param string $name
477
     * @param array $args field configuration
478
     * @return RepeaterBuilder
479
     */
480
    public function addRepeater($name, $args = [])
481
    {
482
        $repeaterBuilder = new RepeaterBuilder($name, $args);
483
        $repeaterBuilder->setParentContext($this);
484
        $this->getFieldManager()->pushField($repeaterBuilder);
485
486
        return $repeaterBuilder;
487
    }
488
489
    /**
490
     * Add a flexible content field. Once adding a layout with `addLayout`,
491
     * any fields added after will be added to that layout until another
492
     * `addLayout` call is made, or until `endFlexibleContent` is called.
493
     * @param string $name
494
     * @param array $args field configuration
495
     * @return FlexibleContentBuilder
496
     */
497
    public function addFlexibleContent($name, $args = [])
498
    {
499
        $flexibleContentBuilder = new FlexibleContentBuilder($name, $args);
500
        $flexibleContentBuilder->setParentContext($this);
501
        $this->getFieldManager()->pushField($flexibleContentBuilder);
502
503
        return $flexibleContentBuilder;
504
    }
505
506
    /**
507
     * Add a choice to the previously added radio, select or checkbox field
508
     * @param string $choice
509
     * @param string $label By default the value of $choice will appear next
510
     * to the field. Optionally pass in a manual value for the label.
511
     * @return $this
512
     */
513
    public function addChoice($choice, $label = null)
514
    {
515
        $field = $this->getFieldManager()->popField();
516
517
        array_key_exists('choices', $field) ?: $field['choices'] = [];
518
        $label ?: $label = $choice;
519
520
        $field['choices'][$choice] = $label;
521
        $this->getFieldManager()->pushField($field);
522
523
        return $this;
524
    }
525
526
    /**
527
     * Add a number of choices to a radio, select or checkbox field at once.
528
     * Each argument will be a choice. Pass in an array of format ['name' => 'label']
529
     * to specifiy a manually set label.
530
     * @return $this
531
     */
532
    public function addChoices()
533
    {
534
        foreach (func_get_args() as $choice) {
535
            if (is_array($choice)) {
536
                $values = each($choice);
537
                $this->addChoice($values['key'], $values['value']);
538
                continue;
539
            }
540
541
            $this->addChoice($choice);
542
        }
543
544
        return $this;
545
    }
546
547
    /**
548
     * Add a conditional logic statement that will determine if the last added
549
     * field will display or not. You can add `or` or `and` calls after
550
     * to build complex logic. Any other function call will return you to the
551
     * parentContext.
552
     * @param  string $name Dependent field name
553
     *                      (choice type: radio, checkbox, select, trueFalse)
554
     * @param  string $operator ==, !=
555
     * @param  string $value    1 or choice value
556
     * @return ConditionalBuilder
557
     */
558
    public function conditional($name, $operator, $value)
559
    {
560
        $field = $this->getFieldManager()->popField();
561
        $conditionalBuilder = new ConditionalBuilder($name, $operator, $value);
562
        $conditionalBuilder->setParentContext($this);
563
564
        $field['conditional_logic'] = $conditionalBuilder;
565
        $this->getFieldManager()->pushField($field);
566
567
        return $conditionalBuilder;
568
    }
569
570
    /**
571
     * @return FieldManager
572
     */
573
    protected function getFieldManager()
574
    {
575
        return $this->fieldManager;
576
    }
577
578
    /**
579
     * @return array
580
     */
581
    public function getFields()
582
    {
583
        return $this->getFieldManager()->getFields();
584
    }
585
586
    /**
587
     * @param string $name [description]
588
     * @return array|Builder
589
     */
590
    public function getField($name)
591
    {
592
        return $this->getFieldManager()->getField($name);
593
    }
594
595
    /**
596
     * Modify an already defined field
597
     * @param  string $name   Name of the field
598
     * @param  array|\Closure  $modify Array of field configs or a closure that accepts
599
     * a FieldsBuilder and returns a FieldsBuilder.
600
     * @throws ModifyFieldReturnTypeException if $modify is a closure and doesn't
601
     * return a FieldsBuilder.
602
     * @throws FieldNotFoundException if the field name doesn't exist.
603
     * @return $this
604
     */
605
    public function modifyField($name, $modify)
606
    {
607
        if (is_array($modify)) {
608
            $this->getFieldManager()->modifyField($name, $modify);
609
        } elseif ($modify instanceof \Closure) {
610
            $field = $this->getField($name);
611
612
            // Initialize Modifying FieldsBuilder
613
            $modifyBuilder = new FieldsBuilder('');
614
            $modifyBuilder->addFields([$field]);
615
616
            /**
617
             * @var FieldsBuilder
618
             */
619
            $modifyBuilder = $modify($modifyBuilder);
620
621
            // Check if a FieldsBuilder is returned
622
            if (!$modifyBuilder instanceof FieldsBuilder) {
623
                throw new ModifyFieldReturnTypeException(gettype($modifyBuilder));
624
            }
625
626
            // Build Modifications
627
            $modifyConfig = $modifyBuilder->build();
628
629
            // Insert field(s)
630
            $this->getFieldManager()->replaceField($name, $modifyConfig['fields']);
631
        }
632
633
        return $this;
634
    }
635
636
    /**
637
     * Remove a field by name
638
     * @param  string $name Field to remove
639
     * @return $this
640
     */
641
    public function removeField($name)
642
    {
643
        $this->getFieldManager()->removeField($name);
644
645
        return $this;
646
    }
647
648
    /**
649
     * Set the default value of previously added field
650
     * @param  string $value
651
     * @return $this
652
     */
653
    public function defaultValue($value)
654
    {
655
        return $this->setConfig('default_value', $value);
656
    }
657
658
    /**
659
     * Mark the previously added field as required
660
     * @param  bool $value
661
     * @return $this
662
     */
663
    public function required($value = true)
664
    {
665
        return $this->setConfig('required', $value ? 1 : 0);
666
    }
667
668
    /**
669
     * Add instructions for the previously added field
670
     * @param  string $value
671
     * @return $this
672
     */
673
    public function instructions($value)
674
    {
675
        return $this->setConfig('instructions', $value);
676
    }
677
678
    /**
679
     * Set a configuration by key on the previously added field
680
     * @param string $key
681
     * @param string $value
682
     * @return $this
683
     */
684
    public function setConfig($key, $value)
685
    {
686
        $field = $this->getFieldManager()->popField();
687
        $field[$key] = $value;
688
        $this->getFieldManager()->pushField($field);
689
690
        return $this;
691
    }
692
693
    /**
694
     * Set the location of the field group. See
695
     * https://github.com/StoutLogic/acf-builder/wiki/location and
696
     * https://www.advancedcustomfields.com/resources/custom-location-rules/
697
     * for more details.
698
     * @param string $param
699
     * @param string $operator
700
     * @param string $value
701
     * @return LocationBuilder
702
     */
703
    public function setLocation($param, $operator, $value)
704
    {
705
        if ($this->getParentContext()) {
706
            return $this->getParentContext()->setLocation($param, $operator, $value);
0 ignored issues
show
Documentation Bug introduced by
The method setLocation does not exist on object<StoutLogic\AcfBuilder\Builder>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
707
        }
708
709
        $this->location = new LocationBuilder($param, $operator, $value);
710
        $this->location->setParentContext($this);
711
712
        return $this->location;
713
    }
714
715
    /**
716
     * @return LocationBuilder
717
     */
718
    public function getLocation()
719
    {
720
        return $this->location;
721
    }
722
723
    /**
724
     * Create a field label based on the field's name. Generates title case.
725
     * @param  string $name
726
     * @return string label
727
     */
728
    protected function generateLabel($name)
729
    {
730
        return ucwords(str_replace("_", " ", $name));
731
    }
732
733
    /**
734
     * Generates a snaked cased name.
735
     * @param  string $name
736
     * @return string
737
     */
738
    protected function generateName($name)
739
    {
740
        return strtolower(str_replace(" ", "_", $name));
741
    }
742
}
743