/**
* Creates a new content draft assigned to the authenticated user.
*
* If a different userId is given in $contentCreateStruct it is assigned to the given user
* but this required special rights for the authenticated user
* (this is useful for content staging where the transfer process does not
* have to authenticate with the user which created the content object in the source server).
* The user has to publish the draft if it should be visible.
* In 4.x at least one location has to be provided in the location creation array.
*
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to create the content in the given location
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if there is a provided remoteId which exists in the system
* or there is no location provided (4.x) or multiple locations
* are under the same parent or if the a field value is not accepted by the field type
* @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $contentCreateStruct is not valid
* @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException if a required field is missing or is set to an empty value
*
* @param \eZ\Publish\API\Repository\Values\Content\ContentCreateStruct $contentCreateStruct
* @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct[] $locationCreateStructs For each location parent under which a location should be created for the content
*
* @return \eZ\Publish\API\Repository\Values\Content\Content - the newly created content draft
*/
public function createContent(APIContentCreateStruct $contentCreateStruct, array $locationCreateStructs = array())
{
if ($contentCreateStruct->mainLanguageCode === null) {
throw new InvalidArgumentException('$contentCreateStruct', "'mainLanguageCode' property must be set");
}
if ($contentCreateStruct->contentType === null) {
throw new InvalidArgumentException('$contentCreateStruct', "'contentType' property must be set");
}
$contentCreateStruct = clone $contentCreateStruct;
if ($contentCreateStruct->ownerId === null) {
$contentCreateStruct->ownerId = $this->repository->getCurrentUserReference()->getUserId();
}
if ($contentCreateStruct->alwaysAvailable === null) {
$contentCreateStruct->alwaysAvailable = false;
}
$contentCreateStruct->contentType = $this->repository->getContentTypeService()->loadContentType($contentCreateStruct->contentType->id);
if (empty($contentCreateStruct->sectionId)) {
if (isset($locationCreateStructs[0])) {
$location = $this->repository->getLocationService()->loadLocation($locationCreateStructs[0]->parentLocationId);
$contentCreateStruct->sectionId = $location->contentInfo->sectionId;
} else {
$contentCreateStruct->sectionId = 1;
}
}
if (!$this->repository->canUser('content', 'create', $contentCreateStruct, $locationCreateStructs)) {
throw new UnauthorizedException('content', 'create', array('parentLocationId' => isset($locationCreateStructs[0]) ? $locationCreateStructs[0]->parentLocationId : null, 'sectionId' => $contentCreateStruct->sectionId));
}
if (!empty($contentCreateStruct->remoteId)) {
try {
$this->loadContentByRemoteId($contentCreateStruct->remoteId);
throw new InvalidArgumentException('$contentCreateStruct', "Another content with remoteId '{$contentCreateStruct->remoteId}' exists");
} catch (APINotFoundException $e) {
// Do nothing
}
} else {
$contentCreateStruct->remoteId = $this->domainMapper->getUniqueHash($contentCreateStruct);
}
$spiLocationCreateStructs = $this->buildSPILocationCreateStructs($locationCreateStructs);
$languageCodes = $this->getLanguageCodesForCreate($contentCreateStruct);
$fields = $this->mapFieldsForCreate($contentCreateStruct);
$fieldValues = array();
$spiFields = array();
$allFieldErrors = array();
$inputRelations = array();
$locationIdToContentIdMapping = array();
foreach ($contentCreateStruct->contentType->getFieldDefinitions() as $fieldDefinition) {
/** @var $fieldType \eZ\Publish\Core\FieldType\FieldType */
$fieldType = $this->fieldTypeRegistry->getFieldType($fieldDefinition->fieldTypeIdentifier);
foreach ($languageCodes as $languageCode) {
$isEmptyValue = false;
$valueLanguageCode = $fieldDefinition->isTranslatable ? $languageCode : $contentCreateStruct->mainLanguageCode;
$isLanguageMain = $languageCode === $contentCreateStruct->mainLanguageCode;
if (isset($fields[$fieldDefinition->identifier][$valueLanguageCode])) {
$fieldValue = $fields[$fieldDefinition->identifier][$valueLanguageCode]->value;
} else {
$fieldValue = $fieldDefinition->defaultValue;
}
$fieldValue = $fieldType->acceptValue($fieldValue);
if ($fieldType->isEmptyValue($fieldValue)) {
$isEmptyValue = 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;
// Only non-empty value for: translatable field or in main language
if (!$isEmptyValue && $fieldDefinition->isTranslatable || !$isEmptyValue && $isLanguageMain) {
$spiFields[] = new SPIField(array('id' => null, 'fieldDefinitionId' => $fieldDefinition->id, 'type' => $fieldDefinition->fieldTypeIdentifier, 'value' => $fieldType->toPersistenceValue($fieldValue), 'languageCode' => $languageCode, 'versionNo' => null));
}
}
}
if (!empty($allFieldErrors)) {
throw new ContentFieldValidationException($allFieldErrors);
}
$spiContentCreateStruct = new SPIContentCreateStruct(array('name' => $this->nameSchemaService->resolve($contentCreateStruct->contentType->nameSchema, $contentCreateStruct->contentType, $fieldValues, $languageCodes), 'typeId' => $contentCreateStruct->contentType->id, 'sectionId' => $contentCreateStruct->sectionId, 'ownerId' => $contentCreateStruct->ownerId, 'locations' => $spiLocationCreateStructs, 'fields' => $spiFields, 'alwaysAvailable' => $contentCreateStruct->alwaysAvailable, 'remoteId' => $contentCreateStruct->remoteId, 'modified' => isset($contentCreateStruct->modificationDate) ? $contentCreateStruct->modificationDate->getTimestamp() : time(), 'initialLanguageId' => $this->persistenceHandler->contentLanguageHandler()->loadByLanguageCode($contentCreateStruct->mainLanguageCode)->id));
$defaultObjectStates = $this->getDefaultObjectStates();
$this->repository->beginTransaction();
try {
$spiContent = $this->persistenceHandler->contentHandler()->create($spiContentCreateStruct);
$this->relationProcessor->processFieldRelations($inputRelations, $spiContent->versionInfo->contentInfo->id, $spiContent->versionInfo->versionNo, $contentCreateStruct->contentType);
foreach ($defaultObjectStates as $objectStateGroupId => $objectState) {
$this->persistenceHandler->objectStateHandler()->setContentState($spiContent->versionInfo->contentInfo->id, $objectStateGroupId, $objectState->id);
}
$this->repository->commit();
} catch (Exception $e) {
$this->repository->rollback();
throw $e;
}
return $this->domainMapper->buildContentDomainObject($spiContent);
}