Mailcode_Date_FormatInfo::initCharacters()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 36
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 28
dl 0
loc 36
rs 9.472
c 1
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
/**
3
 * File containing the {@see Mailcode_Date_FormatInfo} class.
4
 *
5
 * @package Mailcode
6
 * @subpackage Commands
7
 * @see Mailcode_Date_FormatInfo
8
 */
9
10
declare(strict_types=1);
11
12
namespace Mailcode;
13
14
use AppUtils\ConvertHelper;
15
use AppUtils\OperationResult;
16
17
/**
18
 * Main hub for information all around the date format strings
19
 * that can be used in the ShowDate command.
20
 *
21
 * @package Mailcode
22
 * @subpackage Commands
23
 * @author Sebastian Mordziol <[email protected]>
24
 */
25
class Mailcode_Date_FormatInfo
26
{
27
    public const VALIDATION_INVALID_FORMAT_CHARACTER = 55801;
28
    public const VALIDATION_EMPTY_FORMAT_STRING = 55802;
29
30
    public const CHARTYPE_DATE = 'date';
31
    public const CHARTYPE_TIME = 'time';
32
    public const CHARTYPE_PUNCTUATION = 'punctuation';
33
34
    public const CHAR_DAY_LZ = 'd';
35
    public const CHAR_DAY_NZ = 'j';
36
    public const CHAR_MONTH_LZ = 'm';
37
    public const CHAR_MONTH_NZ = 'n';
38
    public const CHAR_YEAR_4 = 'Y';
39
    public const CHAR_YEAR_2 = 'y';
40
    public const CHAR_HOUR_24_LZ = 'H';
41
    public const CHAR_HOUR_24_NZ = 'G';
42
    public const CHAR_HOUR_12_LZ = 'h';
43
    public const CHAR_HOUR_12_NZ = 'g';
44
    public const CHAR_AM_PM = 'a';
45
    public const CHAR_MINUTES_LZ = 'i';
46
    public const CHAR_SECONDS_LZ = 's';
47
    public const CHAR_MILLISECONDS = 'v';
48
    public const CHAR_TIMEZONE = 'e';
49
50
    /**
51
     * @var string
52
     */
53
    private string $defaultFormat = "Y/m/d";
54
55
    /**
56
     * @var Mailcode_Date_FormatInfo_Character[]
57
     */
58
    private array $formatChars = array();
59
60
    /**
61
     * @var string[]
62
     */
63
    private array $allowedChars = array();
64
65
    /**
66
     * @var Mailcode_Date_FormatInfo|NULL
67
     */
68
    private static ?Mailcode_Date_FormatInfo $instance = null;
69
70
    private function __construct()
71
    {
72
        $this->initCharacters();
73
    }
74
75
    public static function getInstance(): Mailcode_Date_FormatInfo
76
    {
77
        if (!isset(self::$instance)) {
78
            self::$instance = new Mailcode_Date_FormatInfo();
79
        }
80
81
        return self::$instance;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::instance could return the type null which is incompatible with the type-hinted return Mailcode\Mailcode_Date_FormatInfo. Consider adding an additional type-check to rule them out.
Loading history...
82
    }
83
84
    /**
85
     * Initialized the list of allowed date formatting
86
     * characters. This is done only once per request
87
     * by storing them statically for performance reasons.
88
     */
89
    private function initCharacters(): void
90
    {
91
        $chars = array(
92
            array(self::CHARTYPE_DATE, self::CHAR_DAY_LZ, t('Day of the month, with leading zeros')),
93
            array(self::CHARTYPE_DATE, self::CHAR_DAY_NZ, t('Day of the month, without leading zeros')),
94
            array(self::CHARTYPE_DATE, self::CHAR_MONTH_LZ, t('Month number, with leading zeros')),
95
            array(self::CHARTYPE_DATE, self::CHAR_MONTH_NZ, t('Month number, without leading zeros')),
96
            array(self::CHARTYPE_DATE, self::CHAR_YEAR_4, t('Year, 4 digits')),
97
            array(self::CHARTYPE_DATE, self::CHAR_YEAR_2, t('Year, 2 digits')),
98
99
            array(self::CHARTYPE_TIME, self::CHAR_HOUR_24_LZ, t('Hour, 24-hour format with leading zeros')),
100
            array(self::CHARTYPE_TIME, self::CHAR_HOUR_24_NZ, t('Hour, 24-hour format without leading zeros')),
101
            array(self::CHARTYPE_TIME, self::CHAR_HOUR_12_LZ, t('Hour, 12-hour format with leading zeros')),
102
            array(self::CHARTYPE_TIME, self::CHAR_HOUR_12_NZ, t('Hour, 12-hour format without leading zeros')),
103
            array(self::CHARTYPE_TIME, self::CHAR_AM_PM, t('AM/PM marker')),
104
            array(self::CHARTYPE_TIME, self::CHAR_MINUTES_LZ, t('Minutes with leading zeros')),
105
            array(self::CHARTYPE_TIME, self::CHAR_SECONDS_LZ, t('Seconds with leading zeros')),
106
            array(self::CHARTYPE_TIME, self::CHAR_MILLISECONDS, t('Milliseconds')),
107
            array(self::CHARTYPE_TIME, self::CHAR_TIMEZONE, t('Timezone')),
108
109
            array(self::CHARTYPE_PUNCTUATION, '.', t('Dot')),
110
            array(self::CHARTYPE_PUNCTUATION, '/', t('Slash')),
111
            array(self::CHARTYPE_PUNCTUATION, '-', t('Hyphen')),
112
            array(self::CHARTYPE_PUNCTUATION, ':', t('Colon')),
113
            array(self::CHARTYPE_PUNCTUATION, ' ', t('Space'))
114
        );
115
116
        foreach ($chars as $def) {
117
            $char = new Mailcode_Date_FormatInfo_Character(
118
                $def[0],
119
                $def[1],
120
                $def[2]
121
            );
122
123
            $this->formatChars[] = $char;
124
            $this->allowedChars[] = $char->getChar();
125
        }
126
    }
127
128
    public function getDefaultFormat(): string
129
    {
130
        return $this->defaultFormat;
131
    }
132
133
    public function setDefaultFormat(string $formatString): void
134
    {
135
        $this->defaultFormat = $formatString;
136
    }
137
138
    /**
139
     * Validates the date format string, by ensuring that
140
     * all the characters it is composed of are known.
141
     *
142
     * @param string $formatString
143
     * @return OperationResult
144
     *
145
     * @see Mailcode_Commands_Command_ShowDate::VALIDATION_EMPTY_FORMAT_STRING
146
     * @see Mailcode_Commands_Command_ShowDate::VALIDATION_INVALID_FORMAT_CHARACTER
147
     */
148
    public function validateFormat(string $formatString): OperationResult
149
    {
150
        $result = new OperationResult($this);
151
152
        $trimmed = trim($formatString);
153
154
        if (empty($trimmed)) {
155
            $result->makeError(
156
                t('Empty date format.'),
157
                self::VALIDATION_EMPTY_FORMAT_STRING
158
            );
159
160
            return $result;
161
        }
162
163
        $chars = ConvertHelper::string2array($formatString);
164
        $total = count($chars);
165
166
        for ($i = 0; $i < $total; $i++) {
167
            $char = $chars[$i];
168
169
            if (!in_array($char, $this->allowedChars)) {
170
                $result->makeError(
171
                    t('Invalid character in date format:') . ' ' .
172
                    t('%1$s at position %2$s.', '<code>' . $char . '</code>', $i + 1),
173
                    self::VALIDATION_INVALID_FORMAT_CHARACTER
174
                );
175
176
                return $result;
177
            }
178
        }
179
180
        return $result;
181
    }
182
183
    /**
184
     * Retrieves all characters that are allowed to
185
     * be used in a date format string, with information
186
     * on each.
187
     *
188
     * @return Mailcode_Date_FormatInfo_Character[]
189
     */
190
    public function getCharactersList(): array
191
    {
192
        return $this->formatChars;
193
    }
194
195
    /**
196
     * Retrieves the characters list, grouped by type label.
197
     *
198
     * @return array<string,array<int,Mailcode_Date_FormatInfo_Character>>
199
     */
200
    public function getCharactersGrouped(): array
201
    {
202
        $grouped = array();
203
204
        foreach ($this->formatChars as $char) {
205
            $type = $char->getTypeLabel();
206
207
            if (!isset($grouped[$type])) {
208
                $grouped[$type] = array();
209
            }
210
211
            $grouped[$type][] = $char;
212
        }
213
214
        $groups = array_keys($grouped);
215
216
        foreach ($groups as $group) {
217
            usort($grouped[$group], function (Mailcode_Date_FormatInfo_Character $a, Mailcode_Date_FormatInfo_Character $b) {
218
                return strnatcasecmp($a->getChar(), $b->getChar());
219
            });
220
        }
221
222
        uksort($grouped, function (string $a, string $b) {
223
            return strnatcasecmp($a, $b);
224
        });
225
226
        return $grouped;
227
    }
228
}
229