Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 50 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
DatabaseMenteeOverviewDataProvider | |
0.00% |
0 / 50 |
|
0.00% |
0 / 6 |
90 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
makeCacheKey | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
invalidateCacheForMentor | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
formatDataForMentee | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getFormattedDataForMentor | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
12 | |||
getFormattedDataForMentee | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace GrowthExperiments\MentorDashboard\MenteeOverview; |
4 | |
5 | use GrowthExperiments\Mentorship\Store\MentorStore; |
6 | use MediaWiki\Json\FormatJson; |
7 | use MediaWiki\User\UserIdentity; |
8 | use stdClass; |
9 | use Wikimedia\LightweightObjectStore\ExpirationAwareness; |
10 | use Wikimedia\ObjectCache\WANObjectCache; |
11 | use Wikimedia\Rdbms\ILoadBalancer; |
12 | |
13 | /** |
14 | * Data provider for MenteeOverview module |
15 | * |
16 | * This data provider loads data from growthexperiments_mentee_data database |
17 | * table and caches them for a while. |
18 | * |
19 | * The table is populated with data from UncachedMenteeOverviewDataProvider, see |
20 | * that class for details about generating the data. |
21 | */ |
22 | class DatabaseMenteeOverviewDataProvider implements MenteeOverviewDataProvider, ExpirationAwareness { |
23 | |
24 | private MentorStore $mentorStore; |
25 | private ILoadBalancer $growthLB; |
26 | protected WANObjectCache $wanCache; |
27 | |
28 | /** |
29 | * @param WANObjectCache $wanCache |
30 | * @param MentorStore $mentorStore |
31 | * @param ILoadBalancer $growthLB |
32 | */ |
33 | public function __construct( |
34 | WANObjectCache $wanCache, |
35 | MentorStore $mentorStore, |
36 | ILoadBalancer $growthLB |
37 | ) { |
38 | $this->wanCache = $wanCache; |
39 | $this->mentorStore = $mentorStore; |
40 | $this->growthLB = $growthLB; |
41 | } |
42 | |
43 | /** |
44 | * @param UserIdentity $mentor |
45 | * @return string |
46 | */ |
47 | private function makeCacheKey( UserIdentity $mentor ): string { |
48 | return $this->wanCache->makeKey( |
49 | 'GrowthExperiments', |
50 | 'MenteeOverviewDataProvider', |
51 | __CLASS__, |
52 | 'Mentor', |
53 | $mentor->getId() |
54 | ); |
55 | } |
56 | |
57 | /** |
58 | * Invalidate cache for given mentor |
59 | * @param UserIdentity $mentor |
60 | */ |
61 | public function invalidateCacheForMentor( UserIdentity $mentor ): void { |
62 | $this->wanCache->delete( $this->makeCacheKey( $mentor ) ); |
63 | } |
64 | |
65 | /** |
66 | * Decode data for particular mentee |
67 | * |
68 | * @param stdClass $row |
69 | * @return array |
70 | */ |
71 | private function formatDataForMentee( stdClass $row ): array { |
72 | $input = FormatJson::decode( $row->mentee_data, true ); |
73 | $input['user_id'] = $row->mentee_id; |
74 | $input['last_active'] ??= $input['last_edit'] ?? $input['registration']; |
75 | return $input; |
76 | } |
77 | |
78 | /** |
79 | * @inheritDoc |
80 | */ |
81 | public function getFormattedDataForMentor( UserIdentity $mentor ): array { |
82 | $method = __METHOD__; |
83 | return $this->wanCache->getWithSetCallback( |
84 | $this->makeCacheKey( $mentor ), |
85 | self::TTL_DAY, |
86 | function ( $oldValue, &$ttl, &$setOpts ) use ( $mentor, $method ) { |
87 | $mentees = $this->mentorStore->getMenteesByMentor( $mentor, MentorStore::ROLE_PRIMARY ); |
88 | if ( $mentees === [] ) { |
89 | $ttl = self::TTL_HOUR; |
90 | return []; |
91 | } |
92 | |
93 | $menteeIds = array_map( static function ( $mentee ) { |
94 | return $mentee->getId(); |
95 | }, $mentees ); |
96 | |
97 | $res = $this->growthLB->getConnection( DB_REPLICA )->newSelectQueryBuilder() |
98 | ->select( [ 'mentee_id', 'mentee_data' ] ) |
99 | ->from( 'growthexperiments_mentee_data' ) |
100 | ->where( [ 'mentee_id' => $menteeIds ] ) |
101 | ->caller( $method ) |
102 | ->fetchResultSet(); |
103 | $data = []; |
104 | foreach ( $res as $row ) { |
105 | $data[] = $this->formatDataForMentee( $row ); |
106 | } |
107 | return $data; |
108 | } |
109 | ); |
110 | } |
111 | |
112 | /** |
113 | * Fetch MenteeOverview data for a given mentee |
114 | * |
115 | * This is useful in other parts of GrowthExperiments that wish |
116 | * to reuse data MenteeOverview has available (Personalized praise, for |
117 | * example). |
118 | * |
119 | * @param UserIdentity $mentee |
120 | * @return array|null Formatted data if exists; null otherwise |
121 | */ |
122 | public function getFormattedDataForMentee( UserIdentity $mentee ): ?array { |
123 | $res = $this->growthLB->getConnection( DB_REPLICA )->newSelectQueryBuilder() |
124 | ->select( [ 'mentee_id', 'mentee_data' ] ) |
125 | ->from( 'growthexperiments_mentee_data' ) |
126 | ->conds( [ |
127 | 'mentee_id' => $mentee->getId() |
128 | ] ) |
129 | ->caller( __METHOD__ ) |
130 | ->fetchRow(); |
131 | |
132 | if ( !$res ) { |
133 | // mentee not found |
134 | return null; |
135 | } |
136 | |
137 | return $this->formatDataForMentee( $res ); |
138 | } |
139 | } |