MessageGroupStats.php

Go to the documentation of this file.
00001 <?php
00019 class MessageGroupStats {
00021     const TABLE = 'translate_groupstats';
00022 
00023     const TOTAL = 0; 
00024     const TRANSLATED = 1; 
00025     const FUZZY = 2; 
00026     const PROOFREAD = 3; 
00027 
00029     protected static $timeStart = null;
00031     protected static $limit = null;
00032 
00039     public static function setTimeLimit( $limit ) {
00040         self::$timeStart = microtime( true );
00041         self::$limit = $limit;
00042     }
00043 
00050     public static function getEmptyStats() {
00051         return array( 0, 0, 0, 0 );
00052     }
00053 
00060     protected static function getUnknownStats() {
00061         return array( null, null, null, null );
00062     }
00063 
00070     public static function forItem( $id, $code ) {
00071         $res = self::selectRowsIdLang( $id, $code );
00072         $stats = self::extractResults( $res );
00073 
00074         /* In case some code calls this for dynamic groups, return the default
00075          * values for unknown/incomplete stats. Calculating these numbers don't
00076          * make sense for dynamic groups, and would just throw an exception. */
00077         $group = MessageGroups::getGroup( $id );
00078         if ( MessageGroups::isDynamic( $group ) ) {
00079             $stats[$id][$code] = self::getUnknownStats();
00080         }
00081 
00082         if ( !isset( $stats[$id][$code] ) ) {
00083             $stats[$id][$code] = self::forItemInternal( $stats, $group, $code );
00084         }
00085 
00086         return $stats[$id][$code];
00087     }
00088 
00094     public static function forLanguage( $code ) {
00095         $stats = self::forLanguageInternal( $code );
00096         $flattened = array();
00097         foreach ( $stats as $group => $languages ) {
00098             $flattened[$group] = $languages[$code];
00099         }
00100 
00101         return $flattened;
00102     }
00103 
00109     public static function forGroup( $id ) {
00110         $group = MessageGroups::getGroup( $id );
00111         if ( $group === null ) {
00112             return array();
00113         }
00114         $stats = self::forGroupInternal( $group );
00115 
00116         return $stats[$id];
00117     }
00118 
00125     public static function forEverything() {
00126         $groups = MessageGroups::singleton()->getGroups();
00127         $stats = array();
00128         foreach ( $groups as $g ) {
00129             $stats = self::forGroupInternal( $g, $stats );
00130         }
00131 
00132         return $stats;
00133     }
00134 
00141     public static function clear( MessageHandle $handle ) {
00142         $dbw = wfGetDB( DB_MASTER );
00143         $conds = array(
00144             'tgs_group' => $handle->getGroupIds(),
00145             'tgs_lang' => $handle->getCode(),
00146         );
00147 
00148         $dbw->delete( self::TABLE, $conds, __METHOD__ );
00149         wfDebugLog( 'messagegroupstats', "Cleared " . serialize( $conds ) );
00150 
00151         // Hooks must return value
00152         return true;
00153     }
00154 
00155     public static function clearGroup( $id ) {
00156         if ( !count( $id ) ) {
00157             return;
00158         }
00159         $dbw = wfGetDB( DB_MASTER );
00160         $conds = array( 'tgs_group' => $id );
00161         $dbw->delete( self::TABLE, $conds, __METHOD__ );
00162         wfDebugLog( 'messagegroupstats', "Cleared " . serialize( $conds ) );
00163     }
00164 
00165     public static function clearLanguage( $code ) {
00166         if ( !count( $code ) ) {
00167             return;
00168         }
00169         $dbw = wfGetDB( DB_MASTER );
00170         $conds = array( 'tgs_lang' => $code );
00171         $dbw->delete( self::TABLE, $conds, __METHOD__ );
00172         wfDebugLog( 'messagegroupstats', "Cleared " . serialize( $conds ) );
00173     }
00174 
00178     public static function clearAll() {
00179         $dbw = wfGetDB( DB_MASTER );
00180         $dbw->delete( self::TABLE, '*' );
00181         wfDebugLog( 'messagegroupstats', "Cleared everything :(" );
00182     }
00183 
00184     protected static function extractResults( $res, $stats = array() ) {
00185         foreach ( $res as $row ) {
00186             $stats[$row->tgs_group][$row->tgs_lang] = self::extractNumbers( $row );
00187         }
00188 
00189         return $stats;
00190     }
00191 
00192     public static function update( MessageHandle $handle, $changes = array() ) {
00193         $dbw = wfGetDB( DB_MASTER );
00194         $conds = array(
00195             'tgs_group' => $handle->getGroupIds(),
00196             'tgs_lang' => $handle->getCode(),
00197         );
00198 
00199         $values = array();
00200         foreach ( array( 'total', 'translated', 'fuzzy', 'proofread' ) as $type ) {
00201             if ( isset( $changes[$type] ) ) {
00202                 $values[] = "tgs_$type=tgs_$type" .
00203                     self::stringifyNumber( $changes[$type] );
00204             }
00205         }
00206 
00207         $dbw->update( self::TABLE, $values, $conds, __METHOD__ );
00208     }
00209 
00215     protected static function extractNumbers( $row ) {
00216         return array(
00217             self::TOTAL => (int)$row->tgs_total,
00218             self::TRANSLATED => (int)$row->tgs_translated,
00219             self::FUZZY => (int)$row->tgs_fuzzy,
00220             self::PROOFREAD => (int)$row->tgs_proofread,
00221         );
00222     }
00223 
00229     protected static function forLanguageInternal( $code, $stats = array() ) {
00230         $res = self::selectRowsIdLang( null, $code );
00231         $stats = self::extractResults( $res, $stats );
00232 
00233         $groups = MessageGroups::singleton()->getGroups();
00234         foreach ( $groups as $id => $group ) {
00235             if ( isset( $stats[$id][$code] ) ) {
00236                 continue;
00237             }
00238             $stats[$id][$code] = self::forItemInternal( $stats, $group, $code );
00239         }
00240 
00241         return $stats;
00242     }
00243 
00248     protected static function expandAggregates( AggregateMessageGroup $agg ) {
00249         $flattened = array();
00250 
00252         foreach ( $agg->getGroups() as $group ) {
00253             if ( $group instanceof AggregateMessageGroup ) {
00254                 $flattened += self::expandAggregates( $group );
00255             } else {
00256                 $flattened[$group->getId()] = $group;
00257             }
00258         }
00259 
00260         return $flattened;
00261     }
00262 
00268     protected static function forGroupInternal( $group, $stats = array() ) {
00269         $id = $group->getId();
00270         $res = self::selectRowsIdLang( $id, null );
00271         $stats = self::extractResults( $res, $stats );
00272 
00273         # Go over each language filling missing entries
00274         $languages = array_keys( Language::getLanguageNames( false ) );
00275         // This is for calculating things in correct order
00276         sort( $languages );
00277         foreach ( $languages as $code ) {
00278             if ( isset( $stats[$id][$code] ) ) {
00279                 continue;
00280             }
00281             $stats[$id][$code] = self::forItemInternal( $stats, $group, $code );
00282         }
00283 
00284         // This is for sorting the values added later in correct order
00285         foreach ( array_keys( $stats ) as $key ) {
00286             ksort( $stats[$key] );
00287         }
00288 
00289         return $stats;
00290     }
00291 
00292     protected static function selectRowsIdLang( $ids = null, $codes = null ) {
00293         $conds = array();
00294         if ( $ids !== null ) {
00295             $conds['tgs_group'] = $ids;
00296         }
00297 
00298         if ( $codes !== null ) {
00299             $conds['tgs_lang'] = $codes;
00300         }
00301 
00302         $dbr = wfGetDB( DB_MASTER );
00303         $res = $dbr->select( self::TABLE, '*', $conds, __METHOD__ );
00304 
00305         return $res;
00306     }
00307 
00308     protected static function forItemInternal( &$stats, $group, $code ) {
00309         $id = $group->getId();
00310 
00311         if ( self::$timeStart !== null && ( microtime( true ) - self::$timeStart ) > self::$limit ) {
00312             return $stats[$id][$code] = self::getUnknownStats();
00313         }
00314 
00315         if ( $group instanceof AggregateMessageGroup ) {
00316             $aggregates = self::getEmptyStats();
00317 
00318             $expanded = self::expandAggregates( $group );
00319             if ( $expanded === array() ) {
00320                 return $aggregates;
00321             }
00322             $res = self::selectRowsIdLang( array_keys( $expanded ), $code );
00323             $stats = self::extractResults( $res, $stats );
00324 
00325             foreach ( $expanded as $sid => $subgroup ) {
00326                 # Discouraged groups may belong to another group, usually if there
00327                 # is an aggregate group for all translatable pages. In that case
00328                 # calculate and store the statistics, but don't count them as part of
00329                 # the aggregate group, so that the numbers in Special:LanguageStats
00330                 # add up. The statistics for discouraged groups can still be viewed
00331                 # through Special:MessageGroupStats.
00332                 if ( !isset( $stats[$sid][$code] ) ) {
00333                     $stats[$sid][$code] = self::forItemInternal( $stats, $subgroup, $code );
00334                 }
00335 
00336                 $include = wfRunHooks( 'Translate:MessageGroupStats:isIncluded', array( $sid, $code ) );
00337                 if ( $include ) {
00338                     $aggregates = self::multiAdd( $aggregates, $stats[$sid][$code] );
00339                 }
00340             }
00341             $stats[$id][$code] = $aggregates;
00342         } else {
00343             $aggregates = self::calculateGroup( $group, $code );
00344         }
00345 
00346         // Don't add nulls to the database, causes annoying warnings
00347         if ( $aggregates[self::TOTAL] === null ) {
00348             return $aggregates;
00349         }
00350 
00351         $data = array(
00352             'tgs_group' => $id,
00353             'tgs_lang' => $code,
00354             'tgs_total' => $aggregates[self::TOTAL],
00355             'tgs_translated' => $aggregates[self::TRANSLATED],
00356             'tgs_fuzzy' => $aggregates[self::FUZZY],
00357             'tgs_proofread' => $aggregates[self::PROOFREAD],
00358         );
00359 
00360         $dbw = wfGetDB( DB_MASTER );
00361         $dbw->insert(
00362             self::TABLE,
00363             $data,
00364             __METHOD__,
00365             array( 'IGNORE' )
00366         );
00367 
00368         return $aggregates;
00369     }
00370 
00371     public static function multiAdd( &$a, $b ) {
00372         if ( $a[0] === null || $b[0] === null ) {
00373             return array_fill( 0, count( $a ), null );
00374         }
00375         foreach ( $a as $i => &$v ) {
00376             $v += $b[$i];
00377         }
00378 
00379         return $a;
00380     }
00381 
00387     protected static function calculateGroup( $group, $code ) {
00388         global $wgTranslateDocumentationLanguageCode;
00389         # Calculate if missing and store in the db
00390         $collection = $group->initCollection( $code );
00391         $collection->setReviewMode( true );
00392 
00393         if ( $code === $wgTranslateDocumentationLanguageCode ) {
00394             $ffs = $group->getFFS();
00395             if ( $ffs instanceof GettextFFS ) {
00396                 $template = $ffs->read( 'en' );
00397                 $infile = array();
00398                 foreach ( $template['TEMPLATE'] as $key => $data ) {
00399                     if ( isset( $data['comments']['.'] ) ) {
00400                         $infile[$key] = '1';
00401                     }
00402                 }
00403                 $collection->setInFile( $infile );
00404             }
00405         }
00406 
00407         $collection->filter( 'ignored' );
00408         $collection->filter( 'optional' );
00409         // Store the count of real messages for later calculation.
00410         $total = count( $collection );
00411 
00412         // Count fuzzy first.
00413         $collection->filter( 'fuzzy' );
00414         $fuzzy = $total - count( $collection );
00415 
00416         // Count the completed translations.
00417         $collection->filter( 'hastranslation', false );
00418         $translated = count( $collection );
00419 
00420         // Count how many of the completed translations
00421         // have been proofread
00422         $collection->filter( 'reviewer', false );
00423         $proofread = count( $collection );
00424 
00425         return array(
00426             self::TOTAL => $total,
00427             self::TRANSLATED => $translated,
00428             self::FUZZY => $fuzzy,
00429             self::PROOFREAD => $proofread,
00430         );
00431     }
00432 
00438     protected static function stringifyNumber( $number ) {
00439         $number = intval( $number );
00440 
00441         return $number < 0 ? "$number" : "+$number";
00442     }
00443 }
Generated on Tue Oct 29 00:00:26 2013 for MediaWiki Translate Extension by  doxygen 1.6.3