21 public const CACHE_TIME = 3 * 24 * 3600;
23 public const CACHE_STALE = 25 * 3600;
28 public function __construct(
31 JobQueueGroup $jobQueue
33 $this->cache = $cache;
34 $this->query = $query;
35 $this->jobQueue = $jobQueue;
43 if ( !$this->isValidLanguage( $language ) ) {
44 throw new InvalidArgumentException(
"Invalid language tag '$language'" );
47 $cachedValue = $this->getFromCache( $language );
49 if ( is_array( $cachedValue ) ) {
50 if ( $this->isStale( $cachedValue ) ) {
51 $this->queueCacheRefresh( $language );
57 $queriedValue = $this->doQueryAndCache( $language );
58 if ( !$queriedValue ) {
59 throw new StatisticsUnavailable(
"Unable to load stats" );
65 private function getFromCache(
string $language ) {
66 $cacheKey = $this->getCacheKey( $language );
67 return $this->cache->get( $cacheKey );
70 private function getCacheKey(
string $language ): string {
71 return $this->cache->makeKey(
'translate-translator-activity-v4', $language );
74 private function isStale( array $value ): bool {
75 $age = intval( ConvertibleTimestamp::now( TS_UNIX ) ) - $value[
'asOfTime'];
76 return $age >= self::CACHE_STALE;
79 private function queueCacheRefresh(
string $language ): void {
80 $job = UpdateTranslatorActivityJob::newJobForLanguage( $language );
81 $this->jobQueue->push( $job );
84 private function doQueryAndCache(
string $language ) {
85 $now = (int)ConvertibleTimestamp::now( TS_UNIX );
87 $work =
new PoolCounterWorkViaCallback(
88 'TranslateFetchTranslators',
"TranslateFetchTranslators-$language", [
89 'doWork' =>
function () use ( $language, $now ) {
90 $users = $this->query->inLanguage( $language );
91 $data = [
'users' => $users,
'asOfTime' => $now ];
92 $this->addToCache( $data, $language );
95 'doCachedWork' =>
function () use ( $language ) {
96 $data = $this->getFromCache( $language );
98 return is_array( $data ) ? $data :
false;
103 return $work->execute();
106 private function addToCache( array $value,
string $language ): void {
107 $cacheKey = $this->getCacheKey( $language );
108 $this->cache->set( $cacheKey, $value, self::CACHE_TIME );
113 $now = (int)ConvertibleTimestamp::now( TS_UNIX );
115 $data = $this->query->inAllLanguages();
117 $validLanguages = TranslateUtils::getLanguageNames(
null );
118 foreach ( $validLanguages as $language ) {
119 $data[$language] = $data[$language] ?? [];
122 foreach ( $data as $language => $users ) {
123 if ( !$this->isValidLanguage( $language ) ) {
127 $data = [
'users' => $users,
'asOfTime' => $now ];
128 $this->addToCache( $data, $language );
137 if ( !$this->isValidLanguage( $language ) ) {
138 throw new InvalidArgumentException(
"Invalid language tag '$language'" );
141 $queriedValue = $this->doQueryAndCache( $language );
142 if ( !$queriedValue ) {
147 private function isValidLanguage(
string $language ): bool {
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'), MessageIndex::singleton());}, '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: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: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: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());}, '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