Completed
Push — master ( 3576d4...095dbc )
by Maxime
12s queued 11s
created

ContentfulMapper::levelFallBack()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 5
ccs 0
cts 4
cp 0
crap 6
rs 10
c 0
b 0
f 0
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
        foreach ($entry['fields'] as $field => $localesData) {
89
            if (isset($localesData[$locale])) {
90
                $payload[$field] = $localesData[$locale];
91
            } else {
92
                if (!in_array($field,
93
                        $dontFallback) && isset($localesData[$fallbackLocale]) && ($this->levelFallBack($field) === 'all')) {
94
                    $payload[$field] = $localesData[$fallbackLocale];
95
                } else {
96
                    $payload[$field] = null;
97
                }
98
            }
99
        }
100
101
        return $payload;
102
    }
103
104
    /**
105
     * Level fallback.
106
     *
107
     * @param  string $field
108
     * @return string
109
     */
110
    protected function levelFallBack($field): string
111
    {
112
        $levelMaster = ['slug'];
113
114
        return in_array($field, $levelMaster) ? 'master' : 'all';
115
    }
116
117
    // --------------------------------------------------------------------------------
118
    // --------------------------------------------------------------------------------
119
    // --------------------------------------------------------------------------------
120
121
    /**
122
     * Map relationships in given payload.
123
     *
124
     * @param  array $payload
125
     * @return array
126
     * @throws \Exception
127
     */
128
    protected function mapRelationships($payload): array
129
    {
130
        $relationships = [];
131
132
        foreach ($payload as $field => $value) {
133
            if (is_array($value)) {
134
                if ($this->isLink($value)) {
135
                    try {
136
                        $relationships[] = $this->relationshipSignature($value,$field);
137
                    } catch (Exception $e) {
138
                        //
139
                    }
140
                } else {
141
                    foreach ($value as $entry) {
142
                        if ($this->isLink($entry)) {
143
                            try {
144
                                $relationships[] = $this->relationshipSignature($entry,$field);
145
                            } catch (Exception $e) {
146
                                //
147
                            }
148
                        }
149
                    }
150
                }
151
            }
152
        }
153
154
        return $relationships;
155
    }
156
157
    /**
158
     * Return relationship signature for given "localized" field.
159
     *
160
     * @param  array $localeField
161
     * @return array|null
162
     * @throws \Exception
163
     */
164
    private function relationshipSignature(array $localeField,string $field=''): ?array
165
    {
166
        if ($localeField['sys']['linkType'] === 'Asset') {
167
            return [
168
                'id' => $localeField['sys']['id'],
169
                'type' => 'asset',
170
                'field' => $field,
171
            ];
172
        } else {
173
            if ($localeField['sys']['linkType'] === 'Entry') {
174
                return [
175
                    'id' => $localeField['sys']['id'],
176
                    'type' => $this->contentTypeFromEntryTypes($localeField['sys']['id']),
177
                    'field' => $field,
178
                ];
179
            }
180
        }
181
182
        throw new Exception('Invalid field signature... ' . PHP_EOL . print_r($localeField, true));
183
    }
184
185
    /**
186
     * Return if field is a Link one.
187
     *
188
     * @param  mixed $localeField
189
     * @return boolean
190
     */
191
    private function isLink($localeField): bool
192
    {
193
        return isset($localeField['sys']) && isset($localeField['sys']['type']) && ($localeField['sys']['type'] === 'Link');
194
    }
195
196
    /**
197
     * Return contentful-type for given Contentful ID from `sync_entries` table.
198
     *
199
     * @param  string $contentfulId
200
     * @return string
201
     * @throws \Exception
202
     */
203
    public function contentTypeFromEntryTypes(string $contentfulId): string
204
    {
205
        $pivot = DB::table('sync_entries')
206
            ->select('contentful_type')
207
            ->where('contentful_id', '=', $contentfulId)
208
            ->first();
209
210
        if (empty($pivot)) {
211
            try {
212
                $entry = app(DeliveryApi::class)->entries([
213
                    'id' => $contentfulId,
214
                    'locale' => '*',
215
                    'content_type' => 'single_entry',
216
                ]);
217
218
                if (!empty($entry) && !empty($entry['sys']['contentType']) && !empty($entry['sys']['contentType']['sys'])) {
219
                    $this->upsertEntryType($entry, $entry['sys']['contentType']['sys']['id']);
220
221
                    return $entry['sys']['contentType']['sys']['id'];
222
                }
223
            } catch (Exception $e) {
224
                throw new Exception('Unknown content-type from synced entry: ' . $contentfulId);
225
            }
226
        }
227
228
        return $pivot->contentful_type;
229
    }
230
231
    // --------------------------------------------------------------------------------
232
    // --------------------------------------------------------------------------------
233
    // --------------------------------------------------------------------------------
234
235
    /**
236
     * Return all locales in entry payload.
237
     *
238
     * @param  array $entry
239
     * @return array
240
     */
241
    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...
242
    {
243
        $locales = [];
244
245
        if (isset($entry['fields']) && !empty($entry['fields'])) {
246
            $firstField = array_first($entry['fields']);
247
            $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

247
            $locales = array_keys(/** @scrutinizer ignore-type */ $firstField);
Loading history...
248
        }
249
250
        return $locales;
251
    }
252
}
253