Completed
Push — master ( cea4d6...c737a9 )
by Maxime
04:01
created

ContentfulModel::getAndSetPayloadContentfulAsset()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
nc 3
nop 3
dl 0
loc 13
ccs 0
cts 13
cp 0
crap 20
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
namespace Distilleries\Contentful\Models\Base;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Database\Eloquent\Model;
7
use Distilleries\Contentful\Models\Asset;
8
use Distilleries\Contentful\Models\Traits\Localable;
9
use Distilleries\Contentful\Models\EntryRelationship;
10
11
abstract class ContentfulModel extends Model
12
{
13
    use Localable;
14
15
    /**
16
     * {@inheritdoc}
17
     */
18
    protected $primaryKey = 'contentful_id';
19
20
    /**
21
     * The content-type ID.
22
     *
23
     * @var string
24
     */
25
    protected $contentType = null;
26
27
    /**
28
     * {@inheritdoc}
29
     */
30
    protected $keyType = 'string';
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    public $incrementing = false;
36
37
    /**
38
     * ContentfulModel constructor.
39
     *
40
     * @param  array $attributes
41
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
42
     */
43
    public function __construct(array $attributes = [])
44
    {
45
        // Override fillable
46
        foreach ($this->defaultFillable() as $defaultFillable) {
47
            if (!in_array($defaultFillable, $this->fillable)) {
48
                $this->fillable[] = $defaultFillable;
49
            }
50
        }
51
52
        // Override casts
53
        foreach ($this->defaultCasts() as $field => $type) {
54
            if (!isset($this->casts[$field])) {
55
                $this->casts[$field] = $type;
56
            }
57
        }
58
59
        $this->initContentType();
60
61
        parent::__construct($attributes);
62
    }
63
64
    /**
65
     * Init model content-type if needed.
66
     *
67
     * @return void
68
     */
69
    protected function initContentType()
70
    {
71
        if (empty($this->contentType)) {
72
            $this->contentType = lcfirst(class_basename(get_class($this)));
73
        }
74
    }
75
76
    /**
77
     * Return default fillable fields.
78
     *
79
     * @return array
80
     */
81
    public function defaultFillable(): array
82
    {
83
        return [
84
            'contentful_id',
85
            'country',
86
            'locale',
87
            'payload',
88
            'created_at',
89
            'updated_at',
90
        ];
91
    }
92
93
    /**
94
     * Return default casted fields.
95
     *
96
     * @return array
97
     */
98
    public function defaultCasts(): array
99
    {
100
        return [
101
            'payload' => 'array',
102
        ];
103
    }
104
105
    // --------------------------------------------------------------------------------
106
    // --------------------------------------------------------------------------------
107
    // --------------------------------------------------------------------------------
108
109
    protected function getAndSetPayloadContentfulAsset(string $payload, $link, $query = null): ?Asset
110
    {
111
        if (!isset($this->attributes[$payload]) && isset($this->payload[$payload])) {
112
            $this->attributes[$payload] = $this->contentfulAsset($link, $query);
113
            return $this->attributes[$payload];
114
        } else {
115
            if (isset($this->attributes[$payload])) {
116
                return $this->attributes[$payload];
117
            } else {
118
                return null;
119
            }
120
        }
121
    }
122
123
124
    /**
125
     * Return Contentful Asset for given link (sys or ID).
126
     *
127
     * @param  array|string|null $link
128
     * @param  callback|null $query
129
     * @return \Distilleries\Contentful\Models\Asset|null
130
     */
131
    protected function contentfulAsset($link, $query = null): ?Asset
132
    {
133
        $assetId = $this->contentfulLinkId($link);
134
135
        if (empty($assetId)) {
136
            return null;
137
        }
138
139
        $instance = (new Asset)->query()
140
            ->where('contentful_id', '=', $assetId)
141
            ->where('locale', '=', $this->locale)
142
            ->where('country', '=', $this->country);
143
144
        if (!empty($query)) {
145
            $instance = call_user_func($query, $instance);
146
        }
147
148
        $asset = $instance->first();
149
150
        return !empty($asset) ? $asset : null;
151
    }
152
153
    /**
154
     * Return payload of related Contentful entries.
155
     *
156
     * @param  string $payload
157
     * @param  array $links
158
     * @param  mixed $query
159
     * @return \Illuminate\Support\Collection
160
     */
161
    protected function getAndSetPayloadContentfulEntries(string $payload, array $links, $query = null): Collection
162
    {
163
        if (!isset($this->attributes[$payload]) && isset($this->payload[$payload])) {
164
            $this->attributes[$payload] = $this->contentfulEntries($links, $query);
165
            return $this->attributes[$payload];
166
        } else {
167
            if (isset($this->attributes[$payload])) {
168
                return $this->attributes[$payload];
169
            } else {
170
                return collect();
171
            }
172
        }
173
    }
174
175
    /**
176
     * Return payload of related Contentful entry.
177
     *
178
     * @param  string $payload
179
     * @param  array $links
180
     * @param  mixed $query
181
     * @return \Distilleries\Contentful\Models\Base\ContentfulModel|null
182
     */
183
    protected function getAndSetPayloadContentfulEntry(string $payload, array $links, $query = null): ?ContentfulModel
184
    {
185
        if (!isset($this->attributes[$payload]) && isset($this->payload[$payload])) {
186
            $this->attributes[$payload] = $this->contentfulEntry($links, $query);
187
            return $this->attributes[$payload];
188
        } else {
189
            if (isset($this->attributes[$payload])) {
190
                return $this->attributes[$payload];
191
            } else {
192
                return null;
193
            }
194
        }
195
    }
196
197
    /**
198
     * Return Contentful Entry for given link (sys or ID).
199
     *
200
     * @param  array|string|null $link
201
     * @param  mixed $query
202
     * @return \Distilleries\Contentful\Models\Base\ContentfulModel|null
203
     */
204
    protected function contentfulEntry($link, $query = null): ?ContentfulModel
205
    {
206
        $entryId = $this->contentfulLinkId($link);
207
208
        if (empty($entryId)) {
209
            return null;
210
        }
211
212
        $entries = $this->contentfulEntries([$entryId], $query);
213
214
        return $entries->isNotEmpty() ? $entries->first() : null;
215
    }
216
217
    /**
218
     * Return Contentful Entries for given ID.
219
     *
220
     * @param  array $links
221
     * @param  mixed $query
222
     * @return \Illuminate\Support\Collection
223
     */
224
    protected function contentfulEntries(array $links, $query = null): Collection
225
    {
226
        $entries = [];
227
228
        $entryIds = [];
229
        foreach ($links as $link) {
230
            $entryId = $this->contentfulLinkId($link);
231
            if (!empty($entryId)) {
232
                $entryIds[] = $entryId;
233
            }
234
        }
235
236
        if (!empty($entryIds)) {
237
            $relationships = EntryRelationship::query()
0 ignored issues
show
Bug introduced by
The method select() does not exist on Illuminate\Database\Eloquent\Builder. Did you maybe mean createSelectWithConstraint()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
238
                ->select('related_contentful_id', 'related_contentful_type', 'order')
239
                ->distinct()
240
                ->locale($this->locale, $this->country)
241
                ->where('source_contentful_id', '=', $this->contentful_id)
242
                ->whereIn('related_contentful_id', $entryIds)
243
                ->orderBy('order', 'asc')
244
                ->get();
245
246
            foreach ($relationships as $relationship) {
247
                if ($relationship->related_contentful_type === 'asset') {
248
                    $model = new Asset;
249
                } else {
250
                    $modelClass = config('contentful.namespace.model') . '\\' . studly_case($relationship->related_contentful_type);
251
                    $model = new $modelClass;
252
                }
253
254
                $instance = $model->query()
255
                    ->where('country', '=', $this->country)
256
                    ->where('locale', '=', $this->locale)
257
                    ->where('contentful_id', '=', $relationship->related_contentful_id);
258
259
                if (!empty($query)) {
260
                    $instance = call_user_func($query, $instance);
261
                }
262
263
                $instance = $instance->first();
264
265
                if (!empty($instance)) {
266
                    $entries[] = $instance;
267
                }
268
            }
269
        }
270
271
        return collect($entries);
272
    }
273
274
    /**
275
     * Return a collection of related models for base Contentful ID.
276
     *
277
     * @param  string $contentfulId
278
     * @param  string $contentfulType
279
     * @return \Illuminate\Support\Collection
280
     */
281
    protected function contentfulRelatedEntries(string $contentfulId, string $contentfulType = ''): Collection
282
    {
283
        $entries = [];
284
285
        $query = EntryRelationship::query()
0 ignored issues
show
Bug introduced by
The method select() does not exist on Illuminate\Database\Eloquent\Builder. Did you maybe mean createSelectWithConstraint()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
286
            ->select('source_contentful_id', 'source_contentful_type', '')
287
            ->locale($this->locale, $this->country)
288
            ->where('related_contentful_id', '=', $contentfulId);
289
290
        if (!empty($contentfulType)) {
291
            $query = $query->where('source_contentful_type', '=', $contentfulType);
292
        }
293
294
        $relationships = $query->orderBy('order', 'asc')->get();
295
        foreach ($relationships as $relationship) {
296
            if ($relationship->source_contentful_type === 'asset') {
297
                $model = new Asset;
298
            } else {
299
                $modelClass = rtrim(config('contentful.namespace.model'),
300
                        '\\') . '\\' . studly_case($relationship->source_contentful_type);
301
                $model = new $modelClass;
302
            }
303
304
            $instance = $model->query()
305
                ->locale($this->locale, $this->country)
306
                ->where('contentful_id', '=', $relationship->source_contentful_id)
307
                ->first();
308
309
            if (!empty($instance)) {
310
                $entries[] = $instance;
311
            }
312
        }
313
314
        return collect($entries);
315
    }
316
317
    /**
318
     * Return Contentful link ID.
319
     *
320
     * @param  mixed $link
321
     * @return string|null
322
     */
323
    protected function contentfulLinkId($link): ?string
324
    {
325
        if (empty($link)) {
326
            return null;
327
        }
328
329
        if (is_string($link)) {
330
            return $link;
331
        }
332
333
        if (is_array($link) and isset($link['sys']) and isset($link['sys']['id'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
334
            return $link['sys']['id'];
335
        }
336
337
        return null;
338
    }
339
340
    /**
341
     * Return model Contentful content-type.
342
     *
343
     * @return string
344
     */
345
    public function getContentType(): string
346
    {
347
        return $this->contentType;
348
    }
349
350
    /**
351
     * Return ID attribute.
352
     *
353
     * @return mixed
354
     */
355
    public function getIdAttribute()
356
    {
357
        return $this->getKey();
358
    }
359
360
    /**
361
     * Magical extended toArray().
362
     *
363
     * @return array
364
     */
365
    public function toArray()
366
    {
367
        $array = parent::toArray();
368
369
        foreach ($this->getMutatedAttributes() as $key) {
370
            if (!array_key_exists($key, $array)) {
371
                $array[$key] = $this->{$key};
372
            }
373
        }
374
375
        return $array;
376
    }
377
}
378