Completed
Push — master ( 13bfeb...08a093 )
by Steve
02:13
created

FieldsBuilder::addImage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
nc 1
cc 1
eloc 2
nop 2
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;
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, array $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|LocationBuilder
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 FieldsBuilder|array $fields
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
164
        foreach ($fields as $field) {
165
            $this->getFieldManager()->pushField($field);
166
        }
167
168
        return $this;
169
    }
170
171
    /**
172
     * Add a field of a specific type
173
     * @param string $name
174
     * @param string $type
175
     * @param array $args field configuration
176
     * @throws FieldNameCollisionException if name already exists.
177
     * @return FieldBuilder
178
     */
179
    public function addField($name, $type, array $args = [])
180
    {
181
        return $this->initializeField(new FieldBuilder($name, $type, $args));
182
    }
183
184
    /**
185
     * Add a field of a choice type, allows choices to be added.
186
     * @param string $name
187
     * @param string $type 'select', 'radio', 'checkbox'
188
     * @param array $args field configuration
189
     * @throws FieldNameCollisionException if name already exists.
190
     * @return FieldBuilder
191
     */
192
    public function addChoiceField($name, $type, array $args = [])
193
    {
194
        return $this->initializeField(new ChoiceFieldBuilder($name, $type, $args));
195
    }
196
197
    /**
198
     * Initialize the FieldBuilder, add to FieldManager
199
     * @param  FieldBuilder $field
200
     * @return FieldBuilder
201
     */
202
    protected function initializeField($field)
203
    {
204
        $field->setParentContext($this);
205
        $this->getFieldManager()->pushField($field);
206
        return $field;
207
    }
208
209
    /**
210
     * @param string $name
211
     * @param array $args field configuration
212
     * @throws FieldNameCollisionException if name already exists.
213
     * @return FieldBuilder
214
     */
215
    public function addText($name, array $args = [])
216
    {
217
        return $this->addField($name, 'text', $args);
218
    }
219
220
    /**
221
     * @param string $name
222
     * @param array $args field configuration
223
     * @throws FieldNameCollisionException if name already exists.
224
     * @return FieldBuilder
225
     */
226
    public function addTextarea($name, array $args = [])
227
    {
228
        return $this->addField($name, 'textarea', $args);
229
    }
230
231
    /**
232
     * @param string $name
233
     * @param array $args field configuration
234
     * @throws FieldNameCollisionException if name already exists.
235
     * @return FieldBuilder
236
     */
237
    public function addNumber($name, array $args = [])
238
    {
239
        return $this->addField($name, 'number', $args);
240
    }
241
242
    /**
243
     * @param string $name
244
     * @param array $args field configuration
245
     * @throws FieldNameCollisionException if name already exists.
246
     * @return FieldBuilder
247
     */
248
    public function addEmail($name, array $args = [])
249
    {
250
        return $this->addField($name, 'email', $args);
251
    }
252
253
    /**
254
     * @param string $name
255
     * @param array $args field configuration
256
     * @throws FieldNameCollisionException if name already exists.
257
     * @return FieldBuilder
258
     */
259
    public function addUrl($name, array $args = [])
260
    {
261
        return $this->addField($name, 'url', $args);
262
    }
263
264
    /**
265
     * @param string $name
266
     * @param array $args field configuration
267
     * @throws FieldNameCollisionException if name already exists.
268
     * @return FieldBuilder
269
     */
270
    public function addPassword($name, array $args = [])
271
    {
272
        return $this->addField($name, 'password', $args);
273
    }
274
275
    /**
276
     * @param string $name
277
     * @param array $args field configuration
278
     * @throws FieldNameCollisionException if name already exists.
279
     * @return FieldBuilder
280
     */
281
    public function addWysiwyg($name, array $args = [])
282
    {
283
        return $this->addField($name, 'wysiwyg', $args);
284
    }
285
286
    /**
287
     * @param string $name
288
     * @param array $args field configuration
289
     * @throws FieldNameCollisionException if name already exists.
290
     * @return FieldBuilder
291
     */
292
    public function addOembed($name, array $args = [])
293
    {
294
        return $this->addField($name, 'oembed', $args);
295
    }
296
297
    /**
298
     * @param string $name
299
     * @param array $args field configuration
300
     * @throws FieldNameCollisionException if name already exists.
301
     * @return FieldBuilder
302
     */
303
    public function addImage($name, array $args = [])
304
    {
305
        return $this->addField($name, 'image', $args);
306
    }
307
308
    /**
309
     * @param string $name
310
     * @param array $args field configuration
311
     * @throws FieldNameCollisionException if name already exists.
312
     * @return FieldBuilder
313
     */
314
    public function addFile($name, array $args = [])
