xref: /plugin/combo/ComboStrap/DateTag.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1<?php
2
3namespace ComboStrap;
4
5
6use syntax_plugin_combo_variable;
7
8/**
9 * Format a date
10 */
11class DateTag
12{
13    public const CANONICAL = "variable:date";
14    public const FORMAT_ATTRIBUTE = "format";
15    public const DATE_ATTRIBUTE = "date";
16    public const TAG = "date";
17    /**
18     * https://www.php.net/manual/en/function.strftime.php
19     */
20    public const DEFAULT_FORMAT = "%A, %d %B %Y";
21
22
23    /**
24     * @param string $date
25     * @param string $format
26     * @param string|null $lang
27     * @return string
28     * @throws ExceptionBadSyntax
29     */
30    public static function formatDateString(string $date, string $format = DateTag::DEFAULT_FORMAT, string $lang = null): string
31    {
32        // https://www.php.net/manual/en/function.date.php
33        // To format dates in other languages, you should use the setlocale() and strftime() functions instead of date().
34        $localeSeparator = '_';
35        if ($lang === null) {
36            try {
37                $lang = Lang::createFromRequestedMarkup()->getValueOrDefault();
38            } catch (ExceptionNotFound $e) {
39                // should never happen but yeah
40                LogUtility::error("Internal Error: The requested page was not found. We were unable to get the page language. Defaulting to the site language");
41                $lang = Site::getLang();
42            }
43        }
44        $actualLocale = setlocale(LC_ALL, 0);
45        try {
46            if ($lang !== null && trim($lang) !== "") {
47                // Set local takes several possible locales value
48                // The lang just works fine but the second argument can be seen in the doc
49                if (strlen(trim($lang)) === 2) {
50                    $derivedLocale = strtolower($lang) . $localeSeparator . strtoupper($lang);
51                } else {
52                    $derivedLocale = $lang;
53                }
54                $newLocale = setlocale(LC_TIME, $lang, $derivedLocale);
55                if ($newLocale === false) {
56                    $newLocale = setlocale(LC_TIME, $lang);
57                    if ($newLocale === false) {
58                        throw new ExceptionBadSyntax("The language ($lang) / locale ($derivedLocale) is not available as locale on the server. You can't then format the value ($date) in this language.");
59                    }
60                }
61            }
62            $date = syntax_plugin_combo_variable::replaceVariablesWithValuesFromContext($date);
63            $timeStamp = Iso8601Date::createFromString($date)->getDateTime()->getTimestamp();
64            $formatted = strftime($format, $timeStamp);
65            if ($formatted === false) {
66                if ($lang === null) {
67                    $lang = "";
68                }
69                throw new ExceptionBadSyntax("Unable to format the date ($date) with the format ($format) and lang ($lang)");
70            }
71            return $formatted;
72        } finally {
73            /**
74             * Restore the locale
75             */
76            setlocale(LC_ALL, $actualLocale);
77        }
78
79    }
80
81    public static function handleEnterAndSpecial()
82    {
83        LogUtility::warning("The date component has been deprecated for the date variable", DateTag::CANONICAL);
84    }
85
86    public static function renderHtml(TagAttributes $tagAttributes): string
87    {
88        /**
89         * Locale
90         */
91        $lang = $tagAttributes->getComponentAttributeValue(Lang::PROPERTY_NAME);
92
93        /**
94         * The format
95         */
96        $format = $tagAttributes->getValue(DateTag::FORMAT_ATTRIBUTE, DateTag::DEFAULT_FORMAT);
97        /**
98         * The date
99         */
100        $defaultDateTime = Iso8601Date::createFromNow()->toString();
101        $date = $tagAttributes->getComponentAttributeValue(DateTag::DATE_ATTRIBUTE, $defaultDateTime);
102        try {
103            return DateTag::formatDateString($date, $format, $lang);
104        } catch (ExceptionBadSyntax $e) {
105            $message = "Error while formatting a date. Error: {$e->getMessage()}";
106            LogUtility::error($message, DateTag::CANONICAL);
107            return LogUtility::wrapInRedForHtml($message);
108        }
109    }
110
111    public static function handleExit(\Doku_Handler $handler)
112    {
113        $callStack = CallStack::createFromHandler($handler);
114        $openingTag = $callStack->moveToPreviousCorrespondingOpeningCall();
115        $call = $callStack->next();
116        if ($call !== false) {
117            $date = $call->getCapturedContent();
118            $openingTag->addAttribute(DateTag::DATE_ATTRIBUTE, $date);
119            $callStack->deleteActualCallAndPrevious();
120        }
121    }
122}
123