Completed
Push — master ( 7ba73a...cfde8a )
by Steve
29s
created

FieldsBuilder::buildLocation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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