Completed
Push — master ( e0c8cf...938a71 )
by Pierre
07:16
created

ConfigurableFactory::getLeap()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 15
nc 4
nop 1
dl 0
loc 24
rs 8.9713
c 0
b 0
f 0
1
<?php
2
3
namespace Popy\Calendar\Factory;
4
5
use InvalidArgumentException;
6
use Popy\Calendar\Calendar\ComposedCalendar;
7
use Popy\Calendar\Converter\AgnosticConverter;
8
use Popy\Calendar\Converter\UnixTimeConverter;
9
use Popy\Calendar\Converter\LeapYearCalculator;
10
use Popy\Calendar\Converter\CompleteLeapYearCalculatorInterface;
11
use Popy\Calendar\Formatter\Localisation;
12
use Popy\Calendar\Formatter\SymbolFormatter;
13
use Popy\Calendar\Formatter\NumberConverter;
14
use Popy\Calendar\Formatter\AgnosticFormatter;
15
use Popy\Calendar\Parser\AgnosticParser;
16
use Popy\Calendar\Parser\ResultMapper;
17
use Popy\Calendar\Parser\FormatLexer;
18
use Popy\Calendar\Parser\FormatParser;
19
use Popy\Calendar\Parser\SymbolParser;
20
21
class ConfigurableFactory
22
{
23
    /**
24
     * Available values for option "leap".
25
     *
26
     * @var array<string>
27
     */
28
    protected $leap = [
29
        'noleap' => LeapYearCalculator\NoLeap::class,
30
        'none'   => LeapYearCalculator\NoLeap::class,
31
        'julian' => LeapYearCalculator\Caesar::class,
32
        'caesar' => LeapYearCalculator\Caesar::class,
33
        'modern'    => LeapYearCalculator\Modern::class,
34
        'gregorian' => LeapYearCalculator\Modern::class,
35
        'futuristic' => LeapYearCalculator\Futuristic::class,
36
        'persian' => LeapYearCalculator\Persian::class,
37
        'hijri'   => LeapYearCalculator\Persian::class,
38
        'von_madler' => LeapYearCalculator\VonMadler::class,
39
        'float' => LeapYearCalculator\FloatBased::class,
40
    ];
41
42
    /**
43
     * Available values for option "locale".
44
     *
45
     * @var array<string>
46
     */
47
    protected $locale = [
48
        'native' => Localisation\NativeHardcoded::class,
49
    ];
50
51
    /**
52
     * Available values for option "month"
53
     *
54
     * @var array<string>
55
     */
56
    protected $month = [
57
        'gregorian' => UnixTimeConverter\GregorianCalendarMonthes::class,
58
        'equal_length' => UnixTimeConverter\EqualLengthMonthes::class,
59
    ];
60
61
    /**
62
     * Available values for option "week"
63
     *
64
     * @var array<string>
65
     */
66
    protected $week = [
67
        'iso' => UnixTimeConverter\Iso8601Weeks::class,
68
        'simple' => UnixTimeConverter\SimpleWeeks::class,
69
    ];
70
71
    /**
72
     * Available values for option "number"
73
     *
74
     * @var array<string>
75
     */
76
    protected $number = [
77
        'two_digits' => NumberConverter\TwoDigitsYear::class,
78
        'roman' => NumberConverter\Roman::class,
79
        'rfc2550' => NumberConverter\RFC2550::class,
80
    ];
81
82
    /**
83
     * Available values for option "additional_symbol_parser"
84
     *
85
     * @var array<string>
86
     */
87
    protected $additional_symbol_parser = [
88
        'none'    => false,
89
        'rfc2550' => SymbolParser\PregNativeRFC2550::class,
90
    ];
91
92
    /**
93
     * Builds a gregorian calendar.
94
     *
95
     * @return ComposedCalendar
96
     */
97
    public function build(array $options = array())
98
    {
99
        return new ComposedCalendar(
100
            $this->get('formatter', $options),
101
            $this->get('parser', $options)
102
        );
103
    }
104
105
    /**
106
     * Builds a date formatter.
107
     *
108
     * @return AgnosticFormatter
109
     */
110
    public function buildFormatter(array $options = array())
111
    {
112
        return $this->get('formatter', $options);
113
    }
114
115
    /**
116
     * Builds a date formatter.
117
     *
118
     * @return AgnosticParser
119
     */
120
    public function buildParser(array $options = array())
121
    {
122
        return $this->get('parser', $options);
123
    }
124
125
    /**
126
     * Builds a date converter.
127
     *
128
     * @return AgnosticConverter
129
     */
130
    public function buildConverter(array $options = array())
131
    {
132
        return $this->get('converter', $options);
133
    }
134
135
    /**
136
     * Generic service getter.
137
     *
138
     * @param string $service  Service name.
139
     * @param array  &$options Option array
140
     *
141
     * @return mixed
142
     */
143
    protected function get($service, array &$options)
144
    {
145
        if (isset($options[$service]) && is_object($options[$service])) {
146
            return $options[$service];
147
        }
148
149
        $service = explode('_', $service);
150
        $service = array_map('ucfirst', $service);
151
        $service = 'get' . implode('', $service);
152
153
        return $options[$service] = $this->$service($options);
154
    }
155
156
    protected function getLeap(array &$options)
157
    {
158
        $leap = $this->getOptionValueChoice(
159
            $options,
160
            'leap',
161
            $this->leap,
162
            'modern'
163
        );
164
165
        if (!is_object($leap)) {
166
            $leap = new $leap(
167
                $this->getOptionValue($options, 'year_length', 365),
168
                $this->getOptionValue($options, 'era_start_year', 1970)
169
            );
170
        }
171
172
        if ($leap instanceof CompleteLeapYearCalculatorInterface) {
173
            return $leap;
174
        }
175
176
        return new LeapYearCalculator\AgnosticCompleteCalculator(
177
            $leap,
178
            (int)$this->getOptionValue($options, 'year_length', 365),
179
            $this->getOptionValue($options, 'era_start_year', 1970)
180
        );
181
    }
182
183
    protected function getLocale(array &$options)
184
    {
185
        $locale = $this->getOptionValueChoice(
186
            $options,
187
            'locale',
188
            $this->locale,
189
            'native'
190
        );
191
192
        if (is_object($locale)) {
193
            return $locale;
194
        }
195
196
        return new $locale();
197
    }
198
199
    protected function getConverter(array &$options)
200
    {
201
        return new AgnosticConverter(new UnixTimeConverter\Chain([
202
            new UnixTimeConverter\StandardDateFactory(),
203
            new UnixTimeConverter\Date(),
204
            new UnixTimeConverter\TimeOffset(),
205
            $this->get('solar', $options),
206
            $this->get('monthes', $options),
207
            $this->get('week', $options),
208
            $this->get('time', $options),
209
        ]));
210
    }
211
212
    protected function getSolar(array &$options)
213
    {
214
        return new UnixTimeConverter\DateSolar(
215
            $this->get('leap', $options),
216
            $this->getOptionValue($options, 'era_start', 0),
217
            $this->getOptionValue($options, 'day_length', false) ?: null
218
        );
219
    }
220
221
    protected function getMonthes(array &$options)
222
    {
223
        $month = $this->getOptionValueChoice(
224
            $options,
225
            'month',
226
            $this->month,
227
            'gregorian'
228
        );
229
230
        if (is_object($month)) {
231
            return $month;
232
        }
233
234
        if ($month === UnixTimeConverter\EqualLengthMonthes::class) {
235
            return new $month($this->get('leap', $options), $this->getOptionValue($options, 'month_length'));
236
        }
237
238
        return new UnixTimeConverter\GregorianCalendarMonthes($this->get('leap', $options));
239
    }
240
241
    protected function getTime(array &$options)
242
    {
243
        $ranges = $this->getOptionValue($options, 'time_ranges', false) ?: null;
244
245
        if ($ranges === 'duodecimal') {
246
            $ranges = null;
247
        }
248
249
        if ($ranges === 'decimal') {
250
            $ranges = [10, 100, 100, 1000, 1000];
251
        }
252
253
        return new UnixTimeConverter\Time(
254
            $ranges,
255
            $this->getOptionValue($options, 'day_length', false) ?: null
256
        );
257
    }
258
259
    protected function getWeek(array &$options)
260
    {
261
        $week = $this->getOptionValueChoice(
262
            $options,
263
            'week',
264
            $this->week,
265
            'iso'
266
        );
267
268
        if (is_object($week)) {
269
            return $week;
270
        }
271
272
        if ($week === UnixTimeConverter\SimpleWeeks::class) {
273
            return new $week($this->getOptionValue($options, 'week_length'));
274
        }
275
276
        return new UnixTimeConverter\Iso8601Weeks(
277
            $this->get('leap', $options),
278
            $this->getOptionValue($options, 'era_start_day_index', 3)
279
        );
280
    }
281
282
    protected function getNumberConverter(array &$options)
283
    {
284
        $number = $this->getOptionValueChoice(
285
            $options,
286
            'number',
287
            $this->number,
288
            'two_digits'
289
        );
290
291
        if (is_object($number)) {
292
            return $number;
293
        }
294
295
        if ($number === NumberConverter\TwoDigitsYear::class) {
296
            return new $number(
297
                $this->getOptionValue($options, 'number_converter_year', 2000),
298
                $this->getOptionValue($options, 'number_converter_late_fifty', true)
299
            );
300
        }
301
302
        return new $number();
303
    }
304
305
    protected function getSymbolFormatter(array &$options)
306
    {
307
        return new SymbolFormatter\Chain([
308
            new SymbolFormatter\Litteral(),
309
            new SymbolFormatter\StandardDate(),
310
            new SymbolFormatter\StandardDateFragmented($this->get('locale', $options)),
311
            new SymbolFormatter\StandardDateSolar($this->get('number_converter', $options)),
312
            new SymbolFormatter\StandardDateTime(),
313
            new SymbolFormatter\StandardRecursive(),
314
            new SymbolFormatter\Litteral(true),
315
        ]);
316
    }
317
318
    protected function getLexer(array &$options)
319
    {
320
        return new FormatLexer\MbString();
321
    }
322
323
    protected function getFormatter(array &$options)
324
    {
325
        return new AgnosticFormatter(
326
            $this->get('lexer', $options),
327
            $this->get('converter', $options),
328
            $this->get('symbol_formatter', $options)
329
        );
330
    }
331
332
    protected function getMapper(array &$options)
333
    {
334
        return new ResultMapper\Chain([
335
            new ResultMapper\StandardDateFactory(),
336
            new ResultMapper\StandardDate(),
337
            new ResultMapper\StandardDateFragmented(),
338
            new ResultMapper\StandardDateSolar(),
339
            new ResultMapper\StandardDateTime(),
340
        ]);
341
    }
342
343
    protected function getAdditionalSymbolParser(array &$options)
344
    {
345
        $parser = $this->getOptionValueChoice(
346
            $options,
347
            'additional_symbol_parser',
348
            $this->additional_symbol_parser,
349
            'none'
350
        );
351
352
        if (is_object($parser)) {
353
            return $parser;
354
        }
355
356
        if ($parser === false) {
0 ignored issues
show
introduced by
The condition $parser === false can never be true.
Loading history...
357
            return null;
358
        }
359
360
        return new $parser($this->get('number_converter', $options));
361
    }
362
363
    protected function getSymbolParser(array &$options)
364
    {
365
        $chain = [
366
            new SymbolParser\PregNativeDate(),
367
            new SymbolParser\PregNativeRecursive(),
368
            new SymbolParser\PregNativeDateSolar($this->get('number_converter', $options)),
369
            new SymbolParser\PregNativeDateFragmented($this->get('locale', $options)),
370
            new SymbolParser\PregNativeDateTime(),
371
        ];
372
373
        if ($additional = $this->get('additional_symbol_parser', $options)) {
374
            array_unshift($chain, $additional);
375
        }
376
377
        return new SymbolParser\Chain($chain);
378
    }
379
380
    protected function getFormatParser(array &$options)
381
    {
382
        return new FormatParser\PregExtendedNative(
383
            $this->get('lexer', $options),
384
            $this->get('symbol_parser', $options)
385
        );
386
    }
387
388
    protected function getParser(array &$options)
389
    {
390
        return new AgnosticParser(
391
            $this->get('format_parser', $options),
392
            $this->get('mapper', $options),
393
            $this->get('converter', $options)
394
        );
395
    }
396
397
    protected function getOptionValue(array $options, $name, $default = null)
398
    {
399
        if (isset($options[$name])) {
400
            return $options[$name];
401
        }
402
403
        if ($default !== null) {
404
            return $default;
405
        }
406
407
        throw new InvalidArgumentException(sprintf(
408
            '"%s" option is required.',
409
            $name
410
        ));
411
    }
412
413
    protected function getOptionValueChoice(array $options, $name, $list, $default = null)
414
    {
415
        $value = $this->getOptionValue($options, $name, $default);
416
417
        if (is_object($value)) {
418
            return $value;
419
        }
420
421
        if (!isset($list[$value])) {
422
            throw new InvalidArgumentException(sprintf(
423
                'Invalid value "%s" for option "%s". possible values are : %s',
424
                $value,
425
                $name,
426
                implode(', ', array_keys($list))
427
            ));
428
        }
429
430
        return $list[$value];
431
    }
432
}
433