Skip to content

Commit

Permalink
Streamline FingerprintPatcher
Browse files Browse the repository at this point in the history
  • Loading branch information
thiemowmde committed Mar 14, 2016
1 parent dfbbd6a commit cfe55dc
Showing 1 changed file with 138 additions and 55 deletions.
193 changes: 138 additions & 55 deletions src/Diff/Internal/FingerprintPatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

namespace Wikibase\DataModel\Services\Diff\Internal;

use Diff\DiffOp\AtomicDiffOp;
use Diff\DiffOp\Diff\Diff;
use Diff\DiffOp\DiffOp;
use Diff\DiffOp\DiffOpAdd;
use Diff\DiffOp\DiffOpChange;
use Diff\DiffOp\DiffOpRemove;
use Diff\Patcher\MapPatcher;
use InvalidArgumentException;
use Diff\Patcher\PatcherException;
use Wikibase\DataModel\Services\Diff\EntityDiff;
use Wikibase\DataModel\Term\AliasGroup;
use Wikibase\DataModel\Term\AliasGroupList;
use Wikibase\DataModel\Term\Fingerprint;
use Wikibase\DataModel\Term\TermList;
Expand All @@ -16,89 +20,168 @@
*
* @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
* @author Thiemo Mättig
*/
class FingerprintPatcher {

/**
* @var MapPatcher
*/
private $patcher;

public function __construct() {
$this->patcher = new MapPatcher();
}

/**
* @param Fingerprint $fingerprint
* @param EntityDiff $patch
*
* @throws InvalidArgumentException
* @throws PatcherException
*/
public function patchFingerprint( Fingerprint $fingerprint, EntityDiff $patch ) {
$labels = $this->patcher->patch(
$fingerprint->getLabels()->toTextArray(),
$patch->getLabelsDiff()
);
$this->patchTermList( $fingerprint->getLabels(), $patch->getLabelsDiff() );
$this->patchTermList( $fingerprint->getDescriptions(), $patch->getDescriptionsDiff() );

$fingerprint->setLabels( $this->newTermListFromArray( $labels ) );

$descriptions = $this->patcher->patch(
$fingerprint->getDescriptions()->toTextArray(),
$patch->getDescriptionsDiff()
);

$fingerprint->setDescriptions( $this->newTermListFromArray( $descriptions ) );

$this->patchAliases( $fingerprint, $patch->getAliasesDiff() );
foreach ( $patch->getAliasesDiff() as $lang => $diffOp ) {
$this->patchAliasGroup( $fingerprint->getAliasGroups(), $lang, $diffOp );
}
}

/**
* @param string[] $termArray
* @param TermList $labels
* @param Diff $patch
*
* @return TermList
* @throws PatcherException
*/
private function newTermListFromArray( array $termArray ) {
$termList = new TermList();

foreach ( $termArray as $language => $labelText ) {
$termList->setTextForLanguage( $language, $labelText );
private function patchTermList( TermList $labels, Diff $patch ) {
foreach ( $patch as $lang => $diffOp ) {
$this->patchTerm( $labels, $lang, $diffOp );
}
}

return $termList;
/**
* @see MapPatcher
*
* @param TermList $labels
* @param string $lang
* @param AtomicDiffOp $diffOp
*
* @throws PatcherException
*/
private function patchTerm( TermList $labels, $lang, AtomicDiffOp $diffOp ) {
$hasLang = $labels->hasTermForLanguage( $lang );

if ( $diffOp instanceof DiffOpAdd ) {
if ( !$hasLang ) {
$labels->setTextForLanguage( $lang, $diffOp->getNewValue() );
}
} elseif ( $diffOp instanceof DiffOpChange ) {
if ( $hasLang
&& $labels->getByLanguage( $lang )->getText() === $diffOp->getOldValue()
) {
$labels->setTextForLanguage( $lang, $diffOp->getNewValue() );
}
} elseif ( $diffOp instanceof DiffOpRemove ) {
if ( $hasLang
&& $labels->getByLanguage( $lang )->getText() === $diffOp->getOldValue()
) {
$labels->removeByLanguage( $lang );
}
} else {
throw new PatcherException( 'Invalid terms diff' );
}
}

private function patchAliases( Fingerprint $fingerprint, Diff $aliasesDiff ) {
$patchedAliases = $this->patcher->patch(
$this->getAliasesArrayForPatching( $fingerprint->getAliasGroups() ),
$aliasesDiff
);
/**
* @see MapPatcher
*
* @param AliasGroupList $groups
* @param string $lang
* @param DiffOp $diffOp
*
* @throws PatcherException
*/
private function patchAliasGroup( AliasGroupList $groups, $lang, DiffOp $diffOp ) {
$hasLang = $groups->hasGroupForLanguage( $lang );

if ( $diffOp instanceof DiffOpAdd ) {
if ( !$hasLang ) {
$groups->setAliasesForLanguage( $lang, $diffOp->getNewValue() );
}
} elseif ( $diffOp instanceof DiffOpChange ) {
$this->applyAliasGroupChange( $groups, $lang, $diffOp );
} elseif ( $diffOp instanceof DiffOpRemove ) {
if ( $hasLang
&& $groups->getByLanguage( $lang )->getAliases() === $diffOp->getOldValue()
) {
$groups->removeByLanguage( $lang );
}
} elseif ( $diffOp instanceof Diff ) {
$this->applyAliasGroupDiff( $groups, $lang, $diffOp );
} else {
throw new PatcherException( 'Invalid aliases diff' );
}
}

$fingerprint->setAliasGroups( $this->getAliasesFromArrayForPatching( $patchedAliases ) );
/**
* @param AliasGroupList $groups
* @param string $lang
* @param DiffOpChange $patch
*/
private function applyAliasGroupChange( AliasGroupList $groups, $lang, DiffOpChange $patch ) {
if ( $groups->hasGroupForLanguage( $lang )
&& $groups->getByLanguage( $lang )->getAliases() === $patch->getOldValue()
) {
$groups->setAliasesForLanguage( $lang, $patch->getNewValue() );
}
}

private function getAliasesArrayForPatching( AliasGroupList $aliases ) {
$textLists = array();
/**
* @param AliasGroupList $groups
* @param string $lang
* @param Diff $patch
*/
private function applyAliasGroupDiff( AliasGroupList $groups, $lang, Diff $patch ) {
$hasLang = $groups->hasGroupForLanguage( $lang );

/**
* @var AliasGroup $aliasGroup
*/
foreach ( $aliases as $languageCode => $aliasGroup ) {
$textLists[$languageCode] = $aliasGroup->getAliases();
if ( $hasLang || !$this->containsOperationsOnOldValues( $patch ) ) {
$aliases = $hasLang ? $groups->getByLanguage( $lang )->getAliases() : array();
$aliases = $this->getPatchedAliases( $aliases, $patch );
$groups->setAliasesForLanguage( $lang, $aliases );
}

return $textLists;
}

/**
* @param array[] $patchedAliases
* @param Diff $diff
*
* @return AliasGroupList
* @return bool
*/
private function getAliasesFromArrayForPatching( array $patchedAliases ) {
$aliases = new AliasGroupList();
private function containsOperationsOnOldValues( Diff $diff ) {
return $diff->getChanges() !== array()
|| $diff->getRemovals() !== array();
}

foreach( $patchedAliases as $languageCode => $aliasList ) {
$aliases->setAliasesForLanguage( $languageCode, $aliasList );
/**
* @see ListPatcher
*
* @param string[] $aliases
* @param Diff $patch
*
* @throws PatcherException
* @return string[]
*/
private function getPatchedAliases( array $aliases, Diff $patch ) {
foreach ( $patch as $diffOp ) {
if ( $diffOp instanceof DiffOpAdd ) {
$aliases[] = $diffOp->getNewValue();
} elseif ( $diffOp instanceof DiffOpChange ) {
$key = array_search( $diffOp->getOldValue(), $aliases, true );

if ( $key !== false ) {
unset( $aliases[$key] );
$aliases[] = $diffOp->getNewValue();
}
} elseif ( $diffOp instanceof DiffOpRemove ) {
$key = array_search( $diffOp->getOldValue(), $aliases, true );

if ( $key !== false ) {
unset( $aliases[$key] );
}
} else {
throw new PatcherException( 'Invalid aliases diff' );
}
}

return $aliases;
Expand Down

0 comments on commit cfe55dc

Please sign in to comment.