Daniel Kinzler has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/378786 )

Change subject: EXPERIMENT: infrastructure for hierarchicaly adressable entities
......................................................................

EXPERIMENT: infrastructure for hierarchicaly adressable entities

Needs https://github.com/wmde/WikibaseDataModel/pull/760

Bug: T165328
Change-Id: I581a2be249c105a971da2c719d605a812fd48013
---
A lib/includes/Store/HierarchicalEntityRevisionLookup.php
A lib/includes/Store/HierarchicalEntityStore.php
2 files changed, 329 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase 
refs/changes/86/378786/1

diff --git a/lib/includes/Store/HierarchicalEntityRevisionLookup.php 
b/lib/includes/Store/HierarchicalEntityRevisionLookup.php
new file mode 100644
index 0000000..9086ada
--- /dev/null
+++ b/lib/includes/Store/HierarchicalEntityRevisionLookup.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace Wikibase\Lib\Store;
+
+use Wikibase\DataModel\Entity\EntityContainer;
+use Wikibase\DataModel\Entity\EntityId;
+use Wikibase\DataModel\Entity\HierarchicalEntityId;
+
+/**
+ * Generic implementation of EntityRevisionLookup for resolving EntityIds that
+ * use a hierarchical addressing scheme.
+ *
+ * @license GPL-2.0+
+ * @author Daniel Kinzler
+ */
+class HierarchicalEntityRevisionLookup implements EntityRevisionLookup {
+
+       /**
+        * @var EntityRevisionLookup
+        */
+       private $lookup;
+
+       /**
+        * @param EntityRevisionLookup $lookup
+        */
+       public function __construct( EntityRevisionLookup $lookup ) {
+               $this->lookup = $lookup;
+       }
+
+       /**
+        * @see EntityRevisionLookup::getEntityRevision.
+        *
+        * This implementation recursively resolves HierarchicalEntityIds.
+        *
+        * @param EntityId $entityId
+        * @param int $revisionId
+        * @param string $mode
+        *
+        * @throws RevisionedUnresolvedRedirectException
+        * @throws StorageException
+        * @return EntityRevision|null
+        */
+       public function getEntityRevision(
+               EntityId $entityId,
+               $revisionId = 0,
+               $mode = self::LATEST_FROM_REPLICA
+       ) {
+               if ( !( $entityId instanceof HierarchicalEntityId ) ) {
+                       return $this->lookup->getEntityRevision( $entityId, 
$revisionId, $mode );
+               }
+
+               $baseId = $entityId->getBaseId();
+               $containerRevision = $this->getEntityRevision( $baseId, 
$revisionId, $mode );
+
+               if ( $containerRevision === null ) {
+                       return null;
+               }
+
+               $container = $containerRevision->getEntity();
+
+               if ( !( $container instanceof  EntityContainer) ) {
+                       throw new StorageException( 'Cannot resolve ID ' . 
$entityId );
+               }
+
+               $entity = $container->getEntity( $entityId );
+
+               return new EntityRevision(
+                       $entity,
+                       $containerRevision->getRevisionId(),
+                       $containerRevision->getTimestamp()
+               );
+       }
+
+       /**
+        * @see EntityRevisionLookup::getLatestRevisionId.
+        *
+        * This implementation finds the root of any hierarchical EntityId 
before looking up the
+        * latest revision.
+        *
+        * @param EntityId $entityId
+        * @param string $mode LATEST_FROM_REPLICA, 
LATEST_FROM_REPLICA_WITH_FALLBACK or LATEST_FROM_MASTER.
+        *        LATEST_FROM_MASTER would force the revision to be determined 
from the canonical master database.
+        *
+        * @return int|false Returns false in case the entity doesn't exist 
(this includes redirects).
+        */
+       public function getLatestRevisionId( EntityId $entityId, $mode = 
self::LATEST_FROM_REPLICA ) {
+               if ( $entityId instanceof HierarchicalEntityId ) {
+                       $entityId = $entityId->getRootId();
+               }
+
+               return $this->lookup->getLatestRevisionId( $entityId, $mode );
+       }
+
+}
diff --git a/lib/includes/Store/HierarchicalEntityStore.php 
b/lib/includes/Store/HierarchicalEntityStore.php
new file mode 100644
index 0000000..703ab10
--- /dev/null
+++ b/lib/includes/Store/HierarchicalEntityStore.php
@@ -0,0 +1,235 @@
+<?php
+
+namespace Wikibase\Lib\Store;
+
+use MWException;
+use PermissionsError;
+use Status;
+use User;
+use Wikibase\DataModel\Entity\EntityContainer;
+use Wikibase\DataModel\Entity\EntityDocument;
+use Wikibase\DataModel\Entity\EntityId;
+use Wikibase\DataModel\Entity\EntityRedirect;
+use Wikibase\DataModel\Entity\HierarchicalEntityId;
+
+/**
+ * A generic EntityStore implementing storage for entities that use an 
hierarchical addressing
+ * scheme.
+ *
+ * @license GPL-2.0+
+ * @author Daniel Kinzler
+ */
+class HierarchicalEntityStore implements EntityStore {
+
+       /**
+        * @var EntityStore
+        */
+       private $store;
+
+       /**
+        * @var EntityRevisionLookup
+        */
+       private $lookup;
+
+       /**
+        * @param EntityStore $store
+        * @param EntityRevisionLookup $lookup
+        */
+       public function __construct( EntityStore $store, EntityRevisionLookup 
$lookup ) {
+               $this->store = $store;
+               $this->lookup = $lookup;
+       }
+
+       /**
+        * @param HierarchicalEntityId $id
+        *
+        * @throws StorageException
+        * @return EntityRevision
+        */
+       private function getContainerRevision(
+               HierarchicalEntityId $id,
+               $revisionId = 0,
+               $mode = EntityRevisionLookup::LATEST_FROM_MASTER
+       ) {
+               $baseId = $id->getBaseId();
+               $rev = $this->lookup->getEntityRevision( $baseId, $revisionId, 
$mode );
+
+               if ( !$rev ) {
+                       throw new StorageException( 'Cannot resolve base entity 
ID ' . $baseId->getSerialization() );
+               }
+
+               if ( !( $rev->getEntity() instanceof  EntityContainer) ) {
+                       throw new StorageException( 'Cannot resolve ID ' . $id 
);
+               }
+
+               return $rev;
+       }
+
+       /**
+        * @param HierarchicalEntityId $id
+        *
+        * @throws StorageException
+        * @return EntityContainer|EntityDocument
+        */
+       private function getContainer( HierarchicalEntityId $id ) {
+               return $this->getContainerRevision( $id )->getEntity();
+       }
+
+       /**
+        * @see EntityStore::assignFreshId
+        *
+        * @param EntityDocument $entity
+        *
+        * @throws StorageException
+        */
+       public function assignFreshId( EntityDocument $entity ) {
+               // FIXME: we will have to know the ID of the parent entity here 
somehow!
+               $this->store->assignFreshId( $entity );
+       }
+
+       /**
+        * @see EntityStore::saveEntity
+        *
+        * @param EntityDocument $entity the entity to save.
+        * @param string $summary the edit summary for the new revision.
+        * @param User $user the user to whom to attribute the edit
+        * @param int $flags EDIT_XXX flags, as defined for 
WikiPage::doEditContent.
+        *        Additionally, the EntityContent::EDIT_XXX constants can be 
used.
+        * @param int|bool $baseRevId the revision ID $entity is based on. 
Saving should fail if
+        * $baseRevId is no longer the current revision.
+        *
+        * @see WikiPage::doEditContent
+        *
+        * @return EntityRevision
+        * @throws StorageException
+        * @throws PermissionsError
+        */
+       public function saveEntity( EntityDocument $entity, $summary, User 
$user, $flags = 0, $baseRevId = false ) {
+               if ( !$entity->getId() ) {
+                       if ( $flags & EDIT_NEW ) {
+                               $this->assignFreshId( $entity );
+                       } else {
+                               throw new StorageException( Status::newFatal( 
'edit-gone-missing' ) );
+                       }
+               }
+
+               $id = $entity->getId();
+
+               if ( $id instanceof HierarchicalEntityId ) {
+                       $rev = $this->getContainerRevision( $id, $baseRevId );
+                       $baseRevId = $rev->getRevisionId();
+                       $entityToSave = $rev->getEntity();
+                       $entityToSave->putEntity( $entity );
+               } else {
+                       $entityToSave = $entity;
+               }
+
+               $this->store->saveEntity( $entityToSave, $summary, $user, 
$flags, $baseRevId );
+       }
+
+       /**
+        * @see EntityStore::saveRedirect
+        *
+        * @param EntityRedirect $redirect the redirect to save.
+        * @param string $summary the edit summary for the new revision.
+        * @param User $user the user to whom to attribute the edit
+        * @param int $flags EDIT_XXX flags, as defined for 
WikiPage::doEditContent.
+        * @param int|bool $baseRevId the revision ID $entity is based on. 
Saving should fail if
+        * $baseRevId is no longer the current revision.
+        *
+        * @see WikiPage::doEditContent
+        *
+        * @return int The new revision ID
+        * @throws StorageException
+        * @throws PermissionsError
+        */
+       public function saveRedirect( EntityRedirect $redirect, $summary, User 
$user, $flags = 0, $baseRevId = false ) {
+               // FIXME: does it make sense to support redirects between 
sub-entities? Implement EntityRedirectContainer
+               $this->store->saveEntity( $redirect, $summary, $user, $flags, 
$baseRevId );
+       }
+
+       /**
+        * @see EntityStore::deleteEntity
+        *
+        * @param EntityId $entityId
+        * @param string $reason the reason for deletion
+        * @param User $user
+        */
+       public function deleteEntity( EntityId $entityId, $reason, User $user ) 
{
+               if ( $entityId instanceof HierarchicalEntityId ) {
+                       $container = $this->getContainer( $entityId );
+                       $container->removeEntity( $entityId );
+                       $this->saveEntity( $container, $reason, $user, 
EDIT_UPDATE );
+               } else {
+                       $this->store->deleteEntity( $entityId, $reason, $user );
+               }
+       }
+
+       /**
+        * @see EntityStore::userWasLastToEdit
+        *
+        * @param User $user the user
+        * @param EntityId $id the entity to check
+        * @param int $lastRevId the revision to check from
+        *
+        * @return bool
+        */
+       public function userWasLastToEdit( User $user, EntityId $id, $lastRevId 
) {
+               if ( $id instanceof HierarchicalEntityId ) {
+                       $id = $id->getRootId();
+               }
+
+               return $this->store->userWasLastToEdit( $user, $id, $lastRevId 
);
+       }
+
+       /**
+        * @see EntityStore::updateWatchlist
+        *
+        * @param User $user
+        * @param EntityId $id the entity to watch
+        * @param bool $watch whether to watch or unwatch the page.
+        *
+        * @throws MWException
+        * @return void
+        */
+       public function updateWatchlist( User $user, EntityId $id, $watch ) {
+               if ( $id instanceof HierarchicalEntityId ) {
+                       $id = $id->getRootId();
+               }
+
+               $this->store->updateWatchlist( $user, $id, $watch );
+       }
+
+       /**
+        * @see EntityStore::isWatching
+        *
+        * @param User $user
+        * @param EntityId $id the entity to watch
+        *
+        * @return bool
+        */
+       public function isWatching( User $user, EntityId $id ) {
+               if ( $id instanceof HierarchicalEntityId ) {
+                       $id = $id->getRootId();
+               }
+
+               return $this->store->isWatching( $user, $id );
+       }
+
+       /**
+        * @see EntityStore::canCreateWithCustomId
+        *
+        * @param EntityId $id
+        *
+        * @return bool
+        */
+       public function canCreateWithCustomId( EntityId $id ) {
+               if ( $id instanceof HierarchicalEntityId ) {
+                       $container = $this->getContainer( $id );
+                       return $container->canAddWithCustomId( $id );
+               } else {
+                       $this->store->canCreateWithCustomId( $id );
+               }
+       }
+
+}

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I581a2be249c105a971da2c719d605a812fd48013
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Daniel Kinzler <daniel.kinz...@wikimedia.de>

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

Reply via email to