Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
ReverseInterwikiLookup
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
4 / 4
13
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 lookup
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
5
 getPrefixTable
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
5
 getDomain
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace MediaWiki\Extension\ReadingLists;
4
5use MediaWiki\Interwiki\InterwikiLookup;
6use MediaWiki\Languages\LanguageNameUtils;
7use MediaWiki\Utils\UrlUtils;
8
9/**
10 * Service for turning domain names into interwiki prefixes.
11 * Assumes a domain name structure somewhat similar to Wikimedia.
12 */
13class ReverseInterwikiLookup implements ReverseInterwikiLookupInterface {
14
15    /** @var string */
16    private $ownDomain;
17
18    /** @var string[] domain name => iw prefix */
19    private $prefixTable;
20
21    /**
22     * @param InterwikiLookup $interwikiLookup
23     * @param LanguageNameUtils $languageNameUtils
24     * @param UrlUtils $urlUtils
25     * @param string $ownDomain
26     */
27    public function __construct(
28        private readonly InterwikiLookup $interwikiLookup,
29        private readonly LanguageNameUtils $languageNameUtils,
30        private readonly UrlUtils $urlUtils,
31        $ownDomain
32    ) {
33        $this->ownDomain = $this->getDomain( $ownDomain );
34    }
35
36    /**
37     * @inheritDoc
38     */
39    public function lookup( $domain ) {
40        $prefixTable = $this->getPrefixTable();
41        $domain = $this->getDomain( $domain );
42
43        if ( $domain === $this->ownDomain ) {
44            return '';
45        }
46
47        if ( array_key_exists( $domain, $prefixTable ) ) {
48            return $prefixTable[$domain];
49        }
50
51        $domainParts = explode( '.', $domain );
52        $targetLang = $domainParts[0];
53        if ( !$this->languageNameUtils->isValidCode( $targetLang ) ) {
54            return null;
55        }
56        $ownDomainParts = explode( '.', $this->ownDomain );
57        $intermediateDomainParts = $domainParts;
58        array_splice( $intermediateDomainParts, 0, 1, $ownDomainParts[0] );
59        $intermediateDomain = implode( '.', $intermediateDomainParts );
60        if ( array_key_exists( $intermediateDomain, $prefixTable ) ) {
61            return [ $prefixTable[$intermediateDomain], $targetLang ];
62        }
63
64        return null;
65    }
66
67    /**
68     * Gets (and caches) interwiki data from the core database.
69     * @return string[] Domain name => interwiki prefix
70     */
71    protected function getPrefixTable() {
72        if ( $this->prefixTable === null ) {
73            $this->prefixTable = [];
74            $iwData = $this->interwikiLookup->getAllPrefixes( true );
75            foreach ( $iwData as $iwRow ) {
76                $url = $this->urlUtils->parse( $iwRow['iw_url'] );
77                if ( !$url || !$url['host'] ) {
78                    continue;
79                }
80                $this->prefixTable[$url['host']] = $iwRow['iw_prefix'];
81            }
82        }
83        return $this->prefixTable;
84    }
85
86    /**
87     * Get the domain part of a domain or URL.
88     * @param string $domainOrUrl
89     * @return string
90     */
91    protected function getDomain( $domainOrUrl ) {
92        $parts = $this->urlUtils->parse( $domainOrUrl );
93        if ( empty( $parts['host'] ) ) {
94            // assume it's just a bare domain name
95            return $domainOrUrl;
96        }
97        return $parts['host'];
98    }
99
100}