ContentfulMapper::contentTypeFromEntryTypes()   A
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 6
eloc 16
c 3
b 0
f 0
nc 7
nop 1
dl 0
loc 26
ccs 0
cts 22
cp 0
crap 42
rs 9.1111
1
<?php
2
3
namespace Distilleries\Contentful\Models\Base;
4
5
use Exception;
6
use Illuminate\Support\Arr;
7
use Illuminate\Support\Str;
8
use Illuminate\Support\Carbon;
9
use Illuminate\Support\Collection;
10
use Illuminate\Support\Facades\DB;
11
use Distilleries\Contentful\Models\Locale;
12
use Distilleries\Contentful\Api\DeliveryApi;
13
use Distilleries\Contentful\Repositories\Traits\EntryType;
14
15
abstract class ContentfulMapper
16
{
17
    use EntryType;
18
19
    /**
20
     * Map entry specific payload.
21
     *
22
     * @param  array  $entry
23
     * @param  string  $locale
24
     * @return array
25
     * @throws \Exception
26
     */
27
    abstract protected function map(array $entry, string $locale): array;
28
29
    /**
30
     * Map entry with common data + specific payload for each locales.
31
     *
32
     * @param  array  $entry
33
     * @param  \Illuminate\Support\Collection  $locales
34
     * @return array
35
     * @throws \Exception
36
     */
37
    public function toLocaleEntries(array $entry, Collection $locales): array
38
    {
39
        $entries = [];
40
41
        $common = [
42
            'contentful_id' => $entry['sys']['id'],
43
            'created_at' => new Carbon($entry['sys']['createdAt']),
44
            'updated_at' => new Carbon($entry['sys']['updatedAt']),
45
        ];
46
47
        foreach ($locales as $locale) {
48
            // Add specific fields
49
            $data = array_merge($common, $this->map($entry, $locale->code));
50
51
            $data['country'] = Locale::getCountry($locale->code);
52
            $data['locale'] = Locale::getLocale($locale->code);
53
54
            if (! isset($data['payload'])) {
55
                $data['payload'] = $this->mapPayload($entry, $locale->code);
56
            }
57
            if (! isset($data['relationships'])) {
58
                $data['relationships'] = $this->mapRelationships($data['payload']);
59
            }
60
            if (isset($data['slug']) && Str::contains($data['slug'], 'untitled-')) {
61
                $data['slug'] = null;
62
            }
63
64
            $entries[] = $data;
65
        }
66
67
        return $entries;
68
    }
69
70
    // --------------------------------------------------------------------------------
71
    // --------------------------------------------------------------------------------
72
    // --------------------------------------------------------------------------------
73
74
    /**
75
     * Return raw entry fields payload for given locale.
76
     *
77
     * @param  array  $entry
78
     * @param  string  $locale
79
     * @return array
80
     */
81
    protected function mapPayload(array $entry, string $locale): array
82
    {
83
        $payload = [];
84
        $dontFallback = config('contentful.payload_fields_not_fallback', []);
85
86
        $fallbackLocale = Locale::fallback($locale);
87
        $fallbackSecondLevel = ! empty($fallbackLocale) ? Locale::fallback($fallbackLocale) : null;
88
89
        foreach ($entry['fields'] as $field => $localesData) {
90
            if (isset($localesData[$locale])) {
91
                $payload[$field] = $localesData[$locale];
92
            } else {
93
                if (! in_array($field, $dontFallback) && isset($localesData[$fallbackLocale]) && ($this->levelFallBack($field) === 'all')) {
94
                    $payload[$field] = $localesData[$fallbackLocale];
95
                } else {
96
                    if (! empty($fallbackSecondLevel) && ! in_array($field, $dontFallback) && isset($localesData[$fallbackSecondLevel]) && ($this->levelFallBack($field) === 'all')) {
97
                        $payload[$field] = $localesData[$fallbackSecondLevel];
98
                    } else {
99
                        $payload[$field] = null;
100
                    }
101
                }
102
            }
103
        }
104
105
        return $payload;
106
    }
107
108
    /**
109
     * Level fallback.
110
     *
111
     * @param  string  $field
112
     * @return string
113
     */
114
    protected function levelFallBack($field): string
115
    {
116
        $levelMaster = ['slug'];
117
118
        return in_array($field, $levelMaster) ? 'master' : 'all';
119
    }
120
121
    // --------------------------------------------------------------------------------
122
    // --------------------------------------------------------------------------------
123
    // --------------------------------------------------------------------------------
124
125
    /**
126
     * Map relationships in given payload.
127
     *
128
     * @param  array  $payload
129
     * @return array
130
     * @throws \Exception
131
     */
132
    protected function mapRelationships($payload): array
133
    {
134
        $relationships = [];
135
136
        foreach ($payload as $field => $value) {
137
            if (is_array($value)) {
138
                if ($this->isLink($value)) {
139
                    try {
140
                        $relationships[] = $this->relationshipSignature($value, $field);
141
                    } catch (Exception $e) {
142
                        //
143
                    }
144
                } else {
145
                    foreach ($value as $entry) {
146
                        if ($this->isLink($entry)) {
147
                            try {
148
                                $relationships[] = $this->relationshipSignature($entry, $field);
149
                            } catch (Exception $e) {
150
                                //
151
                            }
152
                        }
153
                    }
154
                }
155
            }
156
        }
157
158
        return $relationships;
159
    }
160
161
    /**
162
     * Return relationship signature for given "localized" field.
163
     *
164
     * @param  array  $localeField
165
     * @param  string  $field
166
     * @return array|null
167
     * @throws \Exception
168
     */
169
    private function relationshipSignature(array $localeField, string $field = ''): ?array
170
    {
171
        if ($localeField['sys']['linkType'] === 'Asset') {
172
            return [
173
                'id' => $localeField['sys']['id'],
174
                'type' => 'asset',
175
                'field' => $field,
176
            ];
177
        } else {
178
            if ($localeField['sys']['linkType'] === 'Entry') {
179
                return [
180
                    'id' => $localeField['sys']['id'],
181
                    'type' => $this->contentTypeFromEntryTypes($localeField['sys']['id']),
182
                    'field' => $field,
183
                ];
184
            }
185
        }
186
187
        throw new Exception('Invalid field signature... ' . PHP_EOL . print_r($localeField, true));
188
    }
189
190
    /**
191
     * Return if field is a Link one.
192
     *
193
     * @param  mixed  $localeField
194
     * @return boolean
195
     */
196
    private function isLink($localeField): bool
197
    {
198
        return isset($localeField['sys']) && isset($localeField['sys']['type']) && ($localeField['sys']['type'] === 'Link');
199
    }
200
201
    /**
202
     * Return contentful-type for given Contentful ID from `sync_entries` table.
203
     *
204
     * @param  string  $contentfulId
205
     * @return string
206
     * @throws \Exception
207
     */
208
    public function contentTypeFromEntryTypes(string $contentfulId): string
209
    {
210
        $pivot = DB::table('sync_entries')
211
            ->select('contentful_type')
212
            ->where('contentful_id', '=', $contentfulId)
213
            ->first();
214
215
        if (empty($pivot)) {
216
            try {
217
                $entry = app(DeliveryApi::class)->entries([
218
                    'id' => $contentfulId,
219
                    'locale' => '*',
220
                    'content_type' => 'single_entry',
221
                ]);
222
223
                if (! empty($entry) && ! empty($entry['sys']['contentType']) && ! empty($entry['sys']['contentType']['sys'])) {
224
                    $this->upsertEntryType($entry, $entry['sys']['contentType']['sys']['id']);
225
226
                    return $entry['sys']['contentType']['sys']['id'];
227
                }
228
            } catch (Exception $e) {
229
                throw new Exception('Unknown content-type from synced entry: ' . $contentfulId);
230
            }
231
        }
232
233
        return $pivot->contentful_type;
234
    }
235
236
    // --------------------------------------------------------------------------------
237
    // --------------------------------------------------------------------------------
238
    // --------------------------------------------------------------------------------
239
240
    /**
241
     * Return all locales in entry payload.
242
     *
243
     * @param  array  $entry
244
     * @return array
245
     */
246
    private function entryLocales(array $entry): array
0 ignored issues
show
Unused Code introduced by
The method entryLocales() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
247
    {
248
        $locales = [];
249
250
        if (isset($entry['fields']) && ! empty($entry['fields'])) {
251
            $firstField = Arr::first($entry['fields']);
252
            $locales = array_keys($firstField);
0 ignored issues
show
Bug introduced by
It seems like $firstField can also be of type null; however, parameter $input of array_keys() 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

252
            $locales = array_keys(/** @scrutinizer ignore-type */ $firstField);
Loading history...
253
        }
254
255
        return $locales;
256
    }
257
}
258