Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 60 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
DeferredDescriptionUpdate | |
0.00% |
0 / 60 |
|
0.00% |
0 / 3 |
156 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
doUpdate | |
0.00% |
0 / 52 |
|
0.00% |
0 / 1 |
110 | |||
loadDescriptionFromApi | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
16 | * |
17 | * @file |
18 | */ |
19 | |
20 | declare( strict_types=1 ); |
21 | |
22 | namespace MediaWiki\Extension\WikiSEO; |
23 | |
24 | use DeferrableUpdate; |
25 | use Exception; |
26 | use ExtensionDependencyError; |
27 | use MediaWiki\MediaWikiServices; |
28 | use MWException; |
29 | use Title; |
30 | |
31 | /** |
32 | * This runs through the onRevisionDataUpdates hook but only if $wgWikiSeoEnableAutoDescription is enabled |
33 | * and no manual description was set |
34 | * |
35 | * The goal of this class is to automatically set a description for each page after if has been edited. |
36 | * Currently, only TextExtracts is available |
37 | */ |
38 | class DeferredDescriptionUpdate implements DeferrableUpdate { |
39 | |
40 | /** |
41 | * @var Title The title to work on |
42 | */ |
43 | private $title; |
44 | |
45 | /** |
46 | * @var bool Whether to cut of dangling sentences |
47 | */ |
48 | private $clean; |
49 | |
50 | /** |
51 | * Current description property from ParserOutput |
52 | * |
53 | * @var string |
54 | */ |
55 | private $currentDescription; |
56 | |
57 | /** |
58 | * Do a deferred update to the specified title. |
59 | * Usually runs when RevisionDataUpdates occurs |
60 | * |
61 | * @param Title $title |
62 | * @param string|null $currentDescription |
63 | * @param bool $cleanDescription |
64 | */ |
65 | public function __construct( Title $title, ?string $currentDescription, bool $cleanDescription = false ) { |
66 | $this->title = $title; |
67 | $this->currentDescription = $currentDescription ?? ''; |
68 | $this->clean = $cleanDescription; |
69 | } |
70 | |
71 | /** |
72 | * We do have to manually set the page properties, as we have no way of getting the parser or outputpage |
73 | * in a deferred update |
74 | */ |
75 | public function doUpdate(): void { |
76 | try { |
77 | $apiDescription = $this->loadDescriptionFromApi(); |
78 | } catch ( Exception $e ) { |
79 | return; |
80 | } |
81 | |
82 | $apiDescription = trim( $apiDescription ?? '' ); |
83 | $emptyLikeDescriptions = [ '', '…', '\u2026' ]; |
84 | |
85 | // If API response is empty like, or current description is equal to api description, exit early |
86 | if ( in_array( $apiDescription, $emptyLikeDescriptions, true ) || |
87 | strcmp( $this->currentDescription, $apiDescription ) === 0 ) { |
88 | return; |
89 | } |
90 | |
91 | $propertyDescriptions = MediaWikiServices::getInstance()->getPageProps() |
92 | ->getProperties( $this->title, 'description' ); |
93 | |
94 | $dbl = MediaWikiServices::getInstance()->getDBLoadBalancer(); |
95 | $db = $dbl->getConnection( $dbl->getWriterIndex() ); |
96 | |
97 | // Flag indicating if an insert or update should happen |
98 | $shouldInsert = false; |
99 | switch ( true ) { |
100 | case count( $propertyDescriptions ) > 1: |
101 | // There are multiple page props with the name 'description' present |
102 | // This shouldn't happen, but we'll try to clean it here |
103 | $db->delete( |
104 | 'page_props', |
105 | [ |
106 | 'pp_page' => $this->title->getArticleID(), |
107 | 'pp_propname' => 'description', |
108 | ] |
109 | ); |
110 | // Intentional fall-through, as deleting all 'description' props requires inserting a new row |
111 | case empty( $propertyDescriptions ): |
112 | $shouldInsert = true; |
113 | break; |
114 | |
115 | default: |
116 | break; |
117 | } |
118 | |
119 | if ( count( $propertyDescriptions ) === 1 ) { |
120 | $prop = array_shift( $propertyDescriptions ); |
121 | // Sanity check |
122 | $descriptionEqual = strcmp( $prop ?? '', $apiDescription ) === 0; |
123 | if ( $descriptionEqual ) { |
124 | return; |
125 | } |
126 | } |
127 | |
128 | if ( $shouldInsert ) { |
129 | $db->insert( |
130 | 'page_props', |
131 | [ |
132 | 'pp_page' => $this->title->getArticleID(), |
133 | 'pp_propname' => 'description', |
134 | 'pp_value' => $apiDescription, |
135 | 'pp_sortkey' => null, |
136 | ], |
137 | __METHOD__ |
138 | ); |
139 | } else { |
140 | $db->update( |
141 | 'page_props', |
142 | [ |
143 | 'pp_value' => $apiDescription, |
144 | ], |
145 | [ |
146 | 'pp_page' => $this->title->getArticleID(), |
147 | 'pp_propname' => 'description', |
148 | ], |
149 | __METHOD__ |
150 | ); |
151 | } |
152 | } |
153 | |
154 | /** |
155 | * @return string|null |
156 | * @throws ExtensionDependencyError |
157 | * @throws MWException |
158 | */ |
159 | private function loadDescriptionFromApi(): ?string { |
160 | $descriptor = new ApiDescription( |
161 | $this->title, |
162 | $this->clean |
163 | ); |
164 | |
165 | return $descriptor->getDescription(); |
166 | } |
167 | } |