diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php index 55ce64a..efea14c 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php @@ -4,6 +4,7 @@ use Drupal\Component\Plugin\DependentPluginInterface; 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; @@ -208,25 +209,23 @@ public function patch(EntityInterface $original_entity, EntityInterface $entity foreach ($entity->_restSubmittedFields as $field_name) { $field = $entity->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)) { - // 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; - } + // 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. + if (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'."); } + + // Don't allow changing the value of read-only fields. + if ($entity instanceof ContentEntityInterface + && $field->getItemDefinition()->isReadOnly() + && $original_entity->get($field_name)->getValue() !== $entity->get($field_name)->getValue()) { + throw new BadRequestHttpException("The field '$field_name' is read-only."); + } + $original_entity->set($field_name, $field->getValue()); } diff --git a/core/modules/rest/src/Tests/UpdateTest.php b/core/modules/rest/src/Tests/UpdateTest.php index 287c2df..1ed57c9 100644 --- a/core/modules/rest/src/Tests/UpdateTest.php +++ b/core/modules/rest/src/Tests/UpdateTest.php @@ -288,10 +288,13 @@ public function testUpdateComment() { $entity_values['uid'] = $account->id(); $comment = Comment::create($entity_values); $comment->save(); + $comment_id = $comment->id(); $this->pass('Test case 1: PATCH comment using HAL+JSON.'); $comment->setSubject('Initial subject')->save(); $read_only_fields = [ + 'cid', + 'uuid', 'status', 'name', 'created', @@ -305,13 +308,15 @@ public function testUpdateComment() { $this->assertNotEqual('Updated subject', $comment->getSubject()); $comment->setSubject('Updated subject'); $this->patchEntity($comment, $read_only_fields, $account, 'hal_json', 'application/hal+json'); - $comment = Comment::load($comment->id()); + $comment = Comment::load($comment_id); $this->assertEqual('Updated subject', $comment->getSubject()); $this->pass('Test case 1: PATCH comment using JSON.'); $comment->setSubject('Initial subject')->save(); $read_only_fields = [ - 'status', + 'cid', + 'uuid', + 'comment_type', 'pid', // Extra compared to HAL+JSON. 'entity_id', 'uid',