Aleksey Bekh-Ivanov (WMDE) has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/376781 )
Change subject: [WIP] Diffing and Patching Lexeme forms and nextFormId ...................................................................... [WIP] Diffing and Patching Lexeme forms and nextFormId Change-Id: Icfa5d5bfcbe7e48cab9f1d4c99eeba1bd656d39f --- M src/DataModel/Lexeme.php A src/DataModel/LexemePatchAccess.php M src/DataModel/Services/Diff/LexemeDiff.php M src/DataModel/Services/Diff/LexemeDiffer.php M src/DataModel/Services/Diff/LexemePatcher.php M tests/phpunit/composer/DataModel/LexemeTest.php A tests/phpunit/composer/DataModel/Services/Diff/LexemeDifferPatcherTest.php 7 files changed, 241 insertions(+), 2 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/WikibaseLexeme refs/changes/81/376781/1 diff --git a/src/DataModel/Lexeme.php b/src/DataModel/Lexeme.php index 81aa582..b81ae22 100644 --- a/src/DataModel/Lexeme.php +++ b/src/DataModel/Lexeme.php @@ -296,6 +296,24 @@ } /** + * @param int $number + */ + public function increaseNextFormIdTo( $number ) { + if ( !is_int( $number ) ) { + throw new \InvalidArgumentException( '$nextFormId` must be integer' ); + } + + if ( $number < $this->nextFormId ) { + throw new \LogicException( + "Cannot increase `nextFormId` because given number is less than counter value " . + "of this Lexeme. Current=`{$this->nextFormId}`, given=`{$number}`" + ); + } + + $this->nextFormId = $number; + } + + /** * @param TermList $representations * @param ItemId[] $grammaticalFeatures * @@ -313,6 +331,17 @@ $this->forms->remove( $formId ); } + public function patch( callable $patcher ) { + try { + $lexemePatchAccess = new LexemePatchAccess(); + $patcher( $lexemePatchAccess ); + + } finally { + $lexemePatchAccess->close(); + $this->assertCorrectNextFormIdIsGiven( $this->nextFormId, $this->forms ); + } + } + /** * @param mixed $nextFormId * @param Form[] $forms diff --git a/src/DataModel/LexemePatchAccess.php b/src/DataModel/LexemePatchAccess.php new file mode 100644 index 0000000..270ab4c --- /dev/null +++ b/src/DataModel/LexemePatchAccess.php @@ -0,0 +1,13 @@ +<?php + +namespace Wikibase\Lexeme\DataModel; + +class LexemePatchAccess { + + public function addForm( Form $form ) { + } + + public function close() { + } + +} diff --git a/src/DataModel/Services/Diff/LexemeDiff.php b/src/DataModel/Services/Diff/LexemeDiff.php index ee9f4e3..7b9de37 100644 --- a/src/DataModel/Services/Diff/LexemeDiff.php +++ b/src/DataModel/Services/Diff/LexemeDiff.php @@ -20,6 +20,7 @@ * @param DiffOp[] $operations */ public function __construct( array $operations = [] ) { + //TODO Probably can be removed. Does it do anything useful? $this->fixSubstructureDiff( $operations, 'lemmas' ); $this->fixSubstructureDiff( $operations, 'lexicalCategory' ); $this->fixSubstructureDiff( $operations, 'language' ); @@ -56,13 +57,24 @@ } /** + * @return Diff + */ + public function getFormsDiff() { + return isset( $this['forms'] ) ? $this['forms'] : new Diff( [], true ); + } + + /** * Returns if there are any changes (equivalent to: any differences between the entities). * * @return bool */ public function isEmpty() { return $this->getLemmasDiff()->isEmpty() - && $this->getClaimsDiff()->isEmpty(); + && $this->getClaimsDiff()->isEmpty(); + } + + public function getNextFormIdDiff() { + return $this['nextFormId']; } } diff --git a/src/DataModel/Services/Diff/LexemeDiffer.php b/src/DataModel/Services/Diff/LexemeDiffer.php index 374c147..fb4fff2 100644 --- a/src/DataModel/Services/Diff/LexemeDiffer.php +++ b/src/DataModel/Services/Diff/LexemeDiffer.php @@ -3,11 +3,14 @@ namespace Wikibase\Lexeme\DataModel\Services\Diff; use Diff\Differ\MapDiffer; +use Diff\DiffOp\Diff\Diff; +use Diff\DiffOp\DiffOpChange; use UnexpectedValueException; use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Services\Diff\EntityDiff; use Wikibase\DataModel\Services\Diff\EntityDifferStrategy; use Wikibase\DataModel\Services\Diff\StatementListDiffer; +use Wikibase\Lexeme\DataModel\Form; use Wikibase\Lexeme\DataModel\Lexeme; use Wikimedia\Assert\Assert; use InvalidArgumentException; @@ -75,6 +78,13 @@ $to->getStatements() ); + $diffOps['nextFormId'] = $this->getNextFormIdCounterDiff( $from, $to ); + + $diffOps['forms'] = $this->getFormsDiff( + $from->getForms(), + $to->getForms() + ); + return new LexemeDiff( $diffOps ); } @@ -132,4 +142,43 @@ return $this->diffEntities( $entity, new Lexeme() ); } + /** + * @param Form[] $from + * @param Form[] $to + * + * @return Diff; + */ + private function getFormsDiff( array $from, array $to ) { + $differ = new MapDiffer(); + + $differ->setComparisonCallback( function ( Form $from, Form $to ) { + return $from == $to; + } ); + + $from = $this->toFormDiffArray( $from ); + $to = $this->toFormDiffArray( $to ); + + return new Diff( $differ->doDiff( $from, $to ), true ); + } + + /** + * @param Form[] $forms + */ + private function toFormDiffArray( array $forms ) { + $result = []; + foreach ( $forms as $form ) { + $result[$form->getId()->getSerialization()] = $form; + } + + return $result; + } + + private function getNextFormIdCounterDiff( Lexeme $from, Lexeme $to ) { + if ( $to->getNextFormId() <= $from->getNextFormId() ) { + return new Diff( [] ); + } + + return new Diff( [ new DiffOpChange( $from->getNextFormId(), $to->getNextFormId() ) ] ); + } + } diff --git a/src/DataModel/Services/Diff/LexemePatcher.php b/src/DataModel/Services/Diff/LexemePatcher.php index 0ec031c..8f42acd 100644 --- a/src/DataModel/Services/Diff/LexemePatcher.php +++ b/src/DataModel/Services/Diff/LexemePatcher.php @@ -15,6 +15,7 @@ use Wikibase\DataModel\Services\Diff\StatementListPatcher; use Wikibase\DataModel\Services\Diff\TermListPatcher; use Wikibase\DataModel\Term\TermList; +use Wikibase\Lexeme\DataModel\Form; use Wikibase\Lexeme\DataModel\Lexeme; use Wikimedia\Assert\Assert; @@ -57,9 +58,11 @@ */ public function patchEntity( EntityDocument $entity, EntityDiff $patch ) { Assert::parameterType( Lexeme::class, $entity, '$entity' ); - + Assert::parameterType( LexemeDiff::class, $patch, '$patch' ); /** @var Lexeme $entity */ /** @var LexemeDiff $patch */ + + //TODO Lemmas can't be null. Redundant check $lemmas = $entity->getLemmas() !== null ? $entity->getLemmas() : new TermList(); $this->termListPatcher->patchTermList( $lemmas, @@ -80,6 +83,35 @@ $itemId = $this->getPatchedItemId( $patch->getLanguageDiff() ); if ( $itemId !== false ) { $entity->setLanguage( $itemId ); + } + + $this->patchNextFormId( $entity, $patch ); +// nextFormId + + $formsDiff = $patch->getFormsDiff(); + foreach ( $formsDiff as $formDiff ) { + switch ( get_class( $formDiff ) ) { + case DiffOpAdd::class: + /** @var DiffOpAdd $formDiff */ + /** @var Form $form */ + //TODO This is obviously wrong. Needs proper implementation. + $form = $formDiff->getNewValue(); + $entity->addForm( + $form->getRepresentations(), + $form->getGrammaticalFeatures() + ); + break; + case DiffOpRemove::class: + /** @var DiffOpRemove $formDiff */ + /** @var Form $form */ + $form = $formDiff->getOldValue(); + $entity->removeForm( + $form->getId() + ); + break; + default: + throw new PatcherException( 'Invalid forms list diff' ); + } } } @@ -112,4 +144,21 @@ throw new PatcherException( 'Invalid ItemId diff' ); } + private function patchNextFormId( Lexeme $entity, LexemeDiff $patch ) { + $nextFormIdDiffList = $patch->getNextFormIdDiff(); + foreach ( $nextFormIdDiffList as $nextFormIdDiff ) { + switch ( get_class( $nextFormIdDiff ) ) { + case DiffOpChange::class: + /** @var DiffOpChange $nextFormIdDiff */ + $newNumber = $nextFormIdDiff->getNewValue(); + if ( $newNumber > $entity->getNextFormId() ) { + $entity->increaseNextFormIdTo( $newNumber ); + } + break; + default: + throw new PatcherException( 'Invalid forms list diff' ); + } + } + } + } diff --git a/tests/phpunit/composer/DataModel/LexemeTest.php b/tests/phpunit/composer/DataModel/LexemeTest.php index 711bd19..6346c1b 100644 --- a/tests/phpunit/composer/DataModel/LexemeTest.php +++ b/tests/phpunit/composer/DataModel/LexemeTest.php @@ -464,4 +464,28 @@ $this->assertEquals( [], $lexeme->getForms() ); } + public function testIncreaseNextFormIdTo_GivenLexemWithGreaterId_Increases() { + $lexemeWithoutForm = NewLexeme::create()->build(); + $this->assertEquals( 1, $lexemeWithoutForm->getNextFormId() ); + + $lexemeWithoutForm->increaseNextFormIdTo( 2 ); + + $this->assertEquals( 2, $lexemeWithoutForm->getNextFormId() ); + } + + public function testIncreaseNextFormIdTo_GivenLexemWithSmallerId_ThrowsAnException() { + $lexemeWithForm = NewLexeme::havingForm( NewForm::havingId( 'F1' ) )->build(); + $this->assertEquals( 2, $lexemeWithForm->getNextFormId() ); + + $this->setExpectedException( \Exception::class ); + $lexemeWithForm->increaseNextFormIdTo( 1 ); + } + + public function testIncreaseNextFormIdTo_GivenNonInteger_ThrowsAnException() { + $lexeme = NewLexeme::havingId( 'L1' )->build(); + + $this->setExpectedException( \Exception::class ); + $lexeme->increaseNextFormIdTo( 2.0 ); + } + } diff --git a/tests/phpunit/composer/DataModel/Services/Diff/LexemeDifferPatcherTest.php b/tests/phpunit/composer/DataModel/Services/Diff/LexemeDifferPatcherTest.php new file mode 100644 index 0000000..69e0832 --- /dev/null +++ b/tests/phpunit/composer/DataModel/Services/Diff/LexemeDifferPatcherTest.php @@ -0,0 +1,63 @@ +<?php + +namespace Wikibase\Lexeme\Tests\DataModel\Services\Diff; + +use Wikibase\Lexeme\DataModel\FormId; +use Wikibase\Lexeme\DataModel\Services\Diff\LexemeDiffer; +use Wikibase\Lexeme\DataModel\Services\Diff\LexemePatcher; +use Wikibase\Lexeme\Tests\DataModel\NewForm; +use Wikibase\Lexeme\Tests\DataModel\NewLexeme; + +class LexemeDifferPatcherTest extends \PHPUnit_Framework_TestCase { + + public function testAddedFormIsDiffedAndPatched() { + $differ = new LexemeDiffer(); + $patcher = new LexemePatcher(); + $initialLexeme = NewLexeme::create(); + $lexemeWithoutForm = $initialLexeme->build(); + $lexemeWithForm = $initialLexeme->withForm( NewForm::havingId( 'F1' ) )->build(); + + $diff = $differ->diffLexemes( $lexemeWithoutForm, $lexemeWithForm ); + $patcher->patchEntity( $lexemeWithoutForm, $diff ); + + $this->assertTrue( + $lexemeWithoutForm->equals( $lexemeWithForm ), + "Lexemes are not equal" + ); + } + + public function testRemovedFormIsDiffedAndPatched() { + $differ = new LexemeDiffer(); + $patcher = new LexemePatcher(); + $initialLexeme = NewLexeme::create(); + $lexemeWithForm = $initialLexeme->withForm( NewForm::havingId( 'F1' ) )->build(); + $lexemeWithoutForm = $initialLexeme->build(); + + $diff = $differ->diffLexemes( $lexemeWithForm, $lexemeWithoutForm ); + $patcher->patchEntity( $lexemeWithForm, $diff ); + + $this->assertEquals( [], $lexemeWithForm->getForms() ); + } + + public function testDiffAndPatchCanIncreaseNextFormIdCounter() { + $differ = new LexemeDiffer(); + $patcher = new LexemePatcher(); + $initialLexeme = NewLexeme::create(); + $lexemeWithoutForm = $initialLexeme->build(); + $lexemeThatHadForm = $initialLexeme->withForm( NewForm::havingId( 'F1' ) )->build(); + $lexemeThatHadForm->removeForm( new FormId( 'F1' ) ); + + $diff = $differ->diffLexemes( $lexemeWithoutForm, $lexemeThatHadForm ); + $patcher->patchEntity( $lexemeWithoutForm, $diff ); + + $this->assertEquals( + $lexemeThatHadForm->getNextFormId(), + $lexemeWithoutForm->getNextFormId() + ); + $this->assertTrue( + $lexemeWithoutForm->equals( $lexemeThatHadForm ), + "Lexemes are not equal" + ); + } + +} -- To view, visit https://gerrit.wikimedia.org/r/376781 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Icfa5d5bfcbe7e48cab9f1d4c99eeba1bd656d39f Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/WikibaseLexeme Gerrit-Branch: master Gerrit-Owner: Aleksey Bekh-Ivanov (WMDE) <aleksey.bekh-iva...@wikimedia.de> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits