Completed
Push — master ( 4d2d1f...29a520 )
by Maxime
04:53
created

ContentfulMapper::mapPayload()   B

Complexity

Conditions 11
Paths 10

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
cc 11
eloc 20
nc 10
nop 2
dl 0
loc 29
ccs 0
cts 26
cp 0
crap 132
rs 7.3166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

256
            $locales = array_keys(/** @scrutinizer ignore-type */ $firstField);
Loading history...
257
        }
258
259
        return $locales;
260
    }
261
}
262