r113194 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r113193‎ | r113194 | r113195 >
Date:22:59, 6 March 2012
Author:maxsem
Status:ok
Tags:
Comment:
Committing work in progress: plan B for mobile app, action=mobileview (any ideas of better name???). Always parses whole wikitext even if it has to return just one section, unlike action=parse. Because results are cached, it's also faster than one-section action=parse.
Modified paths:
  • /trunk/extensions/MobileFrontend/MobileFrontend.php (modified) (history)
  • /trunk/extensions/MobileFrontend/api/ApiMobileView.php (added) (history)

Diff [purge]

Index: trunk/extensions/MobileFrontend/api/ApiMobileView.php
@@ -0,0 +1,167 @@
 2+<?php
 3+
 4+class ApiMobileView extends ApiBase {
 5+ /**
 6+ * Increment this when changing the format of cached data
 7+ */
 8+ const CACHE_VERSION = 1;
 9+
 10+ public function __construct( $main, $action ) {
 11+ parent::__construct( $main, $action );
 12+ }
 13+
 14+ public function execute() {
 15+ wfProfileIn( __METHOD__ );
 16+ // Enough '*' keys in JSON!!!
 17+ $textElement = $this->getMain()->getPrinter()->getFormat() == 'XML' ? '*' : 'text';
 18+ $params = $this->extractRequestParams();
 19+ $requestedSections = isset( $params['section'] )
 20+ ? $this->parseSections( $params['section'] )
 21+ : array();
 22+ $prop = array_flip( $params['prop'] );
 23+ $sectionProp = $prop['sectionprop'];
 24+
 25+ $title = Title::newFromText( $params['page'] );
 26+ if ( !$title || !$title->exists() ) {
 27+ $this->dieUsage( "Page `$page' does not exist", 'nopage' );
 28+ }
 29+ if ( $title->getNamespace() < 0 || !$title->isLocal() ) {
 30+ $this->dieUsage($description, $errorCode);
 31+ }
 32+ $data = $this->getData( $title, $params['noimages'] );
 33+ if ( isset( $prop['sections'] ) ) {
 34+ $requestedSections = array_flip( $requestedSections );
 35+ $result = $data['sections'];
 36+ for ( $i = 0; $i < count( $data['sections'] ); $i++ ) {
 37+ $result[$i]['id'] = $i;
 38+ if ( isset( $requestedSections[$i] ) && isset( $data['text'][$i] ) ) {
 39+ $result[$i][$textElement] = $data['text'][$i];
 40+ }
 41+ }
 42+ } else {
 43+ $result = array();
 44+ foreach ( $requestedSections as $index ) {
 45+ $section = array( 'id' => $index );
 46+ if ( isset( $data['text'][$index] ) ) {
 47+ $section[$textElement] = $data['text'][$index];
 48+ }
 49+ $result[] = $section;
 50+ }
 51+ }
 52+ $this->getResult()->setIndexedTagName( $result, 'section' );
 53+ $this->getResult()->addValue( null, $this->getModuleName(), array( 'sections' => $result ) );
 54+ }
 55+
 56+ public function getAllowedParams() {
 57+ return array(
 58+ 'page' => array(
 59+ ApiBase::PARAM_REQUIRED => true,
 60+ ),
 61+ 'section' => null,
 62+ 'prop' => array(
 63+ ApiBase::PARAM_DFLT => 'text|sections',
 64+ ApiBase::PARAM_ISMULTI => true,
 65+ ApiBase::PARAM_TYPE => array(
 66+ 'text',
 67+ 'sections',
 68+ )
 69+ ),
 70+ 'sectionprop' => array(
 71+ ApiBase::PARAM_TYPE => array(
 72+ 'toclevel',
 73+ 'level',
 74+ 'line',
 75+ 'number',
 76+ 'index',
 77+ 'fromtitle',
 78+ 'anchor',
 79+ ),
 80+ ApiBase::PARAM_ISMULTI => true,
 81+ ApiBase::PARAM_DFLT => 'toclevel|line',
 82+ ),
 83+ 'noimages' => false,
 84+ );
 85+ }
 86+
 87+ private function parseSections( $str ) {
 88+ $sections = array_map( 'intval', explode( '|', $str ) );
 89+ return $sections;
 90+ }
 91+
 92+ private function getData( $title, $noImages ) {
 93+ global $wgMemc, $wgUseTidy;
 94+
 95+ wfProfileIn( __METHOD__ );
 96+ $wp = WikiPage::factory( $title );
 97+ $parserOptions = ParserOptions::newFromContext( $this );
 98+ $latest = $wp->getLatest();
 99+ $parserCacheKey = ParserCache::singleton()->getKey( $wp, $parserOptions );
 100+ $key = wfMemcKey( 'mf', 'mobileview', self::CACHE_VERSION, $noImages, $parserCacheKey );
 101+ $data = $wgMemc->get( $key );
 102+ if ( $data ) {
 103+ wfProfileOut( __METHOD__ );
 104+ return $data;
 105+ }
 106+ $parserOutput = $wp->getParserOutput( $parserOptions );
 107+ $mf = new MobileFormatter( '<html><body><div id="content">' . $parserOutput->getText() . '</div></body></html>',
 108+ $title,
 109+ 'XHTML'
 110+ );
 111+ $mf->removeImages( $noImages );
 112+ $mf->filterContent();
 113+ $html = $mf->getText( 'content' );
 114+ $data = array();
 115+ $data['sections'] = $parserOutput->getSections();
 116+ $chunks = preg_split( '/<h(?=[1-6]\b)/i', $html );
 117+ $data['text'] = array();
 118+ foreach ( $chunks as $chunk ) {
 119+ if ( count( $data['text'] ) ) {
 120+ $chunk = "<h$chunk";
 121+ }
 122+ if ( $wgUseTidy && count( $chunks ) > 1 ) {
 123+ $chunk = MWTidy::tidy( $chunk );
 124+ }
 125+ $data['text'][] = $chunk;
 126+ }
 127+ if ( count( $chunks ) != count( $data['sections'] ) + 1 ) {
 128+ wfDebug( __METHOD__ . "(): mismatching number of sections from parser and split. oldid=$latest\n" );
 129+ }
 130+ // store for the same time as original parser output
 131+ $wgMemc->set( $key, $data, $parserOutput->getCacheTime() );
 132+ wfProfileOut( __METHOD__ );
 133+ return $data;
 134+ }
 135+
 136+ public function getParamDescription() {
 137+ return array(
 138+
 139+ );
 140+ }
 141+
 142+ public function getDescription() {
 143+ return 'Returns data needed for mobile views';
 144+ }
 145+
 146+ public function getPossibleErrors() {
 147+ return array_merge( parent::getPossibleErrors(),
 148+ array(
 149+ array( 'code' => 'invalid-section', 'info' => '' ),
 150+ )
 151+ );
 152+ }
 153+
 154+ public function getExamples() {
 155+ return array(
 156+ 'api.php?action=mobileview&page=Doom_metal&section=0'
 157+ );
 158+ }
 159+
 160+ public function getHelpUrls() {
 161+ return 'https://www.mediawiki.org/wiki/Extension:MobileFrontend#New_API';
 162+ }
 163+
 164+ public function getVersion() {
 165+ return __CLASS__ . ': $Id$';
 166+ }
 167+
 168+}
Property changes on: trunk/extensions/MobileFrontend/api/ApiMobileView.php
___________________________________________________________________
Added: svn:eol-style
1169 + native
Added: svn:keywords
2170 + Id
Index: trunk/extensions/MobileFrontend/MobileFrontend.php
@@ -49,6 +49,7 @@
5050 'MobileFormatter' => 'MobileFormatter',
5151 'WmlContext' => 'WmlContext',
5252
 53+ 'ApiMobileView' => 'api/ApiMobileView',
5354 'ApiParseExtender' => 'api/ApiParseExtender',
5455 'ApiQueryExcerpts' => 'api/ApiQueryExcerpts',
5556
@@ -114,6 +115,7 @@
115116 $wgExtensionFunctions[] = 'efMobileFrontend_Setup';
116117
117118 $wgAPIPropModules['excerpts'] = 'ApiQueryExcerpts';
 119+$wgAPIModules['mobileview'] = 'ApiMobileView';
118120
119121 $wgHooks['APIGetAllowedParams'][] = 'ApiParseExtender::onAPIGetAllowedParams';
120122 $wgHooks['APIAfterExecute'][] = 'ApiParseExtender::onAPIAfterExecute';

Status & tagging log