Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
48.28% covered (danger)
48.28%
14 / 29
50.00% covered (danger)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
WikifunctionsCallDefaultValues
48.28% covered (danger)
48.28%
14 / 29
50.00% covered (danger)
50.00%
3 / 6
41.12
0.00% covered (danger)
0.00%
0 / 1
 getDefaultValueCallbacks
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 hasDefaultValueCallback
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultValueForType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultLanguage
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
3.33
 getDefaultDate
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
3.07
 getWikidataItem
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2/**
3 * WikiLambda extension handler for default (empty) values for our parser function
4 *
5 * @file
6 * @ingroup Extensions
7 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
8 * @license MIT
9 */
10
11namespace MediaWiki\Extension\WikiLambda\ParserFunction;
12
13use DateTime;
14use DateTimeZone;
15use MediaWiki\Parser\ParserOutput;
16use MediaWiki\Registration\ExtensionRegistry;
17use MediaWiki\Title\Title;
18use Wikimedia\Parsoid\Core\LinkTarget;
19
20class WikifunctionsCallDefaultValues {
21
22    /**
23     * Returns the map of type IDs to default value callbacks.
24     * Each callback should return a default value for the given type.
25     *
26     * To add default values for other types:
27     * 1. Add a new entry in the returned array with the type zid
28     *    as the index, and a callable as its value.
29     * 2. The callable can be an anonymous function or a public static
30     *       named function, which should be implemented below.
31     *
32     * @return array
33     */
34    private static function getDefaultValueCallbacks(): array {
35        return [
36            'Z60' => [ self::class, 'getDefaultLanguage' ],
37            'Z6001' => [ self::class, 'getWikidataItem' ],
38            'Z6091' => [ self::class, 'getWikidataItem' ],
39            'Z20420' => [ self::class, 'getDefaultDate' ],
40        ];
41    }
42
43    /**
44     * Checks whether a default value callback exists for a given type.
45     *
46     * @param string $type
47     * @return bool
48     */
49    public static function hasDefaultValueCallback( string $type ): bool {
50        return array_key_exists( $type, self::getDefaultValueCallbacks() );
51    }
52
53    /**
54     * Returns a callable that provides a default value for the given type.
55     *
56     * @param string $type
57     * @return callable|null
58     */
59    public static function getDefaultValueForType( string $type ): ?callable {
60        return self::getDefaultValueCallbacks()[ $type ] ?? null;
61    }
62
63    // Callables for each type:
64
65    /**
66     * Default Value Callable for Language/Z60:
67     * Returns the language of the page
68     *
69     * @param array $context
70     * @return string
71     */
72    public static function getDefaultLanguage( array $context = [] ): string {
73        // Context doesn't have the info of the page language; return empty string
74        if ( !isset( $context['pageLanguage'] ) || $context['pageLanguage'] === '' ) {
75            return '';
76        }
77        // Return page language Bcp47 code, FunctionCallHandler will convert it to zid
78        return $context[ 'pageLanguage' ];
79    }
80
81    /**
82     * Default Value Callable for Date/Z20420:
83     * Returns today's date in the current locale in the format 'dd-mm-yyyy'
84     *
85     * @param array $context
86     * @return string
87     */
88    public static function getDefaultDate( array $context = [] ): string {
89        global $wgLocaltimezone;
90
91        $cmc = $context['contentMetadataCollector'] ?? null;
92        // In some test cases, $cmc will be a StubMetadataCollector rather than a ParserOutput, so we can't do this
93        if ( $cmc && $cmc instanceof ParserOutput ) {
94            // Make sure our fragment's cache expiry is set to at most 24 hours, as we're adding
95            // a one-day-variant piece of content.
96            $cmc->updateRuntimeAdaptiveExpiry( 24 * 60 * 60 );
97        }
98
99        $date = new DateTime( 'now', new DateTimeZone( $wgLocaltimezone ?? 'UTC' ) );
100        return $date->format( 'd-m-Y' );
101    }
102
103    /**
104     * Default Value Callable for Wikidata Item/Z6001 and Wikidata Item Reference/Z6091
105     * Returns the Wikidata Item ID linked to the client page
106     *
107     * @param array $context
108     * @return string
109     */
110    public static function getWikidataItem( array $context = [] ): string {
111        // Context doesn't have info of the page title; return empty string
112        if ( !isset( $context['linkTarget'] ) ||
113            !( $context['linkTarget'] instanceof LinkTarget ) ) {
114            return '';
115        }
116
117        // The extension doesn't have WikibaseClient loaded; return empty string
118        if ( !ExtensionRegistry::getInstance()->isLoaded( 'WikibaseClient' ) ) {
119            return '';
120        }
121
122        $prefixedTitle = Title::newFromLinkTarget( $context['linkTarget'] )->getPrefixedText();
123        $wbSiteLinkLookup = \Wikibase\Client\WikibaseClient::getStore()->getSiteLinkLookup();
124        $wbClientSettings = \Wikibase\Client\WikibaseClient::getSettings();
125
126        $clientSiteGlobalID = $wbClientSettings->getSetting( 'siteGlobalID' );
127        $entityId = $wbSiteLinkLookup->getItemIdForLink( $clientSiteGlobalID, $prefixedTitle );
128
129        // No linked wikidata item; return empty string
130        if ( !$entityId ) {
131            return '';
132        }
133
134        // Success, return default value wikidata item ID; E.g. Q42
135        return $entityId->getSerialization();
136    }
137}