protected function ResourceTestBase::doTestRelationshipMutation in Drupal 10
Same name and namespace in other branches
- 8 core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php \Drupal\Tests\jsonapi\Functional\ResourceTestBase::doTestRelationshipMutation()
- 9 core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php \Drupal\Tests\jsonapi\Functional\ResourceTestBase::doTestRelationshipMutation()
Performs one round of relationship POST, PATCH and DELETE route testing.
Parameters
array $request_options: Request options to apply.
See also
\GuzzleHttp\ClientInterface::request()
::testRelationships
File
- core/
modules/ jsonapi/ tests/ src/ Functional/ ResourceTestBase.php, line 1439
Class
- ResourceTestBase
- Subclass this for every JSON:API resource type.
Namespace
Drupal\Tests\jsonapi\FunctionalCode
protected function doTestRelationshipMutation(array $request_options) {
/** @var \Drupal\Core\Entity\FieldableEntityInterface $resource */
$resource = $this
->createAnotherEntity('dupe');
$resource
->set('field_jsonapi_test_entity_ref', NULL);
$violations = $resource
->validate();
assert($violations
->count() === 0, (string) $violations);
$resource
->save();
$target_resource = $this
->createUser();
$violations = $target_resource
->validate();
assert($violations
->count() === 0, (string) $violations);
$target_resource
->save();
$target_identifier = static::toResourceIdentifier($target_resource);
$resource_identifier = static::toResourceIdentifier($resource);
$relationship_field_name = 'field_jsonapi_test_entity_ref';
/** @var \Drupal\Core\Access\AccessResultReasonInterface $update_access */
$update_access = static::entityAccess($resource, 'update', $this->account)
->andIf(static::entityFieldAccess($resource, $relationship_field_name, 'edit', $this->account));
$url = Url::fromRoute(sprintf("jsonapi.{$resource_identifier['type']}.{$relationship_field_name}.relationship.patch"), [
'entity' => $resource
->uuid(),
]);
// Test POST: missing content-type.
$response = $this
->request('POST', $url, $request_options);
$this
->assertSame(415, $response
->getStatusCode());
// Set the JSON:API media type header for all subsequent requests.
$request_options[RequestOptions::HEADERS]['Content-Type'] = 'application/vnd.api+json';
if ($update_access
->isAllowed()) {
// Test POST: empty body.
$response = $this
->request('POST', $url, $request_options);
$this
->assertResourceErrorResponse(400, 'Empty request body.', $url, $response, FALSE);
// Test PATCH: empty body.
$response = $this
->request('PATCH', $url, $request_options);
$this
->assertResourceErrorResponse(400, 'Empty request body.', $url, $response, FALSE);
// Test POST: empty data.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [],
]);
$response = $this
->request('POST', $url, $request_options);
$this
->assertResourceResponse(204, NULL, $response);
// Test PATCH: empty data.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [],
]);
$response = $this
->request('PATCH', $url, $request_options);
$this
->assertResourceResponse(204, NULL, $response);
// Test POST: data as resource identifier, not array of identifiers.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => $target_identifier,
]);
$response = $this
->request('POST', $url, $request_options);
$this
->assertResourceErrorResponse(400, 'Invalid body payload for the relationship.', $url, $response, FALSE);
// Test PATCH: data as resource identifier, not array of identifiers.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => $target_identifier,
]);
$response = $this
->request('PATCH', $url, $request_options);
$this
->assertResourceErrorResponse(400, 'Invalid body payload for the relationship.', $url, $response, FALSE);
// Test POST: missing the 'type' field.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => array_intersect_key($target_identifier, [
'id' => 'id',
]),
]);
$response = $this
->request('POST', $url, $request_options);
$this
->assertResourceErrorResponse(400, 'Invalid body payload for the relationship.', $url, $response, FALSE);
// Test PATCH: missing the 'type' field.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => array_intersect_key($target_identifier, [
'id' => 'id',
]),
]);
$response = $this
->request('PATCH', $url, $request_options);
$this
->assertResourceErrorResponse(400, 'Invalid body payload for the relationship.', $url, $response, FALSE);
// If the base resource type is the same as that of the target's (as it
// will be for `user--user`), then the validity error will not be
// triggered, needlessly failing this assertion.
if (static::$resourceTypeName !== $target_identifier['type']) {
// Test POST: invalid target.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$resource_identifier,
],
]);
$response = $this
->request('POST', $url, $request_options);
$this
->assertResourceErrorResponse(400, sprintf('The provided type (%s) does not match the destination resource types (%s).', $resource_identifier['type'], $target_identifier['type']), $url, $response, FALSE);
// Test PATCH: invalid target.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$resource_identifier,
],
]);
$response = $this
->request('POST', $url, $request_options);
$this
->assertResourceErrorResponse(400, sprintf('The provided type (%s) does not match the destination resource types (%s).', $resource_identifier['type'], $target_identifier['type']), $url, $response, FALSE);
}
// Test POST: duplicate targets, no arity.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier,
$target_identifier,
],
]);
$response = $this
->request('POST', $url, $request_options);
$this
->assertResourceErrorResponse(400, 'Duplicate relationships are not permitted. Use `meta.arity` to distinguish resource identifiers with matching `type` and `id` values.', $url, $response, FALSE);
// Test PATCH: duplicate targets, no arity.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier,
$target_identifier,
],
]);
$response = $this
->request('PATCH', $url, $request_options);
$this
->assertResourceErrorResponse(400, 'Duplicate relationships are not permitted. Use `meta.arity` to distinguish resource identifiers with matching `type` and `id` values.', $url, $response, FALSE);
// Test POST: success.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier,
],
]);
$response = $this
->request('POST', $url, $request_options);
$this
->assertResourceResponse(204, NULL, $response);
// Test POST: success, relationship already exists, no arity.
$response = $this
->request('POST', $url, $request_options);
$this
->assertResourceResponse(204, NULL, $response);
// Test POST: success, relationship already exists, new arity.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier + [
'meta' => [
'arity' => 1,
],
],
],
]);
$response = $this
->request('POST', $url, $request_options);
$resource
->set($relationship_field_name, [
$target_resource,
$target_resource,
]);
$expected_document = $this
->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$expected_document['data'][0] += [
'meta' => [
'arity' => 0,
],
];
$expected_document['data'][1] += [
'meta' => [
'arity' => 1,
],
];
$this
->assertResourceResponse(200, $expected_document, $response);
// Test PATCH: success, new value is the same as given value.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier + [
'meta' => [
'arity' => 0,
],
],
$target_identifier + [
'meta' => [
'arity' => 1,
],
],
],
]);
$response = $this
->request('PATCH', $url, $request_options);
$this
->assertResourceResponse(204, NULL, $response);
// Test POST: success, relationship already exists, new arity.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier + [
'meta' => [
'arity' => 2,
],
],
],
]);
$response = $this
->request('POST', $url, $request_options);
$resource
->set($relationship_field_name, [
$target_resource,
$target_resource,
$target_resource,
]);
$expected_document = $this
->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$expected_document['data'][0] += [
'meta' => [
'arity' => 0,
],
];
$expected_document['data'][1] += [
'meta' => [
'arity' => 1,
],
];
$expected_document['data'][2] += [
'meta' => [
'arity' => 2,
],
];
// 200 with response body because the request did not include the
// existing relationship resource identifier object.
$this
->assertResourceResponse(200, $expected_document, $response);
// Test POST: success.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier + [
'meta' => [
'arity' => 0,
],
],
$target_identifier + [
'meta' => [
'arity' => 1,
],
],
],
]);
$response = $this
->request('POST', $url, $request_options);
// 200 with response body because the request did not include the
// resource identifier with arity 2.
$this
->assertResourceResponse(200, $expected_document, $response);
// Test PATCH: success.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier + [
'meta' => [
'arity' => 0,
],
],
$target_identifier + [
'meta' => [
'arity' => 1,
],
],
$target_identifier + [
'meta' => [
'arity' => 2,
],
],
],
]);
$response = $this
->request('PATCH', $url, $request_options);
// 204 no content. PATCH data matches existing data.
$this
->assertResourceResponse(204, NULL, $response);
// Test DELETE: three existing relationships, two removed.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier + [
'meta' => [
'arity' => 0,
],
],
$target_identifier + [
'meta' => [
'arity' => 2,
],
],
],
]);
$response = $this
->request('DELETE', $url, $request_options);
$this
->assertResourceResponse(204, NULL, $response);
// Subsequent GET should return only one resource identifier, with no
// arity.
$resource
->set($relationship_field_name, [
$target_resource,
]);
$expected_document = $this
->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$response = $this
->request('GET', $url, $request_options);
$this
->assertSameDocument($expected_document, Json::decode((string) $response
->getBody()));
// Test DELETE: one existing relationship, removed.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier,
],
]);
$response = $this
->request('DELETE', $url, $request_options);
$resource
->set($relationship_field_name, []);
$this
->assertResourceResponse(204, NULL, $response);
$expected_document = $this
->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$response = $this
->request('GET', $url, $request_options);
$this
->assertSameDocument($expected_document, Json::decode((string) $response
->getBody()));
// Test DELETE: no existing relationships, no op, success.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier,
],
]);
$response = $this
->request('DELETE', $url, $request_options);
$this
->assertResourceResponse(204, NULL, $response);
$expected_document = $this
->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$response = $this
->request('GET', $url, $request_options);
$this
->assertSameDocument($expected_document, Json::decode((string) $response
->getBody()));
// Test PATCH: success, new value is different than existing value.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier + [
'meta' => [
'arity' => 2,
],
],
$target_identifier + [
'meta' => [
'arity' => 3,
],
],
],
]);
$response = $this
->request('PATCH', $url, $request_options);
$resource
->set($relationship_field_name, [
$target_resource,
$target_resource,
]);
$expected_document = $this
->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$expected_document['data'][0] += [
'meta' => [
'arity' => 0,
],
];
$expected_document['data'][1] += [
'meta' => [
'arity' => 1,
],
];
// 200 with response body because arity values are computed; that means
// that the PATCH arity values 2 + 3 will become 0 + 1 if there are not
// already resource identifiers with those arity values.
$this
->assertResourceResponse(200, $expected_document, $response);
// Test DELETE: two existing relationships, both removed because no arity
// was specified.
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier,
],
]);
$response = $this
->request('DELETE', $url, $request_options);
$resource
->set($relationship_field_name, []);
$this
->assertResourceResponse(204, NULL, $response);
$resource
->set($relationship_field_name, []);
$expected_document = $this
->getExpectedGetRelationshipDocument($relationship_field_name, $resource);
$response = $this
->request('GET', $url, $request_options);
$this
->assertSameDocument($expected_document, Json::decode((string) $response
->getBody()));
}
else {
$request_options[RequestOptions::BODY] = Json::encode([
'data' => [
$target_identifier,
],
]);
$response = $this
->request('POST', $url, $request_options);
$message = 'The current user is not allowed to edit this relationship.';
$message .= ($reason = $update_access
->getReason()) ? ' ' . $reason : '';
$this
->assertResourceErrorResponse(403, $message, $url, $response, FALSE);
$response = $this
->request('PATCH', $url, $request_options);
$this
->assertResourceErrorResponse(403, $message, $url, $response, FALSE);
$response = $this
->request('DELETE', $url, $request_options);
$this
->assertResourceErrorResponse(403, $message, $url, $response, FALSE);
}
// Remove the test entities that were created.
$resource
->delete();
$target_resource
->delete();
}