Issues (24)

src/Image.php (16 issues)

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
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)) {
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;
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) {
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
    protected function determineMaxHeight($height, $screenHeight, $screenWidth)
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
    protected function determineMaxWidth($width, $screenHeight, $screenWidth)
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
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