Passed
Pull Request — master (#427)
by
unknown
01:59
created

Model::getFillable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
eloc 1
c 2
b 1
f 1
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Picqer\Financials\Exact;
4
5
/**
6
 * Class Model.
7
 */
8
abstract class Model implements \JsonSerializable
9
{
10
    /**
11
     * @var Connection
12
     */
13
    protected $connection;
14
15
    /**
16
     * @var array The model's attributes
17
     */
18
    protected $attributes = [];
19
20
    /**
21
     * @deferred array The model's collection values
22
     */
23
    protected $deferred = [];
24
25
    /**
26
     * @var array The model's fillable attributes
27
     */
28
    protected $fillable = [];
29
30
    /**
31
     * @var string The URL endpoint of this model
32
     */
33
    protected $url = '';
34
35
    /**
36
     * @var string Name of the primary key for this model
37
     */
38
    protected $primaryKey = 'ID';
39
40
    public function __construct(Connection $connection, array $attributes = [])
41
    {
42
        $this->connection = $connection;
43
        $this->fill($attributes);
44
    }
45
46
    /**
47
     * Get the connection instance.
48
     *
49
     * @return Connection
50
     */
51
    public function connection()
52
    {
53
        return $this->connection;
54
    }
55
56
    /**
57
     * Get the model's attributes.
58
     *
59
     * @return array
60
     */
61
    public function attributes()
62
    {
63
        return $this->attributes;
64
    }
65
66
    /**
67
     * Get the model's url.
68
     *
69
     * @return string
70
     */
71
    public function url()
72
    {
73
        return $this->url;
74
    }
75
76
    /**
77
     * Get the model's primary key.
78
     *
79
     * @return string
80
     */
81
    public function primaryKey()
82
    {
83
        return $this->primaryKey;
84
    }
85
86
    /**
87
     * Get the model's primary key value.
88
     *
89
     * @return mixed
90
     */
91
    public function primaryKeyContent()
92
    {
93
        return $this->__get($this->primaryKey);
94
    }
95
96
    /**
97
     * Fill the entity from an array.
98
     *
99
     * @param array $attributes
100
     */
101
    protected function fill(array $attributes)
102
    {
103
        foreach ($this->fillableFromArray($attributes) as $key => $value) {
104
            if ($this->isFillable($key)) {
105
                $this->setAttribute($key, $value);
106
            }
107
        }
108
    }
109
110
    /**
111
     * Get the fillable attributes of an array.
112
     *
113
     * @param array $attributes
114
     *
115
     * @return array
116
     */
117
    protected function fillableFromArray(array $attributes)
118
    {
119
        if (count($this->fillable) > 0) {
120
            return array_intersect_key($attributes, array_flip($this->fillable));
121
        }
122
123
        return $attributes;
124
    }
125
126
    protected function isFillable($key)
127
    {
128
        return in_array($key, $this->fillable);
129
    }
130
131
    public function getFillable()
132
    {
133
        return $this->fillable;
134
    }
135
136
    protected function setAttribute($key, $value)
137
    {
138
        $this->attributes[$key] = $value;
139
    }
140
141
    /**
142
     * Resolve deferred values.
143
     *
144
     * @param string $key
145
     *
146
     * @return bool Returns true when collection is found
147
     */
148
    protected function lazyLoad($key)
149
    {
150
        // Check previously resolved or manualy set.
151
        if (isset($this->deferred[$key])) {
152
            return true;
153
        }
154
155
        try {
156
            if (array_key_exists($key, $this->attributes) && is_array($this->attributes[$key]) && array_key_exists('__deferred', $this->attributes[$key])) {
157
                $class = preg_replace('/(.+?)s?$/', __NAMESPACE__ . '\\\$1', $key); // Filter plural 's' and add namespace
158
                $deferred = new $class($this->connection());
159
                $uri = $this->attributes[$key]['__deferred']['uri'];
160
                $deferred->connection()->nextUrl = $uri; // $uri is complete, by setting it to nextUrl Connection->formatUrl leaves it as is.
161
                $result = $deferred->connection()->get($uri);
162
                $this->deferred[$key] = $deferred->collectionFromResult($result);
163
164
                return true;
165
            }
166
        } catch (\Exception $e) {
167
            // We tried lets leave it as is.
168
        }
169
170
        return false;
171
    }
172
173
    public function __get($key)
174
    {
175
        if ($this->lazyLoad($key)) {
176
            return $this->deferred[$key];
177
        }
178
179
        if (isset($this->attributes[$key])) {
180
            return $this->attributes[$key];
181
        }
182
    }
183
184
    public function __set($key, $value)
185
    {
186
        if ($this->isFillable($key)) {
187
            if (is_array($value)) {
188
                $this->deferred[$key] = $value;
189
190
                return;
191
            }
192
193
            $this->setAttribute($key, $value);
194
        }
195
    }
196
197
    public function __isset($name)
198
    {
199
        return $this->__get($name) !== null;
200
    }
201
202
    public function __call($name, $arguments)
203
    {
204
        return $this->__get($name);
205
    }
206
207
    /**
208
     * Refresh deferred item by clearing and then lazy loading it.
209
     *
210
     * @param $key
211
     *
212
     * @return mixed
213
     */
214
    public function refresh($key)
215
    {
216
        unset($this->deferred[$key]);
217
218
        return $this->__get($key);
219
    }
220
221
    /**
222
     * Checks if primaryKey holds a value.
223
     *
224
     * @return bool
225
     */
226
    public function exists()
227
    {
228
        if (! array_key_exists($this->primaryKey, $this->attributes)) {
229
            return false;
230
        }
231
232
        return ! empty($this->attributes[$this->primaryKey]);
233
    }
234
235
    /**
236
     * Return the JSON representation of the data.
237
     *
238
     * @param int $options http://php.net/manual/en/json.constants.php
239
     *
240
     * @return string
241
     */
242
    public function json($options = 0, $withDeferred = false)
243
    {
244
        $attributes = $this->attributes;
245
        if ($withDeferred) {
246
            foreach ($this->deferred as $attribute => $collection) {
247
                if (empty($collection)) {
248
                    continue; // Leave orriginal array with __deferred key
249
                }
250
251
                $attributes[$attribute] = [];
252
                foreach ($collection as $value) {
253
                    if (! empty($value->deferred)) {
254
                        $value->attributes = array_merge($value->attributes, $value->deferred);
255
                    }
256
257
                    if (is_a($value, 'Picqer\Financials\Exact\Model')) {
258
                        array_push($attributes[$attribute], $value->attributes);
259
                    } else {
260
                        array_push($attributes[$attribute], $value);
261
                    }
262
                }
263
            }
264
        }
265
266
        return json_encode($attributes, $options);
267
    }
268
269
    /**
270
     * Return serializable data.
271
     *
272
     * @return array
273
     */
274
    public function jsonSerialize()
275
    {
276
        return $this->attributes;
277
    }
278
279
    /**
280
     * Check whether the current user has rights for an action on this endpoint
281
     * https://start.exactonline.nl/docs/HlpRestAPIResources.aspx?SourceAction=10.
282
     *
283
     * @param string $action
284
     *
285
     * @return bool
286
     */
287
    public function userHasRights($action = 'GET')
288
    {
289
        $action = preg_match('/^GET|POST|PUT|DELETE$/i', $action) ? strtoupper($action) : 'GET';
290
        $result = $this->connection()->get('users/UserHasRights', [
291
            'endpoint' => "'{$this->url}'",
292
            'action'   => "'{$action}'",
293
        ]);
294
295
        return isset($result['UserHasRights']) ? $result['UserHasRights'] : null;
296
    }
297
}
298