wikimedia/mediawiki-extensions-Wikibase

View on GitHub
repo/includes/Specials/SpecialWikibaseQueryPage.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

namespace Wikibase\Repo\Specials;

use MediaWiki\Html\Html;
use Wikibase\DataModel\Entity\EntityId;
use Wikibase\Lib\Store\EntityTitleLookup;
use Wikibase\Repo\WikibaseRepo;

/**
 * Base for special pages that show the result of a Query. Rewriting of QueryPage but
 * with abstraction of the storage system and without cache support.
 *
 * @license GPL-2.0-or-later
 * @author Thomas Pellissier Tanon
 */
abstract class SpecialWikibaseQueryPage extends SpecialWikibasePage {

    /**
     * Max server side caching time in seconds.
     */
    protected const CACHE_TTL_IN_SECONDS = 10;

    /**
     * The offset in use
     *
     * @var int
     */
    protected $offset = 0;

    /**
     * The limit in use
     *
     * @var int
     */
    protected $limit = 0;

    /**
     * The number of rows returned by the query. Reading this variable
     * only makes sense in functions that are run after the query has been
     * done.
     *
     * @var int
     */
    protected $numRows;

    /**
     * @var EntityTitleLookup
     */
    private $entityTitleLookup;

    /**
     * @param string $name
     * @param string $restriction
     * @param bool $listed
     */
    public function __construct( $name = '', $restriction = '', $listed = true ) {
        parent::__construct( $name, $restriction, $listed );

        $this->entityTitleLookup = WikibaseRepo::getEntityTitleLookup();
    }

    /**
     * @see SpecialWikibasePage::execute
     *
     * @param string|null $subPage
     */
    public function execute( $subPage ) {
        parent::execute( $subPage );

        $output = $this->getOutput();
        $output->setCdnMaxage( static::CACHE_TTL_IN_SECONDS );
    }

    /**
     * Formats a row for display.
     *
     * @param EntityId $entityId
     *
     * @return string HTML
     */
    protected function formatRow( EntityId $entityId ) {
        $title = $this->entityTitleLookup->getTitleForId( $entityId );
        return $this->getLinkRenderer()->makeKnownLink( $title );
    }

    /**
     * Return the result of the query
     *
     * @param int $offset Start to include at number of entries from the start title
     * @param int $limit Stop at number of entries after start of inclusion
     *
     * @return EntityId[]
     */
    abstract protected function getResult( $offset = 0, $limit = 0 );

    /**
     * Output the query result
     *
     * @param array $query optional array of URL query parameter strings
     * @param string|bool $subPage Optional param for specifying subpage
     */
    protected function showQuery( array $query = [], $subPage = false ) {
        $paging = false;
        $out = $this->getOutput();

        if ( $this->limit == 0 && $this->offset == 0 ) {
            [ $this->limit, $this->offset ] = $this->getRequest()
                ->getLimitOffsetForUser( $this->getUser() );
        }

        $entityIds = $this->getResult( $this->offset, $this->limit + 1 );

        $this->numRows = count( $entityIds );

        $out->addHTML( Html::openElement( 'div', [ 'class' => 'mw-spcontent' ] ) );

        if ( $this->numRows > 0 ) {
            $out->addHTML( $this->msg( 'showingresultsinrange' )->numParams(
                // do not format the one extra row, if exist
                min( $this->numRows, $this->limit ),
                $this->offset + 1, min( $this->numRows, $this->limit ) + $this->offset )->parseAsBlock() );
            // Disable the "next" link when we reach the end
            $paging = $this->buildPrevNextNavigation(
                $this->offset,
                $this->limit,
                $query,
                $this->numRows <= $this->limit,
                $subPage
            );
            $out->addHTML( Html::rawElement( 'p', [], $paging ) );
        } else {
            // No results to show, so don't bother with "showing X of Y" etc.
            // -- just let the user know and give up now
            $out->addWikiMsg( 'specialpage-empty' );
        }

        $this->outputResults(
            $entityIds,
            // do not format the one extra row, if it exist
            min( $this->numRows, $this->limit ),
            $this->offset
        );

        if ( $paging ) {
            $out->addHTML( Html::rawElement( 'p', [], $paging ) );
        }

        $out->addHTML( Html::closeElement( 'div' ) );
    }

    /**
     * Format and output report results using the given information plus OutputPage
     *
     * @param EntityId[] $entityIds
     * @param int $num number of available result rows
     * @param int $offset paging offset
     */
    protected function outputResults( array $entityIds, $num, $offset ) {
        if ( $num > 0 ) {
            $html = Html::openElement( 'ol', [ 'start' => $offset + 1, 'class' => 'special' ] );
            for ( $i = 0; $i < $num; $i++ ) {
                $row = $this->formatRow( $entityIds[$i] );
                $html .= Html::rawElement( 'li', [], $row );
            }
            $html .= Html::closeElement( 'ol' );

            $this->getOutput()->addHTML( $html );
        }
    }

}