Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
31.58% covered (danger)
31.58%
30 / 95
30.00% covered (danger)
30.00%
6 / 20
CRAP
0.00% covered (danger)
0.00%
0 / 1
Image
31.58% covered (danger)
31.58%
30 / 95
30.00% covered (danger)
30.00%
6 / 20
607.03
0.00% covered (danger)
0.00%
0 / 1
 __toString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 tag
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 url
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 publicPath
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 lazy
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 nonlazy
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 width
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 height
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 longSide
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 shortSide
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 fit
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 resize
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 crop
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
90
 freecrop
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 quality
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 link
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 alt
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMediaPath
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 getMediaUrl
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getImage
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Value;
6
7use Cosray\Assets;
8use Cosray\Exception\RuntimeException;
9use Gumlet\ImageResize;
10
11use function Cosray\escape;
12
13class Image extends File
14{
15    protected ?Assets\Size $size = null;
16    protected ?Assets\ResizeMode $resizeMode = null;
17    protected bool $enlarge = false;
18    protected bool $lazy = true;
19    protected ?int $quality = null;
20    protected string $queryString = '';
21
22    public function __toString(): string
23    {
24        return $this->tag(true);
25    }
26
27    public function tag(bool $bust = true, ?string $class = null): string
28    {
29        return sprintf(
30            '<img %ssrc="%s" alt="%s" data-path-original="%s">',
31            $class ? sprintf('class="%s" ', escape($class)) : '',
32            $this->url($bust),
33            escape($this->alt() ?: strip_tags($this->title())),
34            $this->publicPath(),
35        );
36    }
37
38    public function url(bool $bust = false): string
39    {
40        if ($this->lazy) {
41            return $this->getMediaUrl($this->index);
42        }
43
44        return $this->getImage($this->index)->url($bust);
45    }
46
47    public function publicPath(bool $bust = false): string
48    {
49        if ($this->lazy) {
50            return $this->getMediaPath($this->index);
51        }
52
53        return $this->getImage($this->index)->publicPath($bust);
54    }
55
56    public function lazy(): static
57    {
58        $new = clone $this;
59        $new->lazy = true;
60
61        return $new;
62    }
63
64    public function nonlazy(): static
65    {
66        $new = clone $this;
67        $new->lazy = false;
68
69        return $new;
70    }
71
72    public function width(int $width, bool $enlarge = false): static
73    {
74        $new = clone $this;
75        $new->size = new Assets\Size($width);
76        $new->resizeMode = Assets\ResizeMode::Width;
77        $new->enlarge = $enlarge;
78        $new->queryString = "?resize=width&w={$width}" . ($enlarge ? '&enlarge=true' : '');
79
80        return $new;
81    }
82
83    public function height(int $height, bool $enlarge = false): static
84    {
85        $new = clone $this;
86        $new->size = new Assets\Size($height);
87        $new->resizeMode = Assets\ResizeMode::Height;
88        $new->enlarge = $enlarge;
89        $new->queryString = "?resize=height&h={$height}" . ($enlarge ? '&enlarge=true' : '');
90
91        return $new;
92    }
93
94    public function longSide(int $size, bool $enlarge = false): static
95    {
96        $new = clone $this;
97        $new->size = new Assets\Size($size);
98        $new->resizeMode = Assets\ResizeMode::LongSide;
99        $new->enlarge = $enlarge;
100        $new->queryString = "?resize=longside&size={$size}" . ($enlarge ? '&enlarge=true' : '');
101
102        return $new;
103    }
104
105    public function shortSide(int $size, bool $enlarge = false): static
106    {
107        $new = clone $this;
108        $new->size = new Assets\Size($size);
109        $new->resizeMode = Assets\ResizeMode::ShortSide;
110        $new->enlarge = $enlarge;
111        $new->queryString = "?resize=shortside&size={$size}" . ($enlarge ? '&enlarge=true' : '');
112
113        return $new;
114    }
115
116    public function fit(int $width, int $height, bool $enlarge = false): static
117    {
118        $new = clone $this;
119        $new->size = new Assets\Size($width, $height);
120        $new->resizeMode = Assets\ResizeMode::Fit;
121        $new->enlarge = $enlarge;
122        $new->queryString = "?resize=fit&w={$width}&h={$height}" . ($enlarge ? '&enlarge=true' : '');
123
124        return $new;
125    }
126
127    public function resize(int $width, int $height, bool $enlarge = false): static
128    {
129        $new = clone $this;
130        $new->size = new Assets\Size($width, $height);
131        $new->resizeMode = Assets\ResizeMode::Resize;
132        $new->enlarge = $enlarge;
133        $new->queryString = "?resize=resize&w={$width}&h={$height}" . ($enlarge ? '&enlarge=true' : '');
134
135        return $new;
136    }
137
138    public function crop(int $width, int $height, string $position = 'center'): static
139    {
140        $pos = match ($position) {
141            'top' => ImageResize::CROPTOP,
142            'centre' => ImageResize::CROPCENTRE,
143            'center' => ImageResize::CROPCENTER,
144            'bottom' => ImageResize::CROPBOTTOM,
145            'left' => ImageResize::CROPLEFT,
146            'right' => ImageResize::CROPRIGHT,
147            'topcenter' => ImageResize::CROPTOPCENTER,
148            default => throw new RuntimeException('Crop position not supported: ' . $position),
149        };
150
151        $new = clone $this;
152        $new->size = new Assets\Size($width, $height, $pos);
153        $new->resizeMode = Assets\ResizeMode::Crop;
154        $new->queryString = "?resize=crop&w={$width}&h={$height}&pos={$position}";
155
156        return $new;
157    }
158
159    public function freecrop(
160        int $width,
161        int $height,
162        int|false $x = false,
163        int|false $y = false,
164    ): static {
165        $new = clone $this;
166        $new->size = new Assets\Size($width, $height, ['x' => $x, 'y' => $y]);
167        $new->resizeMode = Assets\ResizeMode::FreeCrop;
168        $new->queryString =
169            "?resize=freecrop&w={$width}&h={$height}" . ($x ? "&x={$x}" : '') . ($y ? "&y={$y}" : '');
170
171        return $new;
172    }
173
174    public function quality(int $quality): static
175    {
176        $new = clone $this;
177        $new->quality = $quality;
178
179        return $new;
180    }
181
182    public function link(): string
183    {
184        return $this->textValue('link', $this->index);
185    }
186
187    public function alt(): string
188    {
189        return $this->textValue('alt', $this->index);
190    }
191
192    protected function getMediaPath(int $index): string
193    {
194        return (
195            $this->owner->config()->path->prefix
196            . '/media/image/'
197            . $this->assetsPath()
198            . $this->getFileName($index)
199            . $this->queryString
200            . ($this->quality ? "&quality={$this->quality}" : '')
201        );
202    }
203
204    protected function getMediaUrl(int $index): string
205    {
206        return $this->owner->request()->origin() . $this->getMediaPath($index);
207    }
208
209    protected function getImage(int $index): Assets\Image
210    {
211        $image = $this->getAssets()->image($this->assetsPath() . $this->getFileName($index));
212
213        if ($this->size) {
214            $image = $image->resize($this->size, $this->resizeMode, $this->enlarge, $this->quality);
215        }
216
217        return $image;
218    }
219}