/**
  * Test eZ\Publish\Core\Repository\NameSchemaService method
  * @covers \eZ\Publish\Core\Repository\NameSchemaService::resolve
  * @dataProvider providerForTestResolve
  */
 public function testResolve($nameSchema, $expectedName)
 {
     /** @var $service \eZ\Publish\Core\Repository\NameSchemaService */
     $service = new NameSchemaService($this->repository);
     list($content, $contentType) = $this->buildTestObjects();
     $name = $service->resolve($nameSchema, $contentType, $content->fields, $content->versionInfo->languageCodes);
     self::assertEquals($expectedName, $name);
 }
 /**
  * Recovers the $trashedLocation at its original place if possible.
  *
  * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to recover the trash item at the parent location location
  *
  * If $newParentLocation is provided, $trashedLocation will be restored under it.
  *
  * @param \eZ\Publish\API\Repository\Values\Content\TrashItem $trashItem
  * @param \eZ\Publish\API\Repository\Values\Content\Location $newParentLocation
  *
  * @return \eZ\Publish\API\Repository\Values\Content\Location the newly created or recovered location
  */
 public function recover(APITrashItem $trashItem, Location $newParentLocation = null)
 {
     if (!is_numeric($trashItem->id)) {
         throw new InvalidArgumentValue("id", $trashItem->id, "TrashItem");
     }
     if ($newParentLocation === null && !is_numeric($trashItem->parentLocationId)) {
         throw new InvalidArgumentValue("parentLocationId", $trashItem->parentLocationId, "TrashItem");
     }
     if ($newParentLocation !== null && !is_numeric($newParentLocation->id)) {
         throw new InvalidArgumentValue("parentLocationId", $newParentLocation->id, "Location");
     }
     if ($this->repository->hasAccess('content', 'restore') !== true) {
         throw new UnauthorizedException('content', 'restore');
     }
     $this->repository->beginTransaction();
     try {
         $newParentLocationId = $newParentLocation ? $newParentLocation->id : $trashItem->parentLocationId;
         $newLocationId = $this->persistenceHandler->trashHandler()->recover($trashItem->id, $newParentLocationId);
         $content = $this->repository->getContentService()->loadContent($trashItem->contentId);
         $urlAliasNames = $this->nameSchemaService->resolveUrlAliasSchema($content);
         // Publish URL aliases for recovered location
         foreach ($urlAliasNames as $languageCode => $name) {
             $this->persistenceHandler->urlAliasHandler()->publishUrlAliasForLocation($newLocationId, $newParentLocationId, $name, $languageCode, $content->contentInfo->alwaysAvailable);
         }
         $this->repository->commit();
     } catch (Exception $e) {
         $this->repository->rollback();
         throw $e;
     }
     return $this->repository->getLocationService()->loadLocation($newLocationId);
 }
 /**
  * Moves the subtree to $newParentLocation
  *
  * If a user has the permission to move the location to a target location
  * he can do it regardless of an existing descendant on which the user has no permission.
  *
  * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to move this location to the target
  * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user does not have read access to the whole source subtree
  * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If the new parent is in a subtree of the location
  *
  * @param \eZ\Publish\API\Repository\Values\Content\Location $location
  * @param \eZ\Publish\API\Repository\Values\Content\Location $newParentLocation
  */
 public function moveSubtree(APILocation $location, APILocation $newParentLocation)
 {
     $location = $this->loadLocation($location->id);
     $newParentLocation = $this->loadLocation($newParentLocation->id);
     // check create permission on target location
     if (!$this->repository->canUser('content', 'create', $location->getContentInfo(), $newParentLocation)) {
         throw new UnauthorizedException('content', 'create');
     }
     /** Check read access to whole source subtree
      * @var boolean|\eZ\Publish\API\Repository\Values\Content\Query\Criterion $contentReadCriterion
      */
     $contentReadCriterion = $this->permissionsCriterionHandler->getPermissionsCriterion();
     if ($contentReadCriterion === false) {
         throw new UnauthorizedException('content', 'read');
     } else {
         if ($contentReadCriterion !== true) {
             // Query if there are any content in subtree current user don't have access to
             $query = new Query(array('limit' => 0, 'filter' => new CriterionLogicalAnd(new CriterionSubtree($location->pathString), new CriterionLogicalNot($contentReadCriterion))));
             $result = $this->repository->getSearchService()->findContent($query, array(), false);
             if ($result->totalCount > 0) {
                 throw new UnauthorizedException('content', 'read');
             }
         }
     }
     if (strpos($newParentLocation->pathString, $location->pathString) === 0) {
         throw new InvalidArgumentException("\$newParentLocation", "new parent location is in a subtree of the given \$location");
     }
     $this->repository->beginTransaction();
     try {
         $this->persistenceHandler->locationHandler()->move($location->id, $newParentLocation->id);
         $content = $this->repository->getContentService()->loadContent($location->contentId);
         $urlAliasNames = $this->nameSchemaService->resolveUrlAliasSchema($content);
         foreach ($urlAliasNames as $languageCode => $name) {
             $this->persistenceHandler->urlAliasHandler()->publishUrlAliasForLocation($location->id, $newParentLocation->id, $name, $languageCode, $content->contentInfo->alwaysAvailable);
         }
         $this->persistenceHandler->urlAliasHandler()->locationMoved($location->id, $location->parentLocationId, $newParentLocation->id);
         $this->repository->commit();
     } catch (Exception $e) {
         $this->repository->rollback();
         throw $e;
     }
 }
 /**
  * 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->repository->getFieldTypeService()->buildFieldType($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;
             } else {
                 if (!$isFieldUpdated && $isLanguageNew && !$fieldDefinition->isTranslatable) {
                     $isCopied = true;
                     $fieldValue = $content->getField($fieldDefinition->identifier, $valueLanguageCode)->value;
                 } else {
                     if ($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 '{$fieldDefinition->identifier}' with language '{$languageCode}' is empty");
                 }
             } 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->getCurrentUser()->id, "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);
 }