Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
PageLinksSearch
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 4
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPageLinks
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 getStoriesLinkingToArticle
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 getPagelinksPageQuery
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\Wikistories;
4
5use MediaWiki\Deferred\LinksUpdate\PageLinksTable;
6use MediaWiki\Linker\LinksMigration;
7use MediaWiki\Linker\LinkTarget;
8use MediaWiki\Title\Title;
9use MediaWiki\Title\TitleValue;
10use Wikimedia\Rdbms\IConnectionProvider;
11use Wikimedia\Rdbms\SelectQueryBuilder;
12
13class PageLinksSearch {
14
15    public function __construct(
16        private readonly IConnectionProvider $connectionProvider,
17        private readonly LinksMigration $linksMigration,
18    ) {
19    }
20
21    /**
22     * Get story page ids linked with target article,
23     * including those stories linked with pre-moved
24     * versions of the target article, as instructed.
25     *
26     * Note that the links in the database are recorded as going
27     * from the story to the article.
28     *
29     * @param string $articleTitle
30     * @param int $limit
31     * @param bool $followRedirects
32     * @return int[] Page ids of the related stories
33     */
34    public function getPageLinks( string $articleTitle, int $limit, bool $followRedirects = true ): array {
35        $tv = new TitleValue( NS_MAIN, $articleTitle );
36        $ids = $this->getStoriesLinkingToArticle( $tv, $limit );
37
38        // It is possible that $articleTitle is a redirect target and stories may
39        // have been created and linked with the previous article name
40        // before the article was moved.
41        if ( $followRedirects ) {
42            $title = Title::newFromText( $articleTitle );
43            $redirectSources = $title->getRedirectsHere( NS_MAIN );
44            foreach ( $redirectSources as $redirectSource ) {
45                $storyIds = $this->getStoriesLinkingToArticle( $redirectSource, $limit );
46                $ids = array_merge( $ids, $storyIds );
47            }
48        }
49
50        return $ids;
51    }
52
53    /**
54     * @param LinkTarget $articleTitle
55     * @param int $limit
56     * @return int[] Story page IDs
57     */
58    private function getStoriesLinkingToArticle( LinkTarget $articleTitle, int $limit ): array {
59        $conds = $this->linksMigration->getLinksConditions( 'pagelinks', $articleTitle );
60        $conds[ 'pl_from_namespace' ] = NS_STORY;
61
62        $query = $this->getPagelinksPageQuery()
63            ->select( 'pl_from' )
64            ->where( $conds )
65            ->orderBy( 'page_touched', 'DESC' )
66            ->limit( $limit )
67            ->caller( __METHOD__ );
68
69        $ids = [];
70        $rows = $query->fetchResultSet();
71        foreach ( $rows as $row ) {
72            $ids[] = $row->pl_from;
73        }
74        return $ids;
75    }
76
77    /**
78     * Build a query for "pagelinks JOIN page ON pl_from=page_id"
79     */
80    private function getPagelinksPageQuery(): SelectQueryBuilder {
81        return $this->connectionProvider
82            ->getReplicaDatabase( PageLinksTable::VIRTUAL_DOMAIN )
83            ->newSelectQueryBuilder()
84            ->queryInfo( $this->linksMigration->getQueryInfo( 'pagelinks' ) )
85            ->join( 'page', null, 'pl_from=page_id' );
86    }
87}