Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.37% covered (success)
97.37%
37 / 38
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
MultiListBuilder
97.37% covered (success)
97.37%
37 / 38
0.00% covered (danger)
0.00%
0 / 1
5
0.00% covered (danger)
0.00%
0 / 1
 buildWeightedTags
97.37% covered (success)
97.37%
37 / 38
0.00% covered (danger)
0.00%
0 / 1
5
1<?php
2
3namespace CirrusSearch\Extra\MultiList;
4
5use Wikimedia\Assert\Assert;
6
7/**
8 * Utility class for encoding weighted tags.
9 *
10 * @see https://wikitech.wikimedia.org/wiki/Search/WeightedTags
11 */
12class MultiListBuilder {
13
14    private const WEIGHTED_TAG_DEFAULT_NAME = 'exists';
15
16    /**
17     * @param string $tagPrefix A prefix shared by all `$tagNames`
18     * @param null|null[]|int[] $tagWeightsByName Optional tag weights. A map of optional weights, keyed by tag name.
19     *   Omit for tags which are fully defined by their prefix.
20     *   A single weight ranges between 1-1000.
21     *
22     * @return MultiListWeightedTag[]
23     */
24    public static function buildWeightedTags(
25        string $tagPrefix,
26        ?array $tagWeightsByName = null
27    ): array {
28        Assert::precondition(
29            trim( $tagPrefix ) !== '',
30            "invalid tag prefix [$tagPrefix]: cannot be empty"
31        );
32        Assert::precondition(
33            strpos( $tagPrefix, MultiListItem::DELIMITER ) === false,
34            "invalid tag prefix $tagPrefix: must not contain " . MultiListItem::DELIMITER
35        );
36
37        Assert::parameterType(
38            [
39                'array',
40                'null'
41            ],
42            $tagWeightsByName,
43            '$tagWeightsByName'
44        );
45
46        if ( $tagWeightsByName === null ) {
47            $tagWeightsByName = [ self::WEIGHTED_TAG_DEFAULT_NAME => null ];
48        }
49
50        foreach ( $tagWeightsByName as $tagName => $tagWeight ) {
51            Assert::precondition(
52                strpos( $tagName, MultiListWeightedTag::WEIGHT_DELIMITER ) === false,
53                "invalid tag name $tagName: must not contain " . MultiListWeightedTag::WEIGHT_DELIMITER
54            );
55            if ( $tagWeight !== null ) {
56                Assert::precondition(
57                    is_int( $tagWeight ),
58                    "weights must be integers but $tagWeight is " . get_debug_type( $tagWeight )
59                );
60                Assert::precondition(
61                    $tagWeight >= 1 && $tagWeight <= 1000,
62                    "weights must be between 1 and 1000 (found: $tagWeight)"
63                );
64            }
65        }
66
67        return array_map(
68            static fn ( $tagName ) => new MultiListWeightedTag(
69                $tagPrefix, $tagName, $tagWeightsByName[$tagName]
70            ),
71            array_keys( $tagWeightsByName )
72        );
73    }
74}