315
    {
316
        return $this->addField($name, 'file', $args);
317
    }
318
319
    /**
320
     * @param string $name
321
     * @param array $args field configuration
322
     * @throws FieldNameCollisionException if name already exists.
323
     * @return FieldBuilder
324
     */
325
    public function addGallery($name, array $args = [])
326
    {
327
        return $this->addField($name, 'gallery', $args);
328
    }
329
330
    /**
331
     * @param string $name
332
     * @param array $args field configuration
333
     * @throws FieldNameCollisionException if name already exists.
334
     * @return FieldBuilder
335
     */
336
    public function addTrueFalse($name, array $args = [])
337
    {
338
        return $this->addField($name, 'true_false', $args);
339
    }
340
341
    /**
342
     * @param string $name
343
     * @param array $args field configuration
344
     * @throws FieldNameCollisionException if name already exists.
345
     * @return FieldBuilder
346
     */
347
    public function addSelect($name, array $args = [])
348
    {
349
        return $this->addChoiceField($name, 'select', $args);
350
    }
351
352
    /**
353
     * @param string $name
354
     * @param array $args field configuration
355
     * @throws FieldNameCollisionException if name already exists.
356
     * @return FieldBuilder
357
     */
358
    public function addRadio($name, array $args = [])
359
    {
360
        return $this->addChoiceField($name, 'radio', $args);
361
    }
362
363
    /**
364
     * @param string $name
365
     * @param array $args field configuration
366
     * @throws FieldNameCollisionException if name already exists.
367
     * @return FieldBuilder
368
     */
369
    public function addCheckbox($name, array $args = [])
370
    {
371
        return $this->addChoiceField($name, 'checkbox', $args);
372
    }
373
374
    /**
375
     * @param string $name
376
     * @param array $args field configuration
377
     * @throws FieldNameCollisionException if name already exists.
378
     * @return FieldBuilder
379
     */
380
    public function addPostObject($name, array $args = [])
381
    {
382
        return $this->addField($name, 'post_object', $args);
383
    }
384
385
    /**
386
     * @param string $name
387
     * @param array $args field configuration
388
     * @throws FieldNameCollisionException if name already exists.
389
     * @return FieldBuilder
390
     */
391
    public function addPageLink($name, array $args = [])
392
    {
393
        return $this->addField($name, 'page_link', $args);
394
    }
395
396
    /**
397
     * @param string $name
398
     * @param array $args field configuration
399
     * @throws FieldNameCollisionException if name already exists.
400
     * @return FieldBuilder
401
     */
402
    public function addRelationship($name, array $args = [])
403
    {
404
        return $this->addField($name, 'relationship', $args);
405
    }
406
407
    /**
408
     * @param string $name
409
     * @param array $args field configuration
410
     * @throws FieldNameCollisionException if name already exists.
411
     * @return FieldBuilder
412
     */
413
    public function addTaxonomy($name, array $args = [])
414
    {
415
        return $this->addField($name, 'taxonomy', $args);
416
    }
417
418
    /**
419
     * @param string $name
420
     * @param array $args field configuration
421
     * @throws FieldNameCollisionException if name already exists.
422
     * @return FieldBuilder
423
     */
424
    public function addUser($name, array $args = [])
425
    {
426
        return $this->addField($name, 'user', $args);
427
    }
428
429
    /**
430
     * @param string $name
431
     * @param array $args field configuration
432
     * @throws FieldNameCollisionException if name already exists.
433
     * @return FieldBuilder
434
     */
435
    public function addDatePicker($name, array $args = [])
436
    {
437
        return $this->addField($name, 'date_picker', $args);
438
    }
439
440
    /**
441
     * @param string $name
442
     * @param array $args field configuration
443
     * @throws FieldNameCollisionException if name already exists.
444
     * @return FieldBuilder
445
     */
446
    public function addTimePicker($name, array $args = [])
447
    {
448
        return $this->addField($name, 'time_picker', $args);
449
    }
450
451
    /**
452
     * @param string $name
453
     * @param array $args field configuration
454
     * @throws FieldNameCollisionException if name already exists.
455
     * @return FieldBuilder
456
     */
457
    public function addDateTimePicker($name, array $args = [])
458
    {
459
        return $this->addField($name, 'date_time_picker', $args);
460
    }
461
462
    /**
463
     * @param string $name
464
     * @param array $args field configuration
465
     * @throws FieldNameCollisionException if name already exists.
466
     * @return FieldBuilder
467
     */
468
    public function addColorPicker($name, array $args = [])
469
    {
470
        return $this->addField($name, 'color_picker', $args);
471
    }
472
473
    /**
474
     * @param string $name
475
     * @param array $args field configuration
476
     * @throws FieldNameCollisionException if name already exists.
477
     * @return FieldBuilder
478
     */
