jenkins-bot has submitted this change and it was merged. Change subject: Clean up SecurePoll_CreatePage transactions ......................................................................
Clean up SecurePoll_CreatePage transactions Also fixed some annoying IDEA errors and unused vars Change-Id: I0f8bf0200e69c98f2276bbea4c167e0e0e0f2b3d --- M includes/entities/Election.php M includes/entities/Question.php M includes/main/Context.php M includes/pages/ActionPage.php M includes/pages/CreatePage.php 5 files changed, 164 insertions(+), 154 deletions(-) Approvals: Anomie: Looks good to me, approved jenkins-bot: Verified diff --git a/includes/entities/Election.php b/includes/entities/Election.php index 09e65c0..ff0ef1d 100644 --- a/includes/entities/Election.php +++ b/includes/entities/Election.php @@ -298,7 +298,7 @@ /** * Get the questions in this election - * @return array of SecurePoll_Question objects. + * @return SecurePoll_Question[] */ function getQuestions() { if ( $this->questions === null ) { diff --git a/includes/entities/Question.php b/includes/entities/Question.php index e862dd5..66d4112 100644 --- a/includes/entities/Question.php +++ b/includes/entities/Question.php @@ -5,7 +5,9 @@ * more than one question in an election. */ class SecurePoll_Question extends SecurePoll_Entity { - public $options, $electionId; + /** @var SecurePoll_Option[] */ + public $options; + public $electionId; /** * Constructor diff --git a/includes/main/Context.php b/includes/main/Context.php index c59a7f0..9cc896f 100644 --- a/includes/main/Context.php +++ b/includes/main/Context.php @@ -109,6 +109,7 @@ /** * Get an election object from the store, with a given entity ID. Returns * false if it does not exist. + * @return SecurePoll_Election */ function getElection( $id ) { if( !isset( $this->electionCache[$id] ) ) { @@ -125,6 +126,7 @@ /** * Get an election object from the store, with a given name. Returns false * if there is no such election. + * @return SecurePoll_Election */ function getElectionByTitle( $name ) { $info = $this->getStore()->getElectionInfoByTitle( array( $name ) ); @@ -138,6 +140,7 @@ /** * Get an election object from a securepoll_elections DB row. This will fail * if the current store class does not support database operations. + * @return SecurePoll_Election */ function newElectionFromRow( $row ) { $info = $this->getStore()->decodeElectionRow( $row ); diff --git a/includes/pages/ActionPage.php b/includes/pages/ActionPage.php index e67a8e1..5cf05b0 100644 --- a/includes/pages/ActionPage.php +++ b/includes/pages/ActionPage.php @@ -4,7 +4,15 @@ * Parent class for Special:SecurePoll subpages. */ abstract class SecurePoll_ActionPage { - public $specialPage, $election, $auth, $user; + /** @var SecurePoll_SpecialSecurePoll */ + public $specialPage; + /** @var SecurePoll_Election */ + public $election; + /** @var SecurePoll_Auth */ + public $auth; + /** @var User */ + public $user; + /** @var SecurePoll_Context */ public $context; /** diff --git a/includes/pages/CreatePage.php b/includes/pages/CreatePage.php index 97e9bb3..11cca58 100644 --- a/includes/pages/CreatePage.php +++ b/includes/pages/CreatePage.php @@ -7,6 +7,8 @@ /** * Execute the subpage. * @param $params array Array of subpage parameters. + * @throws MWException + * @throws PermissionsError */ function execute( $params ) { global $wgSecurePollCreateWikiGroupDir, $wgSecurePollCreateWikiGroups; @@ -380,13 +382,15 @@ } $dbw = $this->context->getDB(); - $properties = array(); - $messages = array(); // Check for duplicate titles on the local wiki - $id = $dbw->selectField( 'securepoll_elections', 'el_entity', array( - 'el_title' => $election->title - ), __METHOD__, array( 'FOR UPDATE' ) ); + $id = $dbw->selectField( + 'securepoll_elections', + 'el_entity', + [ 'el_title' => $election->title ], + __METHOD__, + [ 'FOR UPDATE' ] + ); if ( $id && (int)$id !== $election->getId() ) { throw new SecurePoll_StatusException( 'securepoll-create-duplicate-title', SecurePoll_FormStore::getWikiName( wfWikiId() ), wfWikiID() @@ -413,121 +417,118 @@ 'p2.pr_value' => wfWikiID(), ) ); - // Test for duplicate title $id = $rdbw->selectField( 'securepoll_elections', 'el_entity', array( 'el_title' => $formData['election_title'] ) ); + + $lb->reuseConnection( $rdbw ); + if ( $id && $id !== $rId ) { throw new SecurePoll_StatusException( 'securepoll-create-duplicate-title', SecurePoll_FormStore::getWikiName( $dbname ), $dbname ); } - $lb->reuseConnection( $rdbw ); } - } - - // Ok, begin the actual work - $dbw->begin( __METHOD__ ); - try { - if ( $election->getId() > 0 ) { - $id = $dbw->selectField( 'securepoll_elections', 'el_entity', array( - 'el_entity' => $election->getId() - ), __METHOD__, array( 'FOR UPDATE' ) ); - if ( !$id ) { - return Status::newFatal( 'securepoll-create-fail-id-missing' ); - } - } - - // Insert or update the election entity - $fields = array( - 'el_title' => $election->title, - 'el_ballot' => $election->ballotType, - 'el_tally' => $election->tallyType, - 'el_primary_lang' => $election->getLanguage(), - 'el_start_date' => $dbw->timestamp( $election->getStartDate() ), - 'el_end_date' => $dbw->timestamp( $election->getEndDate() ), - 'el_auth_type' => $election->authType, - ); - if ( $election->getId() < 0 ) { - $eId = self::insertEntity( $dbw, 'election' ); - $qIds = array(); - $oIds = array(); - $fields['el_entity'] = $eId; - $dbw->insert( 'securepoll_elections', $fields, __METHOD__ ); - } else { - $eId = $election->getId(); - $dbw->update( 'securepoll_elections', $fields, array( 'el_entity' => $eId ), __METHOD__ ); - - // Delete any questions or options that weren't included in the - // form submission. - $qIds = array(); - $res = $dbw->select( 'securepoll_questions', 'qu_entity', array( 'qu_election' => $eId ) ); - foreach ( $res as $row ) { - $qIds[] = $row->qu_entity; - } - $oIds = array(); - $res = $dbw->select( 'securepoll_options', 'op_entity', array( 'op_election' => $eId ) ); - foreach ( $res as $row ) { - $oIds[] = $row->op_entity; - } - $deleteIds = array_merge( - array_diff( $qIds, $store->qIds ), - array_diff( $oIds, $store->oIds ) - ); - if ( $deleteIds ) { - $dbw->delete( 'securepoll_msgs', array( 'msg_entity' => $deleteIds ), __METHOD__ ); - $dbw->delete( 'securepoll_properties', array( 'pr_entity' => $deleteIds ), __METHOD__ ); - $dbw->delete( 'securepoll_questions', array( 'qu_entity' => $deleteIds ), __METHOD__ ); - $dbw->delete( 'securepoll_options', array( 'op_entity' => $deleteIds ), __METHOD__ ); - $dbw->delete( 'securepoll_entity', array( 'en_id' => $deleteIds ), __METHOD__ ); - } - } - self::savePropertiesAndMessages( $dbw, $eId, $election ); - - // Now do questions and options - $qIndex = 0; - foreach ( $election->getQuestions() as $question ) { - $qId = $question->getId(); - if ( !in_array( $qId, $qIds ) ) { - $qId = self::insertEntity( $dbw, 'question' ); - } - $dbw->replace( 'securepoll_questions', - array( 'qu_entity' ), - array( - 'qu_entity' => $qId, - 'qu_election' => $eId, - 'qu_index' => ++$qIndex, - ), - __METHOD__ - ); - self::savePropertiesAndMessages( $dbw, $qId, $question ); - - foreach ( $question->getOptions() as $option ) { - $oId = $option->getId(); - if ( !in_array( $oId, $oIds ) ) { - $oId = self::insertEntity( $dbw, 'option' ); - } - $dbw->replace( 'securepoll_options', - array( 'op_entity' ), - array( - 'op_entity' => $oId, - 'op_election' => $eId, - 'op_question' => $qId, - ), - __METHOD__ - ); - self::savePropertiesAndMessages( $dbw, $oId, $option ); - } - } - $dbw->commit( __METHOD__ ); - } catch ( Exception $ex ) { - $dbw->rollback( __METHOD__ ); - throw $ex; } } catch ( SecurePoll_StatusException $ex ) { return $ex->status; } + + // Ok, begin the actual work + $dbw->startAtomic( __METHOD__ ); + if ( $election->getId() > 0 ) { + $id = $dbw->selectField( 'securepoll_elections', 'el_entity', array( + 'el_entity' => $election->getId() + ), __METHOD__, array( 'FOR UPDATE' ) ); + if ( !$id ) { + $dbw->endAtomic( __METHOD__ ); + return Status::newFatal( 'securepoll-create-fail-id-missing' ); + } + } + + // Insert or update the election entity + $fields = array( + 'el_title' => $election->title, + 'el_ballot' => $election->ballotType, + 'el_tally' => $election->tallyType, + 'el_primary_lang' => $election->getLanguage(), + 'el_start_date' => $dbw->timestamp( $election->getStartDate() ), + 'el_end_date' => $dbw->timestamp( $election->getEndDate() ), + 'el_auth_type' => $election->authType, + ); + if ( $election->getId() < 0 ) { + $eId = self::insertEntity( $dbw, 'election' ); + $qIds = array(); + $oIds = array(); + $fields['el_entity'] = $eId; + $dbw->insert( 'securepoll_elections', $fields, __METHOD__ ); + } else { + $eId = $election->getId(); + $dbw->update( 'securepoll_elections', $fields, array( 'el_entity' => $eId ), __METHOD__ ); + + // Delete any questions or options that weren't included in the + // form submission. + $qIds = array(); + $res = $dbw->select( 'securepoll_questions', 'qu_entity', array( 'qu_election' => $eId ) ); + foreach ( $res as $row ) { + $qIds[] = $row->qu_entity; + } + $oIds = array(); + $res = $dbw->select( 'securepoll_options', 'op_entity', array( 'op_election' => $eId ) ); + foreach ( $res as $row ) { + $oIds[] = $row->op_entity; + } + $deleteIds = array_merge( + array_diff( $qIds, $store->qIds ), + array_diff( $oIds, $store->oIds ) + ); + if ( $deleteIds ) { + $dbw->delete( 'securepoll_msgs', array( 'msg_entity' => $deleteIds ), __METHOD__ ); + $dbw->delete( 'securepoll_properties', array( 'pr_entity' => $deleteIds ), __METHOD__ ); + $dbw->delete( 'securepoll_questions', array( 'qu_entity' => $deleteIds ), __METHOD__ ); + $dbw->delete( 'securepoll_options', array( 'op_entity' => $deleteIds ), __METHOD__ ); + $dbw->delete( 'securepoll_entity', array( 'en_id' => $deleteIds ), __METHOD__ ); + } + } + self::savePropertiesAndMessages( $dbw, $eId, $election ); + + // Now do questions and options + $qIndex = 0; + foreach ( $election->getQuestions() as $question ) { + $qId = $question->getId(); + if ( !in_array( $qId, $qIds ) ) { + $qId = self::insertEntity( $dbw, 'question' ); + } + $dbw->replace( 'securepoll_questions', + array( 'qu_entity' ), + array( + 'qu_entity' => $qId, + 'qu_election' => $eId, + 'qu_index' => ++$qIndex, + ), + __METHOD__ + ); + self::savePropertiesAndMessages( $dbw, $qId, $question ); + + foreach ( $question->getOptions() as $option ) { + $oId = $option->getId(); + if ( !in_array( $oId, $oIds ) ) { + $oId = self::insertEntity( $dbw, 'option' ); + } + $dbw->replace( 'securepoll_options', + array( 'op_entity' ), + array( + 'op_entity' => $oId, + 'op_election' => $eId, + 'op_question' => $qId, + ), + __METHOD__ + ); + self::savePropertiesAndMessages( $dbw, $oId, $option ); + } + } + $dbw->endAtomic( __METHOD__ ); // Create the "redirect" polls on all the local wikis if ( $store->rId ) { @@ -535,52 +536,47 @@ foreach ( $store->remoteWikis as $dbname ) { $lb = wfGetLB( $dbname ); $dbw = $lb->getConnection( DB_MASTER, array(), $dbname ); - $dbw->begin( __METHOD__ ); - try { - // Find an existing dummy election, if any - $rId = $dbw->selectField( - array( 'p1' => 'securepoll_properties', 'p2' => 'securepoll_properties' ), - 'p1.pr_entity', - array( - 'p1.pr_entity = p2.pr_entity', - 'p1.pr_key' => 'jump-id', - 'p1.pr_value' => $eId, - 'p2.pr_key' => 'main-wiki', - 'p2.pr_value' => wfWikiID(), - ) - ); - if ( !$rId ) { - $rId = self::insertEntity( $dbw, 'election' ); - } - - // Insert it! We don't have to care about questions or options here. - $dbw->replace( 'securepoll_elections', - array( 'el_entity' ), - array( - 'el_entity' => $rId, - 'el_title' => $election->title, - 'el_ballot' => $election->ballotType, - 'el_tally' => $election->tallyType, - 'el_primary_lang' => $election->getLanguage(), - 'el_start_date' => $dbw->timestamp( $election->getStartDate() ), - 'el_end_date' => $dbw->timestamp( $election->getEndDate() ), - 'el_auth_type' => $election->authType, - ), - __METHOD__ - ); - self::savePropertiesAndMessages( $dbw, $rId, $election ); - - // Fix jump-id - $dbw->update( 'securepoll_properties', - array( 'pr_value' => $eId ), - array( 'pr_entity' => $rId, 'pr_key' => 'jump-id' ), - __METHOD__ - ); - $dbw->commit( __METHOD__ ); - } catch ( Exception $ex ) { - $dbw->rollback( __METHOD__ ); - MWExceptionHandler::logException( $ex ); + $dbw->startAtomic( __METHOD__ ); + // Find an existing dummy election, if any + $rId = $dbw->selectField( + array( 'p1' => 'securepoll_properties', 'p2' => 'securepoll_properties' ), + 'p1.pr_entity', + array( + 'p1.pr_entity = p2.pr_entity', + 'p1.pr_key' => 'jump-id', + 'p1.pr_value' => $eId, + 'p2.pr_key' => 'main-wiki', + 'p2.pr_value' => wfWikiID(), + ) + ); + if ( !$rId ) { + $rId = self::insertEntity( $dbw, 'election' ); } + + // Insert it! We don't have to care about questions or options here. + $dbw->replace( 'securepoll_elections', + array( 'el_entity' ), + array( + 'el_entity' => $rId, + 'el_title' => $election->title, + 'el_ballot' => $election->ballotType, + 'el_tally' => $election->tallyType, + 'el_primary_lang' => $election->getLanguage(), + 'el_start_date' => $dbw->timestamp( $election->getStartDate() ), + 'el_end_date' => $dbw->timestamp( $election->getEndDate() ), + 'el_auth_type' => $election->authType, + ), + __METHOD__ + ); + self::savePropertiesAndMessages( $dbw, $rId, $election ); + + // Fix jump-id + $dbw->update( 'securepoll_properties', + array( 'pr_value' => $eId ), + array( 'pr_entity' => $rId, 'pr_key' => 'jump-id' ), + __METHOD__ + ); + $dbw->endAtomic( __METHOD__ ); $lb->reuseConnection( $dbw ); } } @@ -712,6 +708,7 @@ /** * Insert an entry into the securepoll_entities table, and return the ID * + * @param IDatabase $dbw * @param string $type Entity type * @return int */ -- To view, visit https://gerrit.wikimedia.org/r/304812 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I0f8bf0200e69c98f2276bbea4c167e0e0e0f2b3d Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/SecurePoll Gerrit-Branch: master Gerrit-Owner: Aaron Schulz <asch...@wikimedia.org> Gerrit-Reviewer: Anomie <bjor...@wikimedia.org> Gerrit-Reviewer: Tim Starling <tstarl...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits