jenkins-bot has submitted this change and it was merged.

Change subject: Add editentity claims support
......................................................................


Add editentity claims support

This allows the addition and removal of claims
New claims can contain references and qualifiers
Multiple claims can be changed at once
This now allows everything in an entity to change
in a single edit!

Bug: 46709

Change-Id: Id8586795c34eed24f899858b48dec7f299636db9
---
M lib/includes/serializers/ClaimSerializer.php
M repo/includes/api/ApiWikibase.php
M repo/includes/api/EditEntity.php
M repo/tests/phpunit/includes/api/EditEntityTest.php
M repo/tests/phpunit/includes/api/WikibaseApiTestCase.php
5 files changed, 234 insertions(+), 7 deletions(-)

Approvals:
  Tobias Gritschacher: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/lib/includes/serializers/ClaimSerializer.php 
b/lib/includes/serializers/ClaimSerializer.php
index 489e8ed..ec81dcd 100644
--- a/lib/includes/serializers/ClaimSerializer.php
+++ b/lib/includes/serializers/ClaimSerializer.php
@@ -161,7 +161,6 @@
                }
 
                $requiredElements = array(
-                       'id',
                        'mainsnak',
                );
 
@@ -187,7 +186,9 @@
                $claim = new $claimClass( 
$snakUnserializer->newFromSerialization( $serialization['mainsnak'] ) );
                assert( $claim instanceof Claim );
 
-               $claim->setGuid( $serialization['id'] );
+               if( array_key_exists( 'id', $serialization ) ){
+                       $claim->setGuid( $serialization['id'] );
+               }
 
                $claim->setQualifiers( $this->unserializeQualifiers( 
$serialization, $snakUnserializer ) );
 
diff --git a/repo/includes/api/ApiWikibase.php 
b/repo/includes/api/ApiWikibase.php
index 8e74fc5..214426a 100644
--- a/repo/includes/api/ApiWikibase.php
+++ b/repo/includes/api/ApiWikibase.php
@@ -3,9 +3,11 @@
 namespace Wikibase\Api;
 
 use User, Status, ApiBase;
+use Wikibase\Claims;
 use Wikibase\DataModel\SimpleSiteLink;
 use Wikibase\Entity;
 use Wikibase\EntityContent;
+use Wikibase\Lib\Serializers\ClaimsSerializer;
 use Wikibase\Settings;
 use Wikibase\EditEntity;
 use Wikibase\SiteLink;
