Completed
Push — master ( f4588e...60b2e1 )
by Maxime
02:53
created

ContentfulModel::contentfulLinkId()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
nc 4
nop 1
dl 0
loc 16
ccs 0
cts 13
cp 0
crap 42
rs 9.1111
c 0
b 0
f 0
1
<?php
2
3
namespace Distilleries\Contentful\Models\Base;
4
5
use Distilleries\Contentful\Helpers\NamespaceResolver;
6
use Illuminate\Support\Collection;
7
use Illuminate\Database\Eloquent\Model;
8
use Distilleries\Contentful\Models\Asset;
9
use Distilleries\Contentful\Models\Traits\Localable;
10
use Distilleries\Contentful\Models\EntryRelationship;
11
12
abstract class ContentfulModel extends Model
13
{
14
    use Localable;
15
16
    /**
17
     * {@inheritdoc}
18
     */
19
    protected $primaryKey = 'contentful_id';
20
21
    /**
22
     * The content-type ID.
23
     *
24
     * @var string
25
     */
26
    protected $contentType = null;
27
28
    /**
29
     * {@inheritdoc}
30
     */
31
    protected $keyType = 'string';
32
33
    /**
34
     * {@inheritdoc}
35
     */
36
    public $incrementing = false;
37
38
    /**
39
     * ContentfulModel constructor.
40
     *
41
     * @param  array $attributes
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::select('related_contentful_id', 'related_contentful_type')
238
                ->distinct()
239
                ->locale($this->locale, $this->country)
240
                ->where('source_contentful_id', '=', $this->contentful_id)
241
                ->whereIn('related_contentful_id', $entryIds)
242
                ->orderBy('order', 'asc')
243
                ->get();
244
245
            foreach ($relationships as $relationship) {
246
                if ($relationship->related_contentful_type === 'asset') {
247
                    $model = new Asset;
248
                } else {
249
                    $model = NamespaceResolver::model($relationship->related_contentful_type);
250
                }
251
252
                if (!empty($model)) {
253
                    $instance = $model->query()
254
                        ->where('country', '=', $this->country)
255
                        ->where('locale', '=', $this->locale)
256
                        ->where('contentful_id', '=', $relationship->related_contentful_id);
257
258
                    if (!empty($query)) {
259
                        $instance = call_user_func($query, $instance);
260
                    }
261
262
                    $instance = $instance->first();
263
264
                }
265
266
                if (!empty($instance)) {
267
                    $entries[] = $instance;
268
                }
269
            }
270
        }
271
272
        return collect($entries);
273
    }
274
275
    /**
276
     * Return a collection of related models for base Contentful ID.
277
     *
278
     * @param  string $contentfulId
279
     * @param  string $contentfulType
280
     * @return \Illuminate\Support\Collection
281
     */
282
    protected function contentfulRelatedEntries(string $contentfulId, string $contentfulType = ''): Collection
283
    {
284
        $entries = [];
285
286
        $query = EntryRelationship::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
                $model = NamespaceResolver::model($relationship->related_contentful_type);
300
            }
301
302
            $instance = !empty($model) ? $model->query()
303
                ->locale($this->locale, $this->country)
304
                ->where('contentful_id', '=', $relationship->source_contentful_id)
305
                ->first() : null;
306
307
            if (!empty($instance)) {
308
                $entries[] = $instance;
309
            }
310
        }
311
312
        return collect($entries);
313
    }
314
315
    /**
316
     * Return Contentful link ID.
317
     *
318
     * @param  mixed $link
319
     * @return string|null
320
     */
321
    protected function contentfulLinkId($link): ?string
322
    {
323
        if (empty($link)) {
324
            return null;
325
        }
326
327
        if (is_string($link)) {
328
            return $link;
329
        }
330
331
        if (is_array($link) && isset($link['sys']) && isset($link['sys']['id'])) {
332
            return $link['sys']['id'];
333
        }
334
335
        return null;
336
    }
337
338
    /**
339
     * Return model Contentful content-type.
340
     *
341
     * @return string
342
     */
343
    public function getContentType(): string
344
    {
345
        return $this->contentType;
346
    }
347
348
    /**
349
     * Return ID attribute.
350
     *
351
     * @return mixed
352
     */
353
    public function getIdAttribute()
354
    {
355
        return $this->getKey();
356
    }
357
358
    /**
359
     * Magical extended toArray().
360
     *
361
     * @return array
362
     */
363
    public function toArray()
364
    {
365
        $array = parent::toArray();
366
367
        foreach ($this->getMutatedAttributes() as $key) {
368
            if (!array_key_exists($key, $array)) {
369
                $array[$key] = $this->{$key};
370
            }
371
        }
372
373
        return $array;
374
    }
375
}
376