/**
* Updates the fields of a draft.
*
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to update this version
* @throws \eZ\Publish\API\Repository\Exceptions\BadStateException if the version is not a draft
* @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $contentUpdateStruct is not valid
* @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is set to an empty value
*
* @param \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo
* @param \eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct $contentUpdateStruct
*
* @return \eZ\Publish\API\Repository\Values\Content\Content the content draft with the updated fields
*/
public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruct $contentUpdateStruct)
{
$contentUpdateStruct = clone $contentUpdateStruct;
/** @var $content \eZ\Publish\Core\Repository\Values\Content\Content */
$content = $this->loadContent($versionInfo->getContentInfo()->id, null, $versionInfo->versionNo);
if ($content->versionInfo->status !== APIVersionInfo::STATUS_DRAFT) {
throw new BadStateException('$versionInfo', 'Version is not a draft and can not be updated');
}
if (!$this->repository->canUser('content', 'edit', $content)) {
throw new UnauthorizedException('content', 'edit', array('contentId' => $content->id));
}
$mainLanguageCode = $content->contentInfo->mainLanguageCode;
$languageCodes = $this->getLanguageCodesForUpdate($contentUpdateStruct, $content);
$contentType = $this->repository->getContentTypeService()->loadContentType($content->contentInfo->contentTypeId);
$fields = $this->mapFieldsForUpdate($contentUpdateStruct, $contentType, $mainLanguageCode);
$fieldValues = array();
$spiFields = array();
$allFieldErrors = array();
$inputRelations = array();
$locationIdToContentIdMapping = array();
foreach ($contentType->getFieldDefinitions() as $fieldDefinition) {
/** @var $fieldType \eZ\Publish\SPI\FieldType\FieldType */
$fieldType = $this->fieldTypeRegistry->getFieldType($fieldDefinition->fieldTypeIdentifier);
foreach ($languageCodes as $languageCode) {
$isCopied = $isEmpty = $isRetained = false;
$isLanguageNew = !in_array($languageCode, $content->versionInfo->languageCodes);
$valueLanguageCode = $fieldDefinition->isTranslatable ? $languageCode : $mainLanguageCode;
$isFieldUpdated = isset($fields[$fieldDefinition->identifier][$valueLanguageCode]);
$isProcessed = isset($fieldValues[$fieldDefinition->identifier][$valueLanguageCode]);
if (!$isFieldUpdated && !$isLanguageNew) {
$isRetained = true;
$fieldValue = $content->getField($fieldDefinition->identifier, $valueLanguageCode)->value;
} elseif (!$isFieldUpdated && $isLanguageNew && !$fieldDefinition->isTranslatable) {
$isCopied = true;
$fieldValue = $content->getField($fieldDefinition->identifier, $valueLanguageCode)->value;
} elseif ($isFieldUpdated) {
$fieldValue = $fields[$fieldDefinition->identifier][$valueLanguageCode]->value;
} else {
$fieldValue = $fieldDefinition->defaultValue;
}
$fieldValue = $fieldType->acceptValue($fieldValue);
if ($fieldType->isEmptyValue($fieldValue)) {
$isEmpty = true;
if ($fieldDefinition->isRequired) {
throw new ContentValidationException("Value for required field definition '%identifier%' with language '%languageCode%' is empty", ['%identifier%' => $fieldDefinition->identifier, '%languageCode%' => $languageCode]);
}
} else {
$fieldErrors = $fieldType->validate($fieldDefinition, $fieldValue);
if (!empty($fieldErrors)) {
$allFieldErrors[$fieldDefinition->id][$languageCode] = $fieldErrors;
}
}
if (!empty($allFieldErrors)) {
continue;
}
$this->relationProcessor->appendFieldRelations($inputRelations, $locationIdToContentIdMapping, $fieldType, $fieldValue, $fieldDefinition->id);
$fieldValues[$fieldDefinition->identifier][$languageCode] = $fieldValue;
if ($isRetained || $isCopied || $isLanguageNew && $isEmpty || $isProcessed) {
continue;
}
$spiFields[] = new SPIField(array('id' => $isLanguageNew ? null : $content->getField($fieldDefinition->identifier, $languageCode)->id, 'fieldDefinitionId' => $fieldDefinition->id, 'type' => $fieldDefinition->fieldTypeIdentifier, 'value' => $fieldType->toPersistenceValue($fieldValue), 'languageCode' => $languageCode, 'versionNo' => $versionInfo->versionNo));
}
}
if (!empty($allFieldErrors)) {
throw new ContentFieldValidationException($allFieldErrors);
}
$spiContentUpdateStruct = new SPIContentUpdateStruct(array('name' => $this->nameSchemaService->resolveNameSchema($content, $fieldValues, $languageCodes, $contentType), 'creatorId' => $contentUpdateStruct->creatorId ?: $this->repository->getCurrentUserReference()->getUserId(), 'fields' => $spiFields, 'modificationDate' => time(), 'initialLanguageId' => $this->persistenceHandler->contentLanguageHandler()->loadByLanguageCode($contentUpdateStruct->initialLanguageCode)->id));
$existingRelations = $this->loadRelations($versionInfo);
$this->repository->beginTransaction();
try {
$spiContent = $this->persistenceHandler->contentHandler()->updateContent($versionInfo->getContentInfo()->id, $versionInfo->versionNo, $spiContentUpdateStruct);
$this->relationProcessor->processFieldRelations($inputRelations, $spiContent->versionInfo->contentInfo->id, $spiContent->versionInfo->versionNo, $contentType, $existingRelations);
$this->repository->commit();
} catch (Exception $e) {
$this->repository->rollback();
throw $e;
}
return $this->domainMapper->buildContentDomainObject($spiContent, $contentType);
}