Passed
Push — master ( b66c10...181037 )
by y
02:15
created

AbstractEntity::_save()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 14
rs 9.9666
1
<?php
2
3
namespace Helix\Asana\Base;
4
5
use Closure;
6
7
/**
8
 * A resource with a GID.
9
 *
10
 * @method string   getGid          ()
11
 * @method bool     hasGid          ()
12
 * @method string   getResourceType ()
13
 */
14
abstract class AbstractEntity extends Data {
15
16
    /**
17
     * `GET/PUT/DELETE` path.
18
     *
19
     * @return string
20
     */
21
    abstract public function __toString (): string;
22
23
    /**
24
     * Maps lazy-loaded / reloadable mapped {@see Data} to their proper expanded field expression.
25
     *
26
     * If not set here, the field name is used alone.
27
     *
28
     * @var string[]
29
     */
30
    protected static $optFields = [];
31
32
    /**
33
     * @param string $path
34
     * @param array $data
35
     * @param string $field
36
     * @param array $diff
37
     * @return $this
38
     * @internal
39
     */
40
    protected function _addWithPost (string $path, array $data, string $field, array $diff) {
41
        if ($this->hasGid()) {
42
            return $this->_setWithPost($path, $data, $field);
43
        }
44
        return $this->_set($field, array_merge($this->data[$field] ?? [], array_values($diff)));
45
    }
46
47
    /**
48
     * Shortcut to update the cache.
49
     *
50
     * @internal
51
     */
52
    protected function _cache (): void {
53
        $this->api->getCache()->add($this);
54
    }
55
56
    /**
57
     * Activated by trait.
58
     *
59
     * @internal
60
     */
61
    protected function _delete (): void {
62
        $this->api->delete($this);
63
        $this->api->getCache()->remove($this);
64
    }
65
66
    /**
67
     * Lazy-loads missing fields.
68
     *
69
     * @param string $field
70
     * @return mixed
71
     */
72
    protected function _get (string $field) {
73
        if (!array_key_exists($field, $this->data) and isset($this->data['gid'])) {
74
            $this->reload($field);
75
        }
76
        return parent::_get($field);
77
    }
78
79
    /**
80
     * @param string $path
81
     * @param array $data
82
     * @param null|string $field
83
     * @param array|Closure $diff An array to diff, or a closure for filtering.
84
     * @return $this
85
     * @internal
86
     */
87
    protected function _removeWithPost (string $path, array $data, string $field = null, $diff = null) {
88
        if ($this->hasGid()) {
89
            return $this->_setWithPost($path, $data, $field);
1 ignored issue
show
Bug introduced by
It seems like $field can also be of type null; however, parameter $field of Helix\Asana\Base\AbstractEntity::_setWithPost() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

89
            return $this->_setWithPost($path, $data, /** @scrutinizer ignore-type */ $field);
Loading history...
90
        }
91
        elseif (is_array($diff)) {
92
            $this->_set($field, array_values(array_diff($this->data[$field] ?? [], $diff)));
1 ignored issue
show
Bug introduced by
It seems like $field can also be of type null; however, parameter $field of Helix\Asana\Base\Data::_set() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

92
            $this->_set(/** @scrutinizer ignore-type */ $field, array_values(array_diff($this->data[$field] ?? [], $diff)));
Loading history...
93
        }
94
        elseif ($diff instanceof Closure) {
95
            $this->_set($field, array_filter($diff, $this->data[$field] ?? []));
0 ignored issues
show
Bug introduced by
$diff of type Closure is incompatible with the type array expected by parameter $input of array_filter(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
            $this->_set($field, array_filter(/** @scrutinizer ignore-type */ $diff, $this->data[$field] ?? []));
Loading history...
96
        }
97
        return $this;
98
    }
99
100
    /**
101
     * Called by create/update traits.
102
     *
103
     * @param string $dir `POST` directory for creation.
104
     * @return $this
105
     * @internal
106
     */
107
    protected function _save (string $dir = null) {
108
        if (isset($dir)) {
109
            $remote = $this->api->post($dir, $this->getDiff(), ['expand' => 'this']);
110
        }
111
        elseif ($this->isDiff()) {
112
            $remote = $this->api->put($this, $this->getDiff(), ['expand' => 'this']);
113
        }
114
        else {
115
            return $this;
116
        }
117
        /** @var array $remote */
118
        $this->_setData($remote);
119
        $this->_cache();
120
        return $this;
121
    }
122
123
    /**
124
     * Sets/reloads data via `POST` for existing entities. Otherwise stages a value.
125
     *
126
     * @param string $path
127
     * @param array $data
128
     * @param string $field
129
     * @param mixed $value Ignored for existing entities.
130
     * @return $this
131
     * @internal
132
     */
133
    protected function _setWithPost (string $path, array $data, string $field, $value = null) {
134
        if ($this->hasGid()) {
135
            /** @var array $remote */
136
            $remote = $this->api->post($path, $data, ['fields' => static::$optFields[$field] ?? $field]);
137
            if (array_key_exists($field, $this->data)) {
138
                $this->_setMapped($field, $remote[$field]);
139
                $this->_cache();
140
            }
141
            return $this;
142
        }
143
        return $this->_set($field, $value);
144
    }
145
146
    /**
147
     * Cache keys for the entity.
148
     *
149
     * @return string[]
150
     */
151
    public function getCacheKeys () {
152
        return [$this->getGid(), (string)$this];
153
    }
154
155
    /**
156
     * Reloads a specific field, or the whole entity.
157
     *
158
     * @param string $field
159
     * @return $this
160
     */
161
    public function reload (string $field = null) {
162
        if (isset($field)) {
163
            $value = $this->api->get($this, [], ['fields' => static::$optFields[$field] ?? $field])[$field] ?? null;
164
            $this->_setMapped($field, $value);
165
        }
166
        else {
167
            $this->_setData($this->api->get($this, [], ['expand' => 'this']));
1 ignored issue
show
Bug introduced by
It seems like $this->api->get($this, a...ay('expand' => 'this')) can also be of type null; however, parameter $data of Helix\Asana\Base\Data::_setData() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
            $this->_setData(/** @scrutinizer ignore-type */ $this->api->get($this, [], ['expand' => 'this']));
Loading history...
168
        }
169
        $this->_cache();
170
        return $this;
171
    }
172
173
}