Completed
Push — master ( 09a0d6...0aba44 )
by Maxime
45:07 queued 39:59
created

ContentfulModel::initContentType()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 7
ccs 0
cts 7
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Distilleries\Contentful\Models\Base;
4
5
use Distilleries\Contentful\Models\EntryRelationship;
6
use Distilleries\Contentful\Models\Traits\Localable;
7
use Illuminate\Support\Collection;
8
use Illuminate\Database\Eloquent\Model;
9
use Distilleries\Contentful\Models\Asset;
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
     * @var string
23
     */
24
    protected $contentType = null;
25
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
        {
48
            if (!in_array($defaultFillable, $this->fillable))
49
            {
50
                $this->fillable[] = $defaultFillable;
51
            }
52
        }
53
54
        // Override casts
55
        foreach ($this->defaultCasts() as $field => $type)
56
        {
57
            if (!isset($this->casts[$field]))
58
            {
59
                $this->casts[$field] = $type;
60
            }
61
        }
62
63
        $this->initContentType();
64
65
        parent::__construct($attributes);
66
    }
67
68
    protected function initContentType()
69
    {
70
        if (empty($this->contentType))
71
        {
72
            $this->contentType = lcfirst(class_basename(__CLASS__));
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
110
    /**
111
     * Return Contentful Asset for given link (sys or ID).
112
     *
113
     * @param  array|string|null $link
114
     * @return \Distilleries\Contentful\Models\Asset|null
115
     */
116
    protected function contentfulAsset($link): ?Asset
117
    {
118
        $assetId = $this->contentfulLinkId($link);
119
120
        if (empty($assetId))
121
        {
122
            return null;
123
        }
124
125
        $asset = (new Asset)->query()
126
            ->where('contentful_id', '=', $assetId)
127
            ->where('locale', '=', $this->locale)
128
            ->where('country', '=', $this->country)
129
            ->first();
130
131
        return !empty($asset) ? $asset : null;
132
    }
133
134
    /**
135
     * Return Contentful Entry for given link (sys or ID).
136
     *
137
     * @param  array|string|null $link
138
     * @return \Distilleries\Contentful\Models\Base\ContentfulModel|null
139
     */
140
    protected function contentfulEntry($link): ?ContentfulModel
141
    {
142
        $entryId = $this->contentfulLinkId($link);
143
144
        if (empty($entryId))
145
        {
146
            return null;
147
        }
148
149
        $entries = $this->contentfulEntries([$entryId]);
150
151
        return $entries->isNotEmpty() ? $entries->first() : null;
152
    }
153
154
    /**
155
     * Return Contentful Entries for given ID.
156
     *
157
     * @param  array $links
158
     * @return \Illuminate\Support\Collection
159
     */
160
    protected function contentfulEntries(array $links): Collection
161
    {
162
        $entries = [];
163
164
        $entryIds = [];
165
        foreach ($links as $link)
166
        {
167
            $entryId = $this->contentfulLinkId($link);
168
            if (!empty($entryId))
169
            {
170
                $entryIds[] = $entryId;
171
            }
172
        }
173
174
        if (!empty($entryIds))
175
        {
176
            $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...
177
                ->select('related_contentful_id', 'related_contentful_type', 'order')
178
                ->distinct()
179
                ->locale($this->locale, $this->country)
180
                ->where('source_contentful_id', '=', $this->contentful_id)
181
                ->whereIn('related_contentful_id', $entryIds)
182
                ->orderBy('order', 'asc')
183
                ->get();
184
185
            foreach ($relationships as $relationship)
186
            {
187
                if ($relationship->related_contentful_type === 'asset')
188
                {
189
                    $model = new Asset;
190
                } else
191
                {
192
                    $modelClass = config('contentful.namespace.model') . '\\' . studly_case($relationship->related_contentful_type);
193
                    $model = new $modelClass;
194
                }
195
196
                $instance = $model->query()
197
                    ->where('country', '=', $this->country)
198
                    ->where('locale', '=', $this->locale)
199
                    ->where('contentful_id', '=', $relationship->related_contentful_id)
200
                    ->first();
201
202
                if (!empty($instance))
203
                {
204
                    $entries[] = $instance;
205
                }
206
            }
207
        }
208
209
        return collect($entries);
210
    }
211
212
    /**
213
     * Return a collection of related models for base Contentful ID.
214
     *
215
     * @param  string $contentfulId
216
     * @param  string $contentfulType
217
     * @return \Illuminate\Support\Collection
218
     */
219
    protected function contentfulRelatedEntries(string $contentfulId, string $contentfulType = ''): Collection
220
    {
221
        $entries = [];
222
223
        $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...
224
            ->select('source_contentful_id', 'source_contentful_type', '')
225
            ->locale($this->locale, $this->country)
226
            ->where('related_contentful_id', '=', $contentfulId);
227
228
        if (!empty($contentfulType))
229
        {
230
            $query = $query->where('source_contentful_type', '=', $contentfulType);
231
        }
232
233
        $relationships = $query->orderBy('order', 'asc')->get();
234
        foreach ($relationships as $relationship)
235
        {
236
            if ($relationship->source_contentful_type === 'asset')
237
            {
238
                $model = new Asset;
239
            } else
240
            {
241
                $modelClass = rtrim(config('contentful.namespace.model'), '\\') . '\\' . studly_case($relationship->source_contentful_type);
242
                $model = new $modelClass;
243
            }
244
245
            $instance = $model->query()
246
                ->locale($this->locale, $this->country)
247
                ->where('contentful_id', '=', $relationship->source_contentful_id)
248
                ->first();
249
250
            if (!empty($instance))
251
            {
252
                $entries[] = $instance;
253
            }
254
        }
255
256
        return collect($entries);
257
    }
258
259
    /**
260
     * Return Contentful link ID.
261
     *
262
     * @param  mixed $link
263
     * @return string|null
264
     */
265
    protected function contentfulLinkId($link): ?string
266
    {
267
        if (empty($link))
268
        {
269
            return null;
270
        }
271
272
        if (is_string($link))
273
        {
274
            return $link;
275
        }
276
277
        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...
278
        {
279
            return $link['sys']['id'];
280
        }
281
282
        return null;
283
    }
284
285
    public function getContentType(): string
286
    {
287
        return $this->contentType;
288
    }
289
}
290