Completed
Pull Request — master (#41)
by
unknown
02:46
created

Imagy::fileExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php namespace Modules\Media\Image;
2
3
use GuzzleHttp\Mimetypes;
4
use GuzzleHttp\Psr7\Stream;
5
use Illuminate\Contracts\Filesystem\Factory;
6
use Intervention\Image\ImageManager;
7
use Modules\Media\Entities\File;
8
use Modules\Media\ValueObjects\MediaPath;
9
10
class Imagy
11
{
12
    /**
13
     * @var \Intervention\Image\Image
14
     */
15
    private $image;
16
    /**
17
     * @var ImageFactoryInterface
18
     */
19
    private $imageFactory;
20
    /**
21
     * @var ThumbnailsManager
22
     */
23
    private $manager;
24
25
    /**
26
     * All the different images types where thumbnails should be created
27
     * @var array
28
     */
29
    private $imageExtensions = ['jpg', 'png', 'jpeg', 'gif'];
30
    /**
31
     * @var Factory
32
     */
33
    private $filesystem;
34
35
    /**
36
     * @param ImageFactoryInterface $imageFactory
37
     * @param ThumbnailsManager $manager
38
     */
39
    public function __construct(ImageFactoryInterface $imageFactory, ThumbnailsManager $manager)
40
    {
41
        $this->image = app(ImageManager::class);
42
        $this->filesystem = app(Factory::class);
43
        $this->imageFactory = $imageFactory;
44
        $this->manager = $manager;
45
    }
46
47
    /**
48
     * Get an image in the given thumbnail options
49
     * @param  string $path
50
     * @param  string $thumbnail
51
     * @param  bool   $forceCreate
52
     * @return string
53
     */
54
    public function get($path, $thumbnail, $forceCreate = false)
55
    {
56
        if (!$this->isImage($path)) {
57
            return;
58
        }
59
60
        $filename = config('asgard.media.config.files-path') . $this->newFilename($path, $thumbnail);
61
62
        if ($this->returnCreatedFile($filename, $forceCreate)) {
63
            return $filename;
64
        }
65
        if ($this->fileExists($filename) === true) {
66
            $this->filesystem->disk($this->getConfiguredFilesystem())->delete($filename);
67
        }
68
69
        $mediaPath = (new MediaPath($filename))->getUrl();
70
        $this->makeNew($path, $mediaPath, $thumbnail);
0 ignored issues
show
Documentation introduced by
$path is of type string, but the function expects a object<Modules\Media\ValueObjects\MediaPath>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
71
72
        return (new MediaPath($filename))->getUrl();
73
    }
74
75
    /**
76
     * Return the thumbnail path
77
     * @param  string $originalImage
78
     * @param  string $thumbnail
79
     * @return string
80
     */
81
    public function getThumbnail($originalImage, $thumbnail)
82
    {
83
        if (!$this->isImage($originalImage)) {
84
            return $originalImage;
85
        }
86
87
        $path = config('asgard.media.config.files-path') . $this->newFilename($originalImage, $thumbnail);
88
89
        return (new MediaPath($path))->getUrl();
90
    }
91
92
    /**
93
     * Create all thumbnails for the given image path
94
     * @param MediaPath $path
95
     */
96
    public function createAll(MediaPath $path)
97
    {
98
        if (!$this->isImage($path)) {
99
            return;
100
        }
101
102
        foreach ($this->manager->all() as $thumbnail) {
103
            $image = $this->image->make($this->filesystem->disk($this->getConfiguredFilesystem())->get($this->getDestinationPath($path->getRelativeUrl())));
104
            $filename = config('asgard.media.config.files-path') . $this->newFilename($path, $thumbnail->name());
105
            foreach ($thumbnail->filters() as $manipulation => $options) {
106
                $image = $this->imageFactory->make($manipulation)->handle($image, $options);
107
            }
108
            $image = $image->stream(pathinfo($path, PATHINFO_EXTENSION));
109
            $this->writeImage($filename, $image);
0 ignored issues
show
Compatibility introduced by
$image of type object<Psr\Http\Message\StreamInterface> is not a sub-type of object<GuzzleHttp\Psr7\Stream>. It seems like you assume a concrete implementation of the interface Psr\Http\Message\StreamInterface 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...
110
        }
111
    }
112
113
    /**
114
     * Prepend the thumbnail name to filename
115
     * @param $path
116
     * @param $thumbnail
117
     * @return mixed|string
118
     */
119
    private function newFilename($path, $thumbnail)
120
    {
121
        $filename = pathinfo($path, PATHINFO_FILENAME);
122
123
        return $filename . '_' . $thumbnail . '.' . pathinfo($path, PATHINFO_EXTENSION);
124
    }
125
126
    /**
127
     * Return the already created file if it exists and force create is false
128
     * @param  string $filename
129
     * @param  bool   $forceCreate
130
     * @return bool
131
     */
132
    private function returnCreatedFile($filename, $forceCreate)
133
    {
134
        return $this->fileExists($filename) && $forceCreate === false;
135
    }
136
137
    /**
138
     * Write the given image
139
     * @param string $filename
140
     * @param Stream $image
141
     */
142
    private function writeImage($filename, Stream $image)
143
    {
144
        $filename = $this->getDestinationPath($filename);
145
        $resource = $image->detach();
146
        $config = [
147
            'visibility' => 'public',
148
            'mimetype' => Mimetypes::getInstance()->fromFilename($filename),
149
        ];
150
        if ($this->fileExists($filename)) {
151
            return $this->filesystem->disk($this->getConfiguredFilesystem())->updateStream($filename, $resource, $config);
0 ignored issues
show
Bug introduced by
The method updateStream() does not seem to exist on object<Illuminate\Contra...\Filesystem\Filesystem>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
152
        }
153
        $this->filesystem->disk($this->getConfiguredFilesystem())->writeStream($filename, $resource, $config);
0 ignored issues
show
Bug introduced by
The method writeStream() does not seem to exist on object<Illuminate\Contra...\Filesystem\Filesystem>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
154
    }
155
156
    /**
157
     * Make a new image
158
     * @param MediaPath      $path
159
     * @param string      $filename
160
     * @param string null $thumbnail
161
     */
162
    private function makeNew(MediaPath $path, $filename, $thumbnail)
163
    {
164
        $image = $this->image->make($path->getUrl());
165
166
        foreach ($this->manager->find($thumbnail) as $manipulation => $options) {
167
            $image = $this->imageFactory->make($manipulation)->handle($image, $options);
168
        }
169
        $image = $image->stream(pathinfo($path, PATHINFO_EXTENSION));
170
171
        $this->writeImage($filename, $image);
0 ignored issues
show
Compatibility introduced by
$image of type object<Psr\Http\Message\StreamInterface> is not a sub-type of object<GuzzleHttp\Psr7\Stream>. It seems like you assume a concrete implementation of the interface Psr\Http\Message\StreamInterface 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...
172
    }
173
174
    /**
175
     * Check if the given path is en image
176
     * @param  string $path
177
     * @return bool
178
     */
179
    public function isImage($path)
180
    {
181
        return in_array(pathinfo($path, PATHINFO_EXTENSION), $this->imageExtensions);
182
    }
183
184
    /**
185
     * Delete all files on disk for the given file in storage
186
     * This means the original and the thumbnails
187
     * @param $file
188
     * @return bool
189
     */
190
    public function deleteAllFor(File $file)
191
    {
192
        if (!$this->isImage($file->path)) {
193
            return $this->filesystem->disk($this->getConfiguredFilesystem())->delete($this->getDestinationPath($file->path->getRelativeUrl()));
194
        }
195
196
        $paths[] = $this->getDestinationPath($file->path->getRelativeUrl());
0 ignored issues
show
Coding Style Comprehensibility introduced by
$paths was never initialized. Although not strictly required by PHP, it is generally a good practice to add $paths = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
197
        $fileName = pathinfo($file->path, PATHINFO_FILENAME);
198
        $extension = pathinfo($file->path, PATHINFO_EXTENSION);
199
        foreach ($this->manager->all() as $thumbnail) {
200
            $path = config('asgard.media.config.files-path') . "{$fileName}_{$thumbnail->name()}.{$extension}";
201
            if ($this->fileExists($this->getDestinationPath($path))) {
202
                $paths[] = (new MediaPath($this->getDestinationPath($path)))->getRelativeUrl();
203
            }
204
        }
205
206
        return $this->filesystem->disk($this->getConfiguredFilesystem())->delete($paths);
207
    }
208
209
    private function getConfiguredFilesystem()
210
    {
211
        return config('asgard.media.config.filesystem');
212
    }
213
214
    /**
215
     * @param $filename
216
     * @return bool
217
     */
218
    private function fileExists($filename)
219
    {
220
        return $this->filesystem->disk($this->getConfiguredFilesystem())->exists($filename);
221
    }
222
223
    /**
224
     * @param string $path
225
     * @return string
226
     */
227
    private function getDestinationPath($path)
228
    {
229
        if ($this->getConfiguredFilesystem() === 'local') {
230
            return basename(public_path()) . $path;
231
        }
232
233
        return $path;
234
    }
235
}
236