479
    public function addGoogleMap($name, array $args = [])
480
    {
481
        return $this->addField($name, 'google_map', $args);
482
    }
483
484
    /**
485
     * @param string $name
486
     * @param array $args field configuration
487
     * @throws FieldNameCollisionException if name already exists.
488
     * @return FieldBuilder
489
     */
490
    public function addLink($name, array $args = [])
491
    {
492
        return $this->addField($name, 'link', $args);
493
    }
494
495
    /**
496
     * All fields added after will appear under this tab, until another tab
497
     * is added.
498
     * @param string $label Tab label
499
     * @param array $args field configuration
500
     * @throws FieldNameCollisionException if name already exists.
501
     * @return FieldBuilder
502
     */
503
    public function addTab($label, array $args = [])
504
    {
505
        return $this->initializeField(new TabBuilder($label, 'tab', $args));
506
    }
507
508
    /**
509
     * Addes a message field
510
     * @param string $label
511
     * @param string $message
512
     * @param array $args field configuration
513
     * @throws FieldNameCollisionException if name already exists.
514
     * @return FieldBuilder
515
     */
516
    public function addMessage($label, $message, array $args = [])
517
    {
518
        $name = $this->generateName($label).'_message';
519
        $args = array_merge([
520
            'label' => $label,
521
            'message' => $message,
522
        ], $args);
523
524
        return $this->addField($name, 'message', $args);
525
    }
526
527
    /**
528
     * @param string $name
529
     * @param array $args field configuration
530
     * @throws FieldNameCollisionException if name already exists.
531
     * @return GroupBuilder
532
     */
533
    public function addGroup($name, array $args = [])
534
    {
535
        return $this->initializeField(new GroupBuilder($name, 'group', $args));
536
    }
537
538
    /**
539
     * Add a repeater field. Any fields added after will be added to the repeater
540
     * until `endRepeater` is called.
541
     * @param string $name
542
     * @param array $args field configuration
543
     * @throws FieldNameCollisionException if name already exists.
544
     * @return RepeaterBuilder
545
     */
546
    public function addRepeater($name, array $args = [])
547
    {
548
        return $this->initializeField(new RepeaterBuilder($name, 'repeater', $args));
549
    }
550
551
    /**
552
     * Add a flexible content field. Once adding a layout with `addLayout`,
553
     * any fields added after will be added to that layout until another
554
     * `addLayout` call is made, or until `endFlexibleContent` is called.
555
     * @param string $name
556
     * @param array $args field configuration
557
     * @throws FieldNameCollisionException if name already exists.
558
     * @return FlexibleContentBuilder
559
     */
560
    public function addFlexibleContent($name, array $args = [])
561
    {
562
        return $this->initializeField(new FlexibleContentBuilder($name, 'flexible_content', $args));
563
    }
564
565
    /**
566
     * @return FieldManager
567
     */
568
    protected function getFieldManager()
569
    {
570
        return $this->fieldManager;
571
    }
572
573
    /**
574
     * @return NamedBuilder[]
575
     */
576
    public function getFields()
577
    {
578
        return $this->getFieldManager()->getFields();
579
    }
580
581
    /**
582
     * @param string $name [description]
583
     * @return FieldBuilder
584
     */
585
    public function getField($name)
586
    {
587
        return $this->getFieldManager()->getField($name);
588
    }
589
590
    public function fieldExists($name)
591
    {
592
        return $this->getFieldManager()->fieldNameExists($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 location of the field group. See
650
     * https://github.com/StoutLogic/acf-builder/wiki/location and
651
     * https://www.advancedcustomfields.com/resources/custom-location-rules/
652
     * for more details.
653
     * @param string $param
654
     * @param string $operator
655
     * @param string $value
656
     * @return LocationBuilder
657
     */
658
    public function setLocation($param, $operator, $value)
659
    {
660
        if ($this->getParentContext()) {
661
            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...
662
        }
663
664
        $this->location = new LocationBuilder($param, $operator, $value);
665
        $this->location->setParentContext($this);
666
667
        return $this->location;
668
    }
669
670
    /**
671
     * @return LocationBuilder
672
     */
673
    public function getLocation()
674
    {
675
        return $this->location;
676
    }
677
678
    /**
679
     * Create a field label based on the field's name. Generates title case.
680
     * @param  string $name
681
     * @return string label
682
     */
683
    protected function generateLabel($name)
684
    {
685
        return ucwords(str_replace('_', ' ', $name));
686
    }
687
688
    /**
689
     * Generates a snaked cased name.
690
     * @param  string $name
691
     * @return string
692
     */
693
    protected function generateName($name)
694
    {
695
        return strtolower(str_replace(' ', '_', $name));
696
    }
697
698
}
699