Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
43.48% covered (danger)
43.48%
10 / 23
CRAP
85.80% covered (warning)
85.80%
145 / 169
ConfigurableFactory
0.00% covered (danger)
0.00%
0 / 1
43.48% covered (danger)
43.48%
10 / 23
52.06
85.80% covered (warning)
85.80%
145 / 169
 build
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 buildFormatter
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 buildParser
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 buildConverter
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 get
0.00% covered (danger)
0.00%
0 / 1
3.04
83.33% covered (warning)
83.33%
5 / 6
 getLeap
0.00% covered (danger)
0.00%
0 / 1
3.00
94.44% covered (success)
94.44%
17 / 18
 getLocale
0.00% covered (danger)
0.00%
0 / 1
2.01
87.50% covered (warning)
87.50%
7 / 8
 getConverter
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
9 / 9
 getSolar
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
5 / 5
 getMonthes
0.00% covered (danger)
0.00%
0 / 1
3.01
90.00% covered (success)
90.00%
9 / 10
 getTime
0.00% covered (danger)
0.00%
0 / 1
6.20
63.64% covered (warning)
63.64%
7 / 11
 getWeek
0.00% covered (danger)
0.00%
0 / 1
3.00
92.31% covered (success)
92.31%
12 / 13
 getNumberConverter
0.00% covered (danger)
0.00%
0 / 1
3.00
92.31% covered (success)
92.31%
12 / 13
 getSymbolFormatter
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
9 / 9
 getLexer
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getFormatter
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
5 / 5
 getMapper
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
7 / 7
 getAdditionalSymbolParser
0.00% covered (danger)
0.00%
0 / 1
3.01
90.00% covered (success)
90.00%
9 / 10
 getSymbolParser
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
10 / 10
 getFormatParser
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 getParser
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
5 / 5
 getOptionValue
0.00% covered (danger)
0.00%
0 / 1
3.71
57.14% covered (warning)
57.14%
4 / 7
 getOptionValueChoice
