private function propertyMatchesFilter(EntityId $propertyId) { if (isset($this->requestParams['property'])) { try { $parsedProperty = $this->idParser->parse($this->requestParams['property']); } catch (EntityIdParsingException $e) { $this->errorReporter->dieException($e, 'param-invalid'); } /** @var EntityId $parsedProperty */ return $propertyId->equals($parsedProperty); } return true; }
/** * Checks if the required parameters are set and the ones that make no sense given the * snaktype value are not set. * * @params array $params */ private function validateParameters(array $params) { if ($params['snaktype'] === 'value' xor isset($params['value'])) { if ($params['snaktype'] === 'value') { $this->errorReporter->dieError('A value needs to be provided when creating a claim with PropertyValueSnak snak', 'param-missing'); } else { $this->errorReporter->dieError('You cannot provide a value when creating a claim with no PropertyValueSnak as main snak', 'param-illegal'); } } if (!isset($params['property'])) { $this->errorReporter->dieError('A property ID needs to be provided when creating a claim with a Snak', 'param-missing'); } if (isset($params['value']) && json_decode($params['value'], true) === null) { $this->errorReporter->dieError('Could not decode snak value', 'invalid-snak'); } }
/** * @see ModifyEntity::modifyEntity */ protected function modifyEntity(EntityDocument &$entity, array $params, $baseRevId) { if (!$entity instanceof FingerprintProvider) { $this->errorReporter->dieError('The given entity does not contain aliases', 'no-aliases'); } $summary = $this->createSummary($params); $language = $params['language']; /** @var ChangeOp[] $aliasesChangeOps */ $aliasesChangeOps = $this->getChangeOps($params); if (count($aliasesChangeOps) == 1) { $this->applyChangeOp($aliasesChangeOps[0], $entity, $summary); } else { $changeOps = new ChangeOps(); $changeOps->add($aliasesChangeOps); $this->applyChangeOp($changeOps, $entity); // Set the action to 'set' in case we add and remove aliases in a single edit $summary->setAction('set'); $summary->setLanguage($language); // Get the full list of current aliases $fingerprint = $entity->getFingerprint(); $aliases = $fingerprint->hasAliasGroup($language) ? $fingerprint->getAliasGroup($language)->getAliases() : array(); $summary->addAutoSummaryArgs($aliases); } $fingerprint = $entity->getFingerprint(); if ($fingerprint->hasAliasGroup($language)) { $aliasGroupList = $fingerprint->getAliasGroups()->getWithLanguages(array($language)); $this->getResultBuilder()->addAliasGroupList($aliasGroupList, 'entity'); } return $summary; }
private function getEntityIdFromStatementGuid($guid) { if ($this->guidValidator->validateFormat($guid) === false) { $this->errorReporter->dieError('Invalid claim guid', 'invalid-guid'); } return $this->guidParser->parse($guid)->getEntityId()->getSerialization(); }
/** * @param string $arrayParam * * @return array */ private function getArrayFromParam($arrayParam) { $rawArray = json_decode($arrayParam, true); if (!is_array($rawArray) || !count($rawArray)) { $this->errorReporter->dieError('No array or invalid JSON given', 'invalid-json'); } return $rawArray; }
/** * 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 ItemMergeException|RedirectCreationException $ex * * @throws UsageException always */ private function handleException(Exception $ex) { $cause = $ex->getPrevious(); if ($cause) { $this->errorReporter->dieException($cause, $ex->getErrorCode()); } else { $this->errorReporter->dieError($ex->getMessage(), $ex->getErrorCode()); } }
/** * @see ModifyEntity::validateParameters */ protected function validateParameters(array $params) { if ($params['fromsite'] === $params['tosite']) { $this->errorReporter->dieError('The from site cannot match the to site', 'param-illegal'); } if ($params['fromtitle'] === '' || $params['totitle'] === '') { $this->errorReporter->dieError('The from title and to title must have a value', 'param-illegal'); } }
/** * @see ModifyEntity::modifyEntity */ protected function modifyEntity(EntityDocument &$entity, array $params, $baseRevId) { if (!$entity instanceof FingerprintProvider) { $this->errorReporter->dieError('The given entity does not contain descriptions', 'no-descriptions'); } $summary = $this->createSummary($params); $language = $params['language']; $changeOp = $this->getChangeOp($params); $this->applyChangeOp($changeOp, $entity, $summary); $resultBuilder = $this->getResultBuilder(); if ($entity->getFingerprint()->hasDescription($language)) { $termList = $entity->getFingerprint()->getDescriptions()->getWithLanguages(array($language)); $resultBuilder->addDescriptions($termList, 'entity'); } else { $resultBuilder->addRemovedDescription($language, 'entity'); } return $summary; }
/** * Include messages from a Status object in the API call's output. * * An ApiErrorHandler is used to report the status, if necessary. * If $status->isOK() is false, this method will terminate with a UsageException. * * @param Status $status The status to report * @param string $errorCode The API error code to use in case $status->isOK() returns false * @param array $extradata Additional data to include the the error report, * if $status->isOK() returns false * @param int $httpRespCode the HTTP response code to use in case * $status->isOK() returns false.+ * * @throws UsageException If $status->isOK() returns false. */ private function handleStatus(Status $status, $errorCode, array $extradata = array(), $httpRespCode = 0) { if ($status->isGood()) { return; } elseif ($status->isOK()) { $this->errorReporter->reportStatusWarnings($status); } else { $this->errorReporter->reportStatusWarnings($status); $this->errorReporter->dieStatus($status, $errorCode, $httpRespCode, $extradata); } }
/** * @param array $params * @param Statement $statement * * @return string[] */ private function getQualifierHashesFromParams(array $params, Statement $statement) { $qualifiers = $statement->getQualifiers(); $hashes = array(); foreach (array_unique($params['qualifiers']) as $qualifierHash) { if (!$qualifiers->hasSnakHash($qualifierHash)) { $this->errorReporter->dieError('Invalid snak hash', 'no-such-qualifier'); } $hashes[] = $qualifierHash; } return $hashes; }
/** * @param array $params * @param Statement $statement * * @return string[] */ private function getReferenceHashesFromParams(array $params, Statement $statement) { $references = $statement->getReferences(); $hashes = array(); foreach (array_unique($params['references']) as $referenceHash) { if (!$references->hasReferenceHash($referenceHash)) { $this->errorReporter->dieError('Invalid reference hash', 'no-such-reference'); } $hashes[] = $referenceHash; } return $hashes; }
/** * @return ChangeOpQualifier */ private function getChangeOp() { $params = $this->extractRequestParams(); $guid = $params['claim']; $propertyId = $this->modificationHelper->getEntityIdFromString($params['property']); if (!$propertyId instanceof PropertyId) { $this->errorReporter->dieError($propertyId->getSerialization() . ' does not appear to be a property ID', 'param-illegal'); } $newQualifier = $this->modificationHelper->getSnakInstance($params, $propertyId); $snakHash = isset($params['snakhash']) ? $params['snakhash'] : ''; $changeOp = $this->statementChangeOpFactory->newSetQualifierOp($guid, $newQualifier, $snakHash); return $changeOp; }
/** * @param array $params * @return EntityId[] */ private function getEntityIdsFromIdParam($params) { $ids = array(); if (isset($params['ids'])) { foreach ($params['ids'] as $id) { try { $ids[] = $this->idParser->parse($id); } catch (EntityIdParsingException $e) { $this->errorReporter->dieError("Invalid id: {$id}", 'no-such-entity', 0, array('id' => $id)); } } } return $ids; }
/** * @param string $json A JSON-encoded DataValue * * @throws UsageException * @throws LogicException * @return DataValue */ private function decodeDataValue($json) { $data = json_decode($json, true); if (!is_array($data)) { $this->errorReporter->dieError('Failed to decode datavalue', 'baddatavalue'); } try { $value = $this->dataValueFactory->newFromArray($data); return $value; } catch (IllegalValueException $ex) { $this->errorReporter->dieException($ex, 'baddatavalue'); } throw new LogicException('ApiErrorReporter::dieException did not throw a UsageException'); }
/** * @param StatementList $statements * @param string[] $requiredGuids */ private function assertStatementListContainsGuids(StatementList $statements, array $requiredGuids) { $existingGuids = array(); /** @var Statement $statement */ foreach ($statements as $statement) { $guid = $statement->getGuid(); // This array is used as a HashSet where only the keys are used. $existingGuids[$guid] = null; } // Not using array_diff but array_diff_key does have a huge performance impact. $missingGuids = array_diff_key(array_flip($requiredGuids), $existingGuids); if (!empty($missingGuids)) { $this->errorReporter->dieError('Statement(s) with GUID(s) ' . implode(', ', array_keys($missingGuids)) . ' not found', 'invalid-guid'); } }
/** * @param string|null $optionsParam * * @return ParserOptions */ private function getOptionsObject($optionsParam) { $parserOptions = new ParserOptions(); $parserOptions->setOption(ValueParser::OPT_LANG, $this->getLanguage()->getCode()); if (is_string($optionsParam) && $optionsParam !== '') { $options = json_decode($optionsParam, true); if (!is_array($options)) { $this->errorReporter->dieError('Malformed options parameter', 'malformed-options'); } foreach ($options as $name => $value) { $parserOptions->setOption($name, $value); } } return $parserOptions; }
/** * @param array $params * * @throws IllegalValueException * @throws UsageException * @throws LogicException * @return Statement */ private function getClaimFromParams(array $params) { try { $serializedStatement = json_decode($params['claim'], true); if (!is_array($serializedStatement)) { throw new IllegalValueException('Failed to get statement from Serialization'); } $claim = $this->statementDeserializer->deserialize($serializedStatement); if (!$claim instanceof Statement) { throw new IllegalValueException('Failed to get statement from Serialization'); } return $claim; } catch (InvalidArgumentException $invalidArgumentException) { $this->errorReporter->dieError('Failed to get claim from claim Serialization ' . $invalidArgumentException->getMessage(), 'invalid-claim'); } catch (OutOfBoundsException $outOfBoundsException) { $this->errorReporter->dieError('Failed to get claim from claim Serialization ' . $outOfBoundsException->getMessage(), 'invalid-claim'); } // Note: since dieUsage() never returns, this should be unreachable! throw new LogicException('ApiErrorReporter::dieError did not throw an exception'); }
/** * @see ApiBase::execute() * * @since 0.1 */ public function execute() { $params = $this->extractRequestParams(); $user = $this->getUser(); $this->flags = 0; $this->validateParameters($params); // Try to find the entity or fail and create it, or die in the process $entityRev = $this->getEntityRevisionFromApiParams($params); if (is_null($entityRev)) { $entity = $this->createEntity($params['new']); $entityRevId = 0; // HACK: We need to assign an ID early, for things like the ClaimIdGenerator. if ($entity->getId() === null) { $this->getEntityStore()->assignFreshId($entity); } } else { $entity = $entityRev->getEntity(); $entityRevId = $entityRev->getRevisionId(); } if ($entity->getId() === null) { throw new LogicException('The Entity should have an ID at this point!'); } // At this point only change/edit rights should be checked $status = $this->checkPermissions($entity, $user); if (!$status->isOK()) { $this->errorReporter->dieError('You do not have sufficient permissions', 'permissiondenied'); } $summary = $this->modifyEntity($entity, $params, $entityRevId); if (!$summary) { //XXX: This could rather be used for "silent" failure, i.e. in cases where // there was simply nothing to do. $this->errorReporter->dieError('Attempted modification of the item failed', 'failed-modify'); } $this->addFlags($entity->getId() === null); //NOTE: EDIT_NEW will not be set automatically. If the entity doesn't exist, and EDIT_NEW was // not added to $this->flags explicitly, the save will fail. $status = $this->attemptSaveEntity($entity, $summary, $this->flags); $this->addToOutput($entity, $status, $entityRevId); }
/** * @param array $params * * @return ChangeOpSiteLink */ private function getChangeOp(array $params) { if ($this->shouldRemove($params)) { $linksite = $this->stringNormalizer->trimToNFC($params['linksite']); return $this->siteLinkChangeOpFactory->newRemoveSiteLinkOp($linksite); } else { $linksite = $this->stringNormalizer->trimToNFC($params['linksite']); $sites = $this->siteLinkTargetProvider->getSiteList($this->siteLinkGroups); $site = $sites->getSite($linksite); if ($site === false) { $this->errorReporter->dieError('The supplied site identifier was not recognized', 'not-recognized-siteid'); } if (isset($params['linktitle'])) { $page = $site->normalizePageName($this->stringNormalizer->trimWhitespace($params['linktitle'])); if ($page === false) { $this->errorReporter->dieMessage('no-external-page', $linksite, $params['linktitle']); } } else { $page = null; } $badges = isset($params['badges']) ? $this->parseSiteLinkBadges($params['badges']) : null; return $this->siteLinkChangeOpFactory->newSetSiteLinkOp($linksite, $page, $badges); } }
/** * @param array $params */ private function validateParameters(array $params) { if (!$this->modificationHelper->validateStatementGuid($params['claim'])) { $this->errorReporter->dieError('Invalid claim guid', 'invalid-guid'); } }
/** * @see ModifyEntity::createEntity */ protected function createEntity($entityType) { $this->errorReporter->dieError('Could not find an existing entity', 'no-such-entity'); }
/** * @param string $type * @param mixed $value * @param string $message */ private function assertType($type, $value, $message) { if (gettype($value) !== $type) { $this->errorReporter->dieError($message, 'not-recognized-' . $type); } }
/** * @dataProvider warningProvider */ public function testReportStatusWarnings(Status $status, array $expectedDataFields) { $api = new ApiMain(); $localizer = $this->getExceptionLocalizer(); $reporter = new ApiErrorReporter($api, $localizer, Language::factory('de')); $reporter->reportStatusWarnings($status); $result = $api->getResult()->getResultData(); foreach ($expectedDataFields as $path => $value) { $path = explode('/', $path); $this->assertValueAtPath($value, $path, $result); } }