Daniel Kinzler has submitted this change and it was merged.
Change subject: Split up switch-case into separate methods
......................................................................
Split up switch-case into separate methods
- part of EditEntity API refactoring
- get rid of huge switch-case and split it into methods
- remove the EXCLUDE parameter from the EditEntity API
- move aliases operations into seperate ChangeOpAliases class
- move sitelink operations into separate ChangeOpSiteLink class
Bug: 48137
Change-Id: Ic27774f67f8728acbb48cbf945fda063791096cf
---
M repo/Wikibase.classes.php
M repo/Wikibase.hooks.php
M repo/includes/api/EditEntity.php
A repo/includes/changeop/ChangeOpAliases.php
M repo/includes/changeop/ChangeOpDescription.php
M repo/includes/changeop/ChangeOpLabel.php
A repo/includes/changeop/ChangeOpSiteLink.php
M repo/includes/changeop/ChangeOps.php
M repo/tests/phpunit/includes/api/EditEntityTest.php
A repo/tests/phpunit/includes/changeop/ChangeOpAliasesTest.php
A repo/tests/phpunit/includes/changeop/ChangeOpSiteLinkTest.php
M repo/tests/phpunit/includes/changeop/ChangeOpsTest.php
12 files changed, 769 insertions(+), 292 deletions(-)
Approvals:
Daniel Kinzler: Verified; Looks good to me, approved
diff --git a/repo/Wikibase.classes.php b/repo/Wikibase.classes.php
index 1fa252b..6eb7d60 100644
--- a/repo/Wikibase.classes.php
+++ b/repo/Wikibase.classes.php
@@ -49,10 +49,14 @@
'Wikibase\PropertyView' => 'includes/PropertyView.php',
'Wikibase\Summary' => 'includes/Summary.php',
'Wikibase\Repo\WikibaseRepo' => 'includes/WikibaseRepo.php',
+
+ // includes/changeop
'Wikibase\ChangeOps' => 'includes/changeop/ChangeOps.php',
'Wikibase\ChangeOp' => 'includes/changeop/ChangeOp.php',
'Wikibase\ChangeOpLabel' =>
'includes/changeop/ChangeOpLabel.php',
'Wikibase\ChangeOpDescription' =>
'includes/changeop/ChangeOpDescription.php',
+ 'Wikibase\ChangeOpAliases' =>
'includes/changeop/ChangeOpAliases.php',
+ 'Wikibase\ChangeOpSiteLink' =>
'includes/changeop/ChangeOpSiteLink.php',
// includes/actions
'Wikibase\HistoryEntityAction' =>
'includes/actions/HistoryEntityAction.php',
diff --git a/repo/Wikibase.hooks.php b/repo/Wikibase.hooks.php
index 359bfcb..ebd10b3 100755
--- a/repo/Wikibase.hooks.php
+++ b/repo/Wikibase.hooks.php
@@ -190,6 +190,8 @@
'changeop/ChangeOps',
'changeop/ChangeOpLabel',
'changeop/ChangeOpDescription',
+ 'changeop/ChangeOpAliases',
+ 'changeop/ChangeOpSiteLink',
'content/EntityContentFactory',
'content/EntityHandler',
diff --git a/repo/includes/api/EditEntity.php b/repo/includes/api/EditEntity.php
index 65049e6..466cb98 100644
--- a/repo/includes/api/EditEntity.php
+++ b/repo/includes/api/EditEntity.php
@@ -3,9 +3,10 @@
namespace Wikibase\Api;
use Wikibase\ChangeOps;
-
use Wikibase\ChangeOpLabel;
use Wikibase\ChangeOpDescription;
+use Wikibase\ChangeOpAliases;
+use Wikibase\ChangeOpSiteLink;
use ApiBase, User, Status, SiteList;
use Wikibase\SiteLink;
use Wikibase\Entity;
@@ -31,7 +32,23 @@
class EditEntity extends ModifyEntity {
/**
- * @see \Wikibase\Api\Api::getRequiredPermissions()
+ * @since 0.4
+ *
+ * @var string[]
+ */
+ protected $validLanguageCodes;
+
+ /**
+ * @see ApiBase::_construct()
+ */
+ public function __construct( $mainModule, $moduleName ) {
+ parent::__construct( $mainModule, $moduleName );
+
+ $this->validLanguageCodes = array_flip(
Utils::getLanguageCodes() );
+ }
+
+ /**
+ * @see \Wikibase\Api\Api::getRequiredPermissions()
*/
protected function getRequiredPermissions( Entity $entity, array
$params ) {
$permissions = parent::getRequiredPermissions( $entity, $params
);
@@ -43,7 +60,7 @@
}
/**
- * @see \Wikibase\Api\ModifyEntity::findEntity()
+ * @see \Wikibase\Api\ModifyEntity::findEntity()
*/
protected function findEntity( array $params ) {
$entityContent = parent::findEntity( $params );
@@ -96,10 +113,10 @@
*/
protected function modifyEntity( EntityContent &$entityContent, array
$params ) {
wfProfileIn( __METHOD__ );
- $status = Status::newGood();
$summary = $this->createSummary( $params );
$entity = $entityContent->getEntity();
$changeOps = new ChangeOps();
+ $status = Status::newGood();
if ( isset( $params['id'] ) XOR ( isset( $params['site'] ) &&
isset( $params['title'] ) ) ) {
$summary->setAction( $params['clear'] === false ?
'update' : 'override' );
@@ -111,246 +128,48 @@
//TODO: Construct a nice and meaningful summary from the
changes that get applied!
// Perhaps that could be based on the resulting diff?
- if ( isset( $params['data'] ) ) {
- $data = json_decode( $params['data'], true );
- if ( is_null( $data ) ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( $this->msg(
'wikibase-api-json-invalid' )->text(), 'json-invalid' );
- }
- if ( !is_array( $data ) ) { // NOTE: json_decode will
decode any JS literal or structure, not just objects!
- wfProfileOut( __METHOD__ );
- $this->dieUsage( 'Top level structure must be a
JSON object', 'not-recognized-array' );
- }
- $languages = array_flip( Utils::getLanguageCodes() );
-
- if ( isset( $params['clear'] ) && $params['clear'] ) {
- $entityContent->getEntity()->clear();
- }
-
- $title = null;
- $revision = null;
- $page = $entityContent->getWikiPage();
- if ( $page ) {
- $title = $page->getTitle();
- $revision = $page->getRevision();
- }
-
- foreach ( $data as $props => $list ) {
- if ( !is_string( $props ) ) { // NOTE: catch
json_decode returning an indexed array (list)
- $this->dieUsage( 'Top level structure
must be a JSON object', 'not-recognized-string' );
- }
- // unconditional no-ops
- if ( in_array( $props, array( 'length',
'count', 'touched' ) ) ) {
- continue;
- }
- // conditional no-ops
- if ( isset( $params['exclude'] ) && in_array(
$props, $params['exclude'] ) ) {
- continue;
- }
-
- switch ($props) {
-
- // conditional processing
- case 'pageid':
- if ( isset( $data[$props] ) && (
is_object( $page ) ? $page->getId() !== $data[$props] : true ) ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( $this->msg(
'wikibase-api-illegal-field', 'pageid' )->text(), 'illegal-field' );
- }
- break;
- case 'ns':
- // not completely convinced that we can
use title to get the namespace in this case
- if ( isset( $data[$props] ) && (
is_object( $title ) ? $title->getNamespace() !== $data[$props] : true ) ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( $this->msg(
'wikibase-api-illegal-field', 'namespace' )->text(), 'illegal-field' );
- }
- break;
- case 'title':
- if ( isset( $data[$props] ) && (
is_object( $title ) ? $title->getPrefixedText() !== $data[$props] : true ) ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( $this->msg(
'wikibase-api-illegal-field', 'title' )->text(), 'illegal-field' );
- }
- break;
- case 'lastrevid':
- if ( isset( $data[$props] ) && (
is_object( $revision ) ? $revision->getId() !== $data[$props] : true ) ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( $this->msg(
'wikibase-api-illegal-field', 'lastrevid' )->text(), 'illegal-field' );
- }
- break;
-
- // ordinary entries
- case 'labels':
- if ( !is_array( $list ) ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "Key 'labels'
must refer to an array", 'not-recognized-array' );
- }
-
- foreach ( $list as $langCode => $arg ) {
- $status->merge(
$this->checkMultilangArgs( $arg, $langCode, $languages ) );
-
- $language = $arg['language'];
- $newLabel = Utils::trimToNFC(
$arg['value'] );
- $oldLabel = $entity->getLabel(
$language );
-
- if ( array_key_exists(
'remove', $arg ) || $newLabel === "" ) {
- $changeOps->add( new
ChangeOpLabel( $language, null ) );
- }
- else {
- $changeOps->add( new
ChangeOpLabel( $language, $newLabel ) );
- }
- }
-
- if ( !$status->isOk() ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "Contained
status: $1", $status->getWikiText() );
- }
-
- break;
-
- case 'descriptions':
- if ( !is_array( $list ) ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "Key
'descriptions' must refer to an array", 'not-recognized-array' );
- }
-
- foreach ( $list as $langCode => $arg ) {
- $status->merge(
$this->checkMultilangArgs( $arg, $langCode, $languages ) );
-
- $language = $arg['language'];
- $newDescription =
Utils::trimToNFC( $arg['value'] );
- $oldDescription =
$entity->getDescription( $language );
-
- if ( array_key_exists(
'remove', $arg ) || $newDescription === "" ) {
- $changeOps->add( new
ChangeOpDescription( $language, null ) );
- }
- else {
- $changeOps->add( new
ChangeOpDescription( $language, $newDescription ) );
- }
- }
-
- if ( !$status->isOk() ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "Contained
status: $1", $status->getWikiText() );
- }
-
- break;
-
- case 'aliases':
- if ( !is_array( $list ) ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "Key 'aliases'
must refer to an array", 'not-recognized-array' );
- }
-
- $aliases = array();
-
- foreach ( $list as $langCode => $arg ) {
- if ( intval( $langCode ) ) {
- $aliases[] = (
array_values($arg) === $arg ) ? $arg : array( $arg );
- } else {
- $aliases[$langCode] = (
array_values($arg) === $arg ) ? $arg : array( $arg );
- }
- }
-
- $setAliases = array();
- $addAliases = array();
- $remAliases = array();
-
- foreach ( $aliases as $langCode =>
$args ) {
- foreach ( $args as $arg ) {
- $status->merge(
$this->checkMultilangArgs( $arg, $langCode, $languages ) );
- if ( array_key_exists(
'remove', $arg ) ) {
-
$remAliases[$arg['language']][] = Utils::trimToNFC( $arg['value'] );
- }
- elseif (
array_key_exists( 'add', $arg ) ) {
-
$addAliases[$arg['language']][] = Utils::trimToNFC( $arg['value'] );
- }
- else {
-
$setAliases[$arg['language']][] = Utils::trimToNFC( $arg['value'] );
- }
- }
- }
- foreach ( $setAliases as $langCode =>
$strings ) {
-
$entityContent->getEntity()->setAliases( $langCode, $strings );
- }
- foreach ( $remAliases as $langCode =>
$strings ) {
-
$entityContent->getEntity()->removeAliases( $langCode, $strings );
- }
- foreach ( $addAliases as $langCode =>
$strings ) {
-
$entityContent->getEntity()->addAliases( $langCode, $strings );
- }
-
- if ( !$status->isOk() ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "Contained
status: $1", $status->getWikiText() );
- }
-
- unset( $aliases );
- unset( $setAliases );
- unset( $addAliases );
- unset( $remAliases );
-
- break;
-
- case 'sitelinks':
- // TODO: This is a temporary fix that
should be handled properly with an
- // injector/inputter class that is
specific for the given entity
- if (
$entityContent->getEntity()->getType() !== Item::ENTITY_TYPE ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "key can't be
handled: $props", 'not-recognized' );
- }
-
- if ( !is_array( $list ) ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "Key
'sitelinks' must refer to an array", 'not-recognized-array' );
- }
-
- $sites =
$this->getSiteLinkTargetSites();
-
- foreach ( $list as $siteId => $arg ) {
- $status->merge(
$this->checkSiteLinks( $arg, $siteId, $sites ) );
- if ( array_key_exists(
'remove', $arg ) || $arg['title'] === "" ) {
-
$entityContent->getEntity()->removeSiteLink( $arg['site'] );
- }
- else {
- $linkSite =
$sites->getSite( $arg['site'] );
- $linkPage =
$linkSite->normalizePageName( Utils::trimWhitespace( $arg['title'] ) );
-
- if ( $linkPage ===
false ) {
- wfProfileOut(
__METHOD__ );
-
$this->dieUsage( $this->msg( 'wikibase-api-no-external-page' )->text(),
'add-sitelink-failed' );
- }
-
- $link = new SiteLink(
$linkSite, $linkPage );
- $ret =
$entityContent->getEntity()->addSiteLink( $link, 'set' );
-
- if ( $ret === false ) {
- wfProfileOut(
__METHOD__ );
-
$this->dieUsage( $this->msg( 'wikibase-api-add-sitelink-failed' )->text(),
'add-sitelink-failed' );
- }
-
- unset( $linkSite );
- unset( $linkPage );
- unset( $link );
- unset( $ret );
- }
- }
-
- if ( !$status->isOk() ) {
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "Contained
status: $1", $status->getWikiText() );
- }
-
- unset( $sites );
-
- break;
-
- default:
- wfProfileOut( __METHOD__ );
- $this->dieUsage( "unknown key: $props",
'not-recognized' );
- }
- }
+ if ( !isset( $params['data'] ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( $this->msg( 'wikibase-api-no-data'
)->text(), 'no-data' );
}
- $changeOps->apply( $entity );
+ $data = json_decode( $params['data'], true );
+ $status->merge( $this->checkDataProperties( $data,
$entityContent->getWikiPage() ) );
+
+ if ( $params['clear'] ) {
+ $entityContent->getEntity()->clear();
+ }
+
+ if ( array_key_exists( 'labels', $data ) ) {
+ $changeOps->add( $this->getLabelChangeOps(
$data['labels'], $status ) );
+ }
+
+ if ( array_key_exists( 'descriptions', $data ) ) {
+ $changeOps->add( $this->getDescriptionChangeOps(
$data['descriptions'], $status ) );
+ }
+
+ if ( array_key_exists( 'aliases', $data ) ) {
+ $changeOps->add( $this->getAliasesChangeOps(
$data['aliases'], $status ) );
+ }
+
+ if ( array_key_exists( 'sitelinks', $data ) ) {
+ if ( $entity->getType() !== Item::ENTITY_TYPE ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( "key can't be handled:
$props", 'not-recognized' );
+ }
+
+ $changeOps->add( $this->getSiteLinksChangeOps(
$data['sitelinks'], $status ) );
+ }
+
+ if ( !$status->isOk() ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( "Contained status: $1",
$status->getWikiText() );
+ }
+
+ if ( $changeOps->apply( $entity ) === false ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( 'Change could not be applied to
entity', 'edit-entity-apply-failed' );
+ }
// This is already done in createEntity
if ( $entityContent->isNew() ) {
@@ -371,6 +190,240 @@
wfProfileOut( __METHOD__ );
return $summary;
+ }
+
+ /**
+ * @since 0.4
+ *
+ * @param array $labels
+ *
+ * @return ChangeOpLabel[]
+ */
+ protected function getLabelChangeOps( $labels, $status ) {
+ $labelChangeOps = array();
+
+ if ( !is_array( $labels ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( "List of labels must be an array",
'not-recognized-array' );
+ }
+
+ foreach ( $labels as $langCode => $arg ) {
+ $status->merge( $this->checkMultilangArgs( $arg,
$langCode ) );
+
+ $language = $arg['language'];
+ $newLabel = Utils::trimToNFC( $arg['value'] );
+
+ if ( array_key_exists( 'remove', $arg ) || $newLabel
=== "" ) {
+ $labelChangeOps[] = new ChangeOpLabel(
$language, null );
+ }
+ else {
+ $labelChangeOps[] = new ChangeOpLabel(
$language, $newLabel );
+ }
+ }
+
+ return $labelChangeOps;
+ }
+
+ /**
+ * @since 0.4
+ *
+ * @param array $descriptions
+ *
+ * @return ChangeOpdescription[]
+ */
+ protected function getDescriptionChangeOps( $descriptions, $status ) {
+ $descriptionChangeOps = array();
+
+ if ( !is_array( $descriptions ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( "List of descriptions must be an
array", 'not-recognized-array' );
+ }
+
+ foreach ( $descriptions as $langCode => $arg ) {
+ $status->merge( $this->checkMultilangArgs( $arg,
$langCode ) );
+
+ $language = $arg['language'];
+ $newDescription = Utils::trimToNFC( $arg['value'] );
+
+ if ( array_key_exists( 'remove', $arg ) ||
$newDescription === "" ) {
+ $descriptionChangeOps[] = new
ChangeOpDescription( $language, null );
+ }
+ else {
+ $descriptionChangeOps[] = new
ChangeOpDescription( $language, $newDescription );
+ }
+ }
+
+ return $descriptionChangeOps;
+ }
+
+ /**
+ * @since 0.4
+ *
+ * @param array $aliases
+ *
+ * @return ChangeOpAliases[]
+ */
+ protected function getAliasesChangeOps( $aliases, $status ) {
+ $aliasesChangeOps = array();
+
+ if ( !is_array( $aliases ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( "List of aliases must be an array",
'not-recognized-array' );
+ }
+
+ $indexedAliases = array();
+
+ foreach ( $aliases as $langCode => $arg ) {
+ if ( intval( $langCode ) ) {
+ $indexedAliases[] = ( array_values($arg) ===
$arg ) ? $arg : array( $arg );
+ } else {
+ $indexedAliases[$langCode] = (
array_values($arg) === $arg ) ? $arg : array( $arg );
+ }
+ }
+
+ foreach ( $indexedAliases as $langCode => $args ) {
+ foreach ( $args as $arg ) {
+ $status->merge( $this->checkMultilangArgs(
$arg, $langCode ) );
+
+ $alias = array( Utils::trimToNFC( $arg['value']
) );
+ $language = $arg['language'];
+
+ if ( array_key_exists( 'remove', $arg ) ) {
+ $aliasesChangeOps[] = new
ChangeOpAliases( $language, $alias, 'remove' );
+ }
+ elseif ( array_key_exists( 'add', $arg ) ) {
+ $aliasesChangeOps[] = new
ChangeOpAliases( $language, $alias, 'add' );
+ }
+ else {
+ $aliasesChangeOps[] = new
ChangeOpAliases( $language, $alias, 'set' );
+ }
+ }
+ }
+
+ if ( !$status->isOk() ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( "Contained status: $1",
$status->getWikiText() );
+ }
+
+ return $aliasesChangeOps;
+ }
+
+ /**
+ * @since 0.4
+ *
+ * @param array $siteLinks
+ *
+ * @return ChangeOpSiteLink[]
+ */
+ protected function getSitelinksChangeOps( $siteLinks, $status ) {
+ $siteLinksChangeOps = array();
+
+ if ( !is_array( $siteLinks ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( "List of sitelinks must be an array",
'not-recognized-array' );
+ }
+
+ $sites = $this->getSiteLinkTargetSites();
+
+ foreach ( $siteLinks as $siteId => $arg ) {
+ $status->merge( $this->checkSiteLinks( $arg, $siteId,
$sites ) );
+ $globalSiteId = $arg['site'];
+
+ if ( $sites->hasSite( $globalSiteId ) ) {
+ $linkSite = $sites->getSite( $globalSiteId );
+ } else {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( "There is no site for global
site id '$globalSiteId'", 'site-not-found' );
+ }
+
+ if ( array_key_exists( 'remove', $arg ) ||
$arg['title'] === "" ) {
+ $siteLinksChangeOps[] = new ChangeOpSiteLink(
$linkSite, null );
+ } else {
+ $linkPage = $linkSite->normalizePageName(
Utils::trimWhitespace( $arg['title'] ) );
+
+ if ( $linkPage === false ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( $this->msg(
'wikibase-api-no-external-page' )->text(), 'add-sitelink-failed' );
+ }
+
+ $siteLinksChangeOps[] = new ChangeOpSiteLink(
$linkSite, $linkPage );
+ }
+ }
+
+ return $siteLinksChangeOps;
+ }
+
+ /**
+ * @since 0.4
+ *
+ * @param array $data
+ * @param WikiPage|bool $page
+ *
+ * @return Status
+ */
+ protected function checkDataProperties( $data, $page ) {
+ $status = Status::newGood();
+
+ $title = null;
+ $revision = null;
+ if ( $page ) {
+ $title = $page->getTitle();
+ $revision = $page->getRevision();
+ }
+
+ $allowedProps = array(
+ 'length',
+ 'count',
+ 'touched',
+ 'pageid',
+ 'ns',
+ 'title',
+ 'lastrevid',
+ 'labels',
+ 'descriptions',
+ 'aliases',
+ 'sitelinks' );
+
+ if ( is_null( $data ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( $this->msg(
'wikibase-api-json-invalid' )->text(), 'json-invalid' );
+ }
+
+ if ( !is_array( $data ) ) { // NOTE: json_decode will decode
any JS literal or structure, not just objects!
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( 'Top level structure must be a JSON
object', 'not-recognized-array' );
+ }
+
+ foreach ( $data as $prop => $args ) {
+ if ( !is_string( $prop ) ) { // NOTE: catch json_decode
returning an indexed array (list)
+ $this->dieUsage( 'Top level structure must be a
JSON object', 'not-recognized-string' );
+ }
+
+ if ( !in_array( $prop, $allowedProps ) ) {
+ $this->dieUsage( "unknown key: $prop",
'not-recognized' );
+ }
+ }
+
+ // conditional processing
+ if ( isset( $data['pageid'] ) && ( is_object( $page ) ?
$page->getId() !== $data['pageid'] : true ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( $this->msg(
'wikibase-api-illegal-field', 'pageid' )->text(), 'illegal-field' );
+ }
+ // not completely convinced that we can use title to get the
namespace in this case
+ if ( isset( $data['ns'] ) && ( is_object( $title ) ?
$title->getNamespace() !== $data['ns'] : true ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( $this->msg(
'wikibase-api-illegal-field', 'namespace' )->text(), 'illegal-field' );
+ }
+ if ( isset( $data['title'] ) && ( is_object( $title ) ?
$title->getPrefixedText() !== $data['title'] : true ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( $this->msg(
'wikibase-api-illegal-field', 'title' )->text(), 'illegal-field' );
+ }
+ if ( isset( $data['lastrevid'] ) && ( is_object( $revision ) ?
$revision->getId() !== $data['lastrevid'] : true ) ) {
+ wfProfileOut( __METHOD__ );
+ $this->dieUsage( $this->msg(
'wikibase-api-illegal-field', 'lastrevid' )->text(), 'illegal-field' );
+ }
+
+ return $status;
}
/**
@@ -469,11 +522,10 @@
*
* @param $arg Array: The argument array to verify
* @param $langCode string: The language code used in the value part
- * @param &$languages array: The valid language codes as an assoc array
*
* @return Status: The result from the comparison (always true)
*/
- public function checkMultilangArgs( $arg, $langCode, &$languages = null
) {
+ public function checkMultilangArgs( $arg, $langCode ) {
$status = Status::newGood();
if ( !is_array( $arg ) ) {
$this->dieUsage( $this->msg(
'wikibase-api-not-recognized-array' )->text(), 'not-recognized-array' );
@@ -486,7 +538,7 @@
$this->dieUsage( "inconsistent language:
{$langCode} is not equal to {$arg['language']}", 'inconsistent-language' );
}
}
- if ( isset( $languages ) && !array_key_exists(
$arg['language'], $languages ) ) {
+ if ( isset( $this->validLanguageCodes ) && !array_key_exists(
$arg['language'], $this->validLanguageCodes ) ) {
$this->dieUsage( "unknown language:
{$arg['language']}", 'not-recognized-language' );
}
if ( !is_string( $arg['value'] ) ) {
diff --git a/repo/includes/changeop/ChangeOpAliases.php
b/repo/includes/changeop/ChangeOpAliases.php
new file mode 100644
index 0000000..8333f80
--- /dev/null
+++ b/repo/includes/changeop/ChangeOpAliases.php
@@ -0,0 +1,103 @@
+<?php
+
+namespace Wikibase;
+
+use InvalidArgumentException;
+use MWExceptiontion;
+
+/**
+ * Class for aliases change operation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @since 0.4
+ *
+ * @ingroup WikibaseRepo
+ *
+ * @licence GNU GPL v2+
+ * @author Tobias Gritschacher < [email protected] >
+ */
+class ChangeOpAliases implements ChangeOp {
+
+ /**
+ * @since 0.4
+ *
+ * @var string
+ */
+ protected $language;
+
+ /**
+ * @since 0.4
+ *
+ * @var string[]
+ */
+ protected $aliases;
+
+ /**
+ * @since 0.4
+ *
+ * @var array
+ */
+ protected $action;
+
+ /**
+ * @since 0.4
+ *
+ * @param string $language
+ * @param string[] $aliases
+ * @param string $action
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct( $language, array $aliases, $action ) {
+ if ( !is_string( $language ) ) {
+ throw new InvalidArgumentException( '$language needs to
be a string' );
+ }
+
+ if ( !is_string( $action ) ) {
+ throw new InvalidArgumentException( '$action needs to
be a string' );
+ }
+
+ $this->language = $language;
+ $this->aliases = $aliases;
+ $this->action = $action;
+ }
+
+ /**
+ * Applies the change to the given entity
+ *
+ * @since 0.4
+ *
+ * @param Entity $entity
+ *
+ * @return bool
+ *
+ * @throws MWException
+ */
+ public function apply( Entity $entity ) {
+ if ( $this->action === "" || $this->action === "set" ) {
+ $entity->setAliases( $this->language, $this->aliases );
+ } elseif ( $this->action === "add" ) {
+ $entity->addAliases( $this->language, $this->aliases );
+ } elseif ( $this->action === "remove" ) {
+ $entity->removeAliases( $this->language, $this->aliases
);
+ } else {
+ throw new \MWException( "Unknown action: $this->action"
);
+ }
+ return true;
+ }
+
+}
diff --git a/repo/includes/changeop/ChangeOpDescription.php
b/repo/includes/changeop/ChangeOpDescription.php
index e02ad9c..fe86075 100644
--- a/repo/includes/changeop/ChangeOpDescription.php
+++ b/repo/includes/changeop/ChangeOpDescription.php
@@ -68,6 +68,8 @@
* @since 0.4
*
* @param Entity $entity
+ *
+ * @return bool
*/
public function apply( Entity $entity ) {
if ( $this->description === null ) {
@@ -75,6 +77,7 @@
} else {
$entity->setDescription( $this->language,
$this->description );
}
+ return true;
}
}
diff --git a/repo/includes/changeop/ChangeOpLabel.php
b/repo/includes/changeop/ChangeOpLabel.php
index 200d955..0a19a44 100644
--- a/repo/includes/changeop/ChangeOpLabel.php
+++ b/repo/includes/changeop/ChangeOpLabel.php
@@ -68,6 +68,8 @@
* @since 0.4
*
* @param Entity $entity
+ *
+ * @return bool
*/
public function apply( Entity $entity ) {
if ( $this->label === null ) {
@@ -75,6 +77,7 @@
} else {
$entity->setLabel( $this->language, $this->label );
}
+ return true;
}
}
diff --git a/repo/includes/changeop/ChangeOpSiteLink.php
b/repo/includes/changeop/ChangeOpSiteLink.php
new file mode 100644
index 0000000..b6dbe9b
--- /dev/null
+++ b/repo/includes/changeop/ChangeOpSiteLink.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Wikibase;
+
+use InvalidArgumentException;
+use Site;
+
+/**
+ * Class for sitelink change operation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @since 0.4
+ *
+ * @ingroup WikibaseRepo
+ *
+ * @licence GNU GPL v2+
+ * @author Tobias Gritschacher < [email protected] >
+ */
+class ChangeOpSiteLink implements ChangeOp {
+
+ /**
+ * @since 0.4
+ *
+ * @var Site
+ */
+ protected $linkSite;
+
+ /**
+ * @since 0.4
+ *
+ * @var string|null
+ */
+ protected $linkPage;
+
+ /**
+ * @since 0.4
+ *
+ * @param Site $linkSite
+ * @param string|null $linkPage
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct( Site $linkSite, $linkPage ) {
+ if ( !is_string( $linkPage ) && $linkPage !==null ) {
+ throw new InvalidArgumentException( '$linkPage needs to
be a string|null' );
+ }
+
+ $this->linkSite = $linkSite;
+ $this->linkPage = $linkPage;
+ }
+
+ /**
+ * Applies the change to the given entity
+ *
+ * @since 0.4
+ *
+ * @param Entity $entity
+ *
+ * @return SiteLink|bool
+ */
+ public function apply( Entity $entity ) {
+ if ( $this->linkPage === null ) {
+ $entity->removeSiteLink( $this->linkSite->getGlobalId()
);
+ return true; // don't show an error when the sitelink
we try to remove does not exist
+ } else {
+ $siteLink = new SiteLink( $this->linkSite,
$this->linkPage );
+ return $entity->addSiteLink( $siteLink,'set' );
+ }
+ }
+
+}
diff --git a/repo/includes/changeop/ChangeOps.php
b/repo/includes/changeop/ChangeOps.php
index 47c1591..68091b9 100644
--- a/repo/includes/changeop/ChangeOps.php
+++ b/repo/includes/changeop/ChangeOps.php
@@ -2,6 +2,8 @@
namespace Wikibase;
+use InvalidArgumentException;
+
/**
* Class for holding a batch of change operations
*
@@ -49,10 +51,26 @@
*
* @since 0.4
*
- * @param ChangeOp $changeOp
+ * @param ChangeOp|ChangeOp[] $changeOp
+ *
+ * @throws InvalidArgumentException
*/
- public function add( ChangeOp $changeOp ) {
- $this->ops[] = $changeOp;
+ public function add( $changeOp ) {
+ if ( !is_array( $changeOp ) && !( $changeOp instanceof ChangeOp
) ) {
+ throw new InvalidArgumentException( '$changeOp needs to
be an instance of ChangeOp or an array of ChangeOps' );
+ }
+
+ if ( $changeOp instanceof ChangeOp ) {
+ $this->ops[] = $changeOp;
+ } else {
+ foreach ( $changeOp as $op ) {
+ if ( $op instanceof ChangeOp ) {
+ $this->ops[] = $op;
+ } else {
+ throw new InvalidArgumentException(
'array $changeOp must contain ChangeOps only' );
+ }
+ }
+ }
}
/**
@@ -71,11 +89,17 @@
* @since 0.4
*
* @param Entity $entity
+ *
+ * @return bool
*/
public function apply( Entity $entity ) {
foreach ( $this->ops as $op ) {
- $op->apply( $entity );
+ if ( $op->apply( $entity ) === false ) {
+ return false;
+ }
}
+
+ return true;
}
}
diff --git a/repo/tests/phpunit/includes/api/EditEntityTest.php
b/repo/tests/phpunit/includes/api/EditEntityTest.php
index 03cfd53..a03609c 100644
--- a/repo/tests/phpunit/includes/api/EditEntityTest.php
+++ b/repo/tests/phpunit/includes/api/EditEntityTest.php
@@ -212,46 +212,6 @@
}
/**
- * Check success when the entity is set again, with fields in the json
that should be ignored
- */
- function testEditEntityWithIgnoredData() {
- $token = $this->getItemToken();
-
- // these sets of failing data must be merged with an existing
entity
- $ignoredData = array(
- array( 'length' => 999999 ), // always ignored
- array( 'count' => 999999 ), // always ignored
- array( 'touched' => '2000-01-01T18:05:01Z' ), // always
ignored
- array( 'pageid' => 999999 ),
- array( 'ns' => 200 ),
- array( 'title' => 'does-not-exist' ),
- array( 'lastrevid' => 99999999 ),
- );
- foreach ( $ignoredData as $data ) {
- try {
- list($res,,) = $this->doApiRequest(
- array(
- 'action' => 'wbeditentity',
- 'reason' => 'Some reason',
- 'data' => json_encode(
array_merge( self::$entity, $data ) ),
- 'token' => $token,
- 'id' => self::$id, // will now
use default type
- 'exclude' =>
'pageid|ns|title|lastrevid'
- ),
- null,
- false,
- self::$users['wbeditor']->user
- );
- $this->assertSuccess( $res, 'entity', 'id' );
- $this->assertItemEquals( self::$expect,
$res['entity'] );
- }
- catch ( \UsageException $e ) {
- $this->fail( "Got unexpected exception: $e" );
- }
- }
- }
-
- /**
* Check failure to set the same entity again, with illegal field
values in the json
*/
function testEditEntityWithIllegalData() {
@@ -273,7 +233,6 @@
'data' => json_encode(
array_merge( self::$entity, $data ) ),
'token' => $token,
'id' => self::$id,
- //'exclude' => '' // make sure
all critical values are checked per default
),
null,
false,
@@ -324,7 +283,6 @@
'data' => json_encode(
array_merge( $data, self::$entity ) ),
'token' => $token,
'id' => self::$id,
- //'exclude' => '' // make sure
all critical values are checked per default
),
null,
false,
@@ -354,7 +312,6 @@
'token' => $token,
'id' => self::$id,
'clear' => true,
- //'exclude' => '' // make sure all
critical values are checked per default
),
null,
false,
diff --git a/repo/tests/phpunit/includes/changeop/ChangeOpAliasesTest.php
b/repo/tests/phpunit/includes/changeop/ChangeOpAliasesTest.php
new file mode 100644
index 0000000..bef4658
--- /dev/null
+++ b/repo/tests/phpunit/includes/changeop/ChangeOpAliasesTest.php
@@ -0,0 +1,100 @@
+<?php
+
+namespace Wikibase\Test;
+
+use Wikibase\ChangeOpAliases;
+use Wikibase\ItemContent;
+use InvalidArgumentException;
+use MWException;
+
+/**
+ * @covers Wikibase\ChangeOpAliases
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA
+ *
+ * @file
+ * @since 0.4
+ *
+ * @ingroup Wikibase
+ * @ingroup Test
+ *
+ * @group Wikibase
+ * @group WikibaseRepo
+ * @group ChangeOp
+ *
+ * @licence GNU GPL v2+
+ * @author Tobias Gritschacher < [email protected] >
+ */
+class ChangeOpAliasesTest extends \PHPUnit_Framework_TestCase {
+
+ public function invalidConstructorProvider() {
+ $args = array();
+ $args[] = array( 42, array( 'myNewAlias' ), 'add' );
+ $args[] = array( 'en', array( 'myNewAlias' ), 1234 );
+
+ return $args;
+ }
+
+ /**
+ * @dataProvider invalidConstructorProvider
+ * @expectedException InvalidArgumentException
+ *
+ * @param string $language
+ * @param string[] $aliases
+ * @param string $action
+ */
+ public function testInvalidConstruct( $language, $aliases, $action ) {
+ $changeOpLabel = new ChangeOpAliases( $language, $aliases,
$action );
+ }
+
+ public function changeOpAliasesProvider() {
+ $enAliases = array( 'en-alias1', 'en-alias2', 'en-alias3' );
+ $existingEnAliases = array ( 'en-existingAlias1',
'en-existingAlias2' );
+ $item = ItemContent::newEmpty();
+ $entity = $item->getEntity();
+ $entity->setAliases( 'en', $existingEnAliases );
+
+ $args = array();
+ $args[] = array ( clone $entity, new ChangeOpAliases( 'en',
$enAliases, 'add' ), array_merge( $existingEnAliases, $enAliases ) );
+ $args[] = array ( clone $entity, new ChangeOpAliases( 'en',
$enAliases, 'set' ), $enAliases );
+ $args[] = array ( clone $entity, new ChangeOpAliases( 'en',
$enAliases, '' ), $enAliases );
+ $args[] = array ( clone $entity, new ChangeOpAliases( 'en',
$existingEnAliases, 'remove' ), array() );
+
+ return $args;
+ }
+
+ /**
+ * @dataProvider changeOpAliasesProvider
+ *
+ * @param Entity $entity
+ * @param ChangeOpAliases $changeOpAliases
+ * @param string $expectedAliases
+ */
+ public function testApply( $entity, $changeOpAliases, $expectedAliases
) {
+ $changeOpAliases->apply( $entity );
+ $this->assertEquals( $expectedAliases, $entity->getAliases(
'en' ) );
+ }
+
+ /**
+ * @expectedException MWException
+ */
+ public function testApplyWithInvalidAction() {
+ $item = ItemContent::newEmpty();
+ $entity = $item->getEntity();
+ $changeOpAliases = new ChangeOpAliases( 'en', array( 'test' ),
'invalidAction' );
+ $changeOpAliases->apply( $entity );
+ }
+
+}
diff --git a/repo/tests/phpunit/includes/changeop/ChangeOpSiteLinkTest.php
b/repo/tests/phpunit/includes/changeop/ChangeOpSiteLinkTest.php
new file mode 100644
index 0000000..31467fe
--- /dev/null
+++ b/repo/tests/phpunit/includes/changeop/ChangeOpSiteLinkTest.php
@@ -0,0 +1,101 @@
+<?php
+
+namespace Wikibase\Test;
+
+use Wikibase\ChangeOpSiteLink;
+use Wikibase\ItemContent;
+use InvalidArgumentException;
+use Wikibase\SiteLink;
+
+/**
+ * @covers Wikibase\ChangeOpSiteLink
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA
+ *
+ * @file
+ * @since 0.4
+ *
+ * @ingroup Wikibase
+ * @ingroup Test
+ *
+ * @group Wikibase
+ * @group WikibaseRepo
+ * @group ChangeOp
+ *
+ * @licence GNU GPL v2+
+ * @author Tobias Gritschacher < [email protected] >
+ */
+class ChangeOpSiteLinkTest extends \PHPUnit_Framework_TestCase {
+
+ public function invalidConstructorProvider() {
+ $args = array();
+ $args[] = array( $this->getSite( 'enwiki' ), 1234 );
+
+ return $args;
+ }
+
+ /**
+ * @dataProvider invalidConstructorProvider
+ * @expectedException InvalidArgumentException
+ *
+ * @param Site $linkSite
+ * @param string|null $aliases
+ */
+ public function testInvalidConstruct( $linkSite, $linkPage ) {
+ $changeOpSiteLink = new ChangeOpSiteLink( $linkSite, $linkPage
);
+ }
+
+ public function changeOpSiteLinkProvider() {
+ $enWiki = $this->getSite( 'enwiki' );
+ $deWiki = $this->getSite( 'dewiki' );
+ $existingSiteLinks = array( new SiteLink( $deWiki, 'Berlin' ) );
+ $enSiteLink = new SiteLink( $enWiki, 'Berlin' );
+
+ $item = ItemContent::newEmpty();
+ $entity = $item->getEntity();
+ foreach ( $existingSiteLinks as $siteLink ) {
+ $entity->addSiteLink( $siteLink );
+ }
+
+ $args = array();
+ $args[] = array ( clone $entity, new ChangeOpSiteLink( $enWiki,
'Berlin' ), array_merge( $existingSiteLinks, array ( $enSiteLink ) ) );
+ $args[] = array ( clone $entity, new ChangeOpSiteLink( $deWiki,
null ), array() );
+
+ return $args;
+ }
+
+ /**
+ * @dataProvider changeOpSiteLinkProvider
+ *
+ * @param Entity $entity
+ * @param ChangeOpSiteLink $changeOpSiteLink
+ * @param string $expectedSiteLinks
+ */
+ public function testApply( $entity, $changeOpSiteLink,
$expectedSiteLinks ) {
+ $changeOpSiteLink->apply( $entity );
+ $this->assertEquals(
+ SiteLink::siteLinksToArray( $expectedSiteLinks ),
+ SiteLink::siteLinksToArray( $entity->getSiteLinks() )
+ );
+ }
+
+ protected function getSite( $globalId ) {
+ $site = new \MediaWikiSite();
+ $site->setGlobalId( $globalId );
+
+ return $site;
+ }
+
+}
diff --git a/repo/tests/phpunit/includes/changeop/ChangeOpsTest.php
b/repo/tests/phpunit/includes/changeop/ChangeOpsTest.php
index c0f4016..6e15e9e 100644
--- a/repo/tests/phpunit/includes/changeop/ChangeOpsTest.php
+++ b/repo/tests/phpunit/includes/changeop/ChangeOpsTest.php
@@ -67,6 +67,49 @@
$this->assertEquals( array( $changeOp ),
$changeOps->getChangeOps() );
}
+ public function changeOpArrayProvider() {
+ $ops = array();
+ $ops[] = array (
+ array(
+ new ChangeOpLabel( 'en',
'enLabel' ),
+ new ChangeOpLabel( 'de',
'deLabel' ),
+ new ChangeOpDescription( 'en',
'enDescr' ),
+ )
+ );
+
+ return $ops;
+ }
+
+ /**
+ * @dataProvider changeOpArrayProvider
+ *
+ * @param ChangeOp[] $changeOp
+ */
+ public function testAddArray( $changeOpArray ) {
+ $changeOps = new ChangeOps();
+ $changeOps->add( $changeOpArray );
+ $this->assertEquals( $changeOpArray, $changeOps->getChangeOps()
);
+ }
+
+ public function invalidChangeOpProvider() {
+ $ops = array();
+ $ops[] = array ( 1234 );
+ $ops[] = array ( array( new ChangeOpLabel( 'en', 'test' ), 123
) );
+
+ return $ops;
+ }
+
+ /**
+ * @dataProvider invalidChangeOpProvider
+ * @expectedException InvalidArgumentException
+ *
+ * @param $invalidChangeOp
+ */
+ public function testInvalidAdd( $invalidChangeOp ) {
+ $changeOps = new ChangeOps();
+ $changeOps->add( $invalidChangeOp );
+ }
+
public function changeOpsProvider() {
$args = array();
--
To view, visit https://gerrit.wikimedia.org/r/66981
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ic27774f67f8728acbb48cbf945fda063791096cf
Gerrit-PatchSet: 14
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Tobias Gritschacher <[email protected]>
Gerrit-Reviewer: Daniel Kinzler <[email protected]>
Gerrit-Reviewer: Tobias Gritschacher <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits