Passed
Branch develop (d96422)
by Steve
03:03
created

FieldsBuilder::getGroupConfig()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace StoutLogic\AcfBuilder;
4
5
/**
6
 * Builds configurations for ACF Field Groups
7
 */
8
class FieldsBuilder extends ParentDelegationBuilder 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
     * Get a value for a particular key in the group config.
62
     * Returns null if the key isn't defined in the config.
63
     * @param string $key
64
     * @return mixed|null
65
     */
66
    public function getGroupConfig($key)
67
    {
68
        if (array_key_exists($key, $this->config)) {
69
            return $this->config[$key];
70
        }
71
72
        return null;
73
    }
74
75
    /**
76
     * @return string
77
     */
78
    public function getName()
79
    {
80
        return $this->name;
81
    }
82
83
    /**
84
     * Namespace a group key
85
     * Append the namespace 'group' before the set key.
86
     *
87
     * @param  string $key Field Key
88
     * @return string      Field Key
89
     */
90
    private function namespaceGroupKey($key)
91
    {
92
        if (strpos($key, 'group_') !== 0) {
93
            $key = 'group_'.$key;
94
        }
95
        return $key;
96
    }
97
98
    /**
99
     * Build the final config array. Build any other builders that may exist
100
     * in the config.
101
     * @return array Final field config
102
     */
103
    public function build()
104
    {
105
        return array_merge($this->config, [
106
            'fields' => $this->buildFields(),
107
            'location' => $this->buildLocation(),
108
            'key' => $this->namespaceGroupKey($this->config['key']),
109
        ]);
110
    }
111
112
    /**
113
     * Return a fields config array
114
     * @return array
115
     */
116
    private function buildFields()
117
    {
118
        $fields = array_map(function ($field) {
119
            return ($field instanceof Builder) ? $field->build() : $field;
120
        }, $this->getFields());
121
122
        return $this->transformFields($fields);
123
    }
124
125
    /**
126
     * Apply field transforms
127
     * @param  array $fields
128
     * @return array Transformed fields config
129
     */
130
    private function transformFields($fields)
131
    {
132
        $conditionalTransform = new Transform\ConditionalLogic($this);
133
        $namespaceFieldKeyTransform = new Transform\NamespaceFieldKey($this);
134
135
        return
136
            $namespaceFieldKeyTransform->transform(
137
                $conditionalTransform->transform($fields)
138
            );
139
    }
140
141
    /**
142
     * Return a locations config array
143
     * @return array
144
     */
145
    private function buildLocation()
146
    {
147
        $location = $this->getLocation();
148
        return ($location instanceof Builder) ? $location->build() : $location;
149
    }
150
151
    /**
152
     * Add multiple fields either via an array or from another builder
153
     * @param mixed $fields array of fields or a FieldBuilder
154
     * @return $this
155
     */
156
    public function addFields($fields)
157
    {
158
        if ($fields instanceof FieldsBuilder) {
159
            $builder = clone $fields;
160
            $fields = $builder->getFields();
161
        }
162
        foreach ($fields as $field) {
163
            $this->getFieldManager()->pushField($field);
164
        }
165
166
        return $this;
167
    }
168
169
    /**
170
     * Add a field of a specific type
171
     * @param string $name
172
     * @param string $type
173
     * @param array $args field configuration
174
     * @throws FieldNameCollisionException if name already exists.
175
     * @return FieldBuilder
176
     */
177
    public function addField($name, $type, $args = [])
178
    {
179
        return $this->initializeField(new FieldBuilder($name, $type, $args));
180
    }
181
182
    /**
183
     * Add a field of a choice type, allows choices to be added.
184
     * @param string $name
185
     * @param string $type 'select', 'radio', 'checkbox'
186
     * @param array $args field configuration
187
     * @throws FieldNameCollisionException if name already exists.
188
     * @return FieldBuilder
189
     */
190
    public function addChoiceField($name, $type, $args = [])
191
    {
192
        return $this->initializeField(new ChoiceFieldBuilder($name, $type, $args));
193
    }
194
195
    /**
196
     * Initialize the FieldBuilder, add to FieldManager
197
     * @param  FieldBuilder $field
198
     * @return FieldBuilder
199
     */
200
    protected function initializeField($field)
201
    {
202
        $field->setParentContext($this);
203
        $this->getFieldManager()->pushField($field);
204
        return $field;
205
    }
206
207
    /**
208
     * @param string $name
209
     * @param array $args field configuration
210
     * @return $this
211
     */
212
    public function addText($name, $args = [])
213
    {
214
        return $this->addField($name, 'text', $args);
215
    }
216
217
    /**
218
     * @param string $name
219
     * @param array $args field configuration
220
     * @return $this
221
     */
222
    public function addTextarea($name, $args = [])
223
    {
224
        return $this->addField($name, 'textarea', $args);
225
    }
226
227
    /**
228
     * @param string $name
229
     * @param array $args field configuration
230
     * @return $this
231
     */
232
    public function addNumber($name, $args = [])
233
    {
234
        return $this->addField($name, 'number', $args);
235
    }
