Completed
Push — master ( ccf5b6...b858da )
by Mike
13s
created

Image::getUrlAttribute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php namespace GeneaLabs\LaravelImagery;
2
3
use GeneaLabs\LaravelImagery\Jobs\RenderDerivativeImages;
4
use Intervention\Image\ImageManager;
5
use Jenssegers\Model\Model;
6
use Illuminate\Support\Collection;
7
8
class Image extends Model
9
{
10
    protected $originalHeight;
11
    protected $originalWidth;
12
    // protected $htmlAttributes;
13
    protected $heightIsPercentage;
14
    protected $widthIsPercentage;
15
    // protected $source;
16
    // protected $height;
17
    // protected $width;
18
    // protected $originalPath;
19
    protected $alwaysPreserveAspectRatio;
20
    protected $doNotCreateDerivativeImages;
21
    protected $overrideScreenConstraint;
22
    protected $screenConstraintMethod;
23
24
    //TODO: this class needs serious refactoring!!!
25
    public function __construct(
26
        string $source,
27
        string $width = null,
28
        string $height = null,
29
        Collection $htmlAttributes = null,
30
        Collection $options = null
31
    ) {
32
        parent::__construct();
33
34
        $this->createCacheFolderIfMissing();
35
36
        $this->originalHeight = $height;
37
        $this->originalWidth = $width;
38
        $this->htmlAttributes = $htmlAttributes;
0 ignored issues
show
Bug Best Practice introduced by
The property htmlAttributes does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
39
        $this->heightIsPercentage = str_contains($height, '%');
40
        $this->widthIsPercentage = str_contains($width, '%');
41
        $this->source = $source;
0 ignored issues
show
Bug Best Practice introduced by
The property source does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
42
        $this->image = (new ImageManager)->make($source);
0 ignored issues
show
Bug Best Practice introduced by
The property image does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
43
        $this->height = intval($height);
0 ignored issues
show
Bug Best Practice introduced by
The property height does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
44
        $this->width = intval($width);
0 ignored issues
show
Bug Best Practice introduced by
The property width does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
45
        $this->originalPath = public_path(config('genealabs-laravel-imagery.storage-folder') . basename($source));
0 ignored issues
show
Bug Best Practice introduced by
The property originalPath does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
46
        $this->alwaysPreserveAspectRatio = $options->get('alwaysPreserveAspectRatio', true);
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

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

46
        /** @scrutinizer ignore-call */ 
47
        $this->alwaysPreserveAspectRatio = $options->get('alwaysPreserveAspectRatio', true);

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...
47
        $this->doNotCreateDerivativeImages = $options->get('doNotCreateDerivativeImages', false);
48
        $this->overrideScreenConstraint = $options->get('overrideScreenConstraint', false);
49
        $this->screenConstraintMethod = $options->get('screenConstraintMethod', 'contain');
50
51
        if ($this->sourceIsUrl($source)) {
0 ignored issues
show
Unused Code introduced by
The call to GeneaLabs\LaravelImagery\Image::sourceIsUrl() has too many arguments starting with $source. ( Ignorable by Annotation )

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

51
        if ($this->/** @scrutinizer ignore-call */ sourceIsUrl($source)) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
52
            $this->image->save($this->originalPath);
53
        }
54
55
        $this->resizeImage($this->width, $this->height, $this->alwaysPreserveAspectRatio);
56
57
        if (! $this->doNotCreateDerivativeImages) {
58
            $job = (new RenderDerivativeImages($this->source))->onQueue('imagery');
59
            dispatch($job);
60
        }
61
    }
62
63
    protected function resizeImage(int $width, int $height, bool $alwaysPreserveAspect = false)
64
    {
65
        if (! $height || ! $width) {
66
            $height = $height ?: $this->image->getHeight();
67
            $width = $width ?: $this->image->getWidth();
68
        }
69
70
        $screenHeight = $_COOKIE['screenWidth'] ?? null;
0 ignored issues
show
Unused Code introduced by
The assignment to $screenHeight is dead and can be removed.
Loading history...
71
        $screenWidth = $_COOKIE['screenHeight'] ?? null;
72
        $screenHeight = $screenWidth ? intval($screenWidth) : null;
73
        $screenWidth = $screenWidth ? intval($screenWidth) : null;
74
        $height = $this->determineHeight($height, $screenHeight);
75
        $width = $this->determineWidth($width, $screenWidth);
76
77
        if (! $height && ! $width) {
78
            $height = $this->image->height();
79
            $width = $this->image->width();
80
        }
81
82
        $maxHeight = $this->determineMaxHeight($height, $screenHeight, $screenWidth);
83
        $maxWidth = $this->determineMaxWidth($width, $screenHeight, $screenWidth);
84
85
        $this->image->resize($maxWidth, $maxHeight, function ($constraint) use ($alwaysPreserveAspect) {
86
            if ($alwaysPreserveAspect || ! $width || ! $height) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $width seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $height seems to be never defined.
Loading history...
87
                $constraint->aspectRatio();
88
            }
89
90
            $constraint->upsize();
91
        });
92
93
        $this->height = $this->image->height();
0 ignored issues
show
Bug Best Practice introduced by
The property height does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
94
        $this->width = $this->image->width();
0 ignored issues
show
Bug Best Practice introduced by
The property width does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
95
        $this->storeImage();
96
    }
