22 public const CACHE_TIME = 3 * 24 * 3600;
24 public const CACHE_STALE = 25 * 3600;
29 public function __construct(
32 JobQueueGroup $jobQueue
34 $this->cache = $cache;
35 $this->query = $query;
36 $this->jobQueue = $jobQueue;
44 if ( !$this->isValidLanguage( $language ) ) {
45 throw new InvalidArgumentException(
"Invalid language tag '$language'" );
48 $cachedValue = $this->getFromCache( $language );
50 if ( is_array( $cachedValue ) ) {
51 if ( $this->isStale( $cachedValue ) ) {
52 $this->queueCacheRefresh( $language );
58 $queriedValue = $this->doQueryAndCache( $language );
59 if ( !$queriedValue ) {
60 throw new StatisticsUnavailable(
"Unable to load stats" );
66 private function getFromCache(
string $language ) {
67 $cacheKey = $this->getCacheKey( $language );
68 return $this->cache->get( $cacheKey );
71 private function getCacheKey(
string $language ): string {
72 return $this->cache->makeKey(
'translate-translator-activity-v4', $language );
75 private function isStale( array $value ): bool {
76 $age = intval( ConvertibleTimestamp::now( TS_UNIX ) ) - $value[
'asOfTime'];
77 return $age >= self::CACHE_STALE;
80 private function queueCacheRefresh(
string $language ): void {
81 $job = UpdateTranslatorActivityJob::newJobForLanguage( $language );
82 $this->jobQueue->push( $job );
85 private function doQueryAndCache(
string $language ) {
86 $now = (int)ConvertibleTimestamp::now( TS_UNIX );
88 $work =
new PoolCounterWorkViaCallback(
89 'TranslateFetchTranslators',
"TranslateFetchTranslators-$language", [
90 'doWork' =>
function () use ( $language, $now ) {
91 $users = $this->query->inLanguage( $language );
92 $data = [
'users' => $users,
'asOfTime' => $now ];
93 $this->addToCache( $data, $language );
96 'doCachedWork' =>
function () use ( $language ) {
97 $data = $this->getFromCache( $language );
99 return is_array( $data ) ? $data :
false;
104 return $work->execute();
107 private function addToCache( array $value,
string $language ): void {
108 $cacheKey = $this->getCacheKey( $language );
109 $this->cache->set( $cacheKey, $value, self::CACHE_TIME );
114 $now = (int)ConvertibleTimestamp::now( TS_UNIX );
116 $data = $this->query->inAllLanguages();
118 $validLanguages = Utilities::getLanguageNames( LanguageNameUtils::AUTONYMS );
119 foreach ( $validLanguages as $language ) {
120 $data[$language] = $data[$language] ?? [];
123 foreach ( $data as $language => $users ) {
124 if ( !$this->isValidLanguage( $language ) ) {
128 $data = [
'users' => $users,
'asOfTime' => $now ];
129 $this->addToCache( $data, $language );
138 if ( !$this->isValidLanguage( $language ) ) {
139 throw new InvalidArgumentException(
"Invalid language tag '$language'" );
142 $queriedValue = $this->doQueryAndCache( $language );
143 if ( !$queriedValue ) {
148 private function isValidLanguage(
string $language ): bool {
149 return Utilities::isSupportedLanguageCode( $language );
return[ 'Translate:ConfigHelper'=> static function():ConfigHelper { return new ConfigHelper();}, 'Translate:CsvTranslationImporter'=> static function(MediaWikiServices $services):CsvTranslationImporter { return new CsvTranslationImporter( $services->getWikiPageFactory());}, 'Translate:EntitySearch'=> static function(MediaWikiServices $services):EntitySearch { return new EntitySearch($services->getMainWANObjectCache(), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), MessageGroups::singleton(), $services->getNamespaceInfo(), $services->get( 'Translate:MessageIndex'), $services->getTitleParser(), $services->getTitleFormatter());}, 'Translate:ExternalMessageSourceStateImporter'=> static function(MediaWikiServices $services):ExternalMessageSourceStateImporter { return new ExternalMessageSourceStateImporter($services->getMainConfig(), $services->get( 'Translate:GroupSynchronizationCache'), $services->getJobQueueGroup(), LoggerFactory::getInstance( 'Translate.GroupSynchronization'), $services->get( 'Translate:MessageIndex'));}, 'Translate:GroupSynchronizationCache'=> static function(MediaWikiServices $services):GroupSynchronizationCache { return new GroupSynchronizationCache( $services->get( 'Translate:PersistentCache'));}, 'Translate:MessageBundleStore'=> static function(MediaWikiServices $services):MessageBundleStore { return new MessageBundleStore(new RevTagStore(), $services->getJobQueueGroup(), $services->getLanguageNameUtils(), $services->get( 'Translate:MessageIndex'));}, 'Translate:MessageGroupReview'=> static function(MediaWikiServices $services):MessageGroupReview { return new MessageGroupReview($services->getDBLoadBalancer(), $services->getHookContainer());}, 'Translate:MessageGroupStatsTableFactory'=> static function(MediaWikiServices $services):MessageGroupStatsTableFactory { return new MessageGroupStatsTableFactory($services->get( 'Translate:ProgressStatsTableFactory'), $services->getDBLoadBalancer(), $services->getLinkRenderer(), $services->getMainConfig() ->get( 'TranslateWorkflowStates') !==false);}, 'Translate:MessageIndex'=> static function(MediaWikiServices $services):MessageIndex { $params=$services->getMainConfig() ->get( 'TranslateMessageIndex');if(is_string( $params)) { $params=(array) $params;} $class=array_shift( $params);return new $class( $params);}, 'Translate:MessagePrefixStats'=> static function(MediaWikiServices $services):MessagePrefixStats { return new MessagePrefixStats( $services->getTitleParser());}, 'Translate:ParsingPlaceholderFactory'=> static function():ParsingPlaceholderFactory { return new ParsingPlaceholderFactory();}, 'Translate:PersistentCache'=> static function(MediaWikiServices $services):PersistentCache { return new PersistentDatabaseCache($services->getDBLoadBalancer(), $services->getJsonCodec());}, 'Translate:ProgressStatsTableFactory'=> static function(MediaWikiServices $services):ProgressStatsTableFactory { return new ProgressStatsTableFactory($services->getLinkRenderer(), $services->get( 'Translate:ConfigHelper'));}, 'Translate:SubpageListBuilder'=> static function(MediaWikiServices $services):SubpageListBuilder { return new SubpageListBuilder($services->get( 'Translate:TranslatableBundleFactory'), $services->getLinkBatchFactory());}, 'Translate:TranslatableBundleFactory'=> static function(MediaWikiServices $services):TranslatableBundleFactory { return new TranslatableBundleFactory($services->get( 'Translate:TranslatablePageStore'), $services->get( 'Translate:MessageBundleStore'));}, 'Translate:TranslatableBundleMover'=> static function(MediaWikiServices $services):TranslatableBundleMover { return new TranslatableBundleMover($services->getMovePageFactory(), $services->getJobQueueGroup(), $services->getLinkBatchFactory(), $services->get( 'Translate:TranslatableBundleFactory'), $services->get( 'Translate:SubpageListBuilder'), $services->getMainConfig() ->get( 'TranslatePageMoveLimit'));}, 'Translate:TranslatableBundleStatusStore'=> static function(MediaWikiServices $services):TranslatableBundleStatusStore { return new TranslatableBundleStatusStore($services->getDBLoadBalancer() ->getConnection(DB_PRIMARY), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), $services->getDBLoadBalancer() ->getMaintenanceConnectionRef(DB_PRIMARY));}, 'Translate:TranslatablePageParser'=> static function(MediaWikiServices $services):TranslatablePageParser { return new TranslatablePageParser($services->get( 'Translate:ParsingPlaceholderFactory'));}, 'Translate:TranslatablePageStore'=> static function(MediaWikiServices $services):TranslatablePageStore { return new TranslatablePageStore($services->get( 'Translate:MessageIndex'), $services->getJobQueueGroup(), new RevTagStore(), $services->getDBLoadBalancer(), $services->get( 'Translate:TranslatableBundleStatusStore'));}, 'Translate:TranslationStashReader'=> static function(MediaWikiServices $services):TranslationStashReader { $db=$services->getDBLoadBalancer() ->getConnectionRef(DB_REPLICA);return new TranslationStashStorage( $db);}, 'Translate:TranslationStatsDataProvider'=> static function(MediaWikiServices $services):TranslationStatsDataProvider { return new TranslationStatsDataProvider(new ServiceOptions(TranslationStatsDataProvider::CONSTRUCTOR_OPTIONS, $services->getMainConfig()), $services->getObjectFactory());}, 'Translate:TranslationUnitStoreFactory'=> static function(MediaWikiServices $services):TranslationUnitStoreFactory { return new TranslationUnitStoreFactory( $services->getDBLoadBalancer());}, 'Translate:TranslatorActivity'=> static function(MediaWikiServices $services):TranslatorActivity { $query=new TranslatorActivityQuery($services->getMainConfig(), $services->getDBLoadBalancer());return new TranslatorActivity($services->getMainObjectStash(), $query, $services->getJobQueueGroup());}, 'Translate:TtmServerFactory'=> static function(MediaWikiServices $services):TtmServerFactory { $config=$services->getMainConfig();$default=$config->get( 'TranslateTranslationDefaultService');if( $default===false) { $default=null;} return new TtmServerFactory( $config->get( 'TranslateTranslationServices'), $default);}]
@phpcs-require-sorted-array