Passed
Push — new-api ( 18d26d...074931 )
by Sebastian
04:59
created

Locale::factory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 2.0008

Importance

Changes 0
Metric Value
cc 2
eloc 17
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 20
ccs 16
cts 17
cp 0.9412
crap 2.0008
rs 9.7
1
<?php
2
declare(strict_types=1);
3
/*
4
 * citeproc-php
5
 *
6
 * @link        http://github.com/seboettg/citeproc-php for the source repository
7
 * @copyright   Copyright (c) 2016 Sebastian Böttger.
8
 * @license     https://opensource.org/licenses/MIT
9
 */
10
11
namespace Seboettg\CiteProc\Locale;
12
13
use InvalidArgumentException;
14
use Seboettg\CiteProc\Config\Locale as LocaleConfig;
15
use Seboettg\CiteProc\Exception\CiteProcException;
16
use Seboettg\Collection\ArrayList as ArrayList;
17
use Seboettg\Collection\ArrayList\ArrayListInterface;
18
use SimpleXMLElement;
19
use stdClass;
20
use function Seboettg\CiteProc\loadLocales;
21
22
/**
23
 * Class Locale
24
 *
25
 * While localization data can be included in styles, locale files conveniently provide sets of default localization
26
 * data, consisting of terms, date formats and grammar options. These default localizations are drawn from the
27
 * “locales-xx-XX.xml” located in locales folder (which is included as git submodule). These default locales may be
28
 * redefined or supplemented with cs:locale elements, which should be placed in the style sheet directly after the
29
 * cs:info element.
30
 *
31
 * TODO: implement Locale Fallback (http://docs.citationstyles.org/en/stable/specification.html#locale-fallback)
32
 *
33
 * @package Seboettg\CiteProc\Locale
34
 * @author Sebastian Böttger <[email protected]>
35
 */
36
class Locale
37
{
38
    /** @var SimpleXMLElement */
39
    private $localeXml;
40
41
    /** @var string */
42
    private $language;
43
44
    /** @var ArrayListInterface */
45
    private $options;
46
47
    /** @var ArrayListInterface */
48
    private $date;
49
50
    /** @var ArrayListInterface */
51
    private $terms;
52
53
    /** @var ArrayListInterface */
54
    private $optionsXml;
55
56
    /** @var ArrayListInterface */
57
    private $dateXml;
58
59
    /** @var ArrayListInterface */
60
    private $termsXml;
61
62
    /** @var LocaleParser */
63
    private $localeParser;
64
65
    /**
66
     * @param LocaleConfig $localeConfig
67
     * @param null $xmlString
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $xmlString is correct as it would always require null to be passed?
Loading history...
68
     * @return Locale
69
     * @throws CiteProcException
70
     */
71 184
    public static function factory(LocaleConfig $localeConfig, $xmlString = null): Locale
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$xmlString" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$xmlString"; expected 0 but found 1
Loading history...
72
    {
73 184
        $language = (string)$localeConfig;
74 184
        if (!empty($xmlString)) {
75
            $localeXml = new SimpleXMLElement($xmlString);
76
        } else {
77 184
            $localeXml = new SimpleXMLElement(loadLocales((string)$localeConfig));
78
        }
79 184
        $localeParser = new LocaleParser();
80 184
        list($options, $optionsXml, $date, $dateXml, $terms, $termsXml) = $localeParser->parse($localeXml);
81 184
        return new Locale(
82 184
            $localeParser,
83 184
            $localeXml,
84 184
            $language,
85 184
            $options,
86 184
            $optionsXml,
87 184
            $date,
88 184
            $dateXml,
89 184
            $terms,
90 184
            $termsXml
91
        );
92
    }
93
94
    /**
95
     * Locale constructor.
96
     * @param LocaleParser $localeParser
97
     * @param SimpleXMLElement $localeXml
98
     * @param string $language
99
     * @param ArrayListInterface $options
100
     * @param ArrayListInterface $optionsXml
101
     * @param ArrayListInterface $date
102
     * @param ArrayListInterface $dateXml
103
     * @param ArrayListInterface $terms
104
     * @param ArrayListInterface $termsXml
105
     */
106 184
    public function __construct(
107
        LocaleParser $localeParser,
108
        SimpleXMLElement $localeXml,
109
        string $language,
110
        ArrayListInterface $options,
111
        ArrayListInterface $optionsXml,
112
        ArrayListInterface $date,
113
        ArrayListInterface $dateXml,
114
        ArrayListInterface $terms,
115
        ArrayListInterface $termsXml
116
    ) {
117 184
        $this->localeParser = $localeParser;
118 184
        $this->localeXml = $localeXml;
119 184
        $this->language = $language;
120 184
        $this->options = $options;
121 184
        $this->optionsXml = $optionsXml;
122 184
        $this->date = $date;
123 184
        $this->dateXml = $dateXml;
124 184
        $this->terms = $terms;
125 184
        $this->termsXml = $termsXml;
126 184
    }
127
128
    /**
129
     * @param SimpleXMLElement $xml
130
     * @return $this
131
     */
132 54
    public function addXml(SimpleXMLElement $xml): Locale
133
    {
134 54
        $lang = (string) $xml->attributes('http://www.w3.org/XML/1998/namespace')->{'lang'};
135 54
        if (empty($lang) || $this->getLanguage() === $lang || explode('-', $this->getLanguage())[0] === $lang) {
136 51
            list($this->options, $this->optionsXml, $this->date, $this->dateXml, $this->terms, $this->termsXml) =
137 51
                $this->localeParser->parse(
138 51
                    $xml,
139 51
                    $this->options,
140 51
                    $this->optionsXml,
141 51
                    $this->date,
142 51
                    $this->dateXml,
143 51
                    $this->terms,
144 51
                    $this->termsXml
145
                );
146
        }
147 54
        return $this;
148
    }
149
150
    /**
151
     * @return string
152
     */
153 37
    public function getLanguage(): string
154
    {
155 37
        return $this->language;
156
    }
157
158
    /**
159
     * @param string $type
160
     * @param $name
161
     * @param string $form
162
     * @return stdClass|null|bool
163
     */
164 184
    public function filter(string $type, $name, string $form = "long")
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$form" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$form"; expected 0 but found 1
Loading history...
165
    {
166 184
        if ('options' === $type) {
167 183
            return $this->option($name);
168
        }
169 184
        if (!isset($this->{$type})) {
170
            throw new InvalidArgumentException("There is no locale of type \"$type\".");
171
        }
172
173
        /** @var ArrayList $localeList */
174 184
        $localeList = $this->{$type};
175
176 184
        if (is_null($name)) {
177
            $name = "";
178
        }
179
180
        //filter by name
181 184
        $array = $localeList->get($name);
182
183 184
        if (empty($array)) {
184 32
            $ret = new stdClass();
185 32
            $ret->name = null;
186 32
            $ret->single = null;
187 32
            $ret->multiple = null;
188 32
            return $ret;
189
        }
190
191
        //filter by form
192 184
        if ($type !== "options") {
193
            /** @var Term $value */
194
            $array = array_filter($array, function ($term) use ($form) {
195 184
                return $term->form === $form;
196 184
            });
197
        }
198
199 184
        return array_pop($array);
200
    }
201
202 183
    private function option($name)
203
    {
204 183
        $result = null;
205 183
        foreach ($this->options as $key => $value) {
206 183
            if ($key === $name) {
207 183
                if (is_array($value) && isset($value[1]) && is_array($value[1])) {
208 5
                    $result = reset($value[1]);
209
                } else {
210 183
                    $result = reset($value);
211
                }
212
            }
213
        }
214 183
        return $result;
215
    }
216
217
    /**
218
     * @return ArrayListInterface
219
     */
220 17
    public function getDateXml(): ?ArrayListInterface
221
    {
222 17
        return $this->dateXml;
223
    }
224
}
225