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