1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Spatie\MediaLibrary\Models; |
4
|
|
|
|
5
|
|
|
use DateTimeInterface; |
6
|
|
|
use Illuminate\Contracts\Support\Htmlable; |
7
|
|
|
use Illuminate\Contracts\Support\Responsable; |
8
|
|
|
use Illuminate\Database\Eloquent\Model; |
9
|
|
|
use Illuminate\Database\Eloquent\Relations\MorphTo; |
10
|
|
|
use Illuminate\Support\Arr; |
11
|
|
|
use Illuminate\Support\Collection; |
12
|
|
|
use Illuminate\Support\HtmlString; |
13
|
|
|
use Spatie\MediaLibrary\Conversion\Conversion; |
14
|
|
|
use Spatie\MediaLibrary\Conversion\ConversionCollection; |
15
|
|
|
use Spatie\MediaLibrary\Filesystem\Filesystem; |
16
|
|
|
use Spatie\MediaLibrary\HasMedia\HasMedia; |
17
|
|
|
use Spatie\MediaLibrary\Helpers\File; |
18
|
|
|
use Spatie\MediaLibrary\Helpers\TemporaryDirectory; |
19
|
|
|
use Spatie\MediaLibrary\ImageGenerators\FileTypes\Image; |
20
|
|
|
use Spatie\MediaLibrary\Models\Concerns\IsSorted; |
21
|
|
|
use Spatie\MediaLibrary\Models\Traits\CustomMediaProperties; |
22
|
|
|
use Spatie\MediaLibrary\ResponsiveImages\RegisteredResponsiveImages; |
23
|
|
|
use Spatie\MediaLibrary\UrlGenerator\UrlGeneratorFactory; |
24
|
|
|
|
25
|
|
|
class Media extends Model implements Responsable, Htmlable |
26
|
|
|
{ |
27
|
|
|
use IsSorted, |
28
|
|
|
CustomMediaProperties; |
29
|
|
|
|
30
|
|
|
const TYPE_OTHER = 'other'; |
31
|
|
|
|
32
|
|
|
protected $guarded = []; |
33
|
|
|
|
34
|
|
|
protected $casts = [ |
35
|
|
|
'manipulations' => 'array', |
36
|
|
|
'custom_properties' => 'array', |
37
|
|
|
'responsive_images' => 'array', |
38
|
|
|
]; |
39
|
|
|
|
40
|
|
|
public function model(): MorphTo |
41
|
|
|
{ |
42
|
|
|
return $this->morphTo(); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
/* |
46
|
|
|
* Get the full url to a original media file. |
47
|
|
|
*/ |
48
|
|
|
public function getFullUrl(string $conversionName = ''): string |
49
|
|
|
{ |
50
|
|
|
return url($this->getUrl($conversionName)); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/* |
54
|
|
|
* Get the url to a original media file. |
55
|
|
|
*/ |
56
|
|
|
public function getUrl(string $conversionName = ''): string |
57
|
|
|
{ |
58
|
|
|
$urlGenerator = UrlGeneratorFactory::createForMedia($this, $conversionName); |
59
|
|
|
|
60
|
|
|
return $urlGenerator->getUrl(); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
public function getTemporaryUrl(DateTimeInterface $expiration, string $conversionName = '', array $options = []): string |
64
|
|
|
{ |
65
|
|
|
$urlGenerator = UrlGeneratorFactory::createForMedia($this, $conversionName); |
66
|
|
|
|
67
|
|
|
return $urlGenerator->getTemporaryUrl($expiration, $options); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/* |
71
|
|
|
* Get the path to the original media file. |
72
|
|
|
*/ |
73
|
|
|
public function getPath(string $conversionName = ''): string |
74
|
|
|
{ |
75
|
|
|
$urlGenerator = UrlGeneratorFactory::createForMedia($this, $conversionName); |
76
|
|
|
|
77
|
|
|
return $urlGenerator->getPath(); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
public function getImageGenerators(): Collection |
81
|
|
|
{ |
82
|
|
|
return collect(config('medialibrary.image_generators')); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
public function getTypeAttribute(): string |
86
|
|
|
{ |
87
|
|
|
$type = $this->getTypeFromExtension(); |
88
|
|
|
|
89
|
|
|
if ($type !== self::TYPE_OTHER) { |
90
|
|
|
return $type; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
return $this->getTypeFromMime(); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
public function getTypeFromExtension(): string |
97
|
|
|
{ |
98
|
|
|
$imageGenerator = $this->getImageGenerators() |
99
|
|
|
->map(function (string $className) { |
100
|
|
|
return app($className); |
101
|
|
|
}) |
102
|
|
|
->first->canHandleExtension(strtolower($this->extension)); |
103
|
|
|
|
104
|
|
|
return $imageGenerator |
105
|
|
|
? $imageGenerator->getType() |
106
|
|
|
: static::TYPE_OTHER; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
public function getTypeFromMime(): string |
110
|
|
|
{ |
111
|
|
|
$imageGenerator = $this->getImageGenerators() |
112
|
|
|
->map(function (string $className) { |
113
|
|
|
return app($className); |
114
|
|
|
}) |
115
|
|
|
->first->canHandleMime($this->mime_type); |
116
|
|
|
|
117
|
|
|
return $imageGenerator |
118
|
|
|
? $imageGenerator->getType() |
119
|
|
|
: static::TYPE_OTHER; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
public function getExtensionAttribute(): string |
123
|
|
|
{ |
124
|
|
|
return pathinfo($this->file_name, PATHINFO_EXTENSION); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
public function getHumanReadableSizeAttribute(): string |
128
|
|
|
{ |
129
|
|
|
return File::getHumanReadableSize($this->size); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
public function getDiskDriverName(): string |
133
|
|
|
{ |
134
|
|
|
return strtolower(config("filesystems.disks.{$this->disk}.driver")); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/* |
138
|
|
|
* Determine if the media item has a custom property with the given name. |
139
|
|
|
*/ |
140
|
|
|
public function hasCustomProperty(string $propertyName): bool |
141
|
|
|
{ |
142
|
|
|
return Arr::has($this->custom_properties, $propertyName); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Get the value of custom property with the given name. |
147
|
|
|
* |
148
|
|
|
* @param string $propertyName |
149
|
|
|
* @param mixed $default |
150
|
|
|
* |
151
|
|
|
* @return mixed |
152
|
|
|
*/ |
153
|
|
|
public function getCustomProperty(string $propertyName, $default = null) |
154
|
|
|
{ |
155
|
|
|
return Arr::get($this->custom_properties, $propertyName, $default); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* @param string $name |
160
|
|
|
* @param mixed $value |
161
|
|
|
* |
162
|
|
|
* @return $this |
163
|
|
|
*/ |
164
|
|
|
public function setCustomProperty(string $name, $value): self |
165
|
|
|
{ |
166
|
|
|
$customProperties = $this->custom_properties; |
167
|
|
|
|
168
|
|
|
Arr::set($customProperties, $name, $value); |
169
|
|
|
|
170
|
|
|
$this->custom_properties = $customProperties; |
171
|
|
|
|
172
|
|
|
return $this; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
public function forgetCustomProperty(string $name): self |
176
|
|
|
{ |
177
|
|
|
$customProperties = $this->custom_properties; |
178
|
|
|
|
179
|
|
|
Arr::forget($customProperties, $name); |
180
|
|
|
|
181
|
|
|
$this->custom_properties = $customProperties; |
182
|
|
|
|
183
|
|
|
return $this; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/* |
187
|
|
|
* Get all the names of the registered media conversions. |
188
|
|
|
*/ |
189
|
|
|
public function getMediaConversionNames(): array |
190
|
|
|
{ |
191
|
|
|
$conversions = ConversionCollection::createForMedia($this); |
192
|
|
|
|
193
|
|
|
return $conversions->map(function (Conversion $conversion) { |
194
|
|
|
return $conversion->getName(); |
195
|
|
|
})->toArray(); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
public function hasGeneratedConversion(string $conversionName): bool |
199
|
|
|
{ |
200
|
|
|
$generatedConversions = $this->getGeneratedConversions(); |
201
|
|
|
|
202
|
|
|
return $generatedConversions[$conversionName] ?? false; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
public function markAsConversionGenerated(string $conversionName, bool $generated): self |
206
|
|
|
{ |
207
|
|
|
$this->setCustomProperty("generated_conversions.{$conversionName}", $generated); |
208
|
|
|
|
209
|
|
|
$this->save(); |
210
|
|
|
|
211
|
|
|
return $this; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
public function getGeneratedConversions(): Collection |
215
|
|
|
{ |
216
|
|
|
return collect($this->getCustomProperty('generated_conversions', [])); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Create an HTTP response that represents the object. |
221
|
|
|
* |
222
|
|
|
* @param \Illuminate\Http\Request $request |
223
|
|
|
* |
224
|
|
|
* @return \Illuminate\Http\Response |
225
|
|
|
*/ |
226
|
|
|
public function toResponse($request) |
227
|
|
|
{ |
228
|
|
|
$downloadHeaders = [ |
229
|
|
|
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0', |
230
|
|
|
'Content-Type' => $this->mime_type, |
231
|
|
|
'Content-Length' => $this->size, |
232
|
|
|
'Content-Disposition' => 'attachment; filename="'.$this->file_name.'"', |
233
|
|
|
'Pragma' => 'public', |
234
|
|
|
]; |
235
|
|
|
|
236
|
|
|
return response()->stream(function () { |
|
|
|
|
237
|
|
|
$stream = $this->stream(); |
238
|
|
|
|
239
|
|
|
fpassthru($stream); |
240
|
|
|
|
241
|
|
|
if (is_resource($stream)) { |
242
|
|
|
fclose($stream); |
243
|
|
|
} |
244
|
|
|
}, 200, $downloadHeaders); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
public function getResponsiveImageUrls(string $conversionName = ''): array |
248
|
|
|
{ |
249
|
|
|
return $this->responsiveImages($conversionName)->getUrls(); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
public function hasResponsiveImages(string $conversionName = ''): bool |
253
|
|
|
{ |
254
|
|
|
return count($this->getResponsiveImageUrls($conversionName)) > 0; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
public function getSrcset(string $conversionName = ''): string |
258
|
|
|
{ |
259
|
|
|
return $this->responsiveImages($conversionName)->getSrcset(); |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
public function toHtml() |
263
|
|
|
{ |
264
|
|
|
return $this->img(); |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* @param string|array $conversion |
269
|
|
|
* @param array $extraAttributes |
270
|
|
|
* |
271
|
|
|
* @return string |
272
|
|
|
*/ |
273
|
|
|
public function img($conversion = '', array $extraAttributes = []): string |
274
|
|
|
{ |
275
|
|
|
if (! (new Image())->canHandleMime($this->mime_type)) { |
276
|
|
|
return ''; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
if (is_array($conversion)) { |
280
|
|
|
$attributes = $conversion; |
281
|
|
|
|
282
|
|
|
$conversion = $attributes['conversion'] ?? ''; |
283
|
|
|
|
284
|
|
|
unset($attributes['conversion']); |
285
|
|
|
|
286
|
|
|
$extraAttributes = array_merge($attributes, $extraAttributes); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
$attributeString = collect($extraAttributes) |
290
|
|
|
->map(function ($value, $name) { |
291
|
|
|
return $name.'="'.$value.'"'; |
292
|
|
|
})->implode(' '); |
293
|
|
|
|
294
|
|
|
if (strlen($attributeString)) { |
295
|
|
|
$attributeString = ' '.$attributeString; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
$media = $this; |
299
|
|
|
|
300
|
|
|
$viewName = 'image'; |
301
|
|
|
|
302
|
|
|
$width = ''; |
303
|
|
|
|
304
|
|
|
if ($this->hasResponsiveImages($conversion)) { |
305
|
|
|
$viewName = config('medialibrary.responsive_images.use_tiny_placeholders') |
306
|
|
|
? 'responsiveImageWithPlaceholder' |
307
|
|
|
: 'responsiveImage'; |
308
|
|
|
|
309
|
|
|
$width = $this->responsiveImages($conversion)->files->first()->width(); |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
return view("medialibrary::{$viewName}", compact( |
313
|
|
|
'media', |
314
|
|
|
'conversion', |
315
|
|
|
'attributeString', |
316
|
|
|
'width' |
317
|
|
|
)); |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
public function move(HasMedia $model, $collectionName = 'default', string $diskName = ''): self |
321
|
|
|
{ |
322
|
|
|
$newMedia = $this->copy($model, $collectionName, $diskName); |
323
|
|
|
|
324
|
|
|
$this->delete(); |
325
|
|
|
|
326
|
|
|
return $newMedia; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
public function copy(HasMedia $model, $collectionName = 'default', string $diskName = ''): self |
330
|
|
|
{ |
331
|
|
|
$temporaryDirectory = TemporaryDirectory::create(); |
332
|
|
|
|
333
|
|
|
$temporaryFile = $temporaryDirectory->path('/').DIRECTORY_SEPARATOR.$this->file_name; |
334
|
|
|
|
335
|
|
|
app(Filesystem::class)->copyFromMediaLibrary($this, $temporaryFile); |
336
|
|
|
|
337
|
|
|
$newMedia = $model |
338
|
|
|
->addMedia($temporaryFile) |
339
|
|
|
->usingName($this->name) |
340
|
|
|
->withCustomProperties($this->custom_properties) |
341
|
|
|
->toMediaCollection($collectionName, $diskName); |
342
|
|
|
|
343
|
|
|
$temporaryDirectory->delete(); |
344
|
|
|
|
345
|
|
|
return $newMedia; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
public function responsiveImages(string $conversionName = ''): RegisteredResponsiveImages |
349
|
|
|
{ |
350
|
|
|
return new RegisteredResponsiveImages($this, $conversionName); |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
public function stream() |
354
|
|
|
{ |
355
|
|
|
$filesystem = app(Filesystem::class); |
356
|
|
|
|
357
|
|
|
return $filesystem->getStream($this); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
public function __invoke(...$arguments) |
361
|
|
|
{ |
362
|
|
|
return new HtmlString($this->img(...$arguments)); |
363
|
|
|
} |
364
|
|
|
} |
365
|
|
|
|
It seems like the method you are trying to call exists only in some of the possible types.
Let’s take a look at an example:
Available Fixes
Add an additional type-check:
Only allow a single type to be passed if the variable comes from a parameter: