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