Passed
Push — master ( d8dc61...dfdb64 )
by Sebastian
09:05
created

ShowDateTranslation::translate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
c 0
b 0
f 0
dl 0
loc 11
rs 10
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * @package Mailcode
4
 * @subpackage Translator
5
 */
6
7
declare(strict_types=1);
8
9
namespace Mailcode\Translator\Syntax\ApacheVelocity;
10
11
use AppUtils\ConvertHelper;
12
use Mailcode\Mailcode_Commands_Command_ShowDate;
13
use Mailcode\Mailcode_Date_FormatInfo;
14
use Mailcode\Mailcode_Parser_Statement_Tokenizer_Token_StringLiteral;
15
use Mailcode\Mailcode_Parser_Statement_Tokenizer_Token_Variable;
16
use Mailcode\Mailcode_Translator_Command_ShowDate;
17
use Mailcode\Mailcode_Translator_Exception;
18
use Mailcode\Translator\Syntax\ApacheVelocity;
19
use function Mailcode\undollarize;
20
21
/**
22
 * Translates the {@see Mailcode_Commands_Command_ShowDate} command to Apache Velocity.
23
 *
24
 * @package Mailcode
25
 * @subpackage Translator
26
 * @author Sebastian Mordziol <[email protected]>
27
 */
28
class ShowDateTranslation extends ApacheVelocity implements Mailcode_Translator_Command_ShowDate
29
{
30
    public const ERROR_UNKNOWN_DATE_FORMAT_CHARACTER = 55501;
31
    public const ERROR_UNHANDLED_TIME_ZONE_TOKEN_TYPE = 55502;
32
33
    /**
34
     * The date format used in the date variable. This is used to convert
35
     * the native date to the format specified in the variable command.
36
     */
37
    public const DEFAULT_INTERNAL_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
38
39
    /**
40
     * Conversion table for the date format characters, from PHP to Java.
41
     *
42
     * @var array<string,string>
43
     * @see https://stackoverflow.com/questions/12781273/what-are-the-date-formats-available-in-simpledateformat-class
44
     * @see https://www.php.net/manual/en/datetime.format.php
45
     */
46
    public static array $charTable = array(
47
        Mailcode_Date_FormatInfo::CHAR_DAY_LZ => 'dd', // Day of the month with leading zeros
48
        Mailcode_Date_FormatInfo::CHAR_DAY_NZ => 'd', // Day of the month without leading zeros
49
        Mailcode_Date_FormatInfo::CHAR_MONTH_LZ => 'MM', // Month number with leading zeros
50
        Mailcode_Date_FormatInfo::CHAR_MONTH_NZ => 'M', // Month number without leading zeros
51
        Mailcode_Date_FormatInfo::CHAR_YEAR_4 => 'yyyy', // Year with four digits
52
        Mailcode_Date_FormatInfo::CHAR_YEAR_2 => 'yy', // Year with two digits
53
        Mailcode_Date_FormatInfo::CHAR_HOUR_24_LZ => 'HH', // Hour in 24-hour format with leading zeros
54
        Mailcode_Date_FormatInfo::CHAR_HOUR_24_NZ => 'H', // Hour in 24-hour format without leading zeros
55
        Mailcode_Date_FormatInfo::CHAR_HOUR_12_LZ => 'hh', // 12-hour hour with leading zeros
56
        Mailcode_Date_FormatInfo::CHAR_HOUR_12_NZ => 'h', // 12-hour hour without leading zeros
57
        Mailcode_Date_FormatInfo::CHAR_AM_PM => 'a', // am/pm marker (lowercase in Java)
58
        Mailcode_Date_FormatInfo::CHAR_MINUTES_LZ => 'mm', // Minutes with leading zeros
59
        Mailcode_Date_FormatInfo::CHAR_SECONDS_LZ => 'ss', // Seconds with leading zeros
60
        Mailcode_Date_FormatInfo::CHAR_MILLISECONDS => 'SSS', // Milliseconds
61
        Mailcode_Date_FormatInfo::CHAR_TIMEZONE => 'XXX', // Timezone identifier, e.g. "UTC", "GMT" or "Europe/Paris"
62
63
        // PUNCTUATION
64
        '.' => '.',
65
        ':' => ':',
66
        '-' => '-',
67
        '/' => '/',
68
        ' ' => ' ',
69
    );
70
71
    public function getInternalFormat(Mailcode_Commands_Command_ShowDate $command): string
72
    {
73
        $internalFormat = $command->getTranslationParam('internal_format');
74
75
        if (is_string($internalFormat) && !empty($internalFormat)) {
76
            return $internalFormat;
77
        }
78
79
        return self::DEFAULT_INTERNAL_FORMAT;
80
    }
81
82
    public function translate(Mailcode_Commands_Command_ShowDate $command): string
83
    {
84
        $statement = sprintf(
85
            'time.input("%s", $%s).output("%s")%s',
86
            $this->getInternalFormat($command),
87
            undollarize($command->getVariableName()),
88
            $this->resolveJavaFormat($command->getFormatString()),
89
            $this->resolveTimeZoneFormat($command)
90
        );
91
92
        return $this->renderVariableEncodings($command, $statement);
93
    }
94
95
    private function resolveTimeZoneFormat(Mailcode_Commands_Command_ShowDate $command): string
96
    {
97
        $token = $command->getTimezoneToken();
98
99
        if ($token instanceof Mailcode_Parser_Statement_Tokenizer_Token_StringLiteral) {
100
            return sprintf('.zone("%s")', $token->getText());
101
        }
102
103
        if ($token instanceof Mailcode_Parser_Statement_Tokenizer_Token_Variable) {
104
            return sprintf('.zone(%s)', $token->getVariable()->getFullName());
105
        }
106
107
        throw new Mailcode_Translator_Exception(
108
            'Unknown time zone type.',
109
            sprintf(
110
                'The time zone token type is unhandled: [%s].',
111
                get_class($token)
112
            ),
113
            self::ERROR_UNHANDLED_TIME_ZONE_TOKEN_TYPE
114
        );
115
    }
116
117
    /**
118
     * @param string $formatString
119
     * @return string
120
     * @throws Mailcode_Translator_Exception {@see self::ERROR_UNKNOWN_DATE_FORMAT_CHARACTER}
121
     */
122
    private function resolveJavaFormat(string $formatString): string
123
    {
124
        $chars = ConvertHelper::string2array($formatString);
125
        $result = array();
126
127
        foreach ($chars as $char) {
128
            if (!isset(self::$charTable[$char])) {
129
                throw new Mailcode_Translator_Exception(
130
                    'Unknown date format string character',
131
                    sprintf(
132
                        'No translation for character %s available.',
133
                        ConvertHelper::hidden2visible($char)
134
                    ),
135
                    self::ERROR_UNKNOWN_DATE_FORMAT_CHARACTER
136
                );
137
            }
138
139
            $result[] = self::$charTable[$char];
140
        }
141
142
        return implode('', $result);
143
    }
144
}
145