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

tito10047 / progressive-image-bundle / 20661725623

02 Jan 2026 04:11PM UTC coverage: 89.065%. Remained the same
20661725623

push

github

tito10047
replace `grid` with `sizes`: update all references in templates, tests, and documentation to align with the new attribute name; adjust `Image` component logic accordingly and ensure backward compatibility

1 of 1 new or added line in 1 file covered. (100.0%)

111 existing lines in 9 files now uncovered.

562 of 631 relevant lines covered (89.06%)

166.02 hits per line

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

96.23
/src/Service/ResponsiveAttributeGenerator.php
1
<?php
2

3
namespace Tito10047\ProgressiveImageBundle\Service;
4

5
use Tito10047\ProgressiveImageBundle\Dto\BreakpointAssignment;
6
use Tito10047\ProgressiveImageBundle\UrlGenerator\ResponsiveImageUrlGeneratorInterface;
7

8
class ResponsiveAttributeGenerator {
9

10
        /**
11
         * @param $gridConfig  array{
12
         *     layouts: array<string, array{
13
         *            min_viewport: int,
14
         *            max_container: int|null
15
         *       }>,
16
         *     columns: int
17
         * }
18
         * @param $ratioConfig array<string, string>
19
         */
20
        public function __construct(
21
                private array                                $gridConfig,
22
                private array                                $ratioConfig,
23
                private readonly PreloadCollector            $preloadCollector,
24
                private ResponsiveImageUrlGeneratorInterface $urlGenerator
25
        ) {
26
        }
241✔
27

28
        /**
29
         * @return array{sizes: string, srcset: string}
30
         */
31
        public function generate(string $path, array $assignments, int $originalWidth, bool $preload, ?string $pointInterest = null): array {
32
                $assignments = $this->sortAssignments($assignments);
129✔
33

34
                $sizesParts      = [];
129✔
35
                $srcsetParts     = [];
129✔
36
                $processedWidths = [];
129✔
37

38
                foreach ($assignments as $assignment) {
129✔
39
                        $layout = $this->gridConfig['layouts'][$assignment->breakpoint] ?? null;
129✔
40
                        if (!$layout) {
129✔
41
                                continue;
×
42
                        }
43

44
                        [$pixelWidth, $sizeValue] = $this->calculateDimensions($assignment, $layout);
129✔
45

46
                        $size = $this->formatSizePart($layout['min_viewport'], $sizeValue);
129✔
47
                        $sizesParts[]   = $size;
129✔
48

49
                        $url = $this->generateUrl($path, $assignment, (int) round($pixelWidth), $originalWidth, $processedWidths, $pointInterest);
129✔
50

51
                        if ($url) {
129✔
52
                                $actualPixelWidth = (int) round($pixelWidth);
129✔
53
                                if ($preload) {
129✔
UNCOV
54
                                        $this->preloadCollector->add($url, 'image', 'high', "{$actualPixelWidth}w", $size);
14✔
55
                                }
56

57
                                $srcsetParts[] = $url . " {$actualPixelWidth}w";
129✔
58
                        }
59
                }
60

61
                return [
129✔
62
                        'sizes'  => implode(', ', $sizesParts),
129✔
63
                        'srcset' => implode(', ', $srcsetParts),
129✔
64
                ];
129✔
65
        }
66

67
        private function formatSizePart(int $minViewport, string $sizeValue): string {
68
                return $minViewport > 0
129✔
69
                        ? "(min-width: {$minViewport}px) {$sizeValue}"
129✔
70
                        : $sizeValue;
129✔
71
        }
72

73
        /**
74
         * @param BreakpointAssignment[] $assignments
75
         *
76
         * @return BreakpointAssignment[]
77
         */
78
        private function sortAssignments(array $assignments): array {
79
                usort($assignments, fn($a, $b) => ($this->gridConfig['layouts'][$b->breakpoint]['min_viewport'] ?? 0) <=>
129✔
80
                        ($this->gridConfig['layouts'][$a->breakpoint]['min_viewport'] ?? 0)
85✔
81
                );
129✔
82

83
                return $assignments;
129✔
84
        }
85

86
        /**
87
         * @param array{min_viewport: int, max_container: int|null} $layout
88
         *
89
         * @return array{0: float, 1: string}
90
         */
91
        private function calculateDimensions(BreakpointAssignment $assignment, array $layout): array {
92
                $totalCols    = $this->gridConfig['columns'];
129✔
93
                $maxContainer = $layout['max_container'];
129✔
94

95
                if ($maxContainer) {
129✔
96
                        // Fixný kontajner (napr. 1320px) -> šírka v px
97
                        $pixelWidth = ($assignment->columns / $totalCols) * $maxContainer;
129✔
98
                        $sizeValue  = round($pixelWidth) . 'px';
129✔
99
                } else {
100
                        // Fluid (null) -> šírka vo vw
101
                        $vwWidth   = ($assignment->columns / $totalCols) * 100;
85✔
102
                        $sizeValue = round($vwWidth) . 'vw';
85✔
103
                        // Pre výpočet URL odhadneme px šírku z nejakej rozumnej max-šírky (napr. 1920)
104
                        $pixelWidth = ($vwWidth / 100) * 1920;
85✔
105
                }
106

107
                return [$pixelWidth, $sizeValue];
129✔
108
        }
109

110
        /**
111
         * @param array<int, bool> $processedWidths
112
         *
113
         * @return string[]
114
         */
115
        private function generateUrl(
116
                string               $path,
117
                BreakpointAssignment $assignment,
118
                int                  $basePixelWidth,
119
                int                  $originalWidth,
120
                array                &$processedWidths,
121
                ?string              $pointInterest = null
122
        ): ?string {
123
                $ratio = $this->resolveRatio($assignment);
129✔
124

125
                if ($basePixelWidth > $originalWidth || isset($processedWidths[$basePixelWidth])) {
129✔
UNCOV
126
                        return null;
56✔
127
                }
128

129
                $targetH = $ratio ? (int) round($basePixelWidth / $ratio) : null;
129✔
130
                $url     = $this->urlGenerator->generateUrl($path, $basePixelWidth, $targetH, $pointInterest);
129✔
131

132
                $processedWidths[$basePixelWidth] = true;
129✔
133
                return $url;
129✔
134

135
        }
136

137
        private function resolveRatio(BreakpointAssignment $assignment): ?float {
138
                $ratioString = $assignment->ratio ?? null;
129✔
139
                if (!$ratioString) {
129✔
UNCOV
140
                        return null;
84✔
141
                }
142

143
                // Ak je to kľúč v ratioConfig, použijeme ten
144
                if (isset($this->ratioConfig[$ratioString])) {
45✔
145
                        return (float) $this->ratioConfig[$ratioString];
30✔
146
                }
147

148
                // Inak skúsime parsovať formát "3/4" alebo "3-4"
149
                if (preg_match('/^(\d+)[\/-](\d+)$/', $ratioString, $matches)) {
15✔
150
                        return (float) $matches[1] / (float) $matches[2];
15✔
151
                }
152

153
                return null;
×
154
        }
155
}
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