Passed
Push — master ( 23ab98...82cce0 )
by y
01:46
created

FieldValues   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 190
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 55
dl 0
loc 190
rs 10
c 1
b 0
f 0
wmc 23

16 Methods

Rating   Name   Duplication   Size   Complexity  
A count() 0 2 1
A setValue() 0 12 2
A offsetSet() 0 2 1
A __construct() 0 3 1
A getValue() 0 6 2
A offsetExists() 0 2 1
A getCurrentOptionName() 0 2 1
A offsetGet() 0 2 1
A getOptionNames() 0 7 2
A getNames() 0 2 1
A toArray() 0 22 4
A getName() 0 2 1
A _setData() 0 4 1
A offsetUnset() 0 2 1
A getIterator() 0 3 2
A getDiff() 0 4 1
1
<?php
2
3
namespace Helix\Asana\Task;
4
5
use ArrayAccess;
6
use Countable;
7
use Generator;
8
use Helix\Asana\Base\Data;
9
use Helix\Asana\CustomField;
10
use Helix\Asana\Task;
11
use IteratorAggregate;
12
13
/**
14
 * Custom field value adapter for tasks.
15
 *
16
 * Field access is by GID.
17
 *
18
 * Enum values are set by option GID.
19
 */
20
class FieldValues extends Data implements ArrayAccess, Countable, IteratorAggregate {
21
22
    /**
23
     * `[ field gid => data offset ]` and `[ data offset => field gid ]`
24
     *
25
     * @var number[]
26
     */
27
    protected $index = [];
28
29
    /**
30
     * @var Task
31
     */
32
    protected $task;
33
34
    /**
35
     * `[ field gid => type ]`
36
     *
37
     * @var string[]
38
     */
39
    protected $types = [];
40
41
    public function __construct (Task $task, array $data = []) {
42
        $this->task = $task;
43
        parent::__construct($task, $data);
44
    }
45
46
    /**
47
     * Builds the index.
48
     *
49
     * @param array $data
50
     */
51
    protected function _setData (array $data): void {
52
        $this->index = array_column($data, 'gid');
53
        $this->index += array_flip($this->index);
54
        parent::_setData($data);
55
    }
56
57
    /**
58
     * @return int
59
     */
60
    public function count () {
61
        return count($this->data);
62
    }
63
64
    /**
65
     * @param string $enumGid
66
     * @return string
67
     */
68
    public function getCurrentOptionName (string $enumGid) {
69
        return $this->getOptionNames($enumGid)[$this[$enumGid]];
70
    }
71
72
    public function getDiff (): array {
73
        return array_map(function($i) {
74
            return $this[$this->index[$i]];
75
        }, array_keys($this->diff));
76
    }
77
78
    /**
79
     * @return Generator
80
     */
81
    public function getIterator () {
82
        foreach ($this->data as $field) {
83
            yield $this[$field['gid']];
84
        }
85
    }
86
87
    /**
88
     * @param string $fieldGid
89
     * @return string
90
     */
91
    public function getName (string $fieldGid) {
92
        return $this->data[$this->index[$fieldGid]]['name'];
93
    }
94
95
    /**
96
     * Field names, keyed by GID.
97
     *
98
     * @return string[]
99
     */
100
    public function getNames () {
101
        return array_column($this->data, 'name', 'gid');
102
    }
103
104
    /**
105
     * Enum option names, keyed by GID.
106
     *
107
     * @param string $enumGid
108
     * @return string[]
109
     */
110
    public function getOptionNames (string $enumGid) {
111
        // shared. no reason not to?
112
        static $names = [];
113
        if (!isset($names[$enumGid])) {
114
            $names[$enumGid] = array_column($this->data[$this->index[$enumGid]]['enum_options'], 'name', 'gid');
115
        }
116
        return $names[$enumGid];
117
    }
118
119
    /**
120
     * @param string $fieldGid
121
     * @return null|number|string
122
     */
123
    public function getValue (string $fieldGid) {
124
        $field = $this->data[$this->index[$fieldGid]];
125
        if ($field['type'] === CustomField::TYPE_ENUM) {
126
            return $field['enum_value']['gid'] ?? null;
127
        }
128
        return $field["{$field['type']}_value"];
129
    }
130
131
    /**
132
     * @param string $fieldGid
133
     * @return bool
134
     */
135
    public function offsetExists ($fieldGid) {
136
        return array_key_exists($this->index[$fieldGid], $this->data);
137
    }
138
139
    /**
140
     * @param string $fieldGid
141
     * @return null|number|string
142
     */
143
    public function offsetGet ($fieldGid) {
144
        return $this->getValue($fieldGid);
145
    }
146
147
    /**
148
     * @param string $fieldGid
149
     * @param null|number|string $value
150
     */
151
    public function offsetSet ($fieldGid, $value) {
152
        $this->setValue($fieldGid, $value);
153
    }
154
155
    /**
156
     * Custom fields cannot be "removed" through this. This only sets them to `null`.
157
     *
158
     * @param string $fieldGid
159
     */
160
    public function offsetUnset ($fieldGid) {
161
        $this->setValue($fieldGid, null);
162
    }
163
164
    /**
165
     * @param string $fieldGid
166
     * @param null|number|string $value
167
     * @return $this
168
     */
169
    public function setValue (string $fieldGid, $value) {
170
        $i = $this->index[$fieldGid];
171
        $type = $this->data[$i]['type'];
172
        if ($type === CustomField::TYPE_ENUM) {
173
            $this->data[$i]['enum_value']['gid'] = $value;
174
        }
175
        else {
176
            $this->data["{$type}_value"] = $value;
177
        }
178
        $this->diff[$i] = true;
179
        $this->task->diff['custom_fields'] = true;
180
        return $this;
181
    }
182
183
    /**
184
     * Strips Asana's beefy data array down to what we need.
185
     *
186
     * @return array
187
     */
188
    public function toArray (): array {
189
        return array_map(function(array $field) {
190
            // only strip if needed.
191
            if (!isset($field['resource_type'])) {
192
                return $field;
193
            }
194
            $tiny = [
195
                'gid' => $field['gid'],
196
                'name' => $field['name'],
197
                'type' => $field['type'],
198
                "{$field['type']}_value" => $field["{$field['type']}_value"]
199
            ];
200
            if (isset($field['enum_options'])) {
201
                $tiny['enum_options'] = array_map(function(array $option) {
202
                    return ['gid' => $option['gid'], 'name' => $option['name']];
203
                }, $field['enum_options']);
204
                if (isset($tiny['enum_value'])) {
205
                    $tiny['enum_value'] = ['gid' => $tiny['enum_value']['gid']];
206
                }
207
            }
208
            return $tiny;
209
        }, $this->data);
210
    }
211
}