236
237
    /**
238
     * @param string $name
239
     * @param array $args field configuration
240
     * @return $this
241
     */
242
    public function addEmail($name, $args = [])
243
    {
244
        return $this->addField($name, 'email', $args);
245
    }
246
247
    /**
248
     * @param string $name
249
     * @param array $args field configuration
250
     * @return $this
251
     */
252
    public function addUrl($name, $args = [])
253
    {
254
        return $this->addField($name, 'url', $args);
255
    }
256
257
    /**
258
     * @param string $name
259
     * @param array $args field configuration
260
     * @return $this
261
     */
262
    public function addPassword($name, $args = [])
263
    {
264
        return $this->addField($name, 'password', $args);
265
    }
266
267
    /**
268
     * @param string $name
269
     * @param array $args field configuration
270
     * @return $this
271
     */
272
    public function addWysiwyg($name, $args = [])
273
    {
274
        return $this->addField($name, 'wysiwyg', $args);
275
    }
276
277
    /**
278
     * @param string $name
279
     * @param array $args field configuration
280
     * @return $this
281
     */
282
    public function addOembed($name, $args = [])
283
    {
284
        return $this->addField($name, 'oembed', $args);
285
    }
286
287
    /**
288
     * @param string $name
289
     * @param array $args field configuration
290
     * @return $this
291
     */
292
    public function addImage($name, $args = [])
293
    {
294
        return $this->addField($name, 'image', $args);
295
    }
296
297
    /**
298
     * @param string $name
299
     * @param array $args field configuration
300
     * @return $this
301
     */
302
    public function addFile($name, $args = [])
303
    {
304
        return $this->addField($name, 'file', $args);
305
    }
306
307
    /**
308
     * @param string $name
309
     * @param array $args field configuration
310
     * @return $this
311
     */
312
    public function addGallery($name, $args = [])
313
    {
314
        return $this->addField($name, 'gallery', $args);
315
    }
316
317
    /**
318
     * @param string $name
319
     * @param array $args field configuration
320
     * @return $this
321
     */
322
    public function addTrueFalse($name, $args = [])
323
    {
324
        return $this->addField($name, 'true_false', $args);
325
    }
326
327
    /**
328
     * @param string $name
329
     * @param array $args field configuration
330
     * @return $this
331
     */
332
    public function addSelect($name, $args = [])
333
    {
334
        return $this->addChoiceField($name, 'select', $args);
335
    }
336
337
    /**
338
     * @param string $name
339
     * @param array $args field configuration
340
     * @return $this
341
     */
342
    public function addRadio($name, $args = [])
343
    {
344
        return $this->addChoiceField($name, 'radio', $args);
345
    }
346
347
    /**
348
     * @param string $name
349
     * @param array $args field configuration
350
     * @return $this
351
     */
352
    public function addCheckbox($name, $args = [])
353
    {
354
        return $this->addChoiceField($name, 'checkbox', $args);
355
    }
356
357
    /**
358
     * @param string $name
359
     * @param array $args field configuration
360
     * @return $this
361
     */
362
    public function addPostObject($name, $args = [])
363
    {
364
        return $this->addField($name, 'post_object', $args);
365
    }
366
367
    /**
368
     * @param string $name
369
     * @param array $args field configuration
370
     * @return $this
371
     */
372
    public function addPostLink($name, $args = [])
373
    {
374
        return $this->addField($name, 'post_link', $args);
375
    }
376
377
    /**
378
     * @param string $name
379
     * @param array $args field configuration
380
     * @return $this
381
     */
382
    public function addRelationship($name, $args = [])
383
    {
384
        return $this->addField($name, 'relationship', $args);
385
    }
386
387
    /**
388
     * @param string $name
389
     * @param array $args field configuration
390
     * @return $this
391
     */
392
    public function addTaxonomy($name, $args = [])
393
    {
394
        return $this->addField($name, 'taxonomy', $args);
395
    }
396
397
    /**
398
     * @param string $name
399
     * @param array $args field configuration
400
     * @return $this
401
     */
402
    public function addUser($name, $args = [])
403
    {
404
        return $this->addField($name, 'user', $args);
405
    }
406
407
    /**
408
     * @param string $name
409
     * @param array $args field configuration
410
     * @return $this
411
     */
412
    public function addDatePicker($name, $args = [])
413
    {
414
        return $this->addField($name, 'date_picker', $args);
415
    }
416
417
    /**
418
     * @param string $name
419
     * @param array $args field configuration
420
     * @return $this
421
     */
422
    public function addTimePicker($name, $args = [])
423
    {
424
        return $this->addField($name, 'time_picker', $args);
425
    }
426
427
    /**
428
     * @param string $name
429
     * @param array $args field configuration
430
     * @return $this
431
     */
432
    public function addDateTimePicker($name, $args = [])
433
    {
434
        return $this->addField($name, 'date_time_picker', $args);
435
    }
436
437
    /**
438
     * @param string $name
439
     * @param array $args field configuration
440
     * @return $this
441
     */
442
    public function addColorPicker($name, $args = [])
443
    {
444
        return $this->addField($name, 'color_picker', $args);
445
    }
