wikimedia/mediawiki-core

View on GitHub
includes/search/searchwidgets/BasicSearchResultSetWidget.php

Summary

Maintainability
B
4 hrs
Test Coverage
<?php

namespace MediaWiki\Search\SearchWidgets;

use ISearchResultSet;
use MediaWiki\MediaWikiServices;
use MediaWiki\Message\Message;
use MediaWiki\Specials\SpecialSearch;
use MediaWiki\Status\Status;

/**
 * Renders the search result area. Handles Title and Full-Text search results,
 * along with inline and sidebar secondary (interwiki) results.
 */
class BasicSearchResultSetWidget {
    /** @var SpecialSearch */
    protected $specialPage;
    /** @var SearchResultWidget */
    protected $resultWidget;
    /** @var InterwikiSearchResultSetWidget */
    protected $sidebarWidget;

    public function __construct(
        SpecialSearch $specialPage,
        SearchResultWidget $resultWidget,
        SearchResultSetWidget $sidebarWidget
    ) {
        $this->specialPage = $specialPage;
        $this->resultWidget = $resultWidget;
        $this->sidebarWidget = $sidebarWidget;
    }

    /**
     * @param string $term The search term to highlight
     * @param int $offset The offset of the first result in the result set
     * @param ISearchResultSet|null $titleResultSet Results of searching only page titles
     * @param ISearchResultSet|null $textResultSet Results of general full text search.
     * @return string HTML
     */
    public function render(
        $term,
        $offset,
        ISearchResultSet $titleResultSet = null,
        ISearchResultSet $textResultSet = null
    ) {
        $hasTitle = $titleResultSet && $titleResultSet->numRows() > 0;
        $hasText = $textResultSet && $textResultSet->numRows() > 0;
        $hasSecondary =
            $textResultSet &&
            $textResultSet->hasInterwikiResults( ISearchResultSet::SECONDARY_RESULTS );
        $hasSecondaryInline =
            $textResultSet &&
            $textResultSet->hasInterwikiResults( ISearchResultSet::INLINE_RESULTS );

        if ( !$hasTitle && !$hasText && !$hasSecondary && !$hasSecondaryInline ) {
            return '';
        }

        $out = '<div class="mw-search-results-container">';

        if ( $hasTitle ) {
            $out .= $this->header( $this->specialPage->msg( 'titlematches' ) )
                // @phan-suppress-next-line PhanTypeMismatchArgumentNullable titleResultSet is set when used here
                . $this->renderResultSet( $titleResultSet, $offset );
        }

        if ( $hasText ) {
            if ( $hasTitle ) {
                $out .= "<div class='mw-search-visualclear'></div>" .
                    $this->header( $this->specialPage->msg( 'textmatches' ) );
            }
            // @phan-suppress-next-line PhanTypeMismatchArgumentNullable textResultSet is set when used
            $out .= $this->renderResultSet( $textResultSet, $offset );
        }

        if ( $hasSecondaryInline ) {
            $iwResults = $textResultSet->getInterwikiResults( ISearchResultSet::INLINE_RESULTS );
            foreach ( $iwResults as $interwiki => $results ) {
                if ( $results instanceof Status || $results->numRows() === 0 ) {
                    // ignore bad interwikis for now
                    continue;
                }
                $out .=
                    "<h2 class='mw-search-interwiki-header mw-search-visualclear'>" .
                        $this->specialPage->msg( "search-interwiki-results-{$interwiki}" )->parse() .
                    "</h2>";
                $out .=
                    "<div class='mw-search-interwiki-results'>" .
                        $this->renderResultSet( $results, $offset ) .
                    "</div>";
            }
        }

        // Close <div class='mw-search-results-container'>
        $out .= '</div>';

        if ( $hasSecondary ) {
            $out .= $this->sidebarWidget->render(
                $term,
                $textResultSet->getInterwikiResults( ISearchResultSet::SECONDARY_RESULTS )
            );
        }

        // Convert the whole thing to desired language variant
        // TODO: Move this up to Special:Search?
        $converter = MediaWikiServices::getInstance()->getLanguageConverterFactory()
            ->getLanguageConverter();
        return $converter->convert( $out );
    }

    /**
     * Generate a headline for a section of the search results. In prior
     * implementations this was rendering wikitext of '==$1==', but seems
     * a waste to call the full parser to generate this tiny bit of html
     *
     * @param Message $msg i18n message to use as header
     * @return string HTML
     */
    protected function header( Message $msg ) {
        return "<h2>" . $msg->escaped() . "</h2>";
    }

    /**
     * @param ISearchResultSet $resultSet The search results to render
     * @param int $offset Offset of the first result in $resultSet
     * @return string HTML
     */
    protected function renderResultSet( ISearchResultSet $resultSet, $offset ) {
        $hits = [];
        foreach ( $resultSet as $result ) {
            $hits[] = $this->resultWidget->render( $result, $offset++ );
        }

        return "<ul class='mw-search-results'>" . implode( '', $hits ) . "</ul>";
    }
}