| Current File : /home/jvzmxxx/wiki1/extensions/Flow/maintenance/FlowUpdateUserWiki.php |
<?php
use Flow\Container;
use Flow\Model\UUID;
use Flow\Model\PostRevision;
$IP = getenv( 'MW_INSTALL_PATH' );
if ( $IP === false ) {
$IP = dirname( __FILE__ ) . '/../../..';
}
require_once( "$IP/maintenance/Maintenance.php" );
/**
* Update all xxx_user_wiki field to have the correct wiki name
*
* @ingroup Maintenance
*/
class FlowUpdateUserWiki extends LoggedUpdateMaintenance {
/**
* Used to track the number of current updated count
*/
private $updatedCount = 0;
public function __construct() {
parent::__construct();
$this->mDescription = "Update xxx_user_wiki field in tables: flow_workflow, flow_tree_revision, flow_revision";
$this->setBatchSize( 300 );
}
/**
* This is a top-to-bottom update, the process is like this:
* workflow -> header -> header revision -> history
* workflow -> topic list -> post tree revision -> post revision -> history
*
* Some side effect, the script will also update those *_user_wiki fields with
* empty *_user_id and *_user_ip, but this doesn't hurt. Alternatively, we could
* add a check user_id != 0 and user_ip is not null to the query, but this will
* result in more db queries
*
*/
protected function doDBUpdates() {
$id = '';
$count = $this->mBatchSize;
$dbr = Container::get( 'db.factory' )->getDB( DB_SLAVE );
// If table flow_header_revision does not exist, that means the wiki
// has run the data migration before or the wiki starts from scratch,
// there is no point to run the script againt invalid tables
if ( !$dbr->tableExists( 'flow_header_revision', __METHOD__ ) ) {
return true;
}
while ( $count == $this->mBatchSize ) {
$count = 0;
$res = $dbr->select(
array( 'flow_workflow' ),
array( 'workflow_wiki', 'workflow_id', 'workflow_type' ),
array(
'workflow_id > ' . $dbr->addQuotes( $id ),
),
__METHOD__,
array( 'ORDER BY' => 'workflow_id ASC', 'LIMIT' => $this->mBatchSize )
);
if ( $res ) {
foreach ( $res as $row ) {
$count++;
$id = $row->workflow_id;
$uuid = UUID::create( $row->workflow_id );
$workflow = Container::get( 'storage.workflow' )->get( $uuid );
if ( $workflow ) {
// definition type 'topic' is always under a 'discussion' and they
// will be handled while processing 'discussion'
if ( $row->workflow_type == 'discussion' ) {
$this->updateHeader( $workflow, $row->workflow_wiki );
$this->updateTopicList( $workflow, $row->workflow_wiki );
}
}
}
} else {
throw new \MWException( 'SQL error in maintenance script ' . __CLASS__ . '::' . __METHOD__ );
}
}
return true;
}
/**
* Update header
*/
private function updateHeader( $workflow, $wiki ) {
$id = '';
$count = $this->mBatchSize;
$dbr = Container::get( 'db.factory' )->getDB( DB_SLAVE );
while ( $count == $this->mBatchSize ) {
$count = 0;
$res = $dbr->select(
array( 'flow_header_revision', 'flow_revision' ),
array( 'rev_id', 'rev_type' ),
array(
'rev_id > ' . $dbr->addQuotes( $id ),
'header_rev_id = rev_id',
'header_workflow_id' => $workflow->getId()->getBinary()
),
__METHOD__,
array( 'ORDER BY' => 'header_rev_id ASC', 'LIMIT' => $this->mBatchSize )
);
if ( $res ) {
foreach ( $res as $row ) {
$count++;
$id = $row->rev_id;
$revision = Container::get( 'storage.header' )->get( UUID::create( $row->rev_id ) );
if ( $revision ) {
$this->updateRevision( $revision, $wiki );
}
}
} else {
throw new \MWException( 'SQL error in maintenance script ' . __CLASS__ . '::' . __METHOD__ );
}
}
}
/**
* Update topic list
*/
private function updateTopicList( $workflow, $wiki ) {
$id = '';
$count = $this->mBatchSize;
$dbr = Container::get( 'db.factory' )->getDB( DB_SLAVE );
while ( $count == $this->mBatchSize ) {
$count = 0;
$res = $dbr->select(
array( 'flow_topic_list' ),
array( 'topic_id' ),
array(
'topic_list_id' => $workflow->getId()->getBinary(),
'topic_id > ' . $dbr->addQuotes( $id ),
),
__METHOD__,
array( 'ORDER BY' => 'topic_id ASC', 'LIMIT' => $this->mBatchSize )
);
if ( $res ) {
$index = 0;
foreach ( $res as $row ) {
$count++;
$index++;
$id = $row->topic_id;
$post = Container::get( 'loader.root_post' )->get( UUID::create( $row->topic_id ) );
if ( $post ) {
$this->updatePost( $post, $wiki );
}
}
} else {
throw new \MWException( 'SQL error in maintenance script ' . __CLASS__ . '::' . __METHOD__ );
}
}
}
/**
* Update post
*/
private function updatePost( $post, $wiki ) {
$this->updateHistory( $post, $wiki );
$this->updateRevision( $post, $wiki );
foreach ( $post->getChildren() as $child ) {
$this->updatePost( $child, $wiki );
}
}
/**
* Update history revision
*/
private function updateHistory( PostRevision $post, $wiki ) {
if ( $post->getPrevRevisionId() ) {
$parent = Container::get( 'storage.post' )->get( UUID::create( $post->getPrevRevisionId() ) );
if ( $parent ) {
$this->updateRevision( $parent, $wiki );
$this->updateHistory( $parent, $wiki );
}
}
}
/**
* Update either header or post revision
*/
private function updateRevision( $revision, $wiki ) {
if ( !$revision ) {
return;
}
$type = $revision->getRevisionType();
$dbw = Container::get( 'db.factory' )->getDB( DB_MASTER );
$res = $dbw->update(
'flow_revision',
array(
'rev_user_wiki' => $wiki,
'rev_mod_user_wiki' => $wiki,
'rev_edit_user_wiki' => $wiki,
),
array(
'rev_id' => $revision->getRevisionId()->getBinary(),
),
__METHOD__
);
if ( !$res ) {
throw new \MWException( 'SQL error in maintenance script ' . __CLASS__ . '::' . __METHOD__ );
}
$this->checkForSlave();
if ( $type === 'post' ) {
$res = $dbw->update(
'flow_tree_revision',
array(
'tree_orig_user_wiki' => $wiki,
),
array(
'tree_rev_id' => $revision->getRevisionId()->getBinary(),
),
__METHOD__
);
if ( !$res ) {
throw new \MWException( 'SQL error in maintenance script ' . __CLASS__ . '::' . __METHOD__ );
}
$this->checkForSlave();
}
}
private function checkForSlave() {
global $wgFlowCluster;
$this->updatedCount++;
if ( $this->updatedCount > $this->mBatchSize ) {
wfWaitForSlaves( false, false, $wgFlowCluster );
$this->updatedCount = 0;
}
}
/**
* Get the update key name to go in the update log table
*
* @return string
*/
protected function getUpdateKey() {
return 'FlowUpdateUserWiki';
}
}
$maintClass = "FlowUpdateUserWiki";
require_once( DO_MAINTENANCE );