Completed
Pull Request — master (#23)
by Steve
02:25
created

FieldManager::insertFields()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
c 0
b 0
f 0
rs 8.8571
cc 6
eloc 8
nc 7
nop 2
1
<?php
2
3
namespace StoutLogic\AcfBuilder;
4
5
/**
6
 * Manages an array of field configs
7
 */
8
class FieldManager
9
{
10
    /**
11
     * Array of fields
12
     * @var array
13
     */
14
    private $fields;
15
16
    /**
17
     * @param array $fields optional default array of field configs
18
     */
19
    public function __construct($fields = [])
20
    {
21
        $this->fields = $fields;
22
    }
23
24
    /**
25
     * @return NamedBuilder[] field configs
26
     */
27
    public function getFields()
28
    {
29
        return $this->fields;
30
    }
31
32
    /**
33
     * Return int of fields
34
     * @return int field count
35
     */
36
    public function getCount()
37
    {
38
        return count($this->getFields());
39
    }
40
41
    /**
42
     * Add field to end of array
43
     * @param  NamedBuilder $field Field array config or Builder
44
     * @return void
45
     */
46
    public function pushField($field)
47
    {
48
        $this->insertFields($field, $this->getCount());
49
    }
50
51
    /**
52
     * Remove last field from end of array
53
     * @throws \OutOfRangeException if array is empty
54
     * @return NamedBuilder Field array config or Builder
55
     */
56
    public function popField()
57
    {
58
        if ($this->getCount() > 0) {
59
            $fields = $this->removeFieldAtIndex($this->getCount() - 1);
60
            return $fields[0];
61
        }
62
63
        throw new \OutOfRangeException("Can't call popField when the field count is 0");
64
    }
65
66
    /**
67
     * Insert of field at a specific index
68
     * @param  NamedBuilder $fields a single field or an array of fields
69
     * @param  int $index  insertion point
70
     * @return void
71
     */
72
    public function insertFields($fields, $index)
73
    {
74
        if (!$fields instanceof NamedBuilder && !is_array($fields)) {
75
            return;
76
        }
77
78
        // If a singular field config, put into an array of fields
79
        if ($fields instanceof NamedBuilder) {
80
            $fields = [$fields];
81
        }
82
83
84
        foreach ($fields as $i => $field) {
85
            if ($this->validateField($field)) {
86
                array_splice($this->fields, $index + $i, 0, [$field]);
87
            }
88
        }
89
    }
90
91
    /**
92
     * Remove a field at a specific index
93
     * @param  int $index
94
     * @return array  removed field
95
     */
96
    private function removeFieldAtIndex($index)
97
    {
98
        return array_splice($this->fields, $index, 1);
99
    }
100
101
    /**
102
     * Remove a speicifc field by name
103
     * @param  string $name name of the field
104
     * @return void
105
     */
106
    public function removeField($name)
107
    {
108
        $index = $this->getFieldIndex($name);
109
        $this->removeFieldAtIndex($index);
110
    }
111
112
    /**
113
     * Replace a field with a single field or array of fields
114
     * @param  string $name  name of field to replace
115
     * @param  NamedBuilder $field single or array of fields
116
     * @return void
117
     */
118
    public function replaceField($name, $field)
119
    {
120
        $index = $this->getFieldIndex($name);
121
        $this->removeFieldAtIndex($index);
122
        $this->insertFields($field, $index);
123
    }
124
125
    /**
126
     * Check to see if a field name already exists
127
     * @param  string $name field name
128
     * @return bool
129
     */
130
    public function fieldNameExists($name)
131
    {
132
        try {
133
            $this->getFieldIndex($name);
134
        } catch (FieldNotFoundException $e) {
135
            return false;
136
        }
137
138
        return true;
139
    }
140
141
    /**
142
     * Return a field by name
143
     * @param  string $name field name
144
     * @return FieldBuilder
145
     */
146
    public function getField($name)
147
    {
148
        return $this->fields[$this->getFieldIndex($name)];
149
    }
150
151
    /**
152
     * Modify the configuration of a field
153
     * @param  string $name          field name
154
     * @param  array $modifications  field configuration
155
     * @return void
156
     */
157
    public function modifyField($name, $modifications)
158
    {
159
        $field = $this->getField($name)->updateConfig($modifications);
160
        $this->replaceField($name, $field);
161
    }
162
163
    /**
164
     * Validate a field
165
     * @param  NamedBuilder $field
166
     * @return bool
167
     */
168
    private function validateField($field)
169
    {
170
        return $this->validateFieldName($field);
171
    }
172
173
    /**
174
     * Validates that a field's name doesn't already exist
175
     * @param  NamedBuilder $field
176
     * @throws FieldNameCollisionException when the name already exists
177
     * @return bool
178
     */
179
    private function validateFieldName($field)
180
    {
181
        $fieldName = $field->getName();
182
        if (!$fieldName || $this->fieldNameExists($fieldName)) {
183
            throw new FieldNameCollisionException("Field Name: `{$fieldName}` already exists.");
184
        }
185
186
        return true;
187
    }
188
189
    /**
190
     * Return the index in the $this->fields array looked up by the field's name
191
     * @param  string $name Field Name
192
     * @throws FieldNotFoundException if the field name doesn't exist
193
     * @return int Field Index
194
     */
195
    public function getFieldIndex($name)
196
    {
197
        foreach ($this->getFields() as $index => $field) {
198
            if ($field->getName() === $name) {
199
                return $index;
200
            }
201
        }
202
203
        throw new FieldNotFoundException("Field `{$name}` not found.");
204
    }
205
}
206