Passed
Push — master ( 8604b2...06d4b0 )
by Nicolaas
23:02 queued 15:34
created

ImageManipulations::web_p_link()   B

Complexity

Conditions 11
Paths 18

Size

Total Lines 37
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 11
eloc 25
c 2
b 0
f 0
nc 18
nop 1
dl 0
loc 37
rs 7.3166

How to fix   Complexity   

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 Sunnysideup\PerfectCmsImages\Api;
4
5
use SilverStripe\Assets\Image;
6
use SilverStripe\Control\Controller;
7
use SilverStripe\Control\Director;
8
use SilverStripe\Core\Config\Config;
9
use SilverStripe\Core\Convert;
10
use SilverStripe\SiteConfig\SiteConfig;
11
12
class ImageManipulations
13
{
14
    private static $webp_enabled = true;
15
16
    private static $webp_quality = 77;
17
18
    private static $imageLinkCache = [];
19
20
    /**
21
     * work out the best image link.
22
     *
23
     * There are basically three options:
24
     * a. if the height and/or width matches or is smaller than it should be
25
     *    then just return natural image
26
     * b. if crop is set to true then Fill
27
     * c. otherwise resize Height/Width/Both
28
     *
29
     * @param Image     $image
30
     * @param null|bool $useRetina     optional
31
     * @param null|bool $forMobile     optional
32
     * @param null|int  $resizeToWidth optional
33
     */
34
    public static function get_image_link($image, string $name, ?bool $useRetina = null, ?bool $forMobile = null, ?int $resizeToWidth = 0): string
35
    {
36
        $cacheKey = $image->ClassName . '_' . $image->ID . '_' . $name . '_' . ($useRetina ? 'Y' : 'N') . '_' . ($forMobile ? 'MY' : 'MN');
37
        if (empty(self::$imageLinkCache[$cacheKey])) {
38
            //work out perfect width and height
39
            if (null === $useRetina) {
40
                $useRetina = PerfectCMSImages::use_retina($name);
41
            }
42
            $crop = PerfectCMSImages::is_crop($name);
43
44
            $multiplier = PerfectCMSImages::get_multiplier($useRetina);
45
            $perfectWidth = PerfectCMSImages::get_width($name, true);
46
            $perfectHeight = PerfectCMSImages::get_height($name, true);
47
48
            if ($forMobile) {
49
                $perfectWidth = PerfectCMSImages::get_mobile_width($name, true);
50
                $perfectHeight = PerfectCMSImages::get_mobile_height($name, true);
51
            }
52
53
            $perfectWidth *= $multiplier;
54
            $perfectHeight *= $multiplier;
55
56
            //get current width and height
57
            $myWidth = $image->getWidth();
58
            $myHeight = $image->getHeight();
59
60
            //if we are trying to resize to a width that is small than the perfect width
61
            //and the resize width is small than the current width, then lets resize...
62
            if (0 !== (int) $resizeToWidth) {
63
                if ($resizeToWidth < $perfectWidth && $resizeToWidth < $myWidth) {
64
                    $perfectWidth = $resizeToWidth;
65
                }
66
            }
67
            if ($perfectWidth && $perfectHeight) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $perfectWidth of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
68
                //if the height or the width are already perfect then we can not do anything about it.
69
                if ($myWidth === $perfectWidth && $myHeight === $perfectHeight) {
70
                    $link = $image->Link();
71
                } elseif ($myWidth < $perfectWidth || $myHeight < $perfectHeight) {
72
                    $link = $image->Pad(
73
                        $perfectWidth,
74
                        $perfectHeight,
75
                        PerfectCMSImages::get_padding_bg_colour($name)
76
                    )->Link();
77
                } elseif ($crop) {
78
                    $link = $image->Fill($perfectWidth, $perfectHeight)->Link();
79
                } else {
80
                    $link = $image->FitMax($perfectWidth, $perfectHeight)->Link();
81
                }
82
            } elseif ($perfectWidth) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $perfectWidth of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
83
                if ($myWidth === $perfectWidth) {
84
                    $link = $image->Link();
85
                } elseif ($crop) {
86
                    $link = $image->Fill($perfectWidth, $myHeight)->Link();
87
                } else {
88
                    $link = $image->ScaleWidth($perfectWidth)->Link();
89
                }
90
            } elseif ($perfectHeight) {
91
                if ($myHeight === $perfectHeight) {
92
                    $link = $image->Link();
93
                } elseif ($crop) {
94
                    $link = $image->Fill($myWidth, $perfectHeight)->Link();
95
                } else {
96
                    $link = $image->ScaleHeight($perfectHeight)->Link();
97
                }
98
            } elseif ($forMobile) {
99
                $link = '';
100
            } else {
101
                $link = $image->Link();
102
            }
103
            self::$imageLinkCache[$cacheKey] = $link;
104
        }
