Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
CachedMessageGroupFactoryLoader
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 6
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getGroups
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 recache
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 clearCache
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCachedValue
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 getCacheData
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\MessageGroupProcessing;
5
6use CachedMessageGroupLoader;
7use DependencyWrapper;
8use MessageGroup;
9use MessageGroupLoader;
10use Wikimedia\LightweightObjectStore\ExpirationAwareness;
11use Wikimedia\ObjectCache\WANObjectCache;
12use Wikimedia\Rdbms\Database;
13use Wikimedia\Rdbms\IConnectionProvider;
14
15/**
16 * Loads and manages message group factory loaders
17 * @since 2024.05
18 * @license GPL-2.0-or-later
19 * @author Niklas Laxström
20 */
21class CachedMessageGroupFactoryLoader implements CachedMessageGroupLoader, MessageGroupLoader {
22    private WANObjectCache $cache;
23    private IConnectionProvider $dbProvider;
24    private string $cacheKey;
25    private CachedMessageGroupFactory $factory;
26    private const CACHE_TTL = ExpirationAwareness::TTL_DAY;
27
28    public function __construct(
29        WANObjectCache $cache,
30        IConnectionProvider $dbProvider,
31        CachedMessageGroupFactory $factory
32    ) {
33        $this->cache = $cache;
34        $this->cacheKey = $cache->makeKey( 'translate-mg', $factory->getCacheKey() );
35        $this->factory = $factory;
36        $this->dbProvider = $dbProvider;
37    }
38
39    /** @return MessageGroup[] */
40    public function getGroups(): array {
41        return $this->factory->createGroups( $this->getCachedValue()->getValue() );
42    }
43
44    /** @return MessageGroup[] */
45    public function recache(): array {
46        $this->cache->touchCheckKey( $this->cacheKey );
47        return $this->factory->createGroups(
48            $this->factory->getData( $this->dbProvider->getPrimaryDatabase() )
49        );
50    }
51
52    public function clearCache(): void {
53        $this->cache->delete( $this->cacheKey );
54    }
55
56    private function getCachedValue(): DependencyWrapper {
57        return $this->cache->getWithSetCallback(
58            $this->cacheKey,
59            self::CACHE_TTL,
60            fn ( $oldValue, &$ttl, array &$setOpts ) => $this->getCacheData( $setOpts ),
61            [
62                // avoid stampedes (mutex)
63                'lockTSE' => 30,
64                'checkKeys' => [ $this->cacheKey ],
65                'touchedCallback' => static fn ( DependencyWrapper $value ) => $value->isExpired() ? time() : null,
66                'version' => $this->factory->getCacheVersion(),
67            ]
68        );
69    }
70
71    private function getCacheData( array &$setOpts ): DependencyWrapper {
72        $dbr = $this->dbProvider->getReplicaDatabase();
73
74        // Some factories may not use the database, in which case this is superflous.
75        // Having it here for simplicity.
76        $setOpts += Database::getCacheSetOptions( $dbr );
77
78        $wrapper = new DependencyWrapper(
79            $this->factory->getData( $dbr ),
80            $this->factory->getDependencies()
81        );
82        $wrapper->initialiseDeps();
83        return $wrapper;
84    }
85}