Passed
Pull Request — master (#150)
by
unknown
06:37
created

DynamoDbModel   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 423
Duplicated Lines 0 %

Test Coverage

Coverage 78.95%

Importance

Changes 0
Metric Value
wmc 56
eloc 106
dl 0
loc 423
ccs 105
cts 133
cp 0.7895
rs 5.5199
c 0
b 0
f 0

29 Methods

Rating   Name   Duplication   Size   Complexity  
A getDynamoDbClientService() 0 3 1
A unsetDynamoDbClientService() 0 3 1
A setupDynamoDb() 0 4 1
A __construct() 0 9 1
A newCollection() 0 3 1
A setDynamoDbClientService() 0 3 1
B save() 0 33 9
A getKeyNames() 0 3 2
A unmarshalItem() 0 3 1
A marshalValue() 0 3 1
A getMarshaler() 0 3 1
B saveAsync() 0 33 9
A all() 0 5 1
A getKey() 0 3 1
A getDynamoDbIndexKeys() 0 3 1
A hasCompositeKey() 0 3 1
A getKeys() 0 15 3
A update() 0 3 1
A __wakeup() 0 4 1
A refresh() 0 13 2
A newQuery() 0 9 2
A getKeyName() 0 3 1
A setDynamoDbIndexKeys() 0 3 1
A delete() 0 20 5
A create() 0 7 1
A getClient() 0 3 1
A setId() 0 13 3
A marshalItem() 0 3 1
A __sleep() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like DynamoDbModel often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DynamoDbModel, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace BaoPham\DynamoDb;
4
5
use Exception;
6
use DateTime;
7
use Illuminate\Database\Eloquent\Model;
8
9
/**
10
 * Class DynamoDbModel.
11
 */
12
abstract class DynamoDbModel extends Model
13
{
14
    /**
15
     * Always set this to false since DynamoDb does not support incremental Id.
16
     *
17
     * @var bool
18
     */
19
    public $incrementing = false;
20
21
    /**
22
     * @var \BaoPham\DynamoDb\DynamoDbClientInterface
23
     */
24
    protected static $dynamoDb;
25
26
    /**
27
     * @deprecated
28
     * @var \Aws\DynamoDb\Marshaler
29
     */
30
    protected $marshaler;
31
32
    /**
33
     * @deprecated
34
     * @var \BaoPham\DynamoDb\EmptyAttributeFilter
35
     */
36
    protected $attributeFilter;
37
38
    /**
39
     * Indexes.
40
     *   [
41
     *     '<simple_index_name>' => [
42
     *          'hash' => '<index_key>'
43
     *     ],
44
     *     '<composite_index_name>' => [
45
     *          'hash' => '<index_hash_key>',
46
     *          'range' => '<index_range_key>'
47
     *     ],
48
     *   ]
49
     *
50
     * @var array
51
     */
52
    protected $dynamoDbIndexKeys = [];
53
54
    /**
55
     * Array of your composite key.
56
     * ['<hash>', '<range>']
57
     *
58
     * @var array
59
     */
60
    protected $compositeKey = [];
61
62
    /**
63
     * Default Date format
64
     * ISO 8601 Compliant
65
     */
66
    protected $dateFormat = DateTime::ATOM;
67
68
69 123
    public function __construct(array $attributes = [])
70
    {
71 123
        $this->bootIfNotBooted();
72
73 123
        $this->syncOriginal();
74
75 123
        $this->fill($attributes);
76
77 123
        $this->setupDynamoDb();
78 123
    }
79
80
    /**
81
     * Get the DynamoDbClient service that is being used by the models.
82
     *
83
     * @return DynamoDbClientInterface
84
     */
85 3
    public static function getDynamoDbClientService()
86
    {
87 3
        return static::$dynamoDb;
88
    }
89
90
    /**
91
     * Set the DynamoDbClient used by models.
92
     *
93
     * @param DynamoDbClientInterface $dynamoDb
94
     *
95
     * @return void
96
     */
97 138
    public static function setDynamoDbClientService(DynamoDbClientInterface $dynamoDb)
98
    {
99 138
        static::$dynamoDb = $dynamoDb;
100 138
    }
101
102
    /**
103
     * Unset the DynamoDbClient service for models.
104
     *
105
     * @return void
106
     */
107 3
    public static function unsetDynamoDbClientService()
108
    {
109 3
        static::$dynamoDb = null;
110 3
    }
111
112 123
    protected function setupDynamoDb()
113
    {
114 123
        $this->marshaler = static::$dynamoDb->getMarshaler();
115 123
        $this->attributeFilter = static::$dynamoDb->getAttributeFilter();
116 123
    }
117
118 90
    public function newCollection(array $models = [], $index = null)
119
    {
120 90
        return new DynamoDbCollection($models, $index);
121
    }
122
123 8
    public function save(array $options = [])
124
    {
125 8
        $create = !$this->exists;
126
127 8
        if ($this->fireModelEvent('saving') === false) {
128
            return false;
129
        }
130
131 8
        if ($create && $this->fireModelEvent('creating')  === false) {
132
            return false;
133
        }
134
135 8
        if (!$create && $this->fireModelEvent('updating') === false) {
136
            return false;
137
        }
138
139 8
        if ($this->usesTimestamps()) {
140 8
            $this->updateTimestamps();
141
        }
142
143 8
        $saved = $this->newQuery()->save();
144
145 8
        if (!$saved) {
146
            return $saved;
147
        }
148
149 8
        $this->exists = true;
150 8
        $this->wasRecentlyCreated = $create;
151 8
        $this->fireModelEvent($create ? 'created' : 'updated', false);
152
153 8
        $this->finishSave($options);
154
155 8
        return $saved;
156
    }
157
158
    /**
159
     * Saves the model to DynamoDb asynchronously
160
     * And returns a promise
161
     * @param array $options
162
     * @return bool|\GuzzleHttp\Promise\Promise
163
     */
164 4
    public function saveAsync(array $options = [])
165
    {
166 4
        $create = !$this->exists;
167
168 4
        if ($this->fireModelEvent('saving') === false) {
169
            return false;
170
        }
171
172 4
        if ($create && $this->fireModelEvent('creating')  === false) {
173
            return false;
174
        }
175
176 4
        if (!$create && $this->fireModelEvent('updating') === false) {
177
            return false;
178
        }
179
180 4
        if ($this->usesTimestamps()) {
181 4
            $this->updateTimestamps();
182
        }
183
184 4
        $savePromise = $this->newQuery()->saveAsync();
185
186
        $savePromise->then(function ($result) use ($create, $options) {
187 4
            if (array_get($result, '@metadata.statusCode') === 200) {
188 4
                $this->exists = true;
189 4
                $this->wasRecentlyCreated = $create;
190 4
                $this->fireModelEvent($create ? 'created' : 'updated', false);
191
192 4
                $this->finishSave($options);
193
            }
194 4
        });
195
196 4
        return $savePromise;
197
    }
198
199 3
    public function update(array $attributes = [], array $options = [])
200
    {
201 3
        return $this->fill($attributes)->save();
202
    }
203
204
    public static function create(array $attributes = [])
205
    {
206
        $model = new static;
207
208
        $model->fill($attributes)->save();
209
210
        return $model;
211
    }
212
213 2
    public function delete()
214
    {
215 2
        if (is_null($this->getKeyName())) {
216
            throw new Exception('No primary key defined on model.');
217
        }
218
219 2
        if ($this->exists) {
220 2
            if ($this->fireModelEvent('deleting') === false) {
221
                return false;
222
            }
223
224 2
            $this->exists = false;
225
226 2
            $success = $this->newQuery()->delete();
227
228 2
            if ($success) {
229 2
                $this->fireModelEvent('deleted', false);
230
            }
231
232 2
            return $success;
233
        }
234
    }
235
236 7
    public static function all($columns = [])
237
    {
238 7
        $instance = new static;
239
240 7
        return $instance->newQuery()->get($columns);
241
    }
242
243 2
    public function refresh()
244
    {
245 2
        if (! $this->exists) {
246
            return $this;
247
        }
248
249 2
        $query = $this->newQuery();
250
251 2
        $refreshed = $query->find($this->getKeys());
252
253 2
        $this->setRawAttributes($refreshed->toArray());
254
255 2
        return $this;
256
    }
257
258
    /**
259
     * @return DynamoDbQueryBuilder
260
     */
261 123
    public function newQuery()
262
    {
263 123
        $builder = new DynamoDbQueryBuilder($this);
264
265 123
        foreach ($this->getGlobalScopes() as $identifier => $scope) {
266 7
            $builder->withGlobalScope($identifier, $scope);
267
        }
268
269 123
        return $builder;
270
    }
271
272 106
    public function hasCompositeKey()
273
    {
274 106
        return !empty($this->compositeKey);
275
    }
276
277
    /**
278
     * @deprecated
279
     * @param $item
280
     * @return array
281
     */
282
    public function marshalItem($item)
283
    {
284
        return $this->marshaler->marshalItem($item);
285
    }
286
287
    /**
288
     * @deprecated
289
     * @param $value
290
     * @return array
291
     */
292
    public function marshalValue($value)
293
    {
294
        return $this->marshaler->marshalValue($value);
295
    }
296
297
    /**
298
     * @deprecated
299
     * @param $item
300
     * @return array|\stdClass
301
     */
302
    public function unmarshalItem($item)
303
    {
304
        return $this->marshaler->unmarshalItem($item);
305
    }
306
307 32
    public function setId($id)
308
    {
309 32
        if (!is_array($id)) {
310 12
            $this->setAttribute($this->getKeyName(), $id);
311
312 12
            return $this;
313
        }
314
315 22
        foreach ($id as $keyName => $value) {
316 22
            $this->setAttribute($keyName, $value);
317
        }
318
319 22
        return $this;
320
    }
321
322
    /**
323
     * @return \Aws\DynamoDb\DynamoDbClient
324
     */
325 123
    public function getClient()
326
    {
327 123
        return static::$dynamoDb->getClient($this->connection);
328
    }
329
330
    /**
331
     * Get the value of the model's primary key.
332
     *
333
     * @return mixed
334
     */
335
    public function getKey()
336
    {
337
        return $this->getAttribute($this->getKeyName());
338
    }
339
340
    /**
341
     * Get the value of the model's primary / composite key.
342
     * Use this if you always want the key values in associative array form.
343
     *
344
     * @return array
345
     *
346
     * ['id' => 'foo']
347
     *
348
     * or
349
     *
350
     * ['id' => 'foo', 'id2' => 'bar']
351
     */
352 42
    public function getKeys()
353
    {
354 42
        if ($this->hasCompositeKey()) {
355 20
            $key = [];
356
357 20
            foreach ($this->compositeKey as $name) {
358 20
                $key[$name] = $this->getAttribute($name);
359
            }
360
361 20
            return $key;
362
        }
363
364 22
        $name = $this->getKeyName();
365
366 22
        return [$name => $this->getAttribute($name)];
367
    }
368
369
    /**
370
     * Get the primary key for the model.
371
     *
372
     * @return string
373
     */
374 25
    public function getKeyName()
375
    {
376 25
        return $this->primaryKey;
377
    }
378
379
    /**
380
     * Get the primary/composite key for the model.
381
     *
382
     * @return array
383
     */
384 100
    public function getKeyNames()
385
    {
386 100
        return $this->hasCompositeKey() ? $this->compositeKey : [$this->primaryKey];
387
    }
388
389
    /**
390
     * @return array
391
     */
392 70
    public function getDynamoDbIndexKeys()
393
    {
394 70
        return $this->dynamoDbIndexKeys;
395
    }
396
397
    /**
398
     * @param array $dynamoDbIndexKeys
399
     */
400
    public function setDynamoDbIndexKeys($dynamoDbIndexKeys)
401
    {
402
        $this->dynamoDbIndexKeys = $dynamoDbIndexKeys;
403
    }
404
405
    /**
406
     * @deprecated
407
     * @return \Aws\DynamoDb\Marshaler
408
     */
409
    public function getMarshaler()
410
    {
411
        return $this->marshaler;
412
    }
413
414
    /**
415
     * Remove non-serializable properties when serializing.
416
     *
417
     * @return array
418
     */
419 2
    public function __sleep()
420
    {
421 2
        return array_keys(
422 2
            array_except(get_object_vars($this), ['marshaler', 'attributeFilter'])
423
        );
424
    }
425
426
    /**
427
     * When a model is being unserialized, check if it needs to be booted and setup DynamoDB.
428
     *
429
     * @return void
430
     */
431 2
    public function __wakeup()
432
    {
433 2
        parent::__wakeup();
434 2
        $this->setupDynamoDb();
435 2
    }
436
}
437