105
106
        return self::$imageLinkCache[$cacheKey];
107
    }
108
109
    /**
110
     * back-up image.
111
     *
112
     * @return null|Image
113
     */
114
    public static function get_backup_image(string $name)
115
    {
116
        $image = null;
117
        $backupObject = SiteConfig::current_site_config();
118
        if ($backupObject->hasMethod($name)) {
119
            $image = $backupObject->{$name}();
120
        }
121
122
        return $image;
123
    }
124
125
    /**
126
     * placeholder image.
127
     */
128
    public static function get_placeholder_image_tag(string $name): string
129
    {
130
        $multiplier = PerfectCMSImages::get_multiplier(true);
131
        $perfectWidth = PerfectCMSImages::get_width($name, true);
132
        $perfectHeight = PerfectCMSImages::get_height($name, true);
133
        $perfectWidth *= $multiplier;
134
        $perfectHeight *= $multiplier;
135
        if ($perfectWidth || $perfectHeight) {
136
            if (0 === $perfectWidth) {
137
                $perfectWidth = $perfectHeight;
138
            }
139
            if (! $perfectHeight) {
140
                $perfectHeight = $perfectWidth;
141
            }
142
            $text = "{$perfectWidth} x {$perfectHeight} /2 = " . round($perfectWidth / 2) . ' x ' . round($perfectHeight / 2) . '';
143
144
            return 'https://placehold.it/' . $perfectWidth . 'x' . $perfectHeight . '?text=' . urlencode($text);
145
        }
146
147
        return 'https://placehold.it/1500x1500?text=' . urlencode('no size set');
148
    }
149
150
    public static function web_p_link(string $link): string
151
    {
152
        if (self::web_p_enabled() && $link) {
153
            $fileNameWithBaseFolder = Director::baseFolder() . $link;
154
            $arrayOfLink = explode('.', $link);
155
            $extension = array_pop($arrayOfLink);
156
            $pathWithoutExtension = rtrim($link, '.' . $extension);
157
            $webPFileName = $pathWithoutExtension . '_' . $extension . '.webp';
158
            $webPFileNameWithBaseFolder = Director::baseFolder() . $webPFileName;
159
            if (file_exists($fileNameWithBaseFolder)) {
160
                if (isset($_GET['flush'])) {
161
                    unlink($webPFileNameWithBaseFolder);
162
                }
163
                if (file_exists($webPFileNameWithBaseFolder)) {
164
                    //todo: check that image is the same ...
165
                } else {
166
                    list($width, $height, $type) = getimagesize($fileNameWithBaseFolder);
167
                    $img = null;
168
                    if ($width && $height) {
169
                        if (2 === $type) {
170
                            $img = imagecreatefromjpeg($fileNameWithBaseFolder);
171
                        } elseif (3 === $type) {
172
                            $img = imagecreatefrompng($fileNameWithBaseFolder);
173
                            imagesavealpha($img, true);
174
                        }
175
                        if (null !== $img) {
176
                            $quality = Config::inst()->get(ImageManipulations::class, 'webp_quality');
177
                            imagewebp($img, $webPFileNameWithBaseFolder, $quality);
178
                        }
179
                    }
180
                }
181
182
                return $webPFileName;
183
            }
184
        }
185
186
        return $link;
187
    }
188
189
    public static function add_fake_parts($image, string $link): string
190
    {
191
        if (class_exists('HashPathExtension')) {
192
            if ($curr = Controller::curr()) {
193
                if ($curr->hasMethod('HashPath')) {
194
                    $link = $curr->HashPath($link, false);
195
                }
196
            }
197
        }
198
        if ($image->Title) {
199
            $imageClasses = Config::inst()->get(PerfectCMSImages::class, 'perfect_cms_images_append_title_to_image_links_classes');
200
            if (in_array($image->ClassName, $imageClasses, true)) {
201
                $link .= '?title=' . urlencode(Convert::raw2att($image->Title));
0 ignored issues
show
Bug introduced by
It seems like SilverStripe\Core\Convert::raw2att($image->Title) can also be of type array and array; however, parameter $string of urlencode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

201
                $link .= '?title=' . urlencode(/** @scrutinizer ignore-type */ Convert::raw2att($image->Title));
Loading history...
202
            }
203
        }
204
205
        return $link;
206
    }
207
208
    public static function web_p_enabled(): bool
209
    {
210
        if (Config::inst()->get(ImageManipulations::class, 'webp_enabled')) {
211
            if (function_exists('imagewebp')) {
212
                if (function_exists('imagecreatefromjpeg')) {
213
                    if (function_exists('imagecreatefrompng')) {
214
                        return true;
215
                    }
216
                }
217
            }
218
        }
219
220
        return false;
221
    }
222
}
223