Completed
Push — feature-images ( a3efc8...e32785 )
by Arnaud
25:02 queued 05:38
created

Image::prepare()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 12
c 1
b 0
f 0
nc 6
nop 0
dl 0
loc 24
rs 9.8666
1
<?php
2
/*
3
 * This file is part of the Cecil/Cecil package.
4
 *
5
 * Copyright (c) Arnaud Ligny <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Cecil\Assets;
12
13
use Cecil\Builder;
14
use Cecil\Config;
15
use Cecil\Exception\Exception;
16
use Cecil\Util;
17
use Intervention\Image\Exception\NotReadableException;
18
use Intervention\Image\ImageManagerStatic as ImageManager;
19
20
class Image
21
{
22
    /** @var Config */
23
    private $config;
24
    /** @var string */
25
    private $path;
26
    /** @var int */
27
    private $size;
28
    /** @var bool */
29
    private $local = true;
30
    /** @var string */
31
    private $source;
32
    /** @var string */
33
    private $destination = null;
34
    /** @var string */
35
    private $imageRelPath = null;
36
    /** @var string */
37
    private $thumbsDir = null;
38
    /** @var string */
39
    private $cacheDir;
40
41
    const CACHE_IMAGES_DIR = 'images';
42
43
    public function __construct(Builder $builder)
44
    {
45
        $this->config = $builder->getConfig();
46
    }
47
48
    private function prepare(): void
49
    {
50
        // is not a local image?
51
        if (Util::isExternalUrl($this->path)) {
52
            $this->local = false;
53
        }
54
55
        // source file
56
        if (!$this->local) {
57
            $this->source = $this->path;
58
59
            return;
60
        }
61
        $this->source = $this->config->getStaticPath().'/'.ltrim($this->path, '/');
62
        if (!Util::getFS()->exists($this->source)) {
63
            throw new Exception(sprintf('Can\'t process "%s": file doesn\'t exists.', $this->path));
64
        }
65
66
        // ie: .cache/images
67
        $this->cacheDir = (string) $this->config->get('cache.dir')
68
            .'/'.(string) $this->config->get('cache.images.dir');
69
        // ie: /www/website/.cache/images
70
        $this->cachePath = $this->config->getCachePath()
0 ignored issues
show
Bug Best Practice introduced by
The property cachePath does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
71
            .'/'.(string) $this->config->get('cache.images.dir');
72
    }
73
74
    /**
75
     * Resize an image.
76
     *
77
     * @param string $path       Image path (relative from static/ dir or external)
78
     * @param int    $this->size Image new size (width)
79
     *
80
     * @return string Path to image thumbnail
81
     */
82
    public function resize(string $path, int $size): string
83
    {
84
        $this->path = $path;
85
        $this->size = $size;
86
        $this->source = $path;
87
88
        $this->prepare();
89
90
        // is size is already OK?
91
        list($width, $height) = getimagesize($this->source);
92
        if ($width <= $this->size && $height <= $this->size) {
93
            return $this->path;
94
        }
95
96
        // if GD extension is not installed: can't process
97
        if (!extension_loaded('gd')) {
98
            return $this->path;
99
        }
100
101
        // ie: .cache/images/thumbs/300
102
        $this->thumbsDir = $this->cacheDir
103
            .'/'.(string) $this->config->get('cache.images.thumbs.dir').'/'.$this->size;
104
        // ie: .cache/images/thumbs/300/img/logo.png
105
        $this->imageRelPath = $this->thumbsDir.'/'.ltrim($this->path, '/');
106
        // where to write the file
107
        $this->destination = $this->config->getDestinationDir().'/'.$this->imageRelPath;
108
        if ($this->config->isCacheDirIsAbsolute()) {
109
            $this->destination = $this->imageRelPath;
110
        }
111
112
        if (Util::getFS()->exists($this->destination)) {
113
            return $this->path;
114
        }
115
116
        // Image object
117
        try {
118
            $img = ImageManager::make($this->source);
119
120
            // DEBUG
121
            var_dump($img->width());
0 ignored issues
show
Security Debugging Code introduced by
var_dump($img->width()) looks like debug code. Are you sure you do not want to remove it?
Loading history...
122
            var_dump($img->height());
123
124
            $img->resize($this->size, null, function (\Intervention\Image\Constraint $constraint) {
125
                $constraint->aspectRatio();
126
                $constraint->upsize();
127
            });
128
129
            // DEBUG
130
            var_dump($img->width());
131
            var_dump($img->height());
132
            die();
1 ignored issue
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
133
        } catch (NotReadableException $e) {
134
            throw new Exception(sprintf('Cannot get image "%s"', $this->path));
135
        }
136
137
        // return data:image
138
        if (!$this->local) {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
139
            return (string) $img->encode('data-url');
140
        }
141
142
        // save/write file
143
        // is a sub dir is necessary?
144
        $imageSubDir = Util::getFS()->makePathRelative(
145
            '/'.dirname($this->imageRelPath),
146
            '/'.$this->thumbsDir.'/'
147
        );
148
        if (!empty($imageSubDir)) {
149
            $destDir = $this->config->getCacheImagesThumbsPath().'/'.$this->size.'/'.$imageSubDir;
150
            Util::getFS()->mkdir($destDir);
151
        }
152
        $img->save($this->destination);
153
154
        // return relative path
155
        return '/'.$this->config->get('cache.images.dir')
156
            .'/'.(string) $this->config->get('cache.images.thumbs.dir')
157
            .'/'.$this->size
158
            .'/'.ltrim($this->path, '/');
159
    }
160
161
    /**
162
     * Resize with Intervention ImageManager.
163
     *
164
     * @return string
165
     */
166
    private function doResize(): string
0 ignored issues
show
Unused Code introduced by
The method doResize() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
167
    {
168
        try {
169
            //
170
        } catch (\Exception $e) {
0 ignored issues
show
Unused Code introduced by
catch (\Exception $e) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
171
            throw new \Exception(sprintf("Error during \"%s\" process.\n%s", get_class($this), $e->getMessage()));
172
        }
173
    }
174
}
175