Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 86 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
FlowUpdateRevisionContentLength | |
0.00% |
0 / 80 |
|
0.00% |
0 / 5 |
272 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getUpdateKey | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
doDBUpdates | |
0.00% |
0 / 63 |
|
0.00% |
0 / 1 |
72 | |||
updateRevision | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
calcContentLength | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | |
3 | namespace Flow\Maintenance; |
4 | |
5 | use BatchRowIterator; |
6 | use Flow\Container; |
7 | use Flow\Data\ManagerGroup; |
8 | use Flow\DbFactory; |
9 | use Flow\Model\AbstractRevision; |
10 | use Flow\Model\UUID; |
11 | use LoggedUpdateMaintenance; |
12 | use MediaWiki\WikiMap\WikiMap; |
13 | use ReflectionProperty; |
14 | |
15 | $IP = getenv( 'MW_INSTALL_PATH' ); |
16 | if ( $IP === false ) { |
17 | $IP = __DIR__ . '/../../..'; |
18 | } |
19 | |
20 | require_once "$IP/maintenance/Maintenance.php"; |
21 | |
22 | /** |
23 | * @ingroup Maintenance |
24 | */ |
25 | class FlowUpdateRevisionContentLength extends LoggedUpdateMaintenance { |
26 | /** |
27 | * Map from AbstractRevision::getRevisionType() to the class that holds |
28 | * that type. |
29 | * @todo seems this should be elsewhere for access by any code |
30 | * |
31 | * @var string[] |
32 | */ |
33 | private static $revisionTypes = [ |
34 | 'post' => \Flow\Model\PostRevision::class, |
35 | 'header' => \Flow\Model\Header::class, |
36 | 'post-summary' => \Flow\Model\PostSummary::class, |
37 | ]; |
38 | |
39 | /** |
40 | * @var DbFactory |
41 | */ |
42 | protected $dbFactory; |
43 | |
44 | /** |
45 | * @var ManagerGroup |
46 | */ |
47 | protected $storage; |
48 | |
49 | /** |
50 | * @var ReflectionProperty |
51 | */ |
52 | protected $contentLengthProperty; |
53 | |
54 | /** |
55 | * @var ReflectionProperty |
56 | */ |
57 | protected $previousContentLengthProperty; |
58 | |
59 | public function __construct() { |
60 | parent::__construct(); |
61 | $this->addDescription( "Updates content length for revisions with unset content length." ); |
62 | $this->setBatchSize( 300 ); |
63 | $this->requireExtension( 'Flow' ); |
64 | } |
65 | |
66 | public function getUpdateKey() { |
67 | return 'FlowUpdateRevisionContentLength:version2'; |
68 | } |
69 | |
70 | public function doDBUpdates() { |
71 | // Can't be done in constructor, happens too early in |
72 | // boot process |
73 | $this->dbFactory = Container::get( 'db.factory' ); |
74 | $this->storage = Container::get( 'storage' ); |
75 | // Since this is a one-shot maintenance script just reach in via reflection |
76 | // to change lengths |
77 | $this->contentLengthProperty = new ReflectionProperty( |
78 | AbstractRevision::class, |
79 | 'contentLength' |
80 | ); |
81 | $this->contentLengthProperty->setAccessible( true ); |
82 | $this->previousContentLengthProperty = new ReflectionProperty( |
83 | AbstractRevision::class, |
84 | 'previousContentLength' |
85 | ); |
86 | $this->previousContentLengthProperty->setAccessible( true ); |
87 | |
88 | $dbw = $this->dbFactory->getDB( DB_PRIMARY ); |
89 | // Walk through the flow_revision table |
90 | $it = new BatchRowIterator( |
91 | $dbw, |
92 | /* table = */'flow_revision', |
93 | /* primary key = */'rev_id', |
94 | $this->getBatchSize() |
95 | ); |
96 | // Only fetch rows created by users from the current wiki. |
97 | $it->addConditions( [ |
98 | 'rev_user_wiki' => WikiMap::getCurrentWikiId(), |
99 | ] ); |
100 | // We only need the id and type field |
101 | $it->setFetchColumns( [ 'rev_id', 'rev_type' ] ); |
102 | |
103 | $it->setCaller( __METHOD__ ); |
104 | |
105 | $total = $fail = 0; |
106 | foreach ( $it as $batch ) { |
107 | $this->beginTransaction( $dbw, __METHOD__ ); |
108 | foreach ( $batch as $row ) { |
109 | $total++; |
110 | if ( !isset( self::$revisionTypes[$row->rev_type] ) ) { |
111 | $this->output( 'Unknown revision type: ' . $row->rev_type ); |
112 | $fail++; |
113 | continue; |
114 | } |
115 | $om = $this->storage->getStorage( self::$revisionTypes[$row->rev_type] ); |
116 | $revId = UUID::create( $row->rev_id ); |
117 | $obj = $om->get( $revId ); |
118 | if ( !$obj ) { |
119 | $this->output( 'Could not load revision: ' . $revId->getAlphadecimal() ); |
120 | $fail++; |
121 | continue; |
122 | } |
123 | if ( $obj->isFirstRevision() ) { |
124 | $previous = null; |
125 | } else { |
126 | $previous = $om->get( $obj->getPrevRevisionId() ); |
127 | if ( !$previous ) { |
128 | $this->output( 'Could not locate previous revision: ' . |
129 | $obj->getPrevRevisionId()->getAlphadecimal() ); |
130 | $fail++; |
131 | continue; |
132 | } |
133 | } |
134 | |
135 | $this->updateRevision( $obj, $previous ); |
136 | |
137 | try { |
138 | $om->put( $obj ); |
139 | } catch ( \Exception $e ) { |
140 | $this->error( |
141 | 'Failed to update revision ' . $obj->getRevisionId()->getAlphadecimal() . |
142 | ': ' . $e->getMessage() . "\n" . |
143 | 'Please make sure rev_content, rev_content_length, rev_flags & ' . |
144 | 'rev_previous_content_length are part of RevisionStorage::$allowedUpdateColumns.' |
145 | ); |
146 | throw $e; |
147 | } |
148 | $this->output( '.' ); |
149 | } |
150 | $this->commitTransaction( $dbw, __METHOD__ ); |
151 | $this->storage->clear(); |
152 | $this->dbFactory->waitForReplicas(); |
153 | } |
154 | |
155 | return true; |
156 | } |
157 | |
158 | protected function updateRevision( AbstractRevision $revision, AbstractRevision $previous = null ) { |
159 | $this->contentLengthProperty->setValue( |
160 | $revision, |
161 | $this->calcContentLength( $revision ) |
162 | ); |
163 | if ( $previous !== null ) { |
164 | $this->previousContentLengthProperty->setValue( |
165 | $revision, |
166 | $this->calcContentLength( $previous ) |
167 | ); |
168 | } |
169 | } |
170 | |
171 | protected function calcContentLength( AbstractRevision $revision ) { |
172 | if ( $revision->isModerated() && !$revision->isLocked() ) { |
173 | return 0; |
174 | } else { |
175 | return $revision->getContentLength() ?: $revision->calculateContentLength(); |
176 | } |
177 | } |
178 | } |
179 | |
180 | $maintClass = FlowUpdateRevisionContentLength::class; |
181 | require_once RUN_MAINTENANCE_IF_MAIN; |