97
98
    //TODO: refactor to have a single return type, instead of null or int
99 View Code Duplication
    protected function determineMaxHeight($height, $screenHeight, $screenWidth)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
100
    {
101
        if (! $screenHeight || ! $screenWidth) {
102
            return $height;
103
        }
104
105
        $maxHeight = $height ?: $this->image->height();
106
107
        if (! $this->overrideScreenConstraint) {
108
            $maxHeight = $screenHeight < $maxHeight ? $screenHeight : $maxHeight;
109
110
            if ($this->screenConstraintMethod === 'cover') {
111
                $imageToScreenHeight = $screenHeight / $this->image->height();
112
                $imageToScreenWidth = $screenWidth / $this->image->width();
113
114
                if ($imageToScreenHeight < $imageToScreenWidth) {
115
                    $maxHeight = null;
116
                }
117
            }
118
        }
119
120
        return $maxHeight;
121
    }
122
123
    //TODO: refactor to have a single return type, instead of null or int
124 View Code Duplication
    protected function determineMaxWidth($width, $screenHeight, $screenWidth)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
125
    {
126
        if (! $screenHeight || ! $screenWidth) {
127
            return $width;
128
        }
129
130
        $maxWidth = $width ?: $this->image->width();
131
132
        if (! $this->overrideScreenConstraint) {
133
            $maxWidth = $screenWidth < $maxWidth ? $screenWidth : $maxWidth;
134
135
            if ($this->screenConstraintMethod === 'cover') {
136
                $imageToScreenHeight = $screenHeight / $this->image->height();
137
                $imageToScreenWidth = $screenWidth / $this->image->width();
138
                if ($imageToScreenHeight > $imageToScreenWidth) {
139
                    $maxWidth = null;
140
                }
141
            }
142
        }
143
144
        return $maxWidth;
145
    }
146
147
    protected function determineHeight($height, $screenHeight) : int
148
    {
149
        if ($screenHeight && $height && $this->heightIsPercentage) {
150
            return $screenHeight * ($height / 100);
151
        }
152
153
        return $height;
154
    }
155
156
    protected function determineWidth($width, $screenWidth) : int
157
    {
158
        if ($screenWidth && $width && $this->widthIsPercentage) {
159
            return $screenWidth * ($width / 100);
160
        }
161
162
        return $width;
163
    }
164
165
    protected function sourceIsUrl() : bool
166
    {
167
        return collect(parse_url($this->source))->has('scheme');
168
    }
169
170
    protected function storeImage()
171
    {
172
        $this->image
173
            ->save(public_path(config('genealabs-laravel-imagery.storage-folder') . $this->fileName));
0 ignored issues
show
Bug Best Practice introduced by
The property fileName does not exist on GeneaLabs\LaravelImagery\Image. Since you implemented __get, consider adding a @property annotation.
Loading history...
174
    }
175
176
    public function getFileNameAttribute() : string
177
    {
178
        $pathParts = pathinfo($this->source);
179
        $fileName = $pathParts['filename'];
180
        $extension = $pathParts['extension'] ?? '';
181
        $extension = $extension ? ".{$extension}" : '';
182
183
        if ($this->width || $this->height) {
184
            $fileName .= "_{$this->width}x{$this->height}";
185
        }
186
187
        return "{$fileName}{$extension}";
188
    }
