Completed
Push — master ( df9c07...f7c7ac )
by Freek
02:14
created

HasMediaTrait::loadMedia()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 1
nop 1
1
<?php
2
3
namespace Spatie\MediaLibrary\HasMedia;
4
5
use Spatie\MediaLibrary\Media;
6
use Illuminate\Support\Collection;
7
use Spatie\MediaLibrary\MediaRepository;
8
use Spatie\MediaLibrary\Conversion\Conversion;
9
use Spatie\MediaLibrary\Filesystem\Filesystem;
10
use Spatie\MediaLibrary\FileAdder\FileAdderFactory;
11
use Spatie\MediaLibrary\HasMedia\Interfaces\HasMedia;
12
use Spatie\MediaLibrary\Events\CollectionHasBeenCleared;
13
use Spatie\MediaLibrary\Exceptions\MediaCannotBeDeleted;
14
use Spatie\MediaLibrary\Exceptions\MediaCannotBeUpdated;
15
use Spatie\MediaLibrary\Exceptions\FileCannotBeAdded\UnreachableUrl;
16
use Spatie\MediaLibrary\Exceptions\FileCannotBeAdded\InvalidBase64Data;
17
18
trait HasMediaTrait
19
{
20
    /** @var array */
21
    public $mediaConversions = [];
22
23
    /** @var bool */
24
    protected $deletePreservingMedia = false;
25
26
    public static function bootHasMediaTrait()
27
    {
28
        static::deleted(function (HasMedia $entity) {
29
            if ($entity->shouldDeletePreservingMedia()) {
30
                return;
31
            }
32
33
            $entity->media()->get()->each->delete();
34
        });
35
    }
36
37
    /**
38
     * Set the polymorphic relation.
39
     *
40
     * @return mixed
41
     */
42
    public function media()
43
    {
44
        return $this->morphMany(config('medialibrary.media_model'), 'model');
45
    }
46
47
    /**
48
     * Add a file to the medialibrary.
49
     *
50
     * @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $file
51
     *
52
     * @return \Spatie\MediaLibrary\FileAdder\FileAdder
53
     */
54
    public function addMedia($file)
55
    {
56
        return app(FileAdderFactory::class)->create($this, $file);
57
    }
58
59
    /**
60
     * Add a file from a request.
61
     *
62
     * @param string $key
63
     *
64
     * @return \Spatie\MediaLibrary\FileAdder\FileAdder
65
     */
66
    public function addMediaFromRequest(string $key)
67
    {
68
        return app(FileAdderFactory::class)->createFromRequest($this, $key);
69
    }
70
71
    /**
72
     * Add multiple files from a request by keys.
73
     *
74
     * @param string[] $keys
75
     *
76
     * @return \Spatie\MediaLibrary\FileAdder\FileAdder[]
77
     */
78
    public function addMultipleMediaFromRequest(array $keys)
79
    {
80
        return app(FileAdderFactory::class)->createMultipleFromRequest($this, $keys);
81
    }
82
83
    /**
84
     * Add all files from a request.
85
     *
86
     * @return \Spatie\MediaLibrary\FileAdder\FileAdder[]
87
     */
88
    public function addAllMediaFromRequest()
89
    {
90
        return app(FileAdderFactory::class)->createAllFromRequest($this);
91
    }
92
93
    /**
94
     * Add a remote file to the medialibrary.
95
     *
96
     * @param string $url
97
     *
98
     * @return \Spatie\MediaLibrary\FileAdder\FileAdder
99
     *
100
     * @throws \Spatie\MediaLibrary\Exceptions\FileCannotBeAdded
101
     */
102
    public function addMediaFromUrl(string $url)
103
    {
104
        if (! $stream = @fopen($url, 'r')) {
105
            throw UnreachableUrl::create($url);
106
        }
107
108
        $tmpFile = tempnam(sys_get_temp_dir(), 'media-library');
109
        file_put_contents($tmpFile, $stream);
110
111
        $filename = basename(parse_url($url, PHP_URL_PATH));
112
113
        return app(FileAdderFactory::class)
114
            ->create($this, $tmpFile)
115
            ->usingName(pathinfo($filename, PATHINFO_FILENAME))
116
            ->usingFileName($filename);
117
    }
118
119
    /**
120
     * Add a base64 encoded file to the medialibrary.
121
     *
122
     * @param string $base64data
123
     *
124
     * @throws InvalidBase64Data
125
     * @throws \Spatie\MediaLibrary\Exceptions\FileCannotBeAdded
126
     *
127
     * @return \Spatie\MediaLibrary\FileAdder\FileAdder
128
     */
129
    public function addMediaFromBase64(string $base64data)
130
    {
131
        // strip out data uri scheme information (see RFC 2397)
132
        if (strpos($base64data, ';base64') !== false) {
133
            list(, $base64data) = explode(';', $base64data);
134
            list(, $base64data) = explode(',', $base64data);
135
        }
136
137
        // strict mode filters for non-base64 alphabet characters
138
        if (base64_decode($base64data, true) === false) {
139
            throw InvalidBase64Data::create();
140
        }
141
142
        // decoding and then reeconding should not change the data
143
        if (base64_encode(base64_decode($base64data)) !== $base64data) {
144
            throw InvalidBase64Data::create();
145
        }
146
147
        $binaryData = base64_decode($base64data);
148
149
        // temporarily store the decoded data on the filesystem to be able to pass it to the fileAdder
150
        $tmpFile = tempnam(sys_get_temp_dir(), 'medialibrary');
151
        file_put_contents($tmpFile, $binaryData);
152
153
        $file = app(FileAdderFactory::class)
154
            ->create($this, $tmpFile);
155
156
        return $file;
157
    }
158
159
    /**
160
     * Copy a file to the medialibrary.
161
     *
162
     * @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $file
163
     *
164
     * @return \Spatie\MediaLibrary\FileAdder\FileAdder
165
     */
166
    public function copyMedia($file)
167
    {
168
        return $this->addMedia($file)->preservingOriginal();
169
    }
170
171
    /*
172
     * Determine if there is media in the given collection.
173
     */
174
    public function hasMedia(string $collectionName = 'default'): bool
175
    {
176
        return count($this->getMedia($collectionName)) ? true : false;
177
    }
178
179
    /**
180
     * Get media collection by its collectionName.
181
     *
182
     * @param string $collectionName
183
     * @param array|callable  $filters
184
     *
185
     * @return \Illuminate\Support\Collection
186
     */
187
    public function getMedia(string $collectionName = 'default', $filters = []): Collection
188
    {
189
        return app(MediaRepository::class)->getCollection($this, $collectionName, $filters);
190
    }
191
192
    /**
193
     * Get the first media item of a media collection.
194
     *
195
     * @param string $collectionName
196
     * @param array $filters
197
     *
198
     * @return Media|null
199
     */
200
    public function getFirstMedia(string $collectionName = 'default', array $filters = [])
201
    {
202
        $media = $this->getMedia($collectionName, $filters);
203
204
        return $media->first();
205
    }
206
207
    /*
208
     * Get the url of the image for the given conversionName
209
     * for first media for the given collectionName.
210
     * If no profile is given, return the source's url.
211
     */
212
    public function getFirstMediaUrl(string $collectionName = 'default', string $conversionName = ''): string
213
    {
214
        $media = $this->getFirstMedia($collectionName);
215
216
        if (! $media) {
217
            return '';
218
        }
219
220
        return $media->getUrl($conversionName);
221
    }
222
223
    /*
224
     * Get the url of the image for the given conversionName
225
     * for first media for the given collectionName.
226
     * If no profile is given, return the source's url.
227
     */
228
    public function getFirstMediaPath(string $collectionName = 'default', string $conversionName = ''): string
229
    {
230
        $media = $this->getFirstMedia($collectionName);
231
232
        if (! $media) {
233
            return '';
234
        }
235
236
        return $media->getPath($conversionName);
237
    }
238
239
    /**
240
     * Update a media collection by deleting and inserting again with new values.
241
     *
242
     * @param array $newMediaArray
243
     * @param string $collectionName
244
     *
245
     * @return \Illuminate\Support\Collection
246
     *
247
     * @throws \Spatie\MediaLibrary\Exceptions\MediaCannotBeUpdated
248
     */
249
    public function updateMedia(array $newMediaArray, string $collectionName = 'default'): Collection
250
    {
251
        $this->removeMediaItemsNotPresentInArray($newMediaArray, $collectionName);
252
253
        return collect($newMediaArray)
254
            ->map(function (array $newMediaItem) use ($collectionName) {
255
                static $orderColumn = 1;
256
257
                $mediaClass = config('medialibrary.media_model');
258
                $currentMedia = $mediaClass::findOrFail($newMediaItem['id']);
259
260
                if ($currentMedia->collection_name != $collectionName) {
261
                    throw MediaCannotBeUpdated::doesNotBelongToCollection($collectionName, $currentMedia);
262
                }
263
264
                if (array_key_exists('name', $newMediaItem)) {
265
                    $currentMedia->name = $newMediaItem['name'];
266
                }
267
268
                if (array_key_exists('custom_properties', $newMediaItem)) {
269
                    $currentMedia->custom_properties = $newMediaItem['custom_properties'];
270
                }
271
272
                $currentMedia->order_column = $orderColumn++;
273
274
                $currentMedia->save();
275
276
                return $currentMedia;
277
            });
278
    }
279
280
    /**
281
     * @param array $newMediaArray
282
     * @param string $collectionName
283
     */
284
    protected function removeMediaItemsNotPresentInArray(array $newMediaArray, string $collectionName = 'default')
285
    {
286
        $this->getMedia($collectionName)
287
            ->reject(function (Media $currentMediaItem) use ($newMediaArray) {
288
                return in_array($currentMediaItem->id, array_column($newMediaArray, 'id'));
289
            })
290
            ->each->delete();
291
    }
292
293
    /**
294
     * Remove all media in the given collection.
295
     *
296
     * @param string $collectionName
297
     *
298
     * @return $this
299
     */
300
    public function clearMediaCollection(string $collectionName = 'default')
301
    {
302
        $this->getMedia($collectionName)
303
             ->each->delete();
304
305
        event(new CollectionHasBeenCleared($this, $collectionName));
306
307
        if ($this->mediaIsPreloaded()) {
308
            unset($this->media);
309
        }
310
311
        return $this;
312
    }
313
314
    /**
315
     * Remove all media in the given collection except some.
316
     *
317
     * @param string $collectionName
318
     * @param \Spatie\MediaLibrary\Media[]|\Illuminate\Support\Collection $excludedMedia
319
     *
320
     * @return $this
321
     */
322
    public function clearMediaCollectionExcept(string $collectionName = 'default', $excludedMedia = [])
323
    {
324
        $excludedMedia = collect($excludedMedia);
325
326
        if ($excludedMedia->isEmpty()) {
327
            return $this->clearMediaCollection($collectionName);
328
        }
329
330
        $this->getMedia($collectionName)
331
            ->reject(function (Media $media) use ($excludedMedia) {
332
                return $excludedMedia->where('id', $media->id)->count();
333
            })
334
            ->each->delete();
335
336
        if ($this->mediaIsPreloaded()) {
337
            unset($this->media);
338
        }
339
340
        return $this;
341
    }
342
343
    /**
344
     * Delete the associated media with the given id.
345
     * You may also pass a media object.
346
     *
347
     * @param int|\Spatie\MediaLibrary\Media $mediaId
348
     *
349
     * @throws \Spatie\MediaLibrary\Exceptions\MediaCannotBeDeleted
350
     */
351
    public function deleteMedia($mediaId)
352
    {
353
        if ($mediaId instanceof Media) {
354
            $mediaId = $mediaId->id;
355
        }
356
357
        $media = $this->media->find($mediaId);
358
359
        if (! $media) {
360
            throw MediaCannotBeDeleted::doesNotBelongToModel($media, $this);
361
        }
362
363
        $media->delete();
364
    }
365
366
    /*
367
     * Add a conversion.
368
     */
369
    public function addMediaConversion(string $name): Conversion
370
    {
371
        $conversion = Conversion::create($name);
372
373
        $this->mediaConversions[] = $conversion;
374
375
        return $conversion;
376
    }
377
378
    /**
379
     * Delete the model, but preserve all the associated media.
380
     *
381
     * @return bool
382
     */
383
    public function deletePreservingMedia(): bool
384
    {
385
        $this->deletePreservingMedia = true;
386
387
        return $this->delete();
0 ignored issues
show
Bug introduced by
The method delete() does not exist on Spatie\MediaLibrary\HasMedia\HasMediaTrait. Did you maybe mean deleteMedia()?

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...
388
    }
389
390
    /**
391
     * Determines if the media files should be preserved when the media object gets deleted.
392
     *
393
     * @return \Spatie\MediaLibrary\Media
394
     */
395
    public function shouldDeletePreservingMedia()
396
    {
397
        return $this->deletePreservingMedia ?? false;
398
    }
399
400
    protected function mediaIsPreloaded(): bool
401
    {
402
        return $this->relationLoaded('media');
0 ignored issues
show
Bug introduced by
It seems like relationLoaded() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
403
    }
404
405
    /**
406
     * Cache the media on the object.
407
     *
408
     * @param string $collectionName
409
     *
410
     * @return mixed
411
     */
412
    public function loadMedia(string $collectionName)
413
    {
414
        return $this->media
415
            ->filter(function (Media $mediaItem) use ($collectionName) {
416
                if ($collectionName == '') {
417
                    return true;
418
                }
419
420
                return $mediaItem->collection_name === $collectionName;
421
            })
422
            ->sortBy('order_column')
423
            ->values();
424
    }
425
}
426