Passed
Push — master ( 5e67b7...45b155 )
by Brent
04:41 queued 02:26
created

ResponsiveFactory::create()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 53
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 53
rs 7.1199
c 0
b 0
f 0
cc 8
eloc 31
nc 10
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Brendt\Image;
4
5
use Brendt\Image\Config\DefaultConfigurator;
6
use Brendt\Image\Config\ResponsiveFactoryConfigurator;
7
use Brendt\Image\Exception\FileNotFoundException;
8
use Brendt\Image\Scaler\Scaler;
9
use ImageOptimizer\Optimizer;
10
use ImageOptimizer\OptimizerFactory;
11
use Intervention\Image\ImageManager;
12
use Symfony\Component\Filesystem\Filesystem;
13
use Symfony\Component\Finder\Finder;
14
use Symfony\Component\Finder\SplFileInfo;
15
16
class ResponsiveFactory
17
{
18
19
    /**
20
     * The image driver to use.
21
     * Available drivers: 'gd' and 'imagick'.
22
     *
23
     * @var string
24
     */
25
    protected $driver;
26
27
    /**
28
     * The source path to load images from.
29
     *
30
     * @var string
31
     */
32
    protected $sourcePath;
33
34
    /**
35
     * The public path to save rendered images.
36
     *
37
     * @var string
38
     */
39
    protected $publicPath;
40
41
    /**
42
     * Enabled cache will stop generated images from being overwritten.
43
     *
44
     * @var bool
45
     */
46
    private $enableCache;
47
48
    /**
49
     * Enable optimizers will run several image optimizers on the saved files.
50
     *
51
     * @var bool
52
     */
53
    private $optimize;
54
55
    /**
56
     * @var bool
57
     */
58
    private $rebase;
59
60
    /**
61
     * @var array
62
     */
63
    private $optimizerOptions = [];
64
65
    /**
66
     * The Intervention image engine.
67
     *
68
     * @var ImageManager
69
     */
70
    protected $engine;
71
72
    /**
73
     * @var Filesystem
74
     */
75
    protected $fs;
76
77
    /**
78
     * @var Scaler
79
     */
80
    protected $scaler;
81
82
    /**
83
     * @var Optimizer
84
     */
85
    protected $optimizer;
86
87
    /**
88
     * ResponsiveFactory constructor.
89
     *
90
     * @param ResponsiveFactoryConfigurator $configurator
91
     */
92
    public function __construct(ResponsiveFactoryConfigurator $configurator = null) {
93
        $configurator = $configurator ?? new DefaultConfigurator();
94
        $configurator->configure($this);
95
96
        $this->sourcePath = rtrim($this->sourcePath, '/');
97
        $this->publicPath = rtrim($this->publicPath, '/');
98
99
        $this->engine = new ImageManager([
100
            'driver' => $this->driver,
101
        ]);
102
103
        $this->optimizer = (new OptimizerFactory($this->optimizerOptions))->get();
104
        $this->fs = new Filesystem();
105
106
        if (!$this->fs->exists($this->publicPath)) {
107
            $this->fs->mkdir($this->publicPath);
108
        }
109
    }
110
111
    /**
112
     * @param string $src
113
     *
114
     * @return ResponsiveImage
115
     * @throws FileNotFoundException
116
     */
117
    public function create($src) {
118
        $responsiveImage = new ResponsiveImage($src);
119
        $src = $responsiveImage->src();
120
        $sourcePath = $src;
121
        if ($this->rebase) {
122
            $sourcePath = pathinfo($src, PATHINFO_BASENAME);
123
        }
124
        
125
        $sourceImage = $this->getImageFile($this->sourcePath, $sourcePath);
126
127
        if (!$sourceImage) {
128
            throw new FileNotFoundException("{$this->sourcePath}/{$sourcePath}");
129
        }
130
131
        $extension = pathinfo($sourceImage->getExtension(), PATHINFO_EXTENSION);
132
        $fileName = pathinfo($sourceImage->getFilename(), PATHINFO_FILENAME);
133
        $publicImagePath = "{$this->publicPath}/{$src}";
134
        $urlPath = '/' . trim(pathinfo($src, PATHINFO_DIRNAME), '/');
135
136
        $responsiveImage->setExtension($sourceImage->getExtension());
137
        $responsiveImage->setFileName($fileName);
138
        $responsiveImage->setUrlPath($urlPath);
139
140
        if ($this->enableCache && $this->fs->exists($publicImagePath)) {
141
            /** @var SplFileInfo[] $cachedFiles */
142
            $cachedFiles = Finder::create()->files()->in("{$this->publicPath}/{$sourceImage->getRelativePath()}")->name("{$fileName}-*.{$extension}");
143
144
            foreach ($cachedFiles as $cachedFile) {
145
                $cachedFilename = $cachedFile->getFilename();
146
                $size = (int) str_replace(".{$extension}", '', str_replace("{$fileName}-", '', $cachedFilename));
147
148
                $responsiveImage->addSource("{$urlPath}/{$cachedFilename}", $size);
149
            }
150
151
            return $responsiveImage;
152
        }
153
154
        if (!$this->enableCache || !$this->fs->exists($publicImagePath)) {
155
            $this->fs->dumpFile($publicImagePath, $sourceImage->getContents());
156
        }
157
158
        $imageObject = $this->engine->make($sourceImage->getPathname());
159
160
        // TODO: This piece of code should be added as a size and not as a "default".
161
        // It's because the WidthScaler skips the default size.
162
        $width = $imageObject->getWidth();
163
        $responsiveImage->addSource($src, $width);
164
        $imageObject->destroy();
165
166
        $this->createScaledImages($sourceImage, $responsiveImage);
167
168
        return $responsiveImage;
169
    }
170
171
    /**
172
     * Create scaled image files and add them as sources to a Responsive Image, based on an array of file sizes:
173
     * [
174
     *      width => height,
175
     *      ...
176
     * ]
177
     *
178
     * @param SplFileInfo     $sourceImage
179
     * @param ResponsiveImage $responsiveImage
180
     *
181
     * @return ResponsiveImage
182
     */
183
    public function createScaledImages(SplFileInfo $sourceImage, ResponsiveImage $responsiveImage) : ResponsiveImage {
184
        $imageObject = $this->engine->make($sourceImage->getPathname());
185
        $urlPath = $responsiveImage->getUrlPath();
186
        $sizes = $this->scaler->scale($sourceImage, $imageObject);
187
188
        foreach ($sizes as $width => $height) {
189
            $scaledFileSrc = trim("{$urlPath}/{$imageObject->filename}-{$width}.{$imageObject->extension}", '/');
190
            $responsiveImage->addSource($scaledFileSrc, $width);
191
        }
192
193
        $this->scaleProcess($sourceImage, $responsiveImage);
194
195
        return $responsiveImage;
196
    }
197
198
    /**
199
     * @param SplFileInfo     $sourceImage
200
     * @param ResponsiveImage $responsiveImage
201
     */
202
    public function scaleProcess(SplFileInfo $sourceImage, ResponsiveImage $responsiveImage) {
203
        $urlPath = $responsiveImage->getUrlPath();
204
        $imageObject = $this->engine->make($sourceImage->getPathname());
205
        $sizes = $this->scaler->scale($sourceImage, $imageObject);
206
207
        foreach ($sizes as $width => $height) {
208
            $scaledFileSrc = trim("{$urlPath}/{$imageObject->filename}-{$width}.{$imageObject->extension}", '/');
209
            $scaledFilePath = "{$this->getPublicPath()}/{$scaledFileSrc}";
210
211
            $scaledImage = $imageObject->resize((int) $width, (int) $height)->encode($imageObject->extension);
212
213
            if (!$this->enableCache || !$this->fs->exists($scaledFilePath)) {
214
                $this->fs->dumpFile($scaledFilePath, $scaledImage);
215
            }
216
        }
217
218
        $imageObject->destroy();
219
220
        if ($this->optimize) {
221
            $this->optimizeResponsiveImage($responsiveImage);
222
        }
223
    }
224
225
    /**
226
     * Optimize all sources of a Responsive Image
227
     *
228
     * @param ResponsiveImage $responsiveImage
229
     *
230
     * @return ResponsiveImage
231
     */
232
    public function optimizeResponsiveImage(ResponsiveImage $responsiveImage) : ResponsiveImage {
233
        foreach ($responsiveImage->getSrcset() as $imageFile) {
234
            $this->optimizer->optimize("{$this->publicPath}/{$imageFile}");
235
        }
236
237
        return $responsiveImage;
238
    }
239
240
    /**
241
     * @param string $directory
242
     * @param string $path
243
     *
244
     * @return SplFileInfo
245
     */
246
    private function getImageFile(string $directory, string $path) : ?SplFileInfo {
247
        $iterator = Finder::create()->files()->in($directory)->path(ltrim($path, '/'))->getIterator();
248
        $iterator->rewind();
249
250
        return $iterator->current();
251
    }
252
253
    /**
254
     * @param string $driver
255
     *
256
     * @return ResponsiveFactory
257
     */
258
    public function setDriver($driver) : ResponsiveFactory {
259
        $this->driver = $driver;
260
261
        return $this;
262
    }
263
264
    /**
265
     * @param string $publicPath
266
     *
267
     * @return ResponsiveFactory
268
     */
269
    public function setPublicPath($publicPath) : ResponsiveFactory {
270
        $this->publicPath = $publicPath;
271
272
        return $this;
273
    }
274
275
    /**
276
     * @param boolean $enableCache
277
     *
278
     * @return ResponsiveFactory
279
     */
280
    public function setEnableCache($enableCache) : ResponsiveFactory {
281
        $this->enableCache = $enableCache;
282
283
        return $this;
284
    }
285
286
    /**
287
     * @param string $sourcePath
288
     *
289
     * @return ResponsiveFactory
290
     */
291
    public function setSourcePath($sourcePath) : ResponsiveFactory {
292
        $this->sourcePath = $sourcePath;
293
294
        return $this;
295
    }
296
297
    /**
298
     * @param Scaler $scaler
299
     *
300
     * @return ResponsiveFactory
301
     */
302
    public function setScaler($scaler) : ResponsiveFactory {
303
        $this->scaler = $scaler;
304
305
        return $this;
306
    }
307
308
    /**
309
     * @param bool $optimize
310
     *
311
     * @return ResponsiveFactory
312
     */
313
    public function setOptimize(bool $optimize) : ResponsiveFactory {
314
        $this->optimize = $optimize;
315
316
        return $this;
317
    }
318
319
    /**
320
     * @return string
321
     */
322
    public function getPublicPath() : string {
323
        return $this->publicPath;
324
    }
325
326
    /**
327
     * @param mixed $optimizerOptions
328
     *
329
     * @return ResponsiveFactory
330
     */
331
    public function setOptimizerOptions($optimizerOptions) : ResponsiveFactory {
332
        $this->optimizerOptions = $optimizerOptions;
0 ignored issues
show
Documentation Bug introduced by
It seems like $optimizerOptions of type * is incompatible with the declared type array of property $optimizerOptions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
333
334
        return $this;
335
    }
336
337
    /**
338
     * @param bool $rebase
339
     *
340
     * @return ResponsiveFactory
341
     */
342
    public function setRebase(bool $rebase) : ResponsiveFactory {
343
        $this->rebase = $rebase;
344
345
        return $this;
346
    }
347
348
}
349