• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tito10047 / progressive-image-bundle / 20675022582

03 Jan 2026 08:51AM UTC coverage: 86.782%. Remained the same
20675022582

push

github

tito10047
update copyright in LICENSE.md

604 of 696 relevant lines covered (86.78%)

175.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/Twig/Components/Image.php
1
<?php
2

3
/*
4
 * This file is part of the Progressive Image Bundle.
5
 *
6
 * (c) Jozef Môstka <https://github.com/tito10047/progressive-image-bundle>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace Tito10047\ProgressiveImageBundle\Twig\Components;
12

13
use Tito10047\ProgressiveImageBundle\DTO\BreakpointAssignment;
14
use Tito10047\ProgressiveImageBundle\Service\ResponsiveAttributeGenerator;
15
use Tito10047\ProgressiveImageBundle\SrcsetGenerator\SrcsetGeneratorInterface;
16
use Tito10047\ProgressiveImageBundle\Service\PreloadCollector;
17
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
18
use Symfony\UX\TwigComponent\Attribute\PostMount;
19
use Tito10047\ProgressiveImageBundle\Decorators\PathDecoratorInterface;
20
use Tito10047\ProgressiveImageBundle\DTO\ImageMetadata;
21
use Tito10047\ProgressiveImageBundle\Exception\PathResolutionException;
22
use Tito10047\ProgressiveImageBundle\ProgressiveImageBundle;
23
use Tito10047\ProgressiveImageBundle\Service\MetadataReaderInterface;
24

25
#[AsTwigComponent]
26
final class Image {
27

28

29
        public ?string         $src = null;
30
        public ?string         $filter = null;
31
        public ?string         $alt = null;
32
        public ?string         $pointInterest = null;
33
        public array           $context = [];
34
        private ?ImageMetadata $metadata;
35
        private string         $decoratedSrc;
36
        private ?int           $decoratedWidth;
37
        private ?int           $decoratedHeight;
38
        public bool            $preload = false;
39
        public string  $priority = 'high';
40
        public ?string $sizes    = null;
41
        public ?string $ratio    = null;
42
        private array          $breakpoinsts = [];
43
        /**
44
         * @var array{sizes: string, srcset: string}|null
45
         */
46
        private ?array         $responsiveAttributes = null;
47

48
        /**
49
         * @param iterable<PathDecoratorInterface> $pathDecorator
50
         * @param $defaultPreset null|array{
51
         *     widths: array<string, int>,
52
         *     sizes: string
53
         * }
54
         * @param $presets null|array<string,array{
55
         *      widths: array<string, int>,
56
         *      sizes: string
57
         *  }>
58
         */
59
        public function __construct(
60
                private readonly MetadataReaderInterface $analyzer,
61
                private readonly iterable       $pathDecorator,
62
                private readonly ?ResponsiveAttributeGenerator $responsiveAttributeGenerator,
63
                private readonly PreloadCollector            $preloadCollector,
64
        ) {
65
        }
247✔
66

67
        #[PostMount]
68
        public function postMount(): void {
69
                try {
70
                        $this->metadata = $this->analyzer->getMetadata($this->src);
247✔
71
                }catch (PathResolutionException){
104✔
72
                        $this->metadata = null;
104✔
73
                }
74
                $this->decoratedSrc = $this->src;
247✔
75
                $this->decoratedWidth = $this->metadata?->width;
247✔
76
                $this->decoratedHeight = $this->metadata?->height;
247✔
77
                foreach ($this->pathDecorator as $decorator) {
247✔
78
                        $this->decoratedSrc = $decorator->decorate($this->decoratedSrc, $this->context);
57✔
79
                        $size = $decorator->getSize($this->decoratedSrc, $this->context);
57✔
80
                        if ($size){
57✔
81
                                $this->decoratedWidth = $size["width"];
28✔
82
                                $this->decoratedHeight = $size["height"];
28✔
83
                        }
84
                }
85
                $this->breakpoinsts = $this->sizes ? BreakpointAssignment::parseSegments($this->sizes, $this->ratio) : [];
247✔
86
                if ($this->breakpoinsts) {
247✔
87
                        $this->responsiveAttributes = $this->responsiveAttributeGenerator?->generate($this->src, $this->breakpoinsts, $this->decoratedWidth ?? 0, $this->preload, $this->pointInterest);
84✔
88
                }elseif ($this->preload){
163✔
89
                        $this->preloadCollector->add($this->decoratedSrc, "image", $this->priority);
14✔
90
                }
91
        }
92

93
        public function getSrcset():string {
94
                if (!$this->responsiveAttributes){
173✔
95
                        return "";
89✔
96
                }
97
                return "srcset=\"{$this->responsiveAttributes['srcset']}\"";
84✔
98
        }
99

100
        public function getResponsiveSizes():string {
101
                if (!$this->responsiveAttributes){
173✔
102
                        return "";
89✔
103
                }
104
                return "sizes=\"{$this->responsiveAttributes["sizes"]}\"";
84✔
105
        }
106

107
        public function getHash(): ?string {
108
                return $this->metadata?->originalHash;
218✔
109
        }
110

111
        public function getWidth():?int {
112
                return $this->decoratedWidth??$this->metadata?->width;
157✔
113
        }
114

115
        public function getHeight():?int {
116
                return $this->decoratedHeight??$this->metadata?->height;
232✔
117
        }
118

119
        public function getDecoratedSrc(): string {
120
                return $this->decoratedSrc??$this->src;
217✔
121
        }
122

123
        public function getController(): ?string {
124
                return ProgressiveImageBundle::STIMULUS_CONTROLLER;
173✔
125
        }
126

127
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc