function EntityResource::addToRelationshipData

Same name and namespace in other branches
  1. 8.9.x core/modules/jsonapi/src/Controller/EntityResource.php \Drupal\jsonapi\Controller\EntityResource::addToRelationshipData()
  2. 10 core/modules/jsonapi/src/Controller/EntityResource.php \Drupal\jsonapi\Controller\EntityResource::addToRelationshipData()
  3. 11.x core/modules/jsonapi/src/Controller/EntityResource.php \Drupal\jsonapi\Controller\EntityResource::addToRelationshipData()

Adds a relationship to a to-many relationship.

Parameters

\Drupal\jsonapi\ResourceType\ResourceType $resource_type: The base JSON:API resource type for the request to be served.

\Drupal\Core\Entity\FieldableEntityInterface $entity: The requested entity.

string $related: The related field name.

\Symfony\Component\HttpFoundation\Request $request: The request object.

Return value

\Drupal\jsonapi\ResourceResponse The response.

Throws

\Drupal\jsonapi\Exception\EntityAccessDeniedHttpException Thrown when the current user is not allowed to PATCH the selected field(s).

\Symfony\Component\HttpKernel\Exception\ConflictHttpException Thrown when POSTing to a "to-one" relationship.

\Drupal\Core\Entity\EntityStorageException Thrown when the underlying entity cannot be saved.

\Drupal\jsonapi\Exception\UnprocessableHttpEntityException Thrown when the updated entity does not pass validation.

File

core/modules/jsonapi/src/Controller/EntityResource.php, line 622

Class

EntityResource
Process all entity requests.

Namespace

Drupal\jsonapi\Controller

Code

public function addToRelationshipData(ResourceType $resource_type, FieldableEntityInterface $entity, $related, Request $request) {
    $resource_identifiers = $this->deserialize($resource_type, $request, ResourceIdentifier::class, $related);
    $internal_relationship_field_name = $resource_type->getInternalName($related);
    // According to the specification, you are only allowed to POST to a
    // relationship if it is a to-many relationship.
    
    /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $field_list */
    $field_list = $entity->{$internal_relationship_field_name};
    
    /** @var \Drupal\field\Entity\FieldConfig $field_definition */
    $field_definition = $field_list->getFieldDefinition();
    $is_multiple = $field_definition->getFieldStorageDefinition()
        ->isMultiple();
    if (!$is_multiple) {
        throw new ConflictHttpException(sprintf('You can only POST to to-many relationships. %s is a to-one relationship.', $related));
    }
    $original_resource_identifiers = ResourceIdentifier::toResourceIdentifiersWithArityRequired($field_list);
    $new_resource_identifiers = array_udiff(ResourceIdentifier::deduplicate(array_merge($original_resource_identifiers, $resource_identifiers)), $original_resource_identifiers, [
        ResourceIdentifier::class,
        'compare',
    ]);
    // There are no relationships that need to be added so we can exit early.
    if (empty($new_resource_identifiers)) {
        $status = static::relationshipResponseRequiresBody($resource_identifiers, $original_resource_identifiers) ? 200 : 204;
        return $this->getRelationship($resource_type, $entity, $related, $request, $status);
    }
    $main_property_name = $field_definition->getItemDefinition()
        ->getMainPropertyName();
    foreach ($new_resource_identifiers as $new_resource_identifier) {
        $new_field_value = [
            $main_property_name => $this->getEntityFromResourceIdentifier($new_resource_identifier)
                ->id(),
        ];
        // Remove `arity` from the received extra properties, otherwise this
        // will fail field validation.
        $new_field_value += array_diff_key($new_resource_identifier->getMeta(), array_flip([
            ResourceIdentifier::ARITY_KEY,
        ]));
        $field_list->appendItem($new_field_value);
    }
    $this->validate($entity);
    $entity->save();
    $final_resource_identifiers = ResourceIdentifier::toResourceIdentifiersWithArityRequired($field_list);
    $status = static::relationshipResponseRequiresBody($resource_identifiers, $final_resource_identifiers) ? 200 : 204;
    return $this->getRelationship($resource_type, $entity, $related, $request, $status);
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.