xref: /plugin/combo/ComboStrap/PageImageTag.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1<?php
2
3namespace ComboStrap;
4
5use ComboStrap\Meta\Field\AncestorImage;
6use ComboStrap\Meta\Field\FeaturedImage;
7use ComboStrap\TagAttribute\StyleAttribute;
8use syntax_plugin_combo_iterator;
9
10
11class PageImageTag
12{
13
14    public const CANONICAL = PageImageTag::TAG;
15    public const VIGNETTE_TYPE = "vignette";
16    public const DEFAULT_ATTRIBUTE = "default";
17    public const MARKUP = "page-image";
18    public const LOGO_TYPE = "logo";
19    public const DEFAULT_ORDER = [
20        PageImageTag::FEATURED,
21        PageImageTag::FIRST_TYPE,
22        PageImageTag::ANCESTOR_TYPE,
23        PageImageTag::ICON_TYPE,
24        PageImageTag::VIGNETTE_TYPE,
25        PageImageTag::LOGO_TYPE
26    ];
27    public const ANCESTOR_TYPE = "ancestor";
28    public const TAG = "pageimage";
29    public const FEATURED = "featured";
30    public const ICON_TYPE = "icon";
31    public const NONE_TYPE = "none";
32    public const FIRST_TYPE = "first";
33
34    public const TYPES = [
35        PageImageTag::FEATURED,
36        PageImageTag::FIRST_TYPE,
37        PageImageTag::VIGNETTE_TYPE,
38        PageImageTag::ANCESTOR_TYPE,
39        PageImageTag::LOGO_TYPE,
40        PageImageTag::ICON_TYPE
41    ];
42    const DEFAULT_ZOOM = -4;
43
44
45    /**
46     * Because the pageimage can also be used
47     * in a template
48     *
49     * The calculation are done in the {@link syntax_plugin_combo_pageimage::render render function}
50     *
51     */
52    public static function handle($tagAttributes, $handler): array
53    {
54
55        /**
56         * Context
57         */
58        $callStack = CallStack::createFromHandler($handler);
59        $context = PageImageTag::TAG;
60        $parent = $callStack->moveToParent();
61        if ($parent !== false) {
62            $context = $parent->getTagName();
63        }
64
65        return array(
66            PluginUtility::ATTRIBUTES => $tagAttributes->toCallStackArray(),
67            PluginUtility::CONTEXT => $context
68        );
69    }
70
71    public static function render(TagAttributes $tagAttributes, array $data)
72    {
73
74
75        /**
76         * Image selection
77         */
78        $path = syntax_plugin_combo_iterator::getContextPathForComponentThatMayBeInFragment($tagAttributes);
79        $contextPage = MarkupPath::createPageFromPathObject($path);
80
81        /**
82         * Zoom applied only to icon
83         * but we get and **delete** it
84         * because it's not a standard html attribute
85         */
86        $zoom = $tagAttributes->getValueAndRemoveIfPresent(Dimension::ZOOM_ATTRIBUTE, self::DEFAULT_ZOOM);
87
88        /**
89         * Image Order of precedence
90         */
91        $order = self::getOrderOfPreference($tagAttributes);
92        $imageFetcher = null;
93        foreach ($order as $pageImageProcessing) {
94            switch ($pageImageProcessing) {
95                case PageImageTag::FEATURED:
96                    try {
97                        $imagePath = FeaturedImage::createFromResourcePage($contextPage)->getValue();
98                    } catch (ExceptionNotFound $e) {
99                        // ok
100                        continue 2;
101                    }
102                    try {
103                        $imageFetcher = IFetcherLocalImage::createImageFetchFromPath($imagePath);
104                    } catch (ExceptionNotExists|ExceptionBadArgument|ExceptionBadSyntax $e) {
105                        LogUtility::warning("Error while creating the fetcher for the feature image ($imagePath) and the page ($contextPage). Error: {$e->getMessage()}", self::CANONICAL, $e);
106                    }
107                    break;
108                case PageImageTag::ANCESTOR_TYPE:
109                case "parent": // old
110                    try {
111                        $ancestor = AncestorImage::createFromResourcePage($contextPage)->getValue();
112                    } catch (ExceptionNotFound $e) {
113                        continue 2;
114                    }
115                    try {
116                        $imageFetcher = IFetcherLocalImage::createImageFetchFromPath($ancestor);
117                    } catch (ExceptionBadArgument|ExceptionBadSyntax|ExceptionNotExists $e) {
118                        LogUtility::warning("Error while creating the ancestor image handler for the image ($ancestor) and the page ($contextPage). Error: {$e->getMessage()}", self::CANONICAL, $e);
119                    }
120                    break;
121                case PageImageTag::ICON_TYPE:
122                    try {
123                        $icon = FeaturedIcon::createForPage($contextPage)->getValueOrDefault();
124                    } catch (ExceptionNotFound $e) {
125                        continue 2;
126                    }
127
128                    $width = $tagAttributes->getValueAndRemoveIfPresent(Dimension::WIDTH_KEY);
129                    $height = $tagAttributes->getValueAndRemoveIfPresent(Dimension::HEIGHT_KEY);
130                    $ratio = $tagAttributes->getValueAndRemoveIfPresent(Dimension::RATIO_ATTRIBUTE);
131                    if ($width === null && $height !== null && $ratio === null) {
132                        $width = $height;
133                    }
134                    if ($width !== null && $height !== null && $ratio === null) {
135                        $height = $width;
136                    }
137                    $imageFetcher = FetcherSvg::createSvgFromPath($icon)
138                        ->setRequestedZoom($zoom);
139
140                    if ($ratio !== null) {
141                        try {
142                            $imageFetcher->setRequestedAspectRatio($ratio);
143                        } catch (ExceptionBadSyntax $e) {
144                            LogUtility::error("The ratio value ($ratio) is not a valid ratio for the icon image ($icon)");
145                        }
146                    }
147                    if ($width !== null) {
148                        $imageFetcher->setRequestedWidth($width);
149                    }
150                    if ($height !== null) {
151                        $imageFetcher->setRequestedHeight($height);
152                    }
153
154                    break;
155                case PageImageTag::FIRST_TYPE:
156
157                    try {
158                        $firstImagePath = FirstImage::createForPage($contextPage)->getValue();
159                    } catch (ExceptionNotFound $e) {
160                        continue 2;
161                    }
162
163                    try {
164                        $imageFetcher = IFetcherLocalImage::createImageFetchFromPath($firstImagePath);
165                    } catch (ExceptionBadArgument|ExceptionBadSyntax|ExceptionNotExists $e) {
166                        LogUtility::warning("Error while creating the first image handler for the image ($firstImagePath) and the page ($contextPage). Error: {$e->getMessage()}", self::CANONICAL, $e);
167                    }
168                    break;
169                case PageImageTag::VIGNETTE_TYPE:
170                    try {
171                        $imageFetcher = FetcherVignette::createForPage($contextPage);
172                    } catch (ExceptionNotFound|ExceptionBadArgument $e) {
173                        LogUtility::warning("Error while creating the vignette for the page ($contextPage). Error: {$e->getMessage()}", self::CANONICAL, $e);
174                    }
175                    break;
176                case PageImageTag::LOGO_TYPE:
177                    try {
178                        $imageFetcher = FetcherSvg::createSvgFromPath(Site::getLogoAsSvgImage());
179                    } catch (ExceptionNotFound $e) {
180                        LogUtility::info("No page image could be find for the page ($path)", PageImageTag::CANONICAL);
181                    }
182                    break;
183                case PageImageTag::NONE_TYPE:
184                    return false;
185                default:
186                    LogUtility::error("The image ($pageImageProcessing) is an unknown page image type", PageImageTag::CANONICAL);
187                    continue 2;
188            }
189            if ($imageFetcher !== null) {
190                $tagAttributes->addClassName(StyleAttribute::addComboStrapSuffix($pageImageProcessing));
191                break;
192            }
193        }
194
195        if ($imageFetcher === null) {
196            return false;
197        }
198
199        /**
200         * Final building
201         */
202        try {
203            $imageFetcher->buildFromTagAttributes($tagAttributes);
204        } catch (ExceptionBadArgument|ExceptionBadSyntax|ExceptionCompile $e) {
205            LogUtility::error("The image could not be build. Error: {$e->getMessage()}", PageImageTag::CANONICAL, $e);
206        }
207
208        /**
209         * Svg
210         */
211        if ($imageFetcher instanceof FetcherSvg) {
212
213            /**
214             * This is an illustration image
215             * Used by svg to color by default with the primary color for instance
216             *
217             * (Note that because we use icon as page-image type,
218             * the buildFromTagAttributes would have set it to icon)
219             */
220            $imageFetcher->setRequestedType(FetcherSvg::ILLUSTRATION_TYPE);
221
222            /**
223             * When the width requested is small, no zoom out
224             */
225            try {
226                $requestedWidth = $imageFetcher->getRequestedWidth();
227                try {
228                    $pixelWidth = ConditionalLength::createFromString($requestedWidth)->toPixelNumber();
229                    if ($pixelWidth < 30) {
230                        /**
231                         * Icon rendering
232                         */
233                        $imageFetcher
234                            ->setRequestedZoom(1)
235                            ->setRequestedType(FetcherSvg::ICON_TYPE);
236
237                    }
238                } catch (ExceptionCompile $e) {
239                    LogUtility::msg("The width value ($requestedWidth) could not be translated in pixel value. Error: {$e->getMessage()}");
240                }
241            } catch (ExceptionNotFound $e) {
242                // no width
243            }
244
245        }
246
247
248        /**
249         * Img/Svg Tag
250         *
251         * Used as an illustration in a card
252         * If the image is too small, we allow that it will stretch
253         * to take the whole space
254         */
255        if ($data[PluginUtility::CONTEXT] === CardTag::CARD_TAG) {
256            $tagAttributes->addStyleDeclarationIfNotSet("max-width", "100%");
257            $tagAttributes->addStyleDeclarationIfNotSet("max-height", "unset");
258        }
259
260
261        $tagAttributes->setType(self::MARKUP);
262
263        try {
264            return MediaMarkup::createFromFetcher($imageFetcher)
265                ->buildFromTagAttributes($tagAttributes)
266                ->toHtml();
267        } catch (ExceptionCompile $e) {
268            $message = "Error while rendering the page image: {$e->getMessage()}";
269            LogUtility::error($message, self::CANONICAL, $e);
270            return $message;
271        }
272
273    }
274
275    public static function getDefaultAttributes(): array
276    {
277        return [
278            MediaMarkup::LINKING_KEY => MediaMarkup::LINKING_NOLINK_VALUE,
279            TagAttributes::TYPE_KEY => self::FEATURED
280        ];
281    }
282
283    private static function getOrderOfPreference(TagAttributes $tagAttributes): array
284    {
285        // the type is first
286        $type = $tagAttributes->getType();
287        $orderOfPreference[] = $type;
288        // then the default one
289        $default = $tagAttributes->getValueAndRemoveIfPresent(PageImageTag::DEFAULT_ATTRIBUTE);
290        if ($default === null) {
291            $defaultOrderOfPreference = PageImageTag::DEFAULT_ORDER;
292        } else {
293            $defaultOrderOfPreference = explode("|", $default);
294        }
295        foreach ($defaultOrderOfPreference as $defaultImageOrder) {
296            if ($defaultImageOrder === $type) {
297                continue;
298            }
299            $orderOfPreference[] = $defaultImageOrder;
300        }
301        return $orderOfPreference;
302    }
303
304}
305