SpecialLanguageStats.php

Go to the documentation of this file.
00001 <?php
00023 class SpecialLanguageStats extends IncludableSpecialPage {
00027     protected $table;
00028 
00032     protected $targetValueName = array( 'code', 'language' );
00033 
00037     protected $totals;
00038 
00044     protected $timelimit = 8;
00045 
00050     protected $nothing = false;
00051 
00056     protected $incomplete = false;
00057 
00062     protected $noComplete = true;
00063 
00068     protected $noEmpty = false;
00069 
00073     protected $target;
00074 
00079     protected $purge;
00080 
00088     protected $statsCounted = array();
00089 
00093     protected $states;
00094 
00095     public function __construct() {
00096         parent::__construct( 'LanguageStats' );
00097 
00098         $this->target = $this->getLanguage()->getCode();
00099         $this->totals = MessageGroupStats::getEmptyStats();
00100     }
00101 
00102     function execute( $par ) {
00103         $request = $this->getRequest();
00104 
00105         $this->purge = $request->getVal( 'action' ) === 'purge';
00106         $this->table = new StatsTable();
00107 
00108         $this->setHeaders();
00109         $this->outputHeader();
00110 
00111         $out = $this->getOutput();
00112 
00113         $out->addModules( 'ext.translate.special.languagestats' );
00114         $out->addModuleStyles( 'ext.translate.messagetable' );
00115 
00116         $params = explode( '/', $par );
00117 
00118         if ( isset( $params[0] ) && trim( $params[0] ) ) {
00119             $this->target = $params[0];
00120         }
00121 
00122         if ( isset( $params[1] ) ) {
00123             $this->noComplete = (bool)$params[1];
00124         }
00125 
00126         if ( isset( $params[2] ) ) {
00127             $this->noEmpty = (bool)$params[2];
00128         }
00129 
00130         // Whether the form has been submitted, only relevant if not including
00131         $submitted = !$this->including() && $request->getVal( 'x' ) === 'D';
00132 
00133         // Default booleans to false if the form was submitted
00134         foreach ( $this->targetValueName as $key ) {
00135             $this->target = $request->getVal( $key, $this->target );
00136         }
00137         $this->noComplete = $request->getBool(
00138             'suppresscomplete',
00139             $this->noComplete && !$submitted
00140         );
00141         $this->noEmpty = $request->getBool( 'suppressempty', $this->noEmpty && !$submitted );
00142 
00143         if ( !$this->including() ) {
00144             TranslateUtils::addSpecialHelpLink(
00145                 $out,
00146                 'Help:Extension:Translate/Statistics_and_reporting'
00147             );
00148             $out->addHTML( $this->getForm() );
00149         }
00150 
00151         if ( $this->isValidValue( $this->target ) ) {
00152             $this->outputIntroduction();
00153             $output = $this->getTable();
00154             if ( $this->incomplete ) {
00155                 $out->wrapWikiMsg(
00156                     "<div class='error'>$1</div>",
00157                     'translate-langstats-incomplete'
00158                 );
00159             }
00160             if ( $this->nothing ) {
00161                 $out->wrapWikiMsg( "<div class='error'>$1</div>", 'translate-mgs-nothing' );
00162             }
00163             $out->addHTML( $output );
00164         } elseif ( $submitted ) {
00165             $this->invalidTarget();
00166         }
00167     }
00168 
00174     protected function isValidValue( $value ) {
00175         $langs = Language::getLanguageNames( false );
00176 
00177         return isset( $langs[$value] );
00178     }
00179 
00181     protected function invalidTarget() {
00182         $this->getOutput()->wrapWikiMsg(
00183             "<div class='error'>$1</div>",
00184             'translate-page-no-such-language'
00185         );
00186     }
00187 
00193     protected function getForm() {
00194         global $wgScript;
00195 
00196         $out = Html::openElement( 'div' );
00197         $out .= Html::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
00198         $out .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() );
00199         $out .= Html::hidden( 'x', 'D' ); // To detect submission
00200         $out .= Html::openElement( 'fieldset' );
00201         $out .= Html::element(
00202             'legend',
00203             array(),
00204             $this->msg( 'translate-language-code' )->text()
00205         );
00206         $out .= Html::openElement( 'table' );
00207 
00208         $out .= Html::openElement( 'tr' );
00209         $out .= Html::openElement( 'td', array( 'class' => 'mw-label' ) );
00210         $out .= Xml::label(
00211             $this->msg( 'translate-language-code-field-name' )->text(),
00212             'language'
00213         );
00214         $out .= Html::closeElement( 'td' );
00215         $out .= Html::openElement( 'td', array( 'class' => 'mw-input' ) );
00216         $out .= Xml::input( 'language', 10, $this->target, array( 'id' => 'language' ) );
00217         $out .= Html::closeElement( 'td' );
00218         $out .= Html::closeElement( 'tr' );
00219 
00220         $out .= Html::openElement( 'tr' );
00221         $out .= Html::openElement( 'td', array( 'colspan' => 2 ) );
00222         $out .= Xml::checkLabel(
00223             $this->msg( 'translate-suppress-complete' )->text(),
00224             'suppresscomplete',
00225             'suppresscomplete',
00226             $this->noComplete
00227         );
00228         $out .= Html::closeElement( 'td' );
00229         $out .= Html::closeElement( 'tr' );
00230 
00231         $out .= Html::openElement( 'tr' );
00232         $out .= Html::openElement( 'td', array( 'colspan' => 2 ) );
00233         $out .= Xml::checkLabel(
00234             $this->msg( 'translate-ls-noempty' )->text(),
00235             'suppressempty',
00236             'suppressempty',
00237             $this->noEmpty
00238         );
00239         $out .= Html::closeElement( 'td' );
00240         $out .= Html::closeElement( 'tr' );
00241 
00242         $out .= Html::openElement( 'tr' );
00243         $out .= Html::openElement( 'td', array( 'class' => 'mw-input', 'colspan' => 2 ) );
00244         $out .= Xml::submitButton( $this->msg( 'translate-ls-submit' )->text() );
00245         $out .= Html::closeElement( 'td' );
00246         $out .= Html::closeElement( 'tr' );
00247 
00248         $out .= Html::closeElement( 'table' );
00249         $out .= Html::closeElement( 'fieldset' );
00250         /* Since these pages are in the tabgroup with Special:Translate,
00251          * it makes sense to retain the selected group/language parameter
00252          * on post requests even when not relevant to the current page. */
00253         $val = $this->getRequest()->getVal( 'group' );
00254         if ( $val !== null ) {
00255             $out .= Html::hidden( 'group', $val );
00256         }
00257         $out .= Html::closeElement( 'form' );
00258         $out .= Html::closeElement( 'div' );
00259 
00260         return $out;
00261     }
00262 
00266     protected function outputIntroduction() {
00267         $languageName = TranslateUtils::getLanguageName(
00268             $this->target,
00269             $this->getLanguage()->getCode()
00270         );
00271         $task = $this->getUser()->isAllowed( 'translate-messagereview' ) ?
00272             'acceptqueue' :
00273             'reviewall';
00274         $rcInLangLink = Linker::link(
00275             SpecialPage::getTitleFor( 'Translate', '!recent' ),
00276             $this->msg( 'languagestats-recenttranslations' )->escaped(),
00277             array(),
00278             array(
00279                 'task' => $task,
00280                 'language' => $this->target
00281             )
00282         );
00283 
00284         $out = $this->msg( 'languagestats-stats-for', $languageName )->rawParams( $rcInLangLink )
00285             ->parseAsBlock();
00286         $this->getOutput()->addHTML( $out );
00287     }
00288 
00292     function addWorkflowStatesColumn() {
00293         global $wgTranslateWorkflowStates;
00294 
00295         if ( $wgTranslateWorkflowStates ) {
00296             $this->states = $this->getWorkflowStates();
00297 
00298             // An array where keys are state names and values are numbers
00299             $this->table->addExtraColumn( $this->msg( 'translate-stats-workflow' ) );
00300         }
00301 
00302         return;
00303     }
00304 
00305     protected function getWorkflowStateValue( $target ) {
00306         return isset( $this->states[$target] ) ? $this->states[$target] : '';
00307     }
00308 
00315     protected function getWorkflowStateCell( $target, $state ) {
00316         // This will be set by addWorkflowStatesColumn if needed
00317         if ( !isset( $this->states ) ) {
00318             return '';
00319         }
00320 
00321         if ( $state === '' ) {
00322             return "\n\t\t" . $this->table->element( '', '', -1 );
00323         }
00324 
00325         if ( $this instanceof SpecialMessageGroupStats ) {
00326             // Same for every language
00327             $group = MessageGroups::getGroup( $this->target );
00328             $stateConfig = $group->getMessageGroupStates()->getStates();
00329         } else {
00330             // The message group for this row
00331             $group = MessageGroups::getGroup( $target );
00332             $stateConfig = $group->getMessageGroupStates()->getStates();
00333         }
00334 
00335         $sortValue = -1;
00336         $stateColor = '';
00337         if ( isset( $stateConfig[$state] ) ) {
00338             $sortIndex = array_flip( array_keys( $stateConfig ) );
00339             $sortValue = $sortIndex[$state] + 1;
00340 
00341             if ( is_string( $stateConfig[$state] ) ) {
00342                 // BC for old configuration format
00343                 $stateColor = $stateConfig[$state];
00344             } elseif ( isset( $stateConfig[$state]['color'] ) ) {
00345                 $stateColor = $stateConfig[$state]['color'];
00346             }
00347         }
00348 
00349         $stateMessage = $this->msg( "translate-workflow-state-$state" );
00350         $stateText = $stateMessage->isBlank() ? $state : $stateMessage->text();
00351 
00352         return "\n\t\t" . $this->table->element(
00353             $stateText,
00354             $stateColor,
00355             $sortValue
00356         );
00357     }
00358 
00363     function getTable() {
00364         $table = $this->table;
00365 
00366         $this->addWorkflowStatesColumn();
00367         $out = '';
00368 
00369         if ( $this->purge ) {
00370             MessageGroupStats::clearLanguage( $this->target );
00371         }
00372 
00373         MessageGroupStats::setTimeLimit( $this->timelimit );
00374         $cache = MessageGroupStats::forLanguage( $this->target );
00375 
00376         $structure = MessageGroups::getGroupStructure();
00377         foreach ( $structure as $item ) {
00378             $out .= $this->makeGroupGroup( $item, $cache );
00379         }
00380 
00381         if ( $out ) {
00382             $table->setMainColumnHeader( $this->msg( 'translate-ls-column-group' ) );
00383             $out = $table->createHeader() . "\n" . $out;
00384             $out .= Html::closeElement( 'tbody' );
00385 
00386             $out .= Html::openElement( 'tfoot' );
00387             $out .= $table->makeTotalRow(
00388                 $this->msg( 'translate-languagestats-overall' ),
00389                 $this->totals
00390             );
00391             $out .= Html::closeElement( 'tfoot' );
00392 
00393             $out .= Html::closeElement( 'table' );
00394 
00395             return $out;
00396         } else {
00397             $this->nothing = true;
00398 
00399             return '';
00400         }
00401 
00407     }
00408 
00419     protected function makeGroupGroup( $item, array $cache, MessageGroup $parent = null ) {
00420         if ( !is_array( $item ) ) {
00421             return $this->makeGroupRow( $item, $cache, $parent );
00422         }
00423 
00424         // The first group in the array is the parent AggregateMessageGroup
00425         $out = '';
00426         $top = array_shift( $item );
00427         $out .= $this->makeGroupRow( $top, $cache, $parent );
00428 
00429         // Rest are children
00430         foreach ( $item as $subgroup ) {
00431             $out .= $this->makeGroupGroup( $subgroup, $cache, $top );
00432         }
00433 
00434         return $out;
00435     }
00436 
00445     protected function makeGroupRow( MessageGroup $group, array $cache,
00446         MessageGroup $parent = null
00447     ) {
00448         $groupId = $group->getId();
00449 
00450         if ( $this->table->isBlacklisted( $groupId, $this->target ) !== null ) {
00451             return '';
00452         }
00453 
00454         $stats = $cache[$groupId];
00455         $total = $stats[MessageGroupStats::TOTAL];
00456         $translated = $stats[MessageGroupStats::TRANSLATED];
00457         $fuzzy = $stats[MessageGroupStats::FUZZY];
00458 
00459         // Quick checks to see whether filters apply
00460         if ( $this->noComplete && $fuzzy === 0 && $translated === $total ) {
00461             return '';
00462         }
00463         if ( $this->noEmpty && $translated === 0 && $fuzzy === 0 ) {
00464             return '';
00465         }
00466 
00467         // Calculation of summary row values
00468         if ( !$group instanceof AggregateMessageGroup ) {
00469             if ( !isset( $this->statsCounted[$groupId] ) ) {
00470                 $this->totals = MessageGroupStats::multiAdd( $this->totals, $stats );
00471                 $this->statsCounted[$groupId] = true;
00472             }
00473         }
00474 
00475         $state = $this->getWorkflowStateValue( $groupId );
00476 
00477         $params = $stats;
00478         $params[] = $state;
00479         $params[] = $groupId;
00480         $params[] = $this->getLanguage()->getCode();
00481         $params[] = $this->target;
00482         $cachekey = wfMemcKey( __METHOD__, implode( '-', $params ) );
00483         $cacheval = wfGetCache( CACHE_ANYTHING )->get( $cachekey );
00484         if ( !$this->purge && is_string( $cacheval ) ) {
00485             return $cacheval;
00486         }
00487 
00488         $extra = array();
00489         if ( $total === null ) {
00490             $this->incomplete = true;
00491         } elseif ( $translated === $total ) {
00492             $extra = array( 'task' => 'reviewall' );
00493         }
00494 
00495         $rowParams = array();
00496         $rowParams['data-groupid'] = $groupId;
00497         $rowParams['class'] = get_class( $group );
00498         if ( $parent ) {
00499             $rowParams['data-parentgroup'] = $parent->getId();
00500         }
00501 
00502         $out = "\t" . Html::openElement( 'tr', $rowParams );
00503         $out .= "\n\t\t" . Html::rawElement( 'td', array(),
00504             $this->table->makeGroupLink( $group, $this->target, $extra ) );
00505         $out .= $this->table->makeNumberColumns( $stats );
00506         $out .= $this->getWorkflowStateCell( $groupId, $state );
00507         $out .= "\n\t" . Html::closeElement( 'tr' ) . "\n";
00508 
00509         wfGetCache( CACHE_ANYTHING )->set( $cachekey, $out, 3600 * 24 );
00510 
00511         return $out;
00512     }
00513 
00514     protected function getWorkflowStates( $field = 'tgr_group', $filter = 'tgr_lang' ) {
00515         $db = wfGetDB( DB_SLAVE );
00516         $res = $db->select(
00517             'translate_groupreviews',
00518             array( 'tgr_state', $field ),
00519             array( $filter => $this->target ),
00520             __METHOD__
00521         );
00522 
00523         $states = array();
00524         foreach ( $res as $row ) {
00525             $states[$row->$field] = $row->tgr_state;
00526         }
00527 
00528         return $states;
00529     }
00530 }
Generated on Tue Oct 29 00:00:24 2013 for MediaWiki Translate Extension by  doxygen 1.6.3