From 956367fb90710828480ef73af8bbbee5bd7bcb38 Mon Sep 17 00:00:00 2001 From: Subramanya Sastry Date: Fri, 22 Nov 2019 23:18:15 -0600 Subject: [PATCH] Implement ParsoidFetchTemplateData hook for Parsoid/PHP * This hook supports functionality that Parsoid/JS used the MW API for. Parsoid's html2wt code requests templatedata for titles one at a time currently and so this hook also supports lookups one title at a time. This initial implementation is good enough for initial Parsoid/PHP deployment. * As part of later performance optimization, we should figure out if we want to fetch templatedata for all templates in batch mode and work out the details (selser doesn't touch all templates, for one). The hook does accept an array of titles, but it looks them up serially in a simple for-loop. Separately, we need to resolve if this is better architected as a lookup service vs. a hook as it is now (see discussion on gerrit). * Tested locally on my local wiki. Bug: T238954 Change-Id: I01fb6a9f334ca37a703be497524180f87fb8bbf7 --- extension.json | 3 ++ includes/TemplateDataHooks.php | 63 ++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/extension.json b/extension.json index 9bb38b00..3d60d060 100644 --- a/extension.json +++ b/extension.json @@ -41,6 +41,9 @@ ], "EditPage::showEditForm:initial": [ "TemplateDataHooks::onEditPage" + ], + "ParserFetchTemplateData": [ + "TemplateDataHooks::onParserFetchTemplateData" ] }, "MessagesDirs": { diff --git a/includes/TemplateDataHooks.php b/includes/TemplateDataHooks.php index d18ef1bb..a0e76de8 100644 --- a/includes/TemplateDataHooks.php +++ b/includes/TemplateDataHooks.php @@ -159,4 +159,67 @@ class TemplateDataHooks { return $ti->getHtml( $parser->getOptions()->getUserLangObj() ); } + + /** + * Fetch templatedata for an array of titles. + * + * @todo Document this hook + * + * The following questions are yet to be resolved. + * (a) Should we extend functionality to looking up an array of titles instead of one? + * The signature allows for an array of titles to be passed in, but the + * current implementation is not optimized for the multple-title use case. + * (b) Should this be a lookup service instead of this faux hook? + * This will be resolved separately. + * + * @param array $tplTitles + * @param stdclass[] &$tplData + * @return bool + */ + public static function onParserFetchTemplateData( array $tplTitles, array &$tplData ): bool { + $tplData = []; + + // This inefficient implementation is currently tuned for + // Parsoid's use case where it requests info for exactly one title. + // For a real batch use case, this code will need an overhaul. + foreach ( $tplTitles as $tplTitle ) { + $title = Title::newFromText( $tplTitle ); + if ( !$title ) { // Invalid title + $tplData[$tplTitle] = null; + continue; + } + + if ( $title->isRedirect() ) { + $title = ( new WikiPage( $title ) )->getRedirectTarget(); + if ( !$title ) { // Invalid redirecting title + $tplData[$tplTitle] = null; + continue; + } + } + + if ( !$title->exists() ) { + $tplData[$tplTitle] = (object)[ "missing" => true ]; + continue; + } + + $pageId = $title->getArticleID(); + $props = PageProps::getInstance()->getProperties( $title, 'templatedata' ); + if ( !isset( $props[$pageId] ) ) { // No templatedata + $tplData[$tplTitle] = (object)[ "notemplatedata" => true ]; + continue; + } + + $tdb = TemplateDataBlob::newFromDatabase( wfGetDB( DB_REPLICA ), $props[$pageId] ); + $status = $tdb->getStatus(); + if ( !$status->isOK() ) { + // Invalid data. Parsoid has no use for the error. + $tplData[$tplTitle] = (object)[ "notemplatedata" => true ]; + continue; + } + + $tplData[$tplTitle] = $tdb->getData(); + } + + return true; + } }