446
447
    /**
448
     * All fields added after will appear under this tab, until another tab
449
     * is added.
450
     * @param string $label Tab label
451
     * @param array $args field configuration
452
     * @return $this
453
     */
454
    public function addTab($label, $args = [])
455
    {
456
        return $this->initializeField(new TabBuilder($label, 'tab', $args));
457
    }
458
459
    /**
460
     * Addes a message field
461
     * @param string $label
462
     * @param string $message
463
     * @param array $args field configuration
464
     * @return $this
465
     */
466
    public function addMessage($label, $message, $args = [])
467
    {
468
        $name = $this->generateName($label).'_message';
469
        $args = array_merge([
470
            'label' => $label,
471
            'message' => $message,
472
        ], $args);
473
474
        return $this->addField($name, 'message', $args);
475
    }
476
477
    /**
478
     * Add a repeater field. Any fields added after will be added to the repeater
479
     * until `endRepeater` is called.
480
     * @param string $name
481
     * @param array $args field configuration
482
     * @return RepeaterBuilder
483
     */
484
    public function addRepeater($name, $args = [])
485
    {
486
        return $this->initializeField(new RepeaterBuilder($name, 'repeater', $args));
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
        return $this->initializeField(new FlexibleContentBuilder($name, 'flexible_content', $args));
500
    }
501
502
    /**
503
     * @return FieldManager
504
     */
505
    protected function getFieldManager()
506
    {
507
        return $this->fieldManager;
508
    }
509
510
    /**
511
     * @return array
512
     */
513
    public function getFields()
514
    {
515
        return $this->getFieldManager()->getFields();
516
    }
517
518
    /**
519
     * @param string $name [description]
520
     * @return FieldBuilder
521
     */
522
    public function getField($name)
523
    {
524
        return $this->getFieldManager()->getField($name);
525
    }
526
527
    /**
528
     * Modify an already defined field
529
     * @param  string $name   Name of the field
530
     * @param  array|\Closure  $modify Array of field configs or a closure that accepts
531
     * a FieldsBuilder and returns a FieldsBuilder.
532
     * @throws ModifyFieldReturnTypeException if $modify is a closure and doesn't
533
     * return a FieldsBuilder.
534
     * @throws FieldNotFoundException if the field name doesn't exist.
535
     * @return $this
536
     */
537
    public function modifyField($name, $modify)
538
    {
539
        if (is_array($modify)) {
540
            $this->getFieldManager()->modifyField($name, $modify);
541
        } elseif ($modify instanceof \Closure) {
542
            $field = $this->getField($name);
543
544
            // Initialize Modifying FieldsBuilder
545
            $modifyBuilder = new FieldsBuilder('');
546
            $modifyBuilder->addFields([$field]);
547
548
            /**
549
             * @var FieldsBuilder
550
             */
551
            $modifyBuilder = $modify($modifyBuilder);
552
553
            // Check if a FieldsBuilder is returned
554
            if (!$modifyBuilder instanceof FieldsBuilder) {
555
                throw new ModifyFieldReturnTypeException(gettype($modifyBuilder));
556
            }
557
558
            // Build Modifications
559
            $modifyConfig = $modifyBuilder->build();
560
561
            // Insert field(s)
562
            $this->getFieldManager()->replaceField($name, $modifyConfig['fields']);
563
        }
564
565
        return $this;
566
    }
567
568
    /**
569
     * Remove a field by name
570
     * @param  string $name Field to remove
571
     * @return $this
572
     */
573
    public function removeField($name)
574
    {
575
        $this->getFieldManager()->removeField($name);
576
577
        return $this;
578
    }
579
580
    /**
581
     * Set the location of the field group. See
582
     * https://github.com/StoutLogic/acf-builder/wiki/location and
583
     * https://www.advancedcustomfields.com/resources/custom-location-rules/
584
     * for more details.
585
     * @param string $param
586
     * @param string $operator
587
     * @param string $value
588
     * @return LocationBuilder
589
     */
590
    public function setLocation($param, $operator, $value)
591
    {
592
        if ($this->getParentContext()) {
593
            return $this->getParentContext()->setLocation($param, $operator, $value);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface StoutLogic\AcfBuilder\Builder as the method setLocation() does only exist in the following implementations of said interface: StoutLogic\AcfBuilder\FieldsBuilder.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
594
        }
595
596
        $this->location = new LocationBuilder($param, $operator, $value);
597
        $this->location->setParentContext($this);
598
599
        return $this->location;
600
    }
601
602
    /**
603
     * @return LocationBuilder
604
     */
605
    public function getLocation()
606
    {
607
        return $this->location;
608
    }
609
610
    /**
611
     * Create a field label based on the field's name. Generates title case.
612
     * @param  string $name
613
     * @return string label
614
     */
615
    protected function generateLabel($name)
616
    {
617
        return ucwords(str_replace("_", " ", $name));
618
    }
619
620
    /**
621
     * Generates a snaked cased name.
622
     * @param  string $name
623
     * @return string
624
     */
625
    protected function generateName($name)
626
    {
627
        return strtolower(str_replace(" ", "_", $name));
628
    }
629
}
630