0.00% covered (danger)
0.00%
0 / 1
5.32
36.36% covered (danger)
36.36%
4 / 11
<?php
namespace Popy\Calendar\Factory;
use InvalidArgumentException;
use Popy\Calendar\Calendar\ComposedCalendar;
use Popy\Calendar\Converter\AgnosticConverter;
use Popy\Calendar\Converter\UnixTimeConverter;
use Popy\Calendar\Converter\LeapYearCalculator;
use Popy\Calendar\Converter\CompleteLeapYearCalculatorInterface;
use Popy\Calendar\Formatter\Localisation;
use Popy\Calendar\Formatter\SymbolFormatter;
use Popy\Calendar\Formatter\NumberConverter;
use Popy\Calendar\Formatter\AgnosticFormatter;
use Popy\Calendar\Parser\AgnosticParser;
use Popy\Calendar\Parser\ResultMapper;
use Popy\Calendar\Parser\FormatLexer;
use Popy\Calendar\Parser\FormatParser;
use Popy\Calendar\Parser\SymbolParser;
class ConfigurableFactory
{
    /**
     * Available values for option "leap".
     *
     * @var array<string>
     */
    protected $leap = [
        'noleap' => LeapYearCalculator\NoLeap::class,
        'none'   => LeapYearCalculator\NoLeap::class,
        'julian' => LeapYearCalculator\Caesar::class,
        'caesar' => LeapYearCalculator\Caesar::class,
        'modern'    => LeapYearCalculator\Modern::class,
        'gregorian' => LeapYearCalculator\Modern::class,
        'futuristic' => LeapYearCalculator\Futuristic::class,
        'persian' => LeapYearCalculator\Persian::class,
        'hijri'   => LeapYearCalculator\Persian::class,
        'von_madler' => LeapYearCalculator\VonMadler::class,
        'float' => LeapYearCalculator\FloatBased::class,
    ];
    /**
     * Available values for option "locale".
     *
     * @var array<string>
     */
    protected $locale = [
        'native' => Localisation\NativeHardcoded::class,
    ];
    /**
     * Available values for option "month"
     *
     * @var array<string>
     */
    protected $month = [
        'gregorian' => UnixTimeConverter\GregorianCalendarMonthes::class,
        'equal_length' => UnixTimeConverter\EqualLengthMonthes::class,
    ];
    /**
     * Available values for option "week"
     *
     * @var array<string>
     */
    protected $week = [
        'iso' => UnixTimeConverter\Iso8601Weeks::class,
        'simple' => UnixTimeConverter\SimpleWeeks::class,
    ];
    /**
     * Available values for option "number"
     *
     * @var array<string>
     */
    protected $number = [
        'two_digits' => NumberConverter\TwoDigitsYear::class,
        'roman' => NumberConverter\Roman::class,
        'rfc2550' => NumberConverter\RFC2550::class,
    ];
    /**
     * Available values for option "additional_symbol_parser"
     *
     * @var array<string>
     */
    protected $additional_symbol_parser = [
        'none'    => false,
        'rfc2550' => SymbolParser\PregNativeRFC2550::class,
    ];
    /**
     * Builds a gregorian calendar.
     *
     * @return ComposedCalendar
     */
    public function build(array $options = array())
    {
        return new ComposedCalendar(
            $this->get('formatter', $options),
            $this->get('parser', $options)
        );
    }
    /**
     * Builds a date formatter.
     *
     * @return AgnosticFormatter
     */
    public function buildFormatter(array $options = array())
    {
        return $this->get('formatter', $options);
    }
    /**
     * Builds a date formatter.
     *
     * @return AgnosticParser
     */
    public function buildParser(array $options = array())
    {
        return $this->get('parser', $options);
    }
    /**
     * Builds a date converter.
     *
     * @return AgnosticConverter
     */
    public function buildConverter(array $options = array())
    {
        return $this->get('converter', $options);
    }
    /**
     * Generic service getter.
     *
     * @param string $service  Service name.
     * @param array  &$options Option array
     *
     * @return mixed
     */
    protected function get($service, array &$options)
    {
        if (isset($options[$service]) && is_object($options[$service])) {
            return $options[$service];
        }
        $service = explode('_', $service);
        $service = array_map('ucfirst', $service);
        $service = 'get' . implode('', $service);
        return $options[$service] = $this->$service($options);
    }
    protected function getLeap(array &$options)
    {
        $leap = $this->getOptionValueChoice(
            $options,
            'leap',
            $this->leap,
            'modern'
        );
        if (!is_object($leap)) {
            $leap = new $leap(
                $this->getOptionValue($options, 'year_length', 365),
                $this->getOptionValue($options, 'era_start_year', 1970)
            );
        }
        if ($leap instanceof CompleteLeapYearCalculatorInterface) {
            return $leap;
        }
        return new LeapYearCalculator\AgnosticCompleteCalculator(
            $leap,
            (int)$this->getOptionValue($options, 'year_length', 365),
            $this->getOptionValue($options, 'era_start_year', 1970)
        );
    }
    protected function getLocale(array &$options)
    {
        $locale = $this->getOptionValueChoice(
            $options,
            'locale',
            $this->locale,
            'native'
        );
        if (is_object($locale)) {
            return $locale;
        }
        return new $locale();
    }
    protected function getConverter(array &$options)
    {
        return new AgnosticConverter(new UnixTimeConverter\Chain([
            new UnixTimeConverter\StandardDateFactory(),
            new UnixTimeConverter\Date(),
            new UnixTimeConverter\TimeOffset(),
            $this->get('solar', $options),
            $this->get('monthes', $options),
            $this->get('week', $options),
            $this->get('time', $options),
        ]));
    }
    protected function getSolar(array &$options)
    {
        return new UnixTimeConverter\DateSolar(
            $this->get('leap', $options),
            $this->getOptionValue($options, 'era_start', 0),
            $this->getOptionValue($options, 'day_length', false) ?: null
        );
    }
    protected function getMonthes(array &$options)
    {
        $month = $this->getOptionValueChoice(
            $options,
            'month',
            $this->month,
            'gregorian'
        );
        if (is_object($month)) {
            return $month;
        }
        if ($month === UnixTimeConverter\EqualLengthMonthes::class) {
            return new $month($this->get('leap', $options), $this->getOptionValue($options, 'month_length'));
        }
        return new UnixTimeConverter\GregorianCalendarMonthes($this->get('leap', $options));
    }
    protected function getTime(array &$options)
    {
        $ranges = $this->getOptionValue($options, 'time_ranges', false) ?: null;
        if ($ranges === 'duodecimal') {
            $ranges = null;
        }
        if ($ranges === 'decimal') {
            $ranges = [10, 100, 100, 1000, 1000];
        }
        return new UnixTimeConverter\Time(
            $ranges,
            $this->getOptionValue($options, 'day_length', false) ?: null
        );
    }
    protected function getWeek(array &$options)
    {
        $week = $this->getOptionValueChoice(
            $options,
            'week',
            $this->week,
            'iso'
        );
        if (is_object($week)) {
            return $week;
        }
        if ($week === UnixTimeConverter\SimpleWeeks::class) {
            return new $week($this->getOptionValue($options, 'week_length'));
        }
        return new UnixTimeConverter\Iso8601Weeks(
            $this->get('leap', $options),
            $this->getOptionValue($options, 'era_start_day_index', 3)
        );
    }
    protected function getNumberConverter(array &$options)
    {
        $number = $this->getOptionValueChoice(
            $options,
            'number',
            $this->number,
            'two_digits'
        );
        if (is_object($number)) {
            return $number;
        }
        if ($number === NumberConverter\TwoDigitsYear::class) {
            return new $number(
                $this->getOptionValue($options, 'number_converter_year', 2000),
                $this->getOptionValue($options, 'number_converter_late_fifty', true)
            );
        }
        return new $number();
    }
    protected function getSymbolFormatter(array &$options)
    {
        return new SymbolFormatter\Chain([
            new SymbolFormatter\Litteral(),
            new SymbolFormatter\StandardDate(),
            new SymbolFormatter\StandardDateFragmented($this->get('locale', $options)),
            new SymbolFormatter\StandardDateSolar($this->get('number_converter', $options)),
            new SymbolFormatter\StandardDateTime(),
            new SymbolFormatter\StandardRecursive(),
            new SymbolFormatter\Litteral(true),
        ]);
    }
    protected function getLexer(array &$options)
    {
        return new FormatLexer\MbString();
    }
    protected function getFormatter(array &$options)
    {
        return new AgnosticFormatter(
            $this->get('lexer', $options),
            $this->get('converter', $options),
            $this->get('symbol_formatter', $options)
        );
    }
    protected function getMapper(array &$options)
    {
        return new ResultMapper\Chain([
            new ResultMapper\StandardDateFactory(),
            new ResultMapper\StandardDate(),
            new ResultMapper\StandardDateFragmented(),
            new ResultMapper\StandardDateSolar(),
            new ResultMapper\StandardDateTime(),
        ]);
    }
    protected function getAdditionalSymbolParser(array &$options)
    {
        $parser = $this->getOptionValueChoice(
            $options,
            'additional_symbol_parser',
            $this->additional_symbol_parser,
            'none'
        );
        if (is_object($parser)) {
            return $parser;
        }
        if ($parser === false) {
            return null;
        }
        return new $parser($this->get('number_converter', $options));
    }
    protected function getSymbolParser(array &$options)
    {
        $chain = [
            new SymbolParser\PregNativeDate(),
            new SymbolParser\PregNativeRecursive(),
            new SymbolParser\PregNativeDateSolar($this->get('number_converter', $options)),
            new SymbolParser\PregNativeDateFragmented($this->get('locale', $options)),
            new SymbolParser\PregNativeDateTime(),
        ];
        if ($additional = $this->get('additional_symbol_parser', $options)) {
            array_unshift($chain, $additional);
        }
        return new SymbolParser\Chain($chain);
    }
    protected function getFormatParser(array &$options)
    {
        return new FormatParser\PregExtendedNative(
            $this->get('lexer', $options),
            $this->get('symbol_parser', $options)
        );
    }
    protected function getParser(array &$options)
    {
        return new AgnosticParser(
            $this->get('format_parser', $options),
            $this->get('mapper', $options),
            $this->get('converter', $options)
        );
    }
    protected function getOptionValue(array $options, $name, $default = null)
    {
        if (isset($options[$name])) {
            return $options[$name];
        }
        if ($default !== null) {
            return $default;
        }
        throw new InvalidArgumentException(sprintf(
            '"%s" option is required.',
            $name
        ));
    }
    protected function getOptionValueChoice(array $options, $name, $list, $default = null)
    {
        $value = $this->getOptionValue($options, $name, $default);
        if (is_object($value)) {
            return $value;
        }
        if (!isset($list[$value])) {
            throw new InvalidArgumentException(sprintf(
                'Invalid value "%s" for option "%s". possible values are : %s',
                $value,
                $name,
                implode(', ', array_keys($list))
            ));
        }
        return $list[$value];
    }
}