@@ -244,6 +246,33 @@
        }
 
        /**
+        * Get serialized claims and add them to result
+        *
+        * @since 0.5
+        *
+        * @param array $claims the labels to set in the result
+        * @param array|string $path where the data is located
+        * @param string $name name used for the entry
+        * @param string $tag tag used for indexed entries in xml formats and 
similar
+        *
+        */
+       protected function addClaimsToResult( array $claims, $path, $name = 
'claims', $tag = 'claim' ) {
+               $options = new MultiLangSerializationOptions();
+               $options->setUseKeys( $this->getUsekeys() );
+               $claimSerializer = new ClaimsSerializer( $options );
+
+               $value = $claimSerializer->getSerialized( new Claims( $claims ) 
);
+
+               if ( $value !== array() ) {
+                       if ( !$this->getUsekeys() ) {
+                               $this->getResult()->setIndexedTagName( $value, 
$tag );
+                       }
+
+                       $this->getResult()->addValue( $path, $name, $value );
+               }
+       }
+
+       /**
         * Returns the permissions that are required to perform the operation 
specified by
         * the parameters.
         *
diff --git a/repo/includes/api/EditEntity.php b/repo/includes/api/EditEntity.php
index 028172c..f4858f0 100644
--- a/repo/includes/api/EditEntity.php
+++ b/repo/includes/api/EditEntity.php
@@ -2,6 +2,10 @@
 
 namespace Wikibase\Api;
 
+use DataValues\IllegalValueException;
+use MWException;
+use Wikibase\ChangeOpClaim;
+use Wikibase\Claim;
 use Wikibase\EntityContentFactory;
 use InvalidArgumentException;
 use Wikibase\ChangeOps;
@@ -15,9 +19,11 @@
 use Wikibase\Entity;
 use Wikibase\EntityContent;
 use Wikibase\Item;
+use Wikibase\Lib\ClaimGuidGenerator;
 use Wikibase\Property;
 use Wikibase\QueryContent;
 use Wikibase\Utils;
+use WikiPage;
 
 /**
  * Derived class for API modules modifying a single entity identified by id 
xor a combination of site and page title.
@@ -28,6 +34,7 @@
  * @author John Erling Blad < jeb...@gmail.com >
  * @author Daniel Kinzler
  * @author Tobias Gritschacher < tobias.gritschac...@wikimedia.de >
+ * @author Adam Shorland
  */
 class EditEntity extends ModifyEntity {
 
@@ -156,10 +163,19 @@
                if ( array_key_exists( 'sitelinks', $data ) ) {
                        if ( $entity->getType() !== Item::ENTITY_TYPE ) {
                                wfProfileOut( __METHOD__ );
-                               $this->dieUsage( "key can't be handled: 
sitelinks", 'not-recognized' );
+                               $this->dieUsage( "Non Items can not have 
sitelinks", 'not-recognized' );
                        }
 
                        $changeOps->add( $this->getSiteLinksChangeOps( 
$data['sitelinks'], $status ) );
+               }
+
+               if( array_key_exists( 'claims', $data ) ) {
+                       $changeOps->add(
+                               $this->getClaimsChangeOps(
+                                       $data['claims'],
+                                       new ClaimGuidGenerator( 
$entity->getId() )
+                               )
+                       );
                }
 
                if ( !$status->isOk() ) {
@@ -180,6 +196,7 @@
                if ( $entity->getType() === Item::ENTITY_TYPE ) {
                        $this->addSiteLinksToResult( 
$entity->getSimpleSiteLinks(), 'entity' );
                }
+               $this->addClaimsToResult( $entity->getClaims(), 'entity' );
 
                wfProfileOut( __METHOD__ );
                return $summary;
@@ -353,6 +370,53 @@
        }
 
        /**
+        * @since 0.5
+        *
+        * @param array $claims
+        *
+        * @param ClaimGuidGenerator $guidGenerator
+        * @return ChangeOpClaim[]
+        */
+       protected function getClaimsChangeOps( $claims, $guidGenerator ) {
+               $claimChangeOps = array();
+
+               if ( !is_array( $claims ) ) {
+                       $this->dieUsage( "List of claims must be an array", 
'not-recognized-array' );
+               }
+
+               $serializerFactory = new 
\Wikibase\Lib\Serializers\SerializerFactory();
+               $unserializer = $serializerFactory->newUnserializerForClass( 
'Wikibase\Claim' );
+
+               foreach ( $claims as $claimArray ) {
+
+                       try {
+                               $claim = $unserializer->newFromSerialization( 
$claimArray );
+                               assert( $claim instanceof Claim );
+                       } catch ( IllegalValueException $illegalValueException 
) {
+                               $this->dieUsage( 
$illegalValueException->getMessage(), 'invalid-claim' );
+                       } catch ( MWException $mwException ) {
+                               $this->dieUsage( $mwException->getMessage(), 
'invalid-claim' );
+                       }
+
+                       if ( array_key_exists( 'remove', $claimArray ) ) {
+                               if( array_key_exists( 'id', $claimArray ) ){
+                                       $claimChangeOps[] = new ChangeOpClaim( 
$claim, 'remove', $guidGenerator );
+                               } else {
+                                       $this->dieUsage( 'Cannot remove a claim 
with no GUID', 'invalid-claim' );
+                               }
+                       } else {
+
+                               if( array_key_exists( 'id', $claimArray ) ){
+                                       $claimChangeOps[] = new ChangeOpClaim( 
$claim, 'remove', $guidGenerator );
+                               }
+                               $claimChangeOps[] = new ChangeOpClaim( $claim, 
'add', $guidGenerator );
+                       }
+               }
+
+               return $claimChangeOps;
+       }
+
+       /**
         * @since 0.4
         *
         * @param array $data
@@ -382,6 +446,7 @@
                        'descriptions',
                        'aliases',
                        'sitelinks',
+                       'claims',
                        'datatype' );
 
                if ( is_null( $data ) ) {
@@ -398,7 +463,7 @@
                        }
 
                        if ( !in_array( $prop, $allowedProps ) ) {
-                               $this->dieUsage( "unknown key: $prop", 
'not-recognized' );
+                               $this->dieUsage( "Unknown key in json: $prop", 
'not-recognized' );
                        }
                }
 
@@ -434,7 +499,6 @@
                        array( 'code' => 'no-external-page', 'info' => 
$this->msg( 'wikibase-api-no-external-page' )->text() ),
                        array( 'code' => 'invalid-json', 'info' => $this->msg( 
'wikibase-api-invalid-json' )->text() ),
                        array( 'code' => 'not-recognized-string', 'info' => 
$this->msg( 'wikibase-api-not-recognized-string' )->text() ),
-                       array( 'code' => 'not-recognized', 'info' => 
$this->msg( 'wikibase-api-not-recognized' )->text() ),
                        array( 'code' => 'param-illegal', 'info' => $this->msg( 
'wikibase-api-param-illegal' )->text() ),
                        array( 'code' => 'param-missing', 'info' => $this->msg( 
'wikibase-api-param-missing' )->text() ),
                        array( 'code' => 'inconsistent-language', 'info' => 
$this->msg( 'wikibase-api-inconsistent-language' )->text() ),
@@ -517,6 +581,12 @@
                        => 'Create a new property containing the json data, 
returns extended with the item structure',
                        
'api.php?action=wbeditentity&id=Q42&data={"sitelinks":{"nowiki":{"site":"nowiki","title":"København"}}}'
                        => 'Sets sitelink for nowiki, overwriting it if it 
already exists',
+                       
'api.php?action=wbeditentity&id=Q42&data={"claims":[{"mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"ExampleString","type":"string"}},"type":"statement","rank":"normal"}]}'
+                       => 'Creates a new claim on the item for the property 
P56 and a value of "ExampleString"',
+                       
'api.php?action=wbeditentity&id=Q42&data={"claims":[{"id":"Q42$D8404CDA-25E4-4334-AF13-A3290BCD9C0F","mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"FirstClaim","type":"string"}},"remove":""},{"id":"Q42$GH678DSA-01PQ-28XC-HJ90-DDFD9990126X","mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"SecondClaim","type":"string"}},"remove":""}]}'
+                       => 'Removes the claims from the item with the guids 
q42$D8404CDA-25E4-4334-AF13-A3290BCD9C0F and 
q42$GH678DSA-01PQ-28XC-HJ90-DDFD9990126X',
+                       
'api.php?action=wbeditentity&id=Q42&data={"claims":[{"id":"Q42$GH678DSA-01PQ-28XC-HJ90-DDFD9990126X","mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"ChangedString","type":"string"}},"type":"statement","rank":"normal"}]}'
+                       => 'Sets the claim with the GUID to the value of the 
claim',
                );
        }
 
diff --git a/repo/tests/phpunit/includes/api/EditEntityTest.php 
b/repo/tests/phpunit/includes/api/EditEntityTest.php
index e1ac907..9a8d3cd 100644
--- a/repo/tests/phpunit/includes/api/EditEntityTest.php
+++ b/repo/tests/phpunit/includes/api/EditEntityTest.php
@@ -2,10 +2,13 @@
 
 namespace Wikibase\Test\Api;
 use ApiTestCase;
+use Wikibase\DataModel\Entity\EntityId;
+use Wikibase\DataModel\Entity\PropertyId;
+use Wikibase\PropertyContent;
 
 /**
  * Tests for the ApiWikibase class.
-
+ *
  * @since 0.1
  *
  * @ingroup WikibaseRepoTest
@@ -32,14 +35,21 @@
 class EditEntityTest extends WikibaseApiTestCase {
 
        private static $testEntityId;
+       private static $testClaimGuid;
        private static $hasSetup;
        static public $id = null;
 
        public function setup() {
                parent::setup();
 
+               $prop56 = PropertyId::newFromNumber( 56 );
+
                if( !isset( self::$hasSetup ) ){
                        $this->initTestEntities( array( 'Berlin' ) );
+                       $prop = PropertyContent::newEmpty();
+                       $prop->getEntity()->setId( $prop56 );
+                       $prop->getEntity()->setDataTypeId( 'string' );
+                       $prop->save( 'EditEntityTest' );
                }
                self::$hasSetup = true;
        }
@@ -92,6 +102,89 @@
                        array( //14 unset a sitelink using the other sitelink
                                'p' => array( 'site' => 'svwiki', 'title' => 
'FOO', 'data' => '{"sitelinks":{"dewiki":{"site":"dewiki","title":""}}}' ),
                                'e' => array( 'sitelinks' => array( 'svwiki' => 
'FOO' ) ) ),
+
+                       array( //15 add a claim
+                               'p' => array( 'data' => 
'{"claims":[{"mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"imastring","type":"string"}},"type":"statement","rank":"normal"}]}'
 ),
+                               'e' => array( 'claims' => array(
+                                       'P56' => array(
+                                               'mainsnak' => array( 'snaktype' 
=> 'value', 'property' => 'P56',
+                                                       'datavalue' => array(
+                                                               'value' => 
'imastring',
+                                                               'type' => 
'string' ) ),
+                                               'type' => 'statement',
+                                               'rank' => 'normal' ) ) ) ),
+
+                       array( //15 change the claim
+                               'p' => array( 'data' => 
'{"claims":[{"id":"GUID","mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"diffstring","type":"string"}},"type":"statement","rank":"normal"}]}'
 ),
+                               'e' => array( 'claims' => array(
+                                       'P56' => array(
+                                               'mainsnak' => array( 'snaktype' 
=> 'value', 'property' => 'P56',
+                                                       'datavalue' => array(
+                                                               'value' => 
'diffstring',
+                                                               'type' => 
'string' ) ),
+                                               'type' => 'statement',
+                                               'rank' => 'normal' ) ) ) ),
+
+                       array( //15 remove the claim
+                               'p' => array( 'data' => 
'{"claims":[{"id":"GUID","mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"diffstring","type":"string"}},"type":"statement","rank":"normal","remove":""}]}'
 ),
+                               'e' => array( 'claims' => array() ) ),
+
+                       array( //15 add multiple claims
+                               'p' => array(
+                                       'data' => 
'{"claims":[{"mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"imastring1","type":"string"}},"type":"statement","rank":"normal"},'.
+                                       
'{"mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"imastring2","type":"string"}},"type":"statement","rank":"normal"}]}'
 ),
+                               'e' => array( 'claims' => array(
+                                       'P56' => array(
+                                               'mainsnak' => array(
+                                                       'snaktype' => 'value', 
'property' => 'P56',
+                                                       'datavalue' => array(
+                                                               'value' => 
'imastring1',
+                                                               'type' => 
'string' ) ),
+                                               'type' => 'statement',
+                                               'rank' => 'normal' ),
+                                       array(
+                                               'mainsnak' => array(
+                                                       'snaktype' => 'value', 
'property' => 'P56',
+                                                       'datavalue' => array(
+                                                               'value' => 
'imastring2',
+                                                               'type' => 
'string' ) ),
+                                               'type' => 'statement',
+                                               'rank' => 'normal' )
+                               ) )
+                       ),
+
+                       array( //15 clear and add complex claim with qualifiers 
and references
+                               'p' => array( 'clear' => '', 'data' => 
'{"claims": [{"mainsnak": {"snaktype": "value", "property": "P56", "datavalue": 
{ "value": "str", "type": "string" } },'.
+                                       '"qualifiers": { "P56": [ { "snaktype": 
"value", "property": "P56", "datavalue": { "value": "qual", "type": "string" } 
} ] }, "type": "statement", "rank": "normal",'.
+                                       '"references": [ { "snaks": { "P56": [ 
{ "snaktype": "value", "property": "P56", "datavalue": { "value": "src", 
"type": "string" } } ] } } ]}]}' ),
+                               'e' => array( 'claims' => array(
+                                       'P56' => array(
+                                               'mainsnak' => array(
+                                                       'snaktype' => 'value', 
'property' => 'P56',
+                                                       'datavalue' => array(
+                                                               'value' => 
'str',
+                                                               'type' => 
'string' ) ),
+                                               'qualifiers' => array(
+                                                       'P56' => array(
+                                                               'snaktype' => 
'value', 'property' => 'P56',
+                                                               'datavalue' => 
array(
+                                                                       'value' 
=> 'qual',
+                                                                       'type' 
=> 'string' ) ),
+                                               ),
+                                               'type' => 'statement',
+                                               'rank' => 'normal',
+                                               'references' => array(
+                                                       'snaks' => array(
+                                                               'P56' => array(
+                                                                       
'snaktype' => 'value', 'property' => 'P56',
+                                                                       
'datavalue' => array(
+                                                                               
'value' => 'src',
+                                                                               
'type' => 'string' ) ),
+                                                       ),
+                                               ),
+                                       )
+                               ) )
+                       ),
                );
        }
 
@@ -107,13 +200,23 @@
                        && !array_key_exists( 'title', $params) ){
                        $params['id'] = self::$testEntityId;
                }
+               if( array_key_exists( 'data', $params ) && strstr( 
$params['data'], 'GUID' ) ){
+                       $params['data'] = str_replace( 'GUID', 
self::$testClaimGuid, $params['data'] );
+               }
 
                // -- do the request 
--------------------------------------------------
                list($result,,) = $this->doApiRequestWithToken( $params );
 
-               // -- steal stuff for later tests 
-------------------------------------
+               // -- steal ids for later tests 
-------------------------------------
                if( array_key_exists( 'new', $params ) && stristr( 
$params['new'], 'item' ) ){
                        self::$testEntityId = $result['entity']['id'];
+               }
+               if( array_key_exists( 'claims', $result['entity'] ) && 
array_key_exists( 'P56', $result['entity']['claims'] ) ){
+                       foreach( $result['entity']['claims']['P56'] as $claim ){
+                               if( array_key_exists( 'id', $claim ) ){
+                                       self::$testClaimGuid = $claim['id'];
+                               }
+                       }
                }
 
                // -- check the result 
------------------------------------------------
@@ -199,6 +302,12 @@
                                        'data' => 
'{"descriptions":{"en":{"language":"en","value":"'.LangAttributeTestHelper::makeOverlyLongString().'"}}}'),
                                'e' => array( 'exception' => array( 'type' => 
'UsageException' ) ) ),
                        //@todo add check for Bug:52731 once fixed
+                       array( //19 removing invalid claim fails
+                               'p' => array( 'site' => 'enwiki', 'title' => 
'Berlin' , 'data' => '{"claims":[{"remove":""}]}'),
+                               'e' => array( 'exception' => array( 'type' => 
'UsageException', 'code' => 'invalid-claim', 'message' => 'Invalid claim type 
specified'  ) ) ),
+                       array( //20 removing valid claim with no guid fails
+                               'p' => array( 'site' => 'enwiki', 'title' => 
'Berlin' , 'data' => 
'{"remove":"","claims":[{"mainsnak":{"snaktype":"value","property":"P56","datavalue":{"value":"imastring","type":"string"}},"type":"statement","rank":"normal"}]}'),
+                               'e' => array( 'exception' => array( 'type' => 
'UsageException', 'code' => 'not-recognized', 'message' => 'Unknown key in 
json: remove' ) ) ),
                );
        }
 
diff --git a/repo/tests/phpunit/includes/api/WikibaseApiTestCase.php 
b/repo/tests/phpunit/includes/api/WikibaseApiTestCase.php
index 067128d..deb5cf8 100644
--- a/repo/tests/phpunit/includes/api/WikibaseApiTestCase.php
+++ b/repo/tests/phpunit/includes/api/WikibaseApiTestCase.php
@@ -252,6 +252,24 @@
                        // keys are significant in flat form
                        $this->assertArrayEquals( $exp, $data, false, true );
                }
+
+               if ( isset( $expected['claims'] ) ) {
+                       if( empty( $expected['claims'] ) ){
+                               $this->assertArrayNotHasKey( 'claims', $actual 
);
+                       } else {
+                               $data = self::flattenArray( $actual['claims'], 
'mainsnak', 'value', true );
+                               $exp = self::flattenArray( $expected['claims'], 
'language', 'value', true );
+                               for( $i = 0; $i < count( $expected['claims'] ); 
$i++ ){
+                                       $this->assertArrayHasKey( $i, 
$data['id'] );
+                                       $this->assertGreaterThanOrEqual( 39 , 
strlen( $data['id'][$i] ) );
+                               }
+                               //unset stuff we dont actually want to compare
+                               unset( $data['id'] );
+                               unset( $data['hash'] );
+                               unset( $data['qualifiers-order'] );
+                               $this->assertArrayEquals( $exp, $data, false, 
true );
+                       }
+               }
        }
 
        /**

-- 
To view, visit https://gerrit.wikimedia.org/r/81671
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Id8586795c34eed24f899858b48dec7f299636db9
Gerrit-PatchSet: 23
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Addshore <addshorew...@gmail.com>
Gerrit-Reviewer: Addshore <addshorew...@gmail.com>
Gerrit-Reviewer: Aude <aude.w...@gmail.com>
Gerrit-Reviewer: Daniel Kinzler <daniel.kinz...@wikimedia.de>
Gerrit-Reviewer: Hoo man <h...@online.de>
Gerrit-Reviewer: Jeroen De Dauw <jeroended...@gmail.com>
Gerrit-Reviewer: Legoktm <legoktm.wikipe...@gmail.com>
Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de>
Gerrit-Reviewer: Umherirrender <umherirrender_de...@web.de>
Gerrit-Reviewer: jenkins-bot

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to