diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php index d60e423..f46fdf6 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php @@ -6,11 +6,13 @@ use Drupal\Component\Plugin\PluginManagerInterface; use Drupal\Core\Cache\CacheableResponseInterface; use Drupal\Core\Config\Entity\ConfigEntityType; +use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageException; +use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity; use Drupal\rest\Plugin\ResourceBase; use Drupal\rest\ResourceResponse; use Psr\Log\LoggerInterface; @@ -193,9 +195,9 @@ public function post(EntityInterface $entity = NULL) { /** * Responds to entity PATCH requests. * - * @param \Drupal\Core\Entity\EntityInterface $original_entity + * @param \Drupal\Core\Entity\ContentEntityInterface $original_entity * The original entity object. - * @param \Drupal\Core\Entity\EntityInterface $entity + * @param \Drupal\Core\Entity\ContentEntityInterface $entity * The entity. * * @return \Drupal\rest\ModifiedResourceResponse @@ -203,7 +205,7 @@ public function post(EntityInterface $entity = NULL) { * * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ - public function patch(EntityInterface $original_entity, EntityInterface $entity = NULL) { + public function patch(ContentEntityInterface $original_entity, ContentEntityInterface $entity = NULL) { if ($entity == NULL) { throw new BadRequestHttpException('No entity content received.'); } @@ -219,49 +221,50 @@ public function patch(EntityInterface $original_entity, EntityInterface $entity // Overwrite the received properties. $entity_keys = $entity->getEntityType()->getKeys(); foreach ($entity->_restSubmittedFields as $field_name) { - $field = $entity->get($field_name); + foreach ($entity->getTranslationLanguages() as $langcode => $language) { - // Entity key fields need special treatment: together they uniquely - // identify the entity. Therefore it does not make sense to modify any of - // them. However, rather than throwing an error, we just ignore them as - // long as their specified values match their current values. - if (in_array($field_name, $entity_keys, TRUE)) { - // @todo Work around the wrong assumption that entity keys need special - // treatment, when only read-only fields need it. - // This will be fixed in https://www.drupal.org/node/2824851. - if ($entity->getEntityTypeId() == 'comment' && $field_name == 'status' && !$original_entity->get($field_name)->access('edit')) { + if (!$original_entity->hasTranslation($langcode)) { + $original_entity->addTranslation($langcode, $original_entity->toArray()); + } + + $field = $entity->getTranslation($langcode)->get($field_name); + // Entity key fields need special treatment: together they uniquely + // identify the entity. Therefore it does not make sense to modify any of + // them. However, rather than throwing an error, we just ignore them as + // long as their specified values match their current values. + if (in_array($field_name, $entity_keys, TRUE)) { + // @todo Work around the wrong assumption that entity keys need special + // treatment, when only read-only fields need it. + // This will be fixed in https://www.drupal.org/node/2824851. + if ($entity->getEntityTypeId() == 'comment' && $field_name == 'status' && !$original_entity->getTranslation($langcode)->get($field_name)->access('edit')) { + throw new AccessDeniedHttpException("Access denied on updating field '$field_name'."); + } + // Unchanged values for entity keys don't need access checking. + if ($original_entity->getTranslation($langcode)->get($field_name)->getValue() === $entity->getTranslation($langcode)->get($field_name)->getValue()) { + continue; + } + // It is not possible to set the language to NULL as it is automatically + // re-initialized. As it must not be empty, skip it if it is. + elseif (isset($entity_keys['langcode']) && $field_name === $entity_keys['langcode'] && $field->isEmpty()) { + continue; + } + } + if (!$original_entity->getTranslation($langcode)->get($field_name)->access('edit')) { throw new AccessDeniedHttpException("Access denied on updating field '$field_name'."); } - // Unchanged values for entity keys don't need access checking. - if ($original_entity->get($field_name)->getValue() === $entity->get($field_name)->getValue()) { - continue; - } - // It is not possible to set the language to NULL as it is automatically - // re-initialized. As it must not be empty, skip it if it is. - elseif (isset($entity_keys['langcode']) && $field_name === $entity_keys['langcode'] && $field->isEmpty()) { - continue; - } - } - if (!$original_entity->get($field_name)->access('edit')) { - throw new AccessDeniedHttpException("Access denied on updating field '$field_name'."); + $original_entity->getTranslation($langcode)->set($field_name, $field->getValue()); } - $original_entity->set($field_name, $field->getValue()); } // Validate the received data before saving. $this->validate($original_entity); - try { - $original_entity->save(); - $this->logger->notice('Updated entity %type with ID %id.', array('%type' => $original_entity->getEntityTypeId(), '%id' => $original_entity->id())); + $original_entity->save(); + $this->logger->notice('Updated entity %type with ID %id.', array('%type' => $original_entity->getEntityTypeId(), '%id' => $original_entity->id())); - // Return the updated entity in the response body. - return new ModifiedResourceResponse($original_entity, 200); - } - catch (EntityStorageException $e) { - throw new HttpException(500, 'Internal Server Error', $e); - } + // Return the updated entity in the response body. + return new ModifiedResourceResponse($original_entity, 200); } /** diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResourceValidationTrait.php b/core/modules/rest/src/Plugin/rest/resource/EntityResourceValidationTrait.php index 09b4b64..6c51322 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResourceValidationTrait.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResourceValidationTrait.php @@ -3,7 +3,7 @@ namespace Drupal\rest\Plugin\rest\resource; use Drupal\Component\Render\PlainTextOutput; -use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; @@ -13,34 +13,34 @@ */ trait EntityResourceValidationTrait { - /** + /**->getTranslation($langcode) * Verifies that the whole entity does not violate any validation constraints. * - * @param \Drupal\Core\Entity\EntityInterface $entity + * @param \Drupal\Core\Entity\ContentEntityInterface $entity * The entity to validate. * * @throws \Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException * If validation errors are found. */ - protected function validate(EntityInterface $entity) { + protected function validate(ContentEntityInterface $entity) { // @todo Remove when https://www.drupal.org/node/2164373 is committed. if (!$entity instanceof FieldableEntityInterface) { return; } - $violations = $entity->validate(); - - // Remove violations of inaccessible fields as they cannot stem from our - // changes. - $violations->filterByFieldAccess(); - - if ($violations->count() > 0) { - $message = "Unprocessable Entity: validation failed.\n"; - foreach ($violations as $violation) { - // We strip every HTML from the error message to have a nicer to read - // message on REST responses. - $message .= $violation->getPropertyPath() . ': ' . PlainTextOutput::renderFromHtml($violation->getMessage()) . "\n"; + foreach ($entity->getTranslationLanguages() as $langcode => $language) { + $violations = $entity->getTranslation($langcode)->validate(); + // Remove violations of inaccessible fields as they cannot stem from our + // changes. + $violations->filterByFieldAccess(); + if ($violations->count() > 0) { + $message = "Unprocessable Entity: validation failed.\n"; + foreach ($violations as $violation) { + // We strip every HTML from the error message to have a nicer to read + // message on REST responses. + $message .= $violation->getPropertyPath() . ': ' . PlainTextOutput::renderFromHtml($violation->getMessage()) . "\n"; + } + throw new UnprocessableEntityHttpException($message); } - throw new UnprocessableEntityHttpException($message); } }