Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
BasicSearchResultSetWidget
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 4
462
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 render
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
306
 header
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 renderResultSet
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace MediaWiki\Search\SearchWidgets;
4
5use ISearchResultSet;
6use MediaWiki\MediaWikiServices;
7use MediaWiki\Message\Message;
8use MediaWiki\Specials\SpecialSearch;
9use MediaWiki\Status\Status;
10
11/**
12 * Renders the search result area. Handles Title and Full-Text search results,
13 * along with inline and sidebar secondary (interwiki) results.
14 */
15class BasicSearchResultSetWidget {
16    /** @var SpecialSearch */
17    protected $specialPage;
18    /** @var SearchResultWidget */
19    protected $resultWidget;
20    /** @var InterwikiSearchResultSetWidget */
21    protected $sidebarWidget;
22
23    public function __construct(
24        SpecialSearch $specialPage,
25        SearchResultWidget $resultWidget,
26        SearchResultSetWidget $sidebarWidget
27    ) {
28        $this->specialPage = $specialPage;
29        $this->resultWidget = $resultWidget;
30        $this->sidebarWidget = $sidebarWidget;
31    }
32
33    /**
34     * @param string $term The search term to highlight
35     * @param int $offset The offset of the first result in the result set
36     * @param ISearchResultSet|null $titleResultSet Results of searching only page titles
37     * @param ISearchResultSet|null $textResultSet Results of general full text search.
38     * @return string HTML
39     */
40    public function render(
41        $term,
42        $offset,
43        ISearchResultSet $titleResultSet = null,
44        ISearchResultSet $textResultSet = null
45    ) {
46        $hasTitle = $titleResultSet && $titleResultSet->numRows() > 0;
47        $hasText = $textResultSet && $textResultSet->numRows() > 0;
48        $hasSecondary =
49            $textResultSet &&
50            $textResultSet->hasInterwikiResults( ISearchResultSet::SECONDARY_RESULTS );
51        $hasSecondaryInline =
52            $textResultSet &&
53            $textResultSet->hasInterwikiResults( ISearchResultSet::INLINE_RESULTS );
54
55        if ( !$hasTitle && !$hasText && !$hasSecondary && !$hasSecondaryInline ) {
56            return '';
57        }
58
59        $out = '<div class="mw-search-results-container">';
60
61        if ( $hasTitle ) {
62            $out .= $this->header( $this->specialPage->msg( 'titlematches' ) )
63                // @phan-suppress-next-line PhanTypeMismatchArgumentNullable titleResultSet is set when used here
64                . $this->renderResultSet( $titleResultSet, $offset );
65        }
66
67        if ( $hasText ) {
68            if ( $hasTitle ) {
69                $out .= "<div class='mw-search-visualclear'></div>" .
70                    $this->header( $this->specialPage->msg( 'textmatches' ) );
71            }
72            // @phan-suppress-next-line PhanTypeMismatchArgumentNullable textResultSet is set when used
73            $out .= $this->renderResultSet( $textResultSet, $offset );
74        }
75
76        if ( $hasSecondaryInline ) {
77            $iwResults = $textResultSet->getInterwikiResults( ISearchResultSet::INLINE_RESULTS );
78            foreach ( $iwResults as $interwiki => $results ) {
79                if ( $results instanceof Status || $results->numRows() === 0 ) {
80                    // ignore bad interwikis for now
81                    continue;
82                }
83                $out .=
84                    "<h2 class='mw-search-interwiki-header mw-search-visualclear'>" .
85                        $this->specialPage->msg( "search-interwiki-results-{$interwiki}" )->parse() .
86                    "</h2>";
87                $out .=
88                    "<div class='mw-search-interwiki-results'>" .
89                        $this->renderResultSet( $results, $offset ) .
90                    "</div>";
91            }
92        }
93
94        // Close <div class='mw-search-results-container'>
95        $out .= '</div>';
96
97        if ( $hasSecondary ) {
98            $out .= $this->sidebarWidget->render(
99                $term,
100                $textResultSet->getInterwikiResults( ISearchResultSet::SECONDARY_RESULTS )
101            );
102        }
103
104        // Convert the whole thing to desired language variant
105        // TODO: Move this up to Special:Search?
106        $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory()
107            ->getLanguageConverter();
108        return $converter->convert( $out );
109    }
110
111    /**
112     * Generate a headline for a section of the search results. In prior
113     * implementations this was rendering wikitext of '==$1==', but seems
114     * a waste to call the full parser to generate this tiny bit of html
115     *
116     * @param Message $msg i18n message to use as header
117     * @return string HTML
118     */
119    protected function header( Message $msg ) {
120        return "<h2>" . $msg->escaped() . "</h2>";
121    }
122
123    /**
124     * @param ISearchResultSet $resultSet The search results to render
125     * @param int $offset Offset of the first result in $resultSet
126     * @return string HTML
127     */
128    protected function renderResultSet( ISearchResultSet $resultSet, $offset ) {
129        $hits = [];
130        foreach ( $resultSet as $result ) {
131            $hits[] = $this->resultWidget->render( $result, $offset++ );
132        }
133
134        return "<ul class='mw-search-results'>" . implode( '', $hits ) . "</ul>";
135    }
136}