Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
93.24% |
69 / 74 |
|
54.55% |
6 / 11 |
CRAP | |
0.00% |
0 / 1 |
DatabasePageQualityLevelLookup | |
93.24% |
69 / 74 |
|
54.55% |
6 / 11 |
24.18 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isPageTitleInCache | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
flushCacheForPage | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getQualityLevelForPageTitle | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
3.04 | |||
prefetchQualityLevelForTitles | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
fetchQualityLevelForPageTitles | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
fetchQualityLevelForPageTitlesFromPageProperties | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
3.00 | |||
fetchQualityLevelForPageTitlesFromPageCategories | |
95.00% |
19 / 20 |
|
0.00% |
0 / 1 |
4 | |||
filterPagesWithoutKnownQuality | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getCategoryForQualityLevels | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
computeCategoryForQualityLevels | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | |
3 | namespace ProofreadPage\Page; |
4 | |
5 | use InvalidArgumentException; |
6 | use MediaWiki\MediaWikiServices; |
7 | use MediaWiki\Title\Title; |
8 | |
9 | /** |
10 | * @license GPL-2.0-or-later |
11 | * |
12 | * Allows to retrieve the quality level of a Page: page |
13 | * |
14 | * TODO: drop the category fallback when all Wikisource pages will have the relevant page property |
15 | */ |
16 | class DatabasePageQualityLevelLookup implements PageQualityLevelLookup { |
17 | |
18 | /** |
19 | * @var int |
20 | */ |
21 | private $pageNamespaceId; |
22 | |
23 | /** |
24 | * @var Title[] |
25 | */ |
26 | private $categoryForQualityLevel; |
27 | |
28 | /** @var (int|null)[] */ |
29 | private $cache = []; |
30 | |
31 | /** |
32 | * @param int $pageNamespaceId |
33 | */ |
34 | public function __construct( $pageNamespaceId ) { |
35 | $this->pageNamespaceId = $pageNamespaceId; |
36 | } |
37 | |
38 | /** |
39 | * @inheritDoc |
40 | */ |
41 | public function isPageTitleInCache( Title $pageTitle ): bool { |
42 | return array_key_exists( $pageTitle->getDBkey(), $this->cache ); |
43 | } |
44 | |
45 | /** |
46 | * @inheritDoc |
47 | */ |
48 | public function flushCacheForPage( Title $pageTitle ) { |
49 | unset( $this->cache[ $pageTitle->getDBkey() ] ); |
50 | } |
51 | |
52 | /** |
53 | * @inheritDoc |
54 | */ |
55 | public function getQualityLevelForPageTitle( Title $pageTitle ) { |
56 | if ( !$pageTitle->inNamespace( $this->pageNamespaceId ) ) { |
57 | throw new InvalidArgumentException( $pageTitle . ' is not in Page: namespace' ); |
58 | } |
59 | $cacheKey = $pageTitle->getDBkey(); |
60 | if ( !array_key_exists( $cacheKey, $this->cache ) ) { |
61 | $this->fetchQualityLevelForPageTitles( [ $pageTitle ] ); |
62 | } |
63 | return $this->cache[$cacheKey]; |
64 | } |
65 | |
66 | /** |
67 | * @inheritDoc |
68 | */ |
69 | public function prefetchQualityLevelForTitles( array $pageTitles ) { |
70 | $pageTitles = array_filter( $pageTitles, function ( $pageTitle ) { |
71 | return $pageTitle instanceof Title && |
72 | $pageTitle->inNamespace( $this->pageNamespaceId ) && |
73 | !array_key_exists( $pageTitle->getDBkey(), $this->cache ); |
74 | } ); |
75 | |
76 | $this->fetchQualityLevelForPageTitles( $pageTitles ); |
77 | } |
78 | |
79 | /** |
80 | * @param Title[] $pageTitles |
81 | */ |
82 | private function fetchQualityLevelForPageTitles( array $pageTitles ) { |
83 | // We set to unknown all qualities |
84 | foreach ( $pageTitles as $pageTitle ) { |
85 | $this->cache[$pageTitle->getDBkey()] = null; |
86 | } |
87 | |
88 | $this->fetchQualityLevelForPageTitlesFromPageProperties( $pageTitles ); |
89 | $this->fetchQualityLevelForPageTitlesFromPageCategories( |
90 | $this->filterPagesWithoutKnownQuality( $pageTitles ) |
91 | ); |
92 | } |
93 | |
94 | /** |
95 | * @param Title[] $pageTitles |
96 | */ |
97 | private function fetchQualityLevelForPageTitlesFromPageProperties( array $pageTitles ) { |
98 | if ( !$pageTitles ) { |
99 | return; |
100 | } |
101 | |
102 | $dbr = MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->getReplicaDatabase(); |
103 | $results = $dbr->select( |
104 | [ 'page_props', 'page' ], |
105 | [ 'page_title', 'pp_value' ], |
106 | [ |
107 | 'pp_propname' => 'proofread_page_quality_level', |
108 | 'page_id = pp_page', |
109 | 'page_namespace' => $this->pageNamespaceId, |
110 | 'page_title' => array_map( static function ( Title $pageTitle ) { |
111 | return $pageTitle->getDBkey(); |
112 | }, $pageTitles ) |
113 | ], |
114 | __METHOD__ |
115 | ); |
116 | foreach ( $results as $result ) { |
117 | $this->cache[$result->page_title] = intval( $result->pp_value ); |
118 | } |
119 | } |
120 | |
121 | /** |
122 | * @param Title[] $pageTitles |
123 | */ |
124 | private function fetchQualityLevelForPageTitlesFromPageCategories( array $pageTitles ) { |
125 | if ( !$pageTitles ) { |
126 | return; |
127 | } |
128 | |
129 | $pageDbKeys = array_map( static function ( Title $title ){ |
130 | return $title->getDBkey(); |
131 | }, $pageTitles ); |
132 | |
133 | $dbr = MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->getReplicaDatabase(); |
134 | foreach ( $this->getCategoryForQualityLevels() as $qualityLevel => $qualityCategory ) { |
135 | $results = $dbr->select( |
136 | [ 'categorylinks', 'page' ], |
137 | [ 'page_title' ], |
138 | [ |
139 | 'page_id = cl_from', |
140 | 'page_title' => $pageDbKeys, |
141 | 'cl_to' => $qualityCategory->getDBkey(), |
142 | 'page_namespace' => $this->pageNamespaceId |
143 | ], |
144 | __METHOD__ |
145 | ); |
146 | |
147 | foreach ( $results as $result ) { |
148 | $this->cache[$result->page_title] = $qualityLevel; |
149 | } |
150 | } |
151 | } |
152 | |
153 | /** |
154 | * @param array $pageTitles |
155 | * @return array |
156 | */ |
157 | private function filterPagesWithoutKnownQuality( array $pageTitles ) { |
158 | return array_filter( $pageTitles, function ( Title $pageTitle ) { |
159 | return $this->cache[$pageTitle->getDBkey()] === null; |
160 | } ); |
161 | } |
162 | |
163 | /** |
164 | * @return array categoryForQualityLevel |
165 | */ |
166 | private function getCategoryForQualityLevels() { |
167 | if ( $this->categoryForQualityLevel === null ) { |
168 | $this->categoryForQualityLevel = $this->computeCategoryForQualityLevels(); |
169 | } |
170 | return $this->categoryForQualityLevel; |
171 | } |
172 | |
173 | private function computeCategoryForQualityLevels() { |
174 | $qualityCategories = []; |
175 | for ( $qualityLevel = 0; $qualityLevel <= 4; $qualityLevel++ ) { |
176 | $categoryTitle = Title::makeTitleSafe( |
177 | NS_CATEGORY, |
178 | wfMessage( "proofreadpage_quality{$qualityLevel}_category" )->inContentLanguage()->text() |
179 | ); |
180 | if ( $categoryTitle !== null ) { |
181 | $qualityCategories[$qualityLevel] = $categoryTitle; |
182 | } |
183 | } |
184 | return $qualityCategories; |
185 | } |
186 | } |