Completed
Pull Request — master (#333)
by Luc
15:51
created

ImageUploaderService::createUploadImageCommand()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 42
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
c 0
b 0
f 0
rs 8.5806
cc 4
eloc 29
nc 4
nop 4
1
<?php
2
3
namespace CultuurNet\UDB3\Media;
4
5
use Broadway\CommandHandling\CommandBusInterface;
6
use Broadway\UuidGenerator\UuidGeneratorInterface;
7
use CultuurNet\Entry\Number;
8
use CultuurNet\UDB3\Language;
9
use CultuurNet\UDB3\Media\Commands\UploadImage;
10
use CultuurNet\UDB3\Media\Properties\MIMEType;
11
use League\Flysystem\FilesystemInterface;
12
use Symfony\Component\HttpFoundation\File\UploadedFile;
13
use ValueObjects\Identity\UUID;
14
use ValueObjects\Number\Natural;
15
use ValueObjects\StringLiteral\StringLiteral;
16
17
/**
18
 * @todo Move to udb3-symfony
19
 * @see https://jira.uitdatabank.be/browse/III-1513
20
 */
21
class ImageUploaderService implements ImageUploaderInterface
22
{
23
    /**
24
     * @var MediaManagerInterface
25
     */
26
    protected $mediaManager;
27
28
    /**
29
     * @var UuidGeneratorInterface
30
     */
31
    protected $uuidGenerator;
32
33
    /**
34
     * @var CommandBusInterface
35
     */
36
    protected $commandBus;
37
38
    /**
39
     * @var string
40
     */
41
    protected $uploadDirectory;
42
43
    /**
44
     * @var FilesystemInterface
45
     */
46
    protected $filesystem;
47
48
    /**
49
     * @var Natural|null
50
     *  The maximum file size in bytes.
51
     *  There is no limit when the file size if null.
52
     */
53
    protected $maxFileSize;
54
55
    /**
56
     * @param MediaManagerInterface $mediaManager
57
     * @param UuidGeneratorInterface $uuidGenerator
58
     * @param CommandBusInterface $commandBus
59
     * @param FilesystemInterface $filesystem
60
     * @param $uploadDirectory
61
     *
62
     * @param Natural|null $maxFileSize
63
     *  The maximum file size in bytes.
64
     */
65
    public function __construct(
66
        MediaManagerInterface $mediaManager,
67
        UuidGeneratorInterface $uuidGenerator,
68
        CommandBusInterface $commandBus,
69
        FilesystemInterface $filesystem,
70
        $uploadDirectory,
71
        Natural $maxFileSize = null
72
    ) {
73
        $this->mediaManager = $mediaManager;
74
        $this->uuidGenerator = $uuidGenerator;
75
        $this->commandBus = $commandBus;
76
        $this->filesystem = $filesystem;
77
        $this->uploadDirectory = $uploadDirectory;
78
        $this->maxFileSize = $maxFileSize;
79
    }
80
81
    /**
82
     * @inheritdoc
83
     */
84
    public function upload(
85
        UploadedFile $file,
86
        StringLiteral $description,
87
        StringLiteral $copyrightHolder,
88
        Language $language
89
    ) {
90
        $uploadImageCommand = $this->createUploadImageCommand(
91
            $file,
92
            $description,
93
            $copyrightHolder,
94
            $language
95
        );
96
97
        $this->mediaManager->handleUploadImage($uploadImageCommand);
98
99
        return $uploadImageCommand->getFileId();
100
    }
101
102
    /**
103
     * @inheritdoc
104
     */
105
    public function uploadAsync(
106
        UploadedFile $file,
107
        StringLiteral $description,
108
        StringLiteral $copyrightHolder,
109
        Language $language
110
    ) {
111
        $uploadImageCommand = $this->createUploadImageCommand(
112
            $file,
113
            $description,
114
            $copyrightHolder,
115
            $language
116
        );
117
118
        return $this->commandBus->dispatch(
119
            $uploadImageCommand
120
        );
121
    }
122
123
    private function createUploadImageCommand(
124
        UploadedFile $file,
125
        StringLiteral $description,
126
        StringLiteral $copyrightHolder,
127
        Language $language
128
    ) {
129
        if (!$file->isValid()) {
130
            throw new \InvalidArgumentException('The file did not upload correctly.');
131
        }
132
133
        $mimeTypeString = $file->getMimeType();
134
135
        if (!$mimeTypeString) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mimeTypeString of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
136
            throw new \InvalidArgumentException('The type of the uploaded file can not be guessed.');
137
        }
138
139
        $this->guardFileSizeLimit($file);
140
141
        $fileTypeParts = explode('/', $mimeTypeString);
142
        $fileType = array_shift($fileTypeParts);
143
        if ($fileType !== 'image') {
144
            throw new \InvalidArgumentException('The uploaded file is not an image.');
145
        }
146
147
        $mimeType = MIMEType::fromNative($mimeTypeString);
148
149
        $fileId = new UUID($this->uuidGenerator->generate());
150
        $fileName = $fileId . '.' . $file->guessExtension();
151
        $destination = $this->getUploadDirectory() . '/' . $fileName;
152
        $stream = fopen($file->getRealPath(), 'r+');
153
        $this->filesystem->writeStream($destination, $stream);
154
        fclose($stream);
155
156
        return new UploadImage(
157
            $fileId,
158
            $mimeType,
0 ignored issues
show
Compatibility introduced by
$mimeType of type object<ValueObjects\StringLiteral\StringLiteral> is not a sub-type of object<CultuurNet\UDB3\Media\Properties\MIMEType>. It seems like you assume a child class of the class ValueObjects\StringLiteral\StringLiteral to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
159
            $description,
160
            $copyrightHolder,
161
            new StringLiteral($destination),
162
            $language
163
        );
164
    }
165
166
    private function guardFileSizeLimit(UploadedFile $file)
167
    {
168
        $filePath = $file->getRealPath();
169
        $fileSize = filesize($filePath);
170
171
        if ($this->maxFileSize && !$fileSize) {
172
            throw new \InvalidArgumentException('There is a maximum size and we could not determine the size of the uploaded image.');
173
        }
174
175
        if ($this->maxFileSize && $fileSize > $this->maxFileSize->toNative()) {
176
            throw new FileSizeExceededException(
177
                "The file size of the uploaded image is too big."
178
            );
179
        }
180
    }
181
182
    /**
183
     * @inheritdoc
184
     */
185
    public function getUploadDirectory()
186
    {
187
        return $this->uploadDirectory;
188
    }
189
}
190