/** * 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); }
/** * Create a Content Type object. * * The content type is created in the state STATUS_DRAFT. * * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to create a content type * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException In case when * - array of content type groups does not contain at least one content type group * - identifier or remoteId in the content type create struct already exists * - there is a duplicate field identifier in the content type create struct * @throws \eZ\Publish\API\Repository\Exceptions\ContentTypeFieldDefinitionValidationException * if a field definition in the $contentTypeCreateStruct is not valid * @throws \eZ\Publish\API\Repository\Exceptions\ContentTypeValidationException * if a multiple field definitions of a same singular type are given * * @param \eZ\Publish\API\Repository\Values\ContentType\ContentTypeCreateStruct $contentTypeCreateStruct * @param \eZ\Publish\API\Repository\Values\ContentType\ContentTypeGroup[] $contentTypeGroups Required array of {@link ContentTypeGroup} to link type with (must contain one) * * @return \eZ\Publish\API\Repository\Values\ContentType\ContentTypeDraft */ public function createContentType(APIContentTypeCreateStruct $contentTypeCreateStruct, array $contentTypeGroups) { if ($this->repository->hasAccess('class', 'create') !== true) { throw new UnauthorizedException('ContentType', 'create'); } // Prevent argument mutation $contentTypeCreateStruct = clone $contentTypeCreateStruct; $this->validateInputContentTypeCreateStruct($contentTypeCreateStruct); $this->validateInputContentTypeGroups($contentTypeGroups); $initialLanguageId = $this->repository->getContentLanguageService()->loadLanguage($contentTypeCreateStruct->mainLanguageCode)->id; try { $this->contentTypeHandler->loadByIdentifier($contentTypeCreateStruct->identifier); throw new InvalidArgumentException("\$contentTypeCreateStruct", "Another ContentType with identifier '{$contentTypeCreateStruct->identifier}' exists"); } catch (APINotFoundException $e) { // Do nothing } if ($contentTypeCreateStruct->remoteId !== null) { try { $this->contentTypeHandler->loadByRemoteId($contentTypeCreateStruct->remoteId); throw new InvalidArgumentException("\$contentTypeCreateStruct", "Another ContentType with remoteId '{$contentTypeCreateStruct->remoteId}' exists"); } catch (APINotFoundException $e) { // Do nothing } } $fieldDefinitionIdentifierSet = array(); $fieldDefinitionPositionSet = array(); foreach ($contentTypeCreateStruct->fieldDefinitions as $fieldDefinitionCreateStruct) { // Check for duplicate identifiers if (!isset($fieldDefinitionIdentifierSet[$fieldDefinitionCreateStruct->identifier])) { $fieldDefinitionIdentifierSet[$fieldDefinitionCreateStruct->identifier] = true; } else { throw new InvalidArgumentException("\$contentTypeCreateStruct", "Argument contains duplicate field definition identifier '{$fieldDefinitionCreateStruct->identifier}'"); } // Check for duplicate positions if (!isset($fieldDefinitionPositionSet[$fieldDefinitionCreateStruct->position])) { $fieldDefinitionPositionSet[$fieldDefinitionCreateStruct->position] = true; } else { throw new InvalidArgumentException("\$contentTypeCreateStruct", "Argument contains duplicate field definition position '{$fieldDefinitionCreateStruct->position}'"); } } $allValidationErrors = array(); $spiFieldDefinitions = array(); $fieldTypeIdentifierSet = array(); foreach ($contentTypeCreateStruct->fieldDefinitions as $fieldDefinitionCreateStruct) { /** @var $fieldType \eZ\Publish\SPI\FieldType\FieldType */ $fieldType = $this->fieldTypeRegistry->getFieldType($fieldDefinitionCreateStruct->fieldTypeIdentifier); if ($fieldType->isSingular() && isset($fieldTypeIdentifierSet[$fieldDefinitionCreateStruct->fieldTypeIdentifier])) { throw new ContentTypeValidationException("FieldType '{$fieldDefinitionCreateStruct->fieldTypeIdentifier}' is singular and can't be repeated in a ContentType"); } $fieldTypeIdentifierSet[$fieldDefinitionCreateStruct->fieldTypeIdentifier] = true; $fieldType->applyDefaultSettings($fieldDefinitionCreateStruct->fieldSettings); $fieldType->applyDefaultValidatorConfiguration($fieldDefinitionCreateStruct->validatorConfiguration); $validationErrors = $this->validateFieldDefinitionCreateStruct($fieldDefinitionCreateStruct, $fieldType); if (!empty($validationErrors)) { $allValidationErrors[$fieldDefinitionCreateStruct->identifier] = $validationErrors; } if (!empty($allValidationErrors)) { continue; } $spiFieldDefinitions[] = $this->buildSPIFieldDefinitionCreate($fieldDefinitionCreateStruct, $fieldType); } if (!empty($allValidationErrors)) { throw new ContentTypeFieldDefinitionValidationException($allValidationErrors); } $groupIds = array_map(function (ContentTypeGroup $contentTypeGroup) { return $contentTypeGroup->id; }, $contentTypeGroups); if ($contentTypeCreateStruct->creatorId === null) { $contentTypeCreateStruct->creatorId = $this->repository->getCurrentUser()->id; } if ($contentTypeCreateStruct->creationDate === null) { $timestamp = time(); } else { $timestamp = $contentTypeCreateStruct->creationDate->getTimestamp(); } if ($contentTypeCreateStruct->remoteId === null) { $contentTypeCreateStruct->remoteId = $this->domainMapper->getUniqueHash($contentTypeCreateStruct); } $spiContentTypeCreateStruct = new SPIContentTypeCreateStruct(array('identifier' => $contentTypeCreateStruct->identifier, 'name' => $contentTypeCreateStruct->names, 'status' => APIContentType::STATUS_DRAFT, 'description' => $contentTypeCreateStruct->descriptions === null ? array() : $contentTypeCreateStruct->descriptions, 'created' => $timestamp, 'modified' => $timestamp, 'creatorId' => $contentTypeCreateStruct->creatorId, 'modifierId' => $contentTypeCreateStruct->creatorId, 'remoteId' => $contentTypeCreateStruct->remoteId, 'urlAliasSchema' => $contentTypeCreateStruct->urlAliasSchema === null ? '' : $contentTypeCreateStruct->urlAliasSchema, 'nameSchema' => $contentTypeCreateStruct->nameSchema === null ? '' : $contentTypeCreateStruct->nameSchema, 'isContainer' => $contentTypeCreateStruct->isContainer === null ? false : $contentTypeCreateStruct->isContainer, 'initialLanguageId' => $initialLanguageId, 'sortField' => $contentTypeCreateStruct->defaultSortField === null ? Location::SORT_FIELD_PUBLISHED : $contentTypeCreateStruct->defaultSortField, 'sortOrder' => $contentTypeCreateStruct->defaultSortOrder === null ? Location::SORT_ORDER_DESC : $contentTypeCreateStruct->defaultSortOrder, 'groupIds' => $groupIds, 'fieldDefinitions' => $spiFieldDefinitions, 'defaultAlwaysAvailable' => $contentTypeCreateStruct->defaultAlwaysAvailable)); $this->repository->beginTransaction(); try { $spiContentType = $this->contentTypeHandler->create($spiContentTypeCreateStruct); $this->repository->commit(); } catch (Exception $e) { $this->repository->rollback(); throw $e; } return $this->buildContentTypeDraftDomainObject($spiContentType); }