Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.83% covered (success)
95.83%
23 / 24
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
Images
95.83% covered (success)
95.83%
23 / 24
50.00% covered (danger)
50.00%
1 / 2
9
0.00% covered (danger)
0.00%
0 / 1
 render
93.75% covered (success)
93.75%
15 / 16
0.00% covered (danger)
0.00%
0 / 1
6.01
 settings
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Block;
6
7use Cosray\Contract\Block;
8use Cosray\Field;
9use Cosray\Schema\Label;
10use Cosray\Schema\Required;
11use Cosray\Schema\Translate;
12use Cosray\Value\Block as BlockValue;
13use Cosray\Value\Images as ImagesValue;
14use Override;
15
16use function Cosray\escape;
17
18#[Label('block:images')]
19final class Images implements Block
20{
21    private const string THUMB = 'block-thumb';
22
23    #[Label('block:images'), Required, Translate]
24    protected Field\Image $images;
25
26    #[Override]
27    public function render(BlockValue $block, RenderContext $ctx): string
28    {
29        $name = (string) ($ctx->args['thumbSize'] ?? self::THUMB);
30        // Validate the name up front — a typo should fail the render,
31        // not silently emit URLs the fallback route will 404.
32        $ctx->owner->config()->media->sizes->get($name);
33        $prefix = $ctx->prefix();
34        /** @var ImagesValue $images */
35        $images = $block->images;
36        $result = '';
37
38        foreach ($images as $image) {
39            $asset = $ctx->asset((string) ($image->raw()['uid'] ?? ''));
40
41            if ($asset === null) {
42                continue;
43            }
44
45            $alt = escape($image->alt() ?: strip_tags($image->title()));
46            $path = escape($asset->path());
47            $url = $asset->resizable() ? escape($asset->sizePath($name)) : $path;
48
49            $result .= "<div class=\"{$prefix}-blocks-images-image\"><img src=\"{$url}\" alt=\"{$alt}\" data-path-original=\"{$path}\"></div>";
50        }
51
52        if ($result === '') {
53            return '';
54        }
55
56        return "<div class=\"{$prefix}-blocks-images\"{$this->settings($images)}>{$result}</div>";
57    }
58
59    /** The gallery settings as attributes: the ratio as data and custom property, the crop as a flag. */
60    private function settings(ImagesValue $images): string
61    {
62        $attributes = '';
63        $ratio = $images->ratio();
64
65        if ($ratio !== null) {
66            $ratio = escape($ratio);
67            $attributes .= " data-ratio=\"{$ratio}\" style=\"--ratio: {$ratio}\"";
68        }
69
70        if ($images->crop()) {
71            $attributes .= ' data-crop';
72        }
73
74        return $attributes;
75    }
76}