Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 112
ProofreadPageLuaLibrary
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 15
1122
0.00% covered (danger)
0.00%
0 / 112
 register
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 17
 incrementExpensiveFunctionCount
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 addTemplateDependencyOnPage
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 5
 addTemplateDependencyOnAllPagesInIndex
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 6
 doGetIndexProgress
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 16
 getIndexContent
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 8
 doGetIndexFields
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 6
 doGetIndexCategories
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 6
 getPaginationForIndex
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 6
 doGetNumberOfPages
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 doGetPageInIndex
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 6
 doGetPageQuality
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 8
 getIndexForPage
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 5
 doGetIndexForPage
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 7
 doGetPageNumbering
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 11
<?php
namespace ProofreadPage;
use MediaWiki\Logger\LoggerFactory;
use OutOfBoundsException;
use ProofreadPage\Index\IndexContent;
use ProofreadPage\Page\PageLevel;
use Psr\Log\LoggerInterface;
use Scribunto_LuaError;
use Scribunto_LuaLibraryBase;
use Title;
use WikitextContent;
class ProofreadPageLuaLibrary extends Scribunto_LuaLibraryBase {
    /**
     * @var Context
     */
    private $context;
    /**
     * @var LoggerInterface
     */
    private $logger;
    /**
     * @var \ParserOutput|null
     */
    private $parserOutput;
    /** @inheritDoc */
    public function register() {
        $this->context = Context::getDefaultContext();
        $extensionLuaPath = __DIR__ . '/lualib/ProofreadPage.lua';
        // "export" PHP functions to the Lua library interface
        $lib = [
            'doGetIndexProgress' => [ $this, 'doGetIndexProgress' ],
            'doGetIndexFields' => [ $this, 'doGetIndexFields' ],
            'doGetIndexCategories' => [ $this, 'doGetIndexCategories' ],
            'doGetNumberOfPages' => [ $this, 'doGetNumberOfPages' ],
            'doGetPageInIndex' => [ $this, 'doGetPageInIndex' ],
            'doGetIndexPageNumbers' => [ $this, 'doGetIndexPageNumbers' ],
            'doGetPageQuality' => [ $this, 'doGetPageQuality' ],
            'doGetIndexForPage' => [ $this, 'doGetIndexForPage' ],
            'doGetPageNumbering' => [ $this, 'doGetPageNumbering' ]
        ];
        $opts = [
            'NS_INDEX' => $this->context->getIndexNamespaceId(),
            'NS_PAGE' => $this->context->getPageNamespaceId(),
            'qualityLevel' => [
                'WITHOUT_TEXT' => PageLevel::WITHOUT_TEXT,
                'NOT_PROOFREAD' => PageLevel::NOT_PROOFREAD,
                'PROBLEMATIC' => PageLevel::PROBLEMATIC,
                'PROOFREAD' => PageLevel::PROOFREAD,
                'VALIDATED' => PageLevel::VALIDATED,
            ]
        ];
        $this->logger = LoggerFactory::getInstance( 'ext.proofreadPage.lua' );
        if ( $this->getParser() ) {
            $this->parserOutput = $this->getParser()->getOutput();
        }
        return $this->getEngine()->registerInterface( $extensionLuaPath, $lib, $opts );
    }
    /**
     * Increment the Lua engine expensive function count
     */
    public function incrementExpensiveFunctionCount() {
        $this->getEngine()->incrementExpensiveFunctionCount();
    }
    /**
     * Add a parser dependency on the given page (index or otherwise)
     * @param Title|null $pageTitle
     */
    private function addTemplateDependencyOnPage( ?Title $pageTitle ) {
        if ( $this->parserOutput && $pageTitle ) {
            $this->parserOutput->addTemplate(
                $pageTitle,
                $pageTitle->getArticleID(),
                $pageTitle->getLatestRevID()
            );
        }
    }
    /**
     * Add a parser dependency on every page in the index (and the index itself)
     * @param Title|null $indexTitle
     */
    private function addTemplateDependencyOnAllPagesInIndex( ?Title $indexTitle ) {
        if ( $this->parserOutput && $indexTitle ) {
            // this depends on the index itself (for the content)
            $pagination = $this->getPaginationForIndex( $indexTitle );
            $pagination->prefetchPageLinks();
            foreach ( $pagination as $pageTitle ) {
                $this->addTemplateDependencyOnPage( $pageTitle );
            }
        }
    }
    /**
     * Return the index statistics for the given index name
     *
     * This function may be expensive, if the index has not been cached yet.
     *
     * @param string $indexName the index title to get stats for
     * @return array the result table, in an array
     * @throws Scribunto_LuaError if expensive function count exceeded
     */
    public function doGetIndexProgress( string $indexName ): array {
        $indexTitle = Title::makeTitleSafe( $this->context->getIndexNamespaceId(), $indexName );
        $statsLookup = $this->context->getIndexQualityStatsLookup();
        if ( !$statsLookup->isIndexTitleInCache( $indexTitle ) ) {
            $this->logger->debug( "Index stats cache miss: " . $indexTitle->getFullText() );
            $this->incrementExpensiveFunctionCount();
        }
        // Progress depends on every page in the index
        $this->addTemplateDependencyOnAllPagesInIndex( $indexTitle );
        $indexStats = $statsLookup->getStatsForIndexTitle( $indexTitle );
        // Map stats to the Lua table
        $stats = [
            0 => $indexStats->getNumberOfPagesForQualityLevel( 0 ),
            1 => $indexStats->getNumberOfPagesForQualityLevel( 1 ),
            2 => $indexStats->getNumberOfPagesForQualityLevel( 2 ),
            3 => $indexStats->getNumberOfPagesForQualityLevel( 3 ),
            4 => $indexStats->getNumberOfPagesForQualityLevel( 4 ),
            "total" => $indexStats->getNumberOfPages(),
            "existing" => $indexStats->getNumberOfPagesWithAnyQualityLevel(),
            "missing" => $indexStats->getNumberOfPagesWithoutQualityLevel(),
        ];
        return [ $stats ];
    }
    /**
     * Get the IndexContent for a give index
     * @param string $indexName the name of the index
     * @return IndexContent|null the index content (or null if the index is
     *                           not found or the title construction fails)
     */
    private function getIndexContent( string $indexName ): ?IndexContent {
        $indexTitle = Title::makeTitleSafe( $this->context->getIndexNamespaceId(), $indexName );
        $contentLookup = $this->context->getIndexContentLookup();
        if ( !$contentLookup->isIndexTitleInCache( $indexTitle ) ) {
            $this->logger->debug( "Index content cache miss: " . $indexTitle->getFullText() );
            $this->incrementExpensiveFunctionCount();
        }
        // if the index content is needed, there's a dependency on the index
        $this->addTemplateDependencyOnPage( $indexTitle );
        $indexContent = $contentLookup->getIndexContentForTitle( $indexTitle );
        return $indexContent;
    }
    /**
     * Return the index fields for the given index name
     *
     * This function may be expensive, if the index content has not been cached yet.
     *
     * @param string $indexName the index title to get stats for
     * @return array the result table, in an array
     * @throws Scribunto_LuaError if expensive function count exceeded
     */
    public function doGetIndexFields( string $indexName ): array {
        // this can be expensive
        $indexContent = $this->getIndexContent( $indexName );
        $wikitextFields = $indexContent->getFields();
        $textConverter = static function ( WikitextContent $field ): string {
            return $field->getText();
        };
        $textFields = array_map( $textConverter, $wikitextFields );
        return [ $textFields ];
    }
    /**
     * Return the index categories for the given index name
     *
     * Note this is only the categories entered on the index page, and doesn't
     * include categories added by the Index page template or any other
     * expansion of wikitext.
     *
     * This function may be expensive, if the index content has not been cached yet.
     *
     * @param string $indexName the index title to get stats for
     * @return array the result table, in an array
     * @throws Scribunto_LuaError if expensive function count exceeded
     */
    public function doGetIndexCategories( string $indexName ): array {
        // this can be expensive
        $indexContent = $this->getIndexContent( $indexName );
        $categories = $indexContent->getCategories();
        $textConverter = static function ( Title $field ): string {
            return $field->getText();
        };
        // remap into a Lua-esque 1-indexed array of title strings
        $textCategories = array_map( $textConverter, $categories );
        return [ $textCategories ];
    }
    /**
     * Get the Pagination for a given index
     *
     * Increments the expensive function counter if needed
     *
     * @param Title $indexTitle
     * @return \ProofreadPage\Pagination\Pagination
     */
    private function getPaginationForIndex( Title $indexTitle ) {
        $paginationFactory = $this->context->getPaginationFactory();
        if ( !$paginationFactory->isIndexTitleInCache( $indexTitle ) ) {
            $this->logger->debug( "Index pagination cache miss: " . $indexTitle->getFullText() );
            $this->incrementExpensiveFunctionCount();
        }
        // the pagination depends on the index content
        $this->addTemplateDependencyOnPage( $indexTitle );
        // may be expensive, but cached
        return $paginationFactory->getPaginationForIndexTitle( $indexTitle );
    }
    /**
     * Get the total number of page in the index
     * @param string $indexName the index title
     * @return array the number of pages of the index, 0 for an invalid index
     */
    public function doGetNumberOfPages( string $indexName ): array {
        $indexTitle = Title::makeTitleSafe( $this->context->getIndexNamespaceId(), $indexName );
        // may be expensive
        $pagination = $this->getPaginationForIndex( $indexTitle );
        return [ $pagination->getNumberOfPages() ];
    }
    /**
     * The the n'th page in the pagination for an index
     * @param string $indexName the index title
     * @param int $n the index of the pag in that index (1 is the first)
     * @return array the page title, as an array for Lua
     */
    public function doGetPageInIndex( string $indexName, int $n ): array {
        $indexTitle = Title::makeTitleSafe( $this->context->getIndexNamespaceId(), $indexName );
        // may be expensive
        $pagination = $this->getPaginationForIndex( $indexTitle );
        try {
            $pageTitle = $pagination->getPageTitle( $n );
        } catch ( OutOfBoundsException $e ) {
            return [ null ];
        }
        return [ $pageTitle->getText() ];
    }
    /**
     * Get the quality information for a given page
     * @param string $pageName the title of the page to get the info for
     * @return array the quality information as an array
     */
    public function doGetPageQuality( string $pageName ): array {
        $pageTitle = Title::makeTitleSafe( $this->context->getPageNamespaceId(), $pageName );
        $pqLookup = $this->context->getPageQualityLevelLookup();
        if ( !$pqLookup->isPageTitleInCache( $pageTitle ) ) {
            $this->logger->debug( "Page quality cache miss: " . $pageTitle->getFullText() );
            $this->incrementExpensiveFunctionCount();
        }
        // the page quality depends only on that page
        $this->addTemplateDependencyOnPage( $pageTitle );
        $pageLevel = $pqLookup->getQualityLevelForPageTitle( $pageTitle );
        return [ [
            'level' => $pageLevel,
            // 'user' => $pageLevel->getUser(), // T289137
            // 'timestamp' maybe?
        ] ];
    }
    /**
     * Get the title of the index for a given page
     * @param Title $pageTitle
     * @return Title|null the title of the index
     */
    private function getIndexForPage( Title $pageTitle ): ?Title {
        $ifpLookup = $this->context->getIndexForPageLookup();
        if ( !$ifpLookup->isPageTitleInCache( $pageTitle ) ) {
            $this->logger->debug( "Index for page cache miss: " . $pageTitle->getFullText() );
            $this->incrementExpensiveFunctionCount();
        }
        return $ifpLookup->getIndexForPageTitle( $pageTitle );
    }
    /**
     * Get the title of the index for a given page
     * @param string $pageName the title of the page to get the index for
     * @return array the name of the index
     */
    public function doGetIndexForPage( string $pageName ): array {
        $pageTitle = Title::makeTitleSafe( $this->context->getPageNamespaceId(), $pageName );
        $indexTitle = $this->getIndexForPage( $pageTitle );
        // if the page is moved, this could change, and also if the index pagination changes
        $this->addTemplateDependencyOnPage( $pageTitle );
        $this->addTemplateDependencyOnPage( $indexTitle );
        if ( $indexTitle == null ) {
            return [ null ];
        }
        return [ $indexTitle->getBaseText() ];
    }
    /**
     * Get the page numbering for a given page
     * @param string $pageName the title of the page to get the numbering for
     * @return array the name of the index
     */
    public function doGetPageNumbering( string $pageName ): array {
        $pageTitle = Title::makeTitleSafe( $this->context->getPageNamespaceId(), $pageName );
        # may be expensive
        $indexTitle = $this->getIndexForPage( $pageTitle );
        if ( $indexTitle == null ) {
            return [ null ];
        }
        // this is a cached lookup, so we'll only look this indexes pagination up once
        // but that first time is expensive
        $pagination = $this->getPaginationForIndex( $indexTitle );
        $language = $indexTitle->getPageLanguage();
        $pageInPagination = $pagination->getPageNumber( $pageTitle );
        $dispNum = $pagination->getDisplayedPageNumber( $pageInPagination );
        return [ [
            'position' => $pageInPagination,
            'display' => $dispNum->getFormattedPageNumber( $language ),
            'raw' => $dispNum->getRawPageNumber( $language )
        ] ];
    }
}