189
190
    public function getImgAttribute() : string
191
    {
192
        $scriptUrl = mix('js/cookie.js', 'genealabs-laravel-imagery');
193
        $attributes = '';
194
195
        $attributes = $this->htmlAttributes->map(function ($value, $attribute) use (&$attributes) {
0 ignored issues
show
Unused Code introduced by
The import $attributes is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
Bug introduced by
The method map() does not exist on null. ( Ignorable by Annotation )

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

195
        $attributes = $this->htmlAttributes->/** @scrutinizer ignore-call */ map(function ($value, $attribute) use (&$attributes) {

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...
196
            return " {$attribute}=\"{$value}\"";
197
        })->implode('');
198
199
        return "<img src=\"{$this->url}\"
0 ignored issues
show
Bug Best Practice introduced by
The property url does not exist on GeneaLabs\LaravelImagery\Image. Since you implemented __get, consider adding a @property annotation.
Loading history...
200
            width=\"{$this->originalWidth}\"
201
            height=\"{$this->originalHeight}\"{{ $attributes }}
202
        ><script src=\"{$scriptUrl}\"></script>";
203
    }
204
205
    public function getOriginalUrlAttribute() : string
206
    {
207
        return asset(config('genealabs-laravel-imagery.storage-folder') . $this->fileName);
0 ignored issues
show
Bug Best Practice introduced by
The property fileName does not exist on GeneaLabs\LaravelImagery\Image. Since you implemented __get, consider adding a @property annotation.
Loading history...
208
    }
209
210
    public function getPathAttribute() : string
211
    {
212
        return public_path(config('genealabs-laravel-imagery.storage-folder') . $this->fileName);
0 ignored issues
show
Bug Best Practice introduced by
The property fileName does not exist on GeneaLabs\LaravelImagery\Image. Since you implemented __get, consider adding a @property annotation.
Loading history...
213
    }
214
215
    public function getPictureAttribute() : string
216
    {
217
        //TODO: implement img tag attributes, move script to middleware injector
218
        $scriptUrl = mix('js/cookie.js', 'genealabs-laravel-imagery');
219
        $sources = '';
220
221
        foreach (array_reverse(config('genealabs-laravel-imagery.size-presets')) as $sizePreset) {
222
            $image = (new Imagery)->conjure(
223
                $this->source,
224
                $sizePreset,
225
                $sizePreset,
226
                [],
227
                ['doNotCreateDerivativeImages' => true]
228
            );
229
230
            if ($sizePreset < $this->width || $sizePreset < $this->height) {
231
                $sources .= "<source srcset=\"{$image->url}\" media=\"(min-width: {$sizePreset}px)\">";
0 ignored issues
show
Bug Best Practice introduced by
The property url does not exist on GeneaLabs\LaravelImagery\Image. Since you implemented __get, consider adding a @property annotation.
Loading history...
232
            }
233
        }
234
235
        return "
236
            <picture>
237
                {$sources}
238
                <img src=\"{$this->url}\">
239
            </picture>
240
            <script src=\"{$scriptUrl}\"></script>
241
        ";
242
    }
243
244
    public function getUrlAttribute() : string
245
    {
246
        return asset(config('genealabs-laravel-imagery.storage-folder') . $this->fileName);
0 ignored issues
show
Bug Best Practice introduced by
The property fileName does not exist on GeneaLabs\LaravelImagery\Image. Since you implemented __get, consider adding a @property annotation.
Loading history...
247
    }
248
249
    protected function createCacheFolderIfMissing()
250
    {
251
        app('filesystem')->disk('public')->makeDirectory(config('genealabs-laravel-imagery.storage-folder'));
252
253
        if (! file_exists(public_path(config('genealabs-laravel-imagery.storage-folder')))) {
254
            symlink(
255
                rtrim(storage_path('app/public/' . config('genealabs-laravel-imagery.storage-folder')), '/'),
256
                rtrim(public_path(config('genealabs-laravel-imagery.storage-folder')), '/')
257
            );
258
        }
259
    }
260
}
261