Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
CollationFactory
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 5
90
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getCategoryCollation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultCollationName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 makeCollation
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
30
 instantiateCollation
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 * http://www.gnu.org/copyleft/gpl.html
18 *
19 * @file
20 */
21
22namespace MediaWiki\Collation;
23
24use Collation;
25use InvalidArgumentException;
26use MediaWiki\Config\ServiceOptions;
27use MediaWiki\HookContainer\HookContainer;
28use MediaWiki\HookContainer\HookRunner;
29use MediaWiki\MainConfigNames;
30use Wikimedia\ObjectFactory\ObjectFactory;
31
32/**
33 * Common factory to construct collation classes.
34 *
35 * @since 1.37
36 */
37class CollationFactory {
38    /**
39     * @internal For use by ServiceWiring
40     */
41    public const CONSTRUCTOR_OPTIONS = [
42        MainConfigNames::CategoryCollation,
43    ];
44
45    private const CORE_COLLATIONS = [
46        'uppercase' => [
47            'class' => \UppercaseCollation::class,
48            'services' => [
49                'LanguageFactory',
50            ]
51        ],
52        'numeric' => [
53            'class' => \NumericUppercaseCollation::class,
54            'services' => [
55                'LanguageFactory',
56                'ContentLanguage',
57            ]
58        ],
59        'identity' => [
60            'class' => \IdentityCollation::class,
61            'services' => [
62                'ContentLanguage',
63            ]
64        ],
65        'uca-default' => [
66            'class' => \IcuCollation::class,
67            'services' => [
68                'LanguageFactory',
69            ],
70            'args' => [
71                'root',
72            ]
73        ],
74        'uca-default-u-kn' => [
75            'class' => \IcuCollation::class,
76            'services' => [
77                'LanguageFactory',
78            ],
79            'args' => [
80                'root-u-kn',
81            ]
82        ],
83        'xx-uca-ckb' => [
84            'class' => \CollationCkb::class,
85            'services' => [
86                'LanguageFactory',
87            ]
88        ],
89        'uppercase-ab' => [
90            'class' => \AbkhazUppercaseCollation::class,
91            'services' => [
92                'LanguageFactory',
93            ]
94        ],
95        'uppercase-ba' => [
96            'class' => \BashkirUppercaseCollation::class,
97            'services' => [
98                'LanguageFactory',
99            ]
100        ],
101    ];
102
103    /** @var ServiceOptions */
104    private $options;
105
106    /** @var ObjectFactory */
107    private $objectFactory;
108
109    /** @var HookRunner */
110    private $hookRunner;
111
112    /**
113     * @param ServiceOptions $options
114     * @param ObjectFactory $objectFactory
115     * @param HookContainer $hookContainer
116     */
117    public function __construct(
118        ServiceOptions $options,
119        ObjectFactory $objectFactory,
120        HookContainer $hookContainer
121    ) {
122        $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
123        $this->options = $options;
124        $this->objectFactory = $objectFactory;
125        $this->hookRunner = new HookRunner( $hookContainer );
126    }
127
128    /**
129     * @return Collation
130     */
131    public function getCategoryCollation(): Collation {
132        return $this->makeCollation( $this->getDefaultCollationName() );
133    }
134
135    public function getDefaultCollationName(): string {
136        return $this->options->get( MainConfigNames::CategoryCollation );
137    }
138
139    /**
140     * @param string $collationName
141     * @return Collation
142     */
143    public function makeCollation( string $collationName ): Collation {
144        if ( isset( self::CORE_COLLATIONS[$collationName] ) ) {
145            return $this->instantiateCollation( self::CORE_COLLATIONS[$collationName] );
146        }
147
148        if ( preg_match( '/^uca-([A-Za-z@=-]+)$/', $collationName, $match ) ) {
149            return $this->instantiateCollation( [
150                'class' => \IcuCollation::class,
151                'services' => [
152                    'LanguageFactory',
153                ],
154                'args' => [
155                    $match[1],
156                ]
157            ] );
158        } elseif ( preg_match( '/^remote-uca-([A-Za-z@=-]+)$/', $collationName, $match ) ) {
159            return $this->instantiateCollation( [
160                'class' => \RemoteIcuCollation::class,
161                'services' => [
162                    'ShellboxClientFactory'
163                ],
164                'args' => [
165                    $match[1]
166                ]
167            ] );
168        }
169
170        // Provide a mechanism for extensions to hook in.
171        $collationObject = null;
172        $this->hookRunner->onCollation__factory( $collationName, $collationObject );
173
174        if ( !$collationObject instanceof Collation ) {
175            throw new InvalidArgumentException( __METHOD__ . ": unknown collation type \"$collationName\"" );
176        }
177
178        return $collationObject;
179    }
180
181    /**
182     * @param array $spec
183     * @return Collation
184     */
185    private function instantiateCollation( $spec ): Collation {
186        return $this->objectFactory->createObject(
187            $spec,
188            [
189                'assertClass' => Collation::class
190            ]
191        );
192    }
193
194}