Completed
Push — master ( 833832...c34869 )
by Freek
08:48 queued 01:44
created

src/FileAdder/FileAdder.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Spatie\MediaLibrary\FileAdder;
4
5
use Spatie\MediaLibrary\Helpers\File;
6
use Spatie\MediaLibrary\Models\Media;
7
use Illuminate\Database\Eloquent\Model;
8
use Spatie\MediaLibrary\HasMedia\HasMedia;
9
use Spatie\MediaLibrary\File as PendingFile;
10
use Spatie\MediaLibrary\Filesystem\Filesystem;
11
use Spatie\MediaLibrary\Jobs\GenerateResponsiveImages;
12
use Symfony\Component\HttpFoundation\File\UploadedFile;
13
use Spatie\MediaLibrary\MediaCollection\MediaCollection;
14
use Symfony\Component\HttpFoundation\File\File as SymfonyFile;
15
use Spatie\MediaLibrary\Exceptions\FileCannotBeAdded\UnknownType;
16
use Spatie\MediaLibrary\Exceptions\FileCannotBeAdded\FileIsTooBig;
17
use Spatie\MediaLibrary\Exceptions\FileCannotBeAdded\DiskDoesNotExist;
18
use Spatie\MediaLibrary\Exceptions\FileCannotBeAdded\FileDoesNotExist;
19
use Spatie\MediaLibrary\ImageGenerators\FileTypes\Image as ImageGenerator;
20
use Spatie\MediaLibrary\Exceptions\FileCannotBeAdded\FileUnacceptableForCollection;
21
22
class FileAdder
23
{
24
    /** @var \Illuminate\Database\Eloquent\Model subject */
25
    protected $subject;
26
27
    /** @var \Spatie\MediaLibrary\Filesystem\Filesystem */
28
    protected $filesystem;
29
30
    /** @var bool */
31
    protected $preserveOriginal = false;
32
33
    /** @var string|\Symfony\Component\HttpFoundation\File\UploadedFile */
34
    protected $file;
35
36
    /** @var array */
37
    protected $properties = [];
38
39
    /** @var array */
40
    protected $customProperties = [];
41
42
    /** @var array */
43
    protected $manipulations = [];
44
45
    /** @var string */
46
    protected $pathToFile;
47
48
    /** @var string */
49
    protected $fileName;
50
51
    /** @var string */
52
    protected $mediaName;
53
54
    /** @var string */
55
    protected $diskName = '';
56
57
    /** @var null|callable */
58
    protected $fileNameSanitizer;
59
60
    /** @var bool */
61
    protected $generateResponsiveImages = false;
62
63
    /** @var array */
64
    protected $customHeaders = [];
65
66
    /**
67
     * @param Filesystem $fileSystem
68
     */
69
    public function __construct(Filesystem $fileSystem)
70
    {
71
        $this->filesystem = $fileSystem;
72
73
        $this->fileNameSanitizer = function ($fileName) {
74
            return $this->defaultSanitizer($fileName);
75
        };
76
    }
77
78
    /**
79
     * @param \Illuminate\Database\Eloquent\Model $subject
80
     *
81
     * @return FileAdder
82
     */
83
    public function setSubject(Model $subject)
84
    {
85
        $this->subject = $subject;
86
87
        return $this;
88
    }
89
90
    /*
91
     * Set the file that needs to be imported.
92
     *
93
     * @param string|\Symfony\Component\HttpFoundation\File\UploadedFile $file
94
     *
95
     * @return $this
96
     */
97
    public function setFile($file): self
98
    {
99
        $this->file = $file;
100
101
        if (is_string($file)) {
102
            $this->pathToFile = $file;
103
            $this->setFileName(pathinfo($file, PATHINFO_BASENAME));
104
            $this->mediaName = pathinfo($file, PATHINFO_FILENAME);
105
106
            return $this;
107
        }
108
109
        if ($file instanceof UploadedFile) {
0 ignored issues
show
The class Symfony\Component\HttpFoundation\File\UploadedFile does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
110
            $this->pathToFile = $file->getPath().'/'.$file->getFilename();
111
            $this->setFileName($file->getClientOriginalName());
112
            $this->mediaName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
113
114
            return $this;
115
        }
116
117
        if ($file instanceof SymfonyFile) {
0 ignored issues
show
The class Symfony\Component\HttpFoundation\File\File does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
118
            $this->pathToFile = $file->getPath().'/'.$file->getFilename();
119
            $this->setFileName(pathinfo($file->getFilename(), PATHINFO_BASENAME));
120
            $this->mediaName = pathinfo($file->getFilename(), PATHINFO_FILENAME);
121
122
            return $this;
123
        }
124
125
        throw UnknownType::create();
126
    }
127
128
    public function preservingOriginal(): self
129
    {
130
        $this->preserveOriginal = true;
131
132
        return $this;
133
    }
134
135
    public function usingName(string $name): self
136
    {
137
        return $this->setName($name);
138
    }
139
140
    public function setName(string $name): self
141
    {
142
        $this->mediaName = $name;
143
144
        return $this;
145
    }
146
147
    public function usingFileName(string $fileName): self
148
    {
149
        return $this->setFileName($fileName);
150
    }
151
152
    public function setFileName(string $fileName): self
153
    {
154
        $this->fileName = $fileName;
155
156
        return $this;
157
    }
158
159
    public function withCustomProperties(array $customProperties): self
160
    {
161
        $this->customProperties = $customProperties;
162
163
        return $this;
164
    }
165
166
    public function withManipulations(array $manipulations): self
167
    {
168
        $this->manipulations = $manipulations;
169
170
        return $this;
171
    }
172
173
    public function withProperties(array $properties): self
174
    {
175
        $this->properties = $properties;
176
177
        return $this;
178
    }
179
180
    public function withAttributes(array $properties): self
181
    {
182
        return $this->withProperties($properties);
183
    }
184
185
    public function withResponsiveImages(): self
186
    {
187
        $this->generateResponsiveImages = true;
188
189
        return $this;
190
    }
191
192
    public function addCustomHeaders(array $customRemoteHeaders): self
193
    {
194
        $this->customHeaders = $customRemoteHeaders;
195
196
        $this->filesystem->addCustomRemoteHeaders($customRemoteHeaders);
197
198
        return $this;
199
    }
200
201
    public function toMediaCollectionOnCloudDisk(string $collectionName = 'default'): Media
202
    {
203
        return $this->toMediaCollection($collectionName, config('filesystems.cloud'));
204
    }
205
206
    public function toMediaCollection(string $collectionName = 'default', string $diskName = ''): Media
207
    {
208
        if (! is_file($this->pathToFile)) {
209
            throw FileDoesNotExist::create($this->pathToFile);
210
        }
211
212
        if (filesize($this->pathToFile) > config('medialibrary.max_file_size')) {
213
            throw FileIsTooBig::create($this->pathToFile);
214
        }
215
216
        $mediaClass = config('medialibrary.media_model');
217
        /** @var \Spatie\MediaLibrary\Models\Media $media */
218
        $media = new $mediaClass();
219
220
        $media->name = $this->mediaName;
221
222
        $this->fileName = ($this->fileNameSanitizer)($this->fileName);
223
224
        $media->file_name = $this->fileName;
225
226
        $media->disk = $this->determineDiskName($diskName, $collectionName);
227
228
        if (is_null(config("filesystems.disks.{$media->disk}"))) {
229
            throw DiskDoesNotExist::create($media->disk);
230
        }
231
232
        $media->collection_name = $collectionName;
233
234
        $media->mime_type = File::getMimetype($this->pathToFile);
235
        $media->size = filesize($this->pathToFile);
236
        $media->custom_properties = $this->customProperties;
237
238
        $media->responsive_images = [];
239
240
        $media->manipulations = $this->manipulations;
241
242
        if (filled($this->customHeaders)) {
243
            $media->setCustomHeaders($this->customHeaders);
244
        }
245
246
        $media->fill($this->properties);
247
248
        $this->attachMedia($media);
249
250
        return $media;
251
    }
252
253
    protected function determineDiskName(string $diskName, string $collectionName): string
254
    {
255
        if ($diskName !== '') {
256
            return $diskName;
257
        }
258
259
        if ($collection = $this->getMediaCollection($collectionName)) {
260
            $collectionDiskName = $collection->diskName;
261
262
            if ($collectionDiskName !== '') {
263
                return $collectionDiskName;
264
            }
265
        }
266
267
        return config('medialibrary.disk_name');
268
    }
269
270
    public function defaultSanitizer(string $fileName): string
271
    {
272
        return str_replace(['#', '/', '\\', ' '], '-', $fileName);
273
    }
274
275
    public function sanitizingFileName(callable $fileNameSanitizer): self
276
    {
277
        $this->fileNameSanitizer = $fileNameSanitizer;
278
279
        return $this;
280
    }
281
282
    protected function attachMedia(Media $media)
283
    {
284
        if (! $this->subject->exists) {
285
            $this->subject->prepareToAttachMedia($media, $this);
286
287
            $class = get_class($this->subject);
288
289
            $class::created(function ($model) {
290
                $model->processUnattachedMedia(function (Media $media, self $fileAdder) use ($model) {
291
                    $this->processMediaItem($model, $media, $fileAdder);
292
                });
293
            });
294
295
            return;
296
        }
297
298
        $this->processMediaItem($this->subject, $media, $this);
299
    }
300
301
    protected function processMediaItem(HasMedia $model, Media $media, self $fileAdder)
302
    {
303
        $this->guardAgainstDisallowedFileAdditions($media, $model);
304
305
        $model->media()->save($media);
306
307
        $this->filesystem->add($fileAdder->pathToFile, $media, $fileAdder->fileName);
308
309
        if (! $fileAdder->preserveOriginal) {
310
            unlink($fileAdder->pathToFile);
311
        }
312
313
        if ($this->generateResponsiveImages && (new ImageGenerator())->canConvert($media)) {
314
            $generateResponsiveImagesJobClass = config('medialibrary.jobs.generate_responsive_images', GenerateResponsiveImages::class);
315
316
            $job = new $generateResponsiveImagesJobClass($media);
317
318
            if ($customQueue = config('medialibrary.queue_name')) {
319
                $job->onQueue($customQueue);
320
            }
321
322
            dispatch($job);
323
        }
324
325
        if (optional($this->getMediaCollection($media->collection_name))->singleFile) {
326
            $model->clearMediaCollectionExcept($media->collection_name, $media);
327
        }
328
    }
329
330
    protected function getMediaCollection(string $collectionName): ?MediaCollection
331
    {
332
        $this->subject->registerMediaCollections();
333
334
        return collect($this->subject->mediaCollections)
335
            ->first(function (MediaCollection $collection) use ($collectionName) {
336
                return $collection->name === $collectionName;
337
            });
338
    }
339
340
    protected function guardAgainstDisallowedFileAdditions(Media $media)
341
    {
342
        $file = PendingFile::createFromMedia($media);
343
344
        if (! $collection = $this->getMediaCollection($media->collection_name)) {
345
            return;
346
        }
347
348
        if (! ($collection->acceptsFile)($file, $this->subject)) {
349
            throw FileUnacceptableForCollection::create($file, $collection, $this->subject);
350
        }
351
    }
352
}
353