Passed
Push — master ( 388738...0eb3d2 )
by Pierre
06:08
created

ConfigurableFactory::getMapper()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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