Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up entity patching code #196

Merged
merged 15 commits into from
Sep 22, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/Entity/Diff/EntityPatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace Wikibase\DataModel\Entity\Diff;

use InvalidArgumentException;
use RuntimeException;
use Wikibase\DataModel\Entity\EntityDocument;

/**
* @since 1.1
*
* @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
* @author Christoph Fischer < christoph.fischer@wikimedia.de >
*/
class EntityPatcher {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot see why we need this class. Per below we shouldn't have an EntityPatcherStrategy interface and then we also won't need and cannot have an EntityPatcher.


/**
* @var EntityPatcherStrategy[]
*/
private $patcherStrategies;

public function __construct() {
$this->registerEntityPatcherStrategy( new ItemPatcher() );
$this->registerEntityPatcherStrategy( new PropertyPatcher() );
}

public function registerEntityPatcherStrategy( EntityPatcherStrategy $patcherStrategy ) {
$this->patcherStrategies[] = $patcherStrategy;
}

/**
* @param EntityDocument $entity
* @param EntityDiff $patch
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function patchEntity( EntityDocument $entity, EntityDiff $patch ) {
$this->getPatcherStrategy( $entity->getType() )->patchEntity( $entity, $patch );
}

private function getPatcherStrategy( $entityType ) {
foreach ( $this->patcherStrategies as $patcherStrategy ) {
if ( $patcherStrategy->canPatchEntityType( $entityType ) ) {
return $patcherStrategy;
}
}

throw new RuntimeException( 'Patching the provided types of entities is not supported' );
}

}
31 changes: 31 additions & 0 deletions src/Entity/Diff/EntityPatcherStrategy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Wikibase\DataModel\Entity\Diff;

use InvalidArgumentException;
use Wikibase\DataModel\Entity\EntityDocument;

/**
* @since 1.1
*
* @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
interface EntityPatcherStrategy {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the benefit of this interface. EntityDocument is only about ids and the ids will never get patched because they are immutable. Therefore we will also most likely kill the EntityDiff class entirely because it contains now EntityStuff but only stuff specific for fingerprints or claims/statements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason we have this interface is so that we can have EntityPatcher, or rather the functionality EntityPatcher provides. The users of DataModel have places where they have something of type Entity and need to patch it. In many cases having something of an unknown Entity types is bad, but still DM needs to support its current users. This dispatcher + strategy approach allows DM to support this without itself having any patching logic that deals with entities of unknown type.


/**
* @param string $entityType
*
* @return boolean
*/
public function canPatchEntityType( $entityType );

/**
* @param EntityDocument $entity
* @param EntityDiff $patch
*
* @throws InvalidArgumentException
*/
public function patchEntity( EntityDocument $entity, EntityDiff $patch );

}
96 changes: 96 additions & 0 deletions src/Entity/Diff/FingerprintPatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

namespace Wikibase\DataModel\Entity\Diff;

use Diff\DiffOp\Diff\Diff;
use Diff\Patcher\MapPatcher;
use InvalidArgumentException;
use Wikibase\DataModel\Term\AliasGroup;
use Wikibase\DataModel\Term\AliasGroupList;
use Wikibase\DataModel\Term\Fingerprint;
use Wikibase\DataModel\Term\TermList;

/**
* Package private.
*
* @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
class FingerprintPatcher {

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

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

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

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

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

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

$this->patchAliases( $fingerprint, $patch->getAliasesDiff() );
}

private function newTermListFromArray( $termArray ) {
$termList = new TermList();

foreach ( $termArray as $language => $labelText ) {
$termList->setTextForLanguage( $language, $labelText );
}

return $termList;
}

private function patchAliases( Fingerprint $fingerprint, Diff $aliasesDiff ) {
$patchedAliases = $this->patcher->patch(
$this->getAliasesArrayForPatching( $fingerprint->getAliasGroups() ),
$aliasesDiff
);

$fingerprint->setAliasGroups( $this->getAliasesFromArrayForPatching( $patchedAliases ) );
}

private function getAliasesArrayForPatching( AliasGroupList $aliases ) {
$textLists = array();

/**
* @var AliasGroup $aliasGroup
*/
foreach ( $aliases as $languageCode => $aliasGroup ) {
$textLists[$languageCode] = $aliasGroup->getAliases();
}

return $textLists;
}

private function getAliasesFromArrayForPatching( array $patchedAliases ) {
$aliases = new AliasGroupList();

foreach( $patchedAliases as $languageCode => $aliasList ) {
$aliases->setAliasesForLanguage( $languageCode, $aliasList );
}

return $aliases;
}

}
83 changes: 83 additions & 0 deletions src/Entity/Diff/ItemPatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace Wikibase\DataModel\Entity\Diff;

use InvalidArgumentException;
use Wikibase\DataModel\Entity\EntityDocument;
use Wikibase\DataModel\Entity\Item;
use Wikibase\DataModel\Statement\StatementListPatcher;

/**
* @since 1.1
*
* @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
class ItemPatcher implements EntityPatcherStrategy {

/**
* @var FingerprintPatcher
*/
private $fingerprintPatcher;

/**
* @var StatementListPatcher
*/
private $statementListPatcher;

/**
* @var SiteLinkListPatcher
*/
private $siteLinkListPatcher;

public function __construct() {
$this->fingerprintPatcher = new FingerprintPatcher();
$this->statementListPatcher = new StatementListPatcher();
$this->siteLinkListPatcher = new SiteLinkListPatcher();
}

/**
* @param string $entityType
*
* @return boolean
*/
public function canPatchEntityType( $entityType ) {
return $entityType === 'item';
}

/**
* @param EntityDocument $entity
* @param EntityDiff $patch
*
* @return Item
* @throws InvalidArgumentException
*/
public function patchEntity( EntityDocument $entity, EntityDiff $patch ) {
$this->assertIsItem( $entity );

$this->patchItem( $entity, $patch );
}

private function assertIsItem( EntityDocument $item ) {
if ( !( $item instanceof Item ) ) {
throw new InvalidArgumentException( 'All entities need to be items' );
}
}

private function patchItem( Item $item, EntityDiff $patch ) {
$this->fingerprintPatcher->patchFingerprint( $item->getFingerprint(), $patch );

if ( $patch instanceof ItemDiff ) {
$item->setSiteLinkList( $this->siteLinkListPatcher->getPatchedSiteLinkList(
$item->getSiteLinkList(),
$patch->getSiteLinkDiff()
) );
}

$item->setStatements( $this->statementListPatcher->getPatchedStatementList(
$item->getStatements(),
$patch->getClaimsDiff()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a problem of this patch but we have to remember that this isn't very sane. EntityDiff should not know about claims.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should also not know about fingerprints. And the "claims" in the names here should be changed to "statements". That's an EntityDiff problem though, which is for another time.

) );
}

}
58 changes: 58 additions & 0 deletions src/Entity/Diff/PropertyPatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace Wikibase\DataModel\Entity\Diff;

use InvalidArgumentException;
use Wikibase\DataModel\Entity\EntityDocument;
use Wikibase\DataModel\Entity\Property;

/**
* @since 1.1
*
* @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
class PropertyPatcher implements EntityPatcherStrategy {

/**
* @var FingerprintPatcher
*/
private $fingerprintPatcher;

public function __construct() {
$this->fingerprintPatcher = new FingerprintPatcher();
}

/**
* @param string $entityType
*
* @return boolean
*/
public function canPatchEntityType( $entityType ) {
return $entityType === 'property';
}

/**
* @param EntityDocument $entity
* @param EntityDiff $patch
*
* @return Property
* @throws InvalidArgumentException
*/
public function patchEntity( EntityDocument $entity, EntityDiff $patch ) {
$this->assertIsProperty( $entity );

$this->patchProperty( $entity, $patch );
}

private function assertIsProperty( EntityDocument $property ) {
if ( !( $property instanceof Property ) ) {
throw new InvalidArgumentException( 'All entities need to be properties' );
}
}

private function patchProperty( Property $property, EntityDiff $patch ) {
$this->fingerprintPatcher->patchFingerprint( $property->getFingerprint(), $patch );
}

}
Loading