/**
  * @see EntityLookup::hasEntity
  *
  * @param EntityId $entityId
  *
  * @throws EntityLookupException
  * @return bool
  */
 public function hasEntity(EntityId $entityId)
 {
     try {
         return $this->lookup->getLatestRevisionId($entityId) !== false;
     } catch (EntityLookupException $ex) {
         throw $ex;
     } catch (\Exception $ex) {
         // TODO: catch more specific exception once EntityRevisionLookup contract gets clarified
         throw new EntityLookupException($entityId, null, $ex);
     }
 }
 /**
  * @param PropertyId $propertyId
  * @param User $user User to attribute the changes made to.
  * @param string $dataTypeId
  *
  * @throws InvalidArgumentException
  * @throws StorageException
  */
 public function changeDataType(PropertyId $propertyId, User $user, $dataTypeId)
 {
     $entityRevision = $this->entityRevisionLookup->getEntityRevision($propertyId, EntityRevisionLookup::LATEST_FROM_MASTER);
     if ($entityRevision === null) {
         throw new StorageException("Could not load property: " . $propertyId->getSerialization());
     }
     /* @var $property Property */
     $property = $entityRevision->getEntity();
     $oldDataTypeId = $property->getDataTypeId();
     $this->assertDataTypesCompatible($oldDataTypeId, $dataTypeId);
     $property->setDataTypeId($dataTypeId);
     $this->entityStore->saveEntity($property, 'Changed data type from ' . $oldDataTypeId . ' to ' . $dataTypeId, $user, EDIT_UPDATE, $entityRevision->getRevisionId());
 }
Esempio n. 3
0
 /**
  * Get the entity using the id, site and title params passed to the api
  *
  * @param array $params
  *
  * @return EntityRevision Found existing entity
  */
 protected function getEntityRevisionFromApiParams(array $params)
 {
     $entityRevision = null;
     $entityId = $this->getEntityIdFromParams($params);
     // Things that use this method assume null means we want a new entity
     if ($entityId !== null) {
         $baseRevisionId = isset($params['baserevid']) ? (int) $params['baserevid'] : 0;
         if ($baseRevisionId === 0) {
             $baseRevisionId = EntityRevisionLookup::LATEST_FROM_MASTER;
         }
         try {
             $entityRevision = $this->revisionLookup->getEntityRevision($entityId, $baseRevisionId);
         } catch (EntityLookupException $ex) {
             $this->errorReporter->dieException($ex, 'no-such-entity');
         } catch (StorageException $ex) {
             // @fixme EntityRevisionLookup still throws BadRevisionException, which
             // is a subclass of StorageException, so we still have some inconsistency
             // and need to check both.
             $this->errorReporter->dieException($ex, 'no-such-entity');
         }
         if ($entityRevision === null) {
             $this->errorReporter->dieError("Can't access entity " . $entityId . ', revision may have been deleted.', 'no-such-entity');
         }
     }
     return $entityRevision;
 }
 /**
  * Loads the requested Entity. Redirects are resolved if no specific revision
  * is requested.
  *
  * @param EntityId $id
  * @param int $revision The revision ID (use 0 for the current revision).
  *
  * @return array list( EntityRevision, RedirectRevision|null )
  * @throws HttpError
  */
 private function getEntityRevision(EntityId $id, $revision)
 {
     $prefixedId = $id->getSerialization();
     if ($revision === 0) {
         $revision = EntityRevisionLookup::LATEST_FROM_SLAVE;
     }
     $redirectRevision = null;
     try {
         $entityRevision = $this->entityRevisionLookup->getEntityRevision($id, $revision);
         if ($entityRevision === null) {
             wfDebugLog(__CLASS__, __FUNCTION__ . ": entity not found: {$prefixedId}");
             throw new HttpError(404, wfMessage('wikibase-entitydata-not-found')->params($prefixedId));
         }
     } catch (RevisionedUnresolvedRedirectException $ex) {
         $redirectRevision = new RedirectRevision(new EntityRedirect($id, $ex->getRedirectTargetId()), $ex->getRevisionId(), $ex->getRevisionTimestamp());
         if (is_string($revision)) {
             // If no specific revision is requested, resolve the redirect.
             list($entityRevision, ) = $this->getEntityRevision($ex->getRedirectTargetId(), $revision);
         } else {
             // The requested revision is a redirect
             wfDebugLog(__CLASS__, __FUNCTION__ . ": revision {$revision} of {$prefixedId} is a redirect: {$ex}");
             $msg = wfMessage('wikibase-entitydata-bad-revision');
             throw new HttpError(400, $msg->params($prefixedId, $revision));
         }
     } catch (BadRevisionException $ex) {
         wfDebugLog(__CLASS__, __FUNCTION__ . ": could not load revision {$revision} or {$prefixedId}: {$ex}");
         $msg = wfMessage('wikibase-entitydata-bad-revision');
         throw new HttpError(404, $msg->params($prefixedId, $revision));
     } catch (StorageException $ex) {
         wfDebugLog(__CLASS__, __FUNCTION__ . ": failed to load {$prefixedId}: {$ex} (revision {$revision})");
         $msg = wfMessage('wikibase-entitydata-storage-error');
         throw new HttpError(500, $msg->params($prefixedId, $revision));
     }
     return array($entityRevision, $redirectRevision);
 }
 /**
  * @see ModifyEntity::modifyEntity
  */
 protected function modifyEntity(EntityDocument &$entity, array $params, $baseRevId)
 {
     $this->validateDataParameter($params);
     $data = json_decode($params['data'], true);
     $this->validateDataProperties($data, $entity, $baseRevId);
     $exists = $this->entityExists($entity->getId());
     if ($params['clear']) {
         if ($params['baserevid'] && $exists) {
             $latestRevision = $this->revisionLookup->getLatestRevisionId($entity->getId(), EntityRevisionLookup::LATEST_FROM_MASTER);
             if (!$baseRevId === $latestRevision) {
                 $this->errorReporter->dieError('Tried to clear entity using baserevid of entity not equal to current revision', 'editconflict');
             }
         }
         $entity = $this->clearEntity($entity);
     }
     // if we create a new property, make sure we set the datatype
     if (!$exists && $entity instanceof Property) {
         if (!isset($data['datatype'])) {
             $this->errorReporter->dieError('No datatype given', 'param-illegal');
         } else {
             $entity->setDataTypeId($data['datatype']);
         }
     }
     $changeOps = $this->getChangeOps($data, $entity);
     $this->applyChangeOp($changeOps, $entity);
     $this->buildResult($entity);
     return $this->getSummary($params);
 }
 /**
  * Load the entity content of the given revision.
  *
  * Will fail by calling dieException() $this->errorReporter if the revision
  * cannot be found or cannot be loaded.
  *
  * @since 0.5
  *
  * @param EntityId $entityId EntityId of the page to load the revision for
  * @param int|string $revId revision to load. If not given, the current revision will be loaded.
  *
  * @throws UsageException
  * @throws LogicException
  *
  * @return EntityRevision
  */
 public function loadEntityRevision(EntityId $entityId, $revId = EntityRevisionLookup::LATEST_FROM_MASTER)
 {
     try {
         $revision = $this->entityRevisionLookup->getEntityRevision($entityId, $revId);
         if (!$revision) {
             $this->errorReporter->dieError('Entity ' . $entityId->getSerialization() . ' not found', 'cant-load-entity-content');
         }
         return $revision;
     } catch (RevisionedUnresolvedRedirectException $ex) {
         $this->errorReporter->dieException($ex, 'unresolved-redirect');
     } catch (BadRevisionException $ex) {
         $this->errorReporter->dieException($ex, 'nosuchrevid');
     } catch (StorageException $ex) {
         $this->errorReporter->dieException($ex, 'cant-load-entity-content');
     }
     throw new LogicException('ApiErrorReporter::dieException did not throw a UsageException');
 }
 /**
  * @param EntityId $entityId
  * @param bool $resolveRedirects
  *
  * @return null|EntityRevision
  */
 private function getEntityRevision(EntityId $entityId, $resolveRedirects = false)
 {
     $entityRevision = null;
     try {
         $entityRevision = $this->entityRevisionLookup->getEntityRevision($entityId);
     } catch (RevisionedUnresolvedRedirectException $ex) {
         if ($resolveRedirects) {
             $entityId = $ex->getRedirectTargetId();
             $entityRevision = $this->getEntityRevision($entityId, false);
         }
     }
     return $entityRevision;
 }
 /**
  * Either throws an exception or returns a EntityDocument object.
  *
  * @param ItemId $itemId
  *
  * @return EntityDocument
  * @throws ItemMergeException
  */
 private function loadEntity(ItemId $itemId)
 {
     try {
         $revision = $this->entityRevisionLookup->getEntityRevision($itemId, EntityRevisionLookup::LATEST_FROM_MASTER);
         if (!$revision) {
             throw new ItemMergeException("Entity {$itemId} not found", 'no-such-entity');
         }
         return $revision->getEntity();
     } catch (StorageException $ex) {
         throw new ItemMergeException($ex->getMessage(), 'cant-load-entity-content', $ex);
     } catch (RevisionedUnresolvedRedirectException $ex) {
         throw new ItemMergeException($ex->getMessage(), 'cant-load-entity-content', $ex);
     }
 }
 /**
  * Loads the entity for this entity id.
  *
  * @since 0.5
  *
  * @param EntityId $id
  * @param int|string $revisionId
  *
  * @throws MessageException
  * @throws UserInputException
  * @return EntityRevision
  */
 protected function loadEntity(EntityId $id, $revisionId = EntityRevisionLookup::LATEST_FROM_MASTER)
 {
     try {
         $entity = $this->entityRevisionLookup->getEntityRevision($id, $revisionId);
         if ($entity === null) {
             throw new UserInputException('wikibase-wikibaserepopage-invalid-id', array($id->getSerialization()), 'Entity id is unknown');
         }
     } catch (RevisionedUnresolvedRedirectException $ex) {
         throw new UserInputException('wikibase-wikibaserepopage-unresolved-redirect', array($id->getSerialization()), 'Entity id refers to a redirect');
     } catch (StorageException $ex) {
         throw new MessageException('wikibase-wikibaserepopage-storage-exception', array($id->getSerialization(), $ex->getMessage()), 'Entity could not be loaded');
     }
     return $entity;
 }
 /**
  * @see EntityRevisionLookup::getLatestRevisionId
  *
  * @note: If this lookup is configured to verify revisions, this just delegates
  * to the underlying lookup. Otherwise, it may return the ID of a cached
  * revision.
  *
  * @param EntityId $entityId
  * @param string $mode
  *
  * @return int|false
  */
 public function getLatestRevisionId(EntityId $entityId, $mode = self::LATEST_FROM_SLAVE)
 {
     // If we do not need to verify the revision, and the revision isn't
     // needed for an update, we can get the revision from the cached object.
     // XXX: whether this is actually quicker depends on the cache.
     if (!($this->shouldVerifyRevision || $mode === self::LATEST_FROM_MASTER)) {
         $key = $this->getCacheKey($entityId);
         /** @var EntityRevision $entityRevision */
         $entityRevision = $this->cache->get($key);
         if ($entityRevision) {
             return $entityRevision->getRevisionId();
         }
     }
     return $this->lookup->getLatestRevisionId($entityId, $mode);
 }
 /**
  * @param EntityId $entityId
  *
  * @throws RedirectCreationException
  */
 private function checkEmpty(EntityId $entityId)
 {
     try {
         $revision = $this->entityRevisionLookup->getEntityRevision($entityId, EntityRevisionLookup::LATEST_FROM_MASTER);
         if (!$revision) {
             throw new RedirectCreationException("Entity {$entityId} not found", 'no-such-entity');
         }
         $entity = $revision->getEntity();
         if (!$entity->isEmpty()) {
             throw new RedirectCreationException("Entity {$entityId} is not empty", 'target-not-empty');
         }
     } catch (RevisionedUnresolvedRedirectException $ex) {
         // Nothing to do. It's ok to override a redirect with a redirect.
     } catch (StorageException $ex) {
         throw new RedirectCreationException($ex->getMessage(), 'cant-load-entity-content', $ex);
     }
 }
 /**
  * @see EntityInfoBuilder::removeMissing
  */
 public function removeMissing($redirects = 'keep-redirects')
 {
     foreach (array_keys($this->entityInfo) as $key) {
         $id = $this->parseId($key);
         try {
             $rev = $this->entityRevisionLookup->getEntityRevision($id);
         } catch (RevisionedUnresolvedRedirectException $ex) {
             if ($redirects === 'keep-redirects') {
                 continue;
             } else {
                 $rev = null;
             }
         }
         if (!$rev) {
             unset($this->entityInfo[$key]);
         }
     }
 }
 /**
  * Combines a set of changes into one change. All changes are assume to have been performed
  * by the same user on the same entity. They are further assumed to be UPDATE actions
  * and sorted in causal (chronological) order.
  *
  * If $changes is empty, this method returns null. If $changes contains exactly one change,
  * that change is returned. Otherwise, a combined change is returned.
  *
  * @param EntityChange[] $changes The changes to combine.
  *
  * @throws MWException
  * @return Change a combined change representing the activity from all the original changes.
  */
 private function mergeChanges(array $changes)
 {
     if (empty($changes)) {
         return null;
     } elseif (count($changes) === 1) {
         return reset($changes);
     }
     // we now assume that we have a list if EntityChanges,
     // all done by the same user on the same entity.
     /* @var EntityChange $last */
     /* @var EntityChange $first */
     $last = end($changes);
     $first = reset($changes);
     $minor = true;
     $bot = true;
     $ids = array();
     foreach ($changes as $change) {
         $ids[] = $change->getId();
         $meta = $change->getMetadata();
         $minor &= isset($meta['minor']) && (bool) $meta['minor'];
         $bot &= isset($meta['bot']) && (bool) $meta['bot'];
     }
     $lastmeta = $last->getMetadata();
     $firstmeta = $first->getMetadata();
     $entityId = $first->getEntityId();
     $parentRevId = $firstmeta['parent_id'];
     $latestRevId = $lastmeta['rev_id'];
     $entityRev = $this->entityRevisionLookup->getEntityRevision($entityId, $latestRevId);
     if (!$entityRev) {
         throw new MWException("Failed to load revision {$latestRevId} of {$entityId}");
     }
     $parentRev = $parentRevId ? $this->entityRevisionLookup->getEntityRevision($entityId, $parentRevId) : null;
     //XXX: we could avoid loading the entity data by merging the diffs programatically
     //     instead of re-calculating.
     $change = $this->changeFactory->newFromUpdate($parentRev ? EntityChange::UPDATE : EntityChange::ADD, $parentRev === null ? null : $parentRev->getEntity(), $entityRev->getEntity());
     $change->setFields(array('revision_id' => $last->getField('revision_id'), 'user_id' => $last->getField('user_id'), 'object_id' => $last->getField('object_id'), 'time' => $last->getField('time')));
     $change->setMetadata(array_merge($lastmeta, array('parent_id' => $parentRevId, 'minor' => $minor, 'bot' => $bot)));
     $info = $change->hasField('info') ? $change->getField('info') : array();
     $info['change-ids'] = $ids;
     $info['changes'] = $changes;
     $change->setField('info', $info);
     return $change;
 }
 /**
  * Generates HTML of the term box, to be injected into the entity page.
  *
  * @param EntityId $entityId
  * @param int $revisionId
  *
  * @throws InvalidArgumentException
  * @return string HTML
  */
 public function renderTermBox(EntityId $entityId, $revisionId)
 {
     $languages = array_merge(array($this->uiLanguage->getCode()), $this->getExtraUserLanguages());
     try {
         // we may want to cache this...
         $entityRev = $this->entityRevisionLookup->getEntityRevision($entityId, $revisionId);
     } catch (StorageException $ex) {
         // Could not load entity revision, $revisionId might be a deleted revision
         return '';
     }
     if (!$entityRev) {
         // Could not load entity revision, entity might not exist for $entityId.
         return '';
     }
     $entity = $entityRev->getEntity();
     $entityTermsView = new EntityTermsView($this->templateFactory, null, $this->languageNameLookup, $this->uiLanguage->getCode());
     // FIXME: assumes all entities have a fingerprint
     $html = $entityTermsView->getEntityTermsForLanguageListView($entity->getFingerprint(), $languages, $this->targetPage);
     return $html;
 }
 /**
  * Produces RDF dump of the entity
  *
  * @param EntityId $entityId
  *
  * @throws EntityLookupException
  * @throws StorageException
  * @return string|null RDF
  */
 protected function generateDumpForEntityId(EntityId $entityId)
 {
     try {
         $entityRevision = $this->entityRevisionLookup->getEntityRevision($entityId);
         if (!$entityRevision) {
             throw new EntityLookupException($entityId, 'Entity not found: ' . $entityId->getSerialization());
         }
         $this->rdfBuilder->addEntityRevisionInfo($entityRevision->getEntity()->getId(), $entityRevision->getRevisionId(), $entityRevision->getTimestamp());
         $this->rdfBuilder->addEntity($entityRevision->getEntity());
     } catch (MWContentSerializationException $ex) {
         throw new StorageException('Deserialization error for ' . $entityId->getSerialization());
     } catch (RevisionedUnresolvedRedirectException $e) {
         if ($e->getRevisionId() > 0) {
             $this->rdfBuilder->addEntityRevisionInfo($entityId, $e->getRevisionId(), $e->getRevisionTimestamp());
         }
         $this->rdfBuilder->addEntityRedirect($entityId, $e->getRedirectTargetId());
     }
     $rdf = $this->rdfBuilder->getRDF();
     return $rdf;
 }
 /**
  * @param EntityId $entityId
  *
  * @throws RedirectCreationException
  */
 private function checkCanCreateRedirect(EntityId $entityId)
 {
     try {
         $revision = $this->entityRevisionLookup->getEntityRevision($entityId, EntityRevisionLookup::LATEST_FROM_MASTER);
         if (!$revision) {
             $title = $this->entityTitleLookup->getTitleForId($entityId);
             if (!$title || !$title->isDeleted()) {
                 throw new RedirectCreationException("Couldn't get Title for {$entityId} or Title is not deleted", 'no-such-entity');
             }
         } else {
             $entity = $revision->getEntity();
             if (!$entity->isEmpty()) {
                 throw new RedirectCreationException("Can't create redirect on non empty item {$entityId}", 'origin-not-empty');
             }
         }
     } catch (RevisionedUnresolvedRedirectException $ex) {
         // Nothing to do. It's ok to override a redirect with a redirect.
     } catch (StorageException $ex) {
         throw new RedirectCreationException($ex->getMessage(), 'cant-load-entity-content', $ex);
     }
 }
Esempio n. 17
0
 /**
  * Returns the edits base revision.
  * If no base revision was supplied to the constructor, this will return null.
  * In the trivial non-conflicting case, this will be the same as $this->getLatestRevision().
  *
  * @return EntityRevision|null
  * @throws MWException
  */
 private function getBaseRevision()
 {
     if ($this->baseRev === null) {
         $baseRevId = $this->getBaseRevisionId();
         if ($baseRevId === false) {
             return null;
         } elseif ($baseRevId === $this->getLatestRevisionId()) {
             $this->baseRev = $this->getLatestRevision();
         } else {
             if ($baseRevId === 0) {
                 $baseRevId = EntityRevisionLookup::LATEST_FROM_MASTER;
             }
             $id = $this->newEntity->getId();
             $this->baseRev = $this->entityRevisionLookup->getEntityRevision($id, $baseRevId);
             if ($this->baseRev === null) {
                 throw new MWException('Base revision ID not found: rev ' . $baseRevId . ' of ' . $id->getSerialization());
             }
         }
     }
     return $this->baseRev;
 }
 /**
  * @return Item|null
  */
 private function getItem()
 {
     $params = $this->getParams();
     try {
         $itemId = new ItemId($params['entityId']);
     } catch (InvalidArgumentException $ex) {
         wfDebugLog('UpdateRepo', __FUNCTION__ . ": Invalid ItemId serialization " . $params['entityId'] . " given.");
         return null;
     }
     try {
         $entityRevision = $this->entityRevisionLookup->getEntityRevision($itemId, EntityRevisionLookup::LATEST_FROM_MASTER);
     } catch (StorageException $ex) {
         wfDebugLog('UpdateRepo', __FUNCTION__ . ": EntityRevision couldn't be loaded for " . $itemId->getSerialization() . ": " . $ex->getMessage());
         return null;
     }
     if ($entityRevision) {
         return $entityRevision->getEntity();
     }
     wfDebugLog('UpdateRepo', __FUNCTION__ . ": EntityRevision not found for " . $itemId->getSerialization());
     return null;
 }