jsonapi.services.yml | 6 ++- src/EventSubscriber/ResourceResponseSubscriber.php | 22 +++++++--- .../ResourceResponseSubscriberTest.php} | 48 +++++++++++----------- 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/jsonapi.services.yml b/jsonapi.services.yml index 60eb736..0b10a97 100644 --- a/jsonapi.services.yml +++ b/jsonapi.services.yml @@ -100,9 +100,13 @@ services: - { name: event_subscriber } arguments: ['@serializer', '%serializer.formats%'] + logger.channel.jsonapi: + parent: logger.channel_base + arguments: ['jsonapi'] + # Event subscribers. jsonapi.resource_response.subscriber: class: Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber tags: - { name: event_subscriber } - arguments: ['@serializer', '@renderer', '@current_route_match'] + arguments: ['@serializer', '@renderer', '@logger.channel.jsonapi'] diff --git a/src/EventSubscriber/ResourceResponseSubscriber.php b/src/EventSubscriber/ResourceResponseSubscriber.php index 651d4d8..b7d543d 100644 --- a/src/EventSubscriber/ResourceResponseSubscriber.php +++ b/src/EventSubscriber/ResourceResponseSubscriber.php @@ -2,8 +2,10 @@ namespace Drupal\jsonapi\EventSubscriber; +use Drupal\Component\Serialization\Json; use Drupal\Core\Cache\CacheableResponse; use Drupal\Core\Cache\CacheableResponseInterface; +use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\Core\Render\RenderContext; use Drupal\Core\Render\RendererInterface; use Drupal\jsonapi\ResourceResponse; @@ -48,16 +50,26 @@ class ResourceResponseSubscriber implements EventSubscriberInterface { protected $renderer; /** + * The JSON API logger channel. + * + * @var \Drupal\Core\Logger\LoggerChannelInterface + */ + protected $logger; + + /** * Constructs a ResourceResponseSubscriber object. * * @param \Symfony\Component\Serializer\SerializerInterface $serializer * The serializer. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer. + * @param \Drupal\Core\Logger\LoggerChannelInterface $logger + * The JSON API logger channel. */ - public function __construct(SerializerInterface $serializer, RendererInterface $renderer) { + public function __construct(SerializerInterface $serializer, RendererInterface $renderer, LoggerChannelInterface $logger) { $this->serializer = $serializer; $this->renderer = $renderer; + $this->logger = $logger; } /** @@ -162,7 +174,7 @@ class ResourceResponseSubscriber implements EventSubscriberInterface { * @return bool * FALSE if the response failed validation, otherwise TRUE. */ - protected static function validateResponse(Response $response) { + protected function validateResponse(Response $response) { if (!class_exists("\\JsonSchema\\Validator")) { return TRUE; } @@ -174,15 +186,15 @@ class ResourceResponseSubscriber implements EventSubscriberInterface { } $validator = new \JsonSchema\Validator; - $schema_path = DRUPAL_ROOT . '/' . drupal_get_path('module', 'jsonapi') . '/schema.json'; + $schema_path = dirname(dirname(__DIR__)) .'/schema.json'; $validator->check($response_data, (object)['$ref' => 'file://' . $schema_path]); if (!$validator->isValid()) { - \Drupal::logger('jsonapi')->debug('Response failed validation: @data', [ + $this->logger->debug('Response failed validation: @data', [ '@data' => Json::encode($response_data), ]); - \Drupal::logger('jsonapi')->debug('Validation errors: @errors', [ + $this->logger->debug('Validation errors: @errors', [ '@errors' => Json::encode($validator->getErrors()), ]); } diff --git a/tests/src/Kernel/Controller/RequestHandlerTest.php b/tests/src/Unit/EventSubscriber/ResourceResponseSubscriberTest.php similarity index 57% rename from tests/src/Kernel/Controller/RequestHandlerTest.php rename to tests/src/Unit/EventSubscriber/ResourceResponseSubscriberTest.php index fca04e3..fd372e0 100644 --- a/tests/src/Kernel/Controller/RequestHandlerTest.php +++ b/tests/src/Unit/EventSubscriber/ResourceResponseSubscriberTest.php @@ -1,38 +1,39 @@ prophesize(Serializer::class)->reveal(), + $this->prophesize(RendererInterface::class)->reveal(), + $this->prophesize(LoggerChannelInterface::class)->reveal() + ); - public function testResponseValidation() { // Check that the validation class is enabled. $this->assertTrue( class_exists("\\JsonSchema\\Validator"), 'The JSON Schema validator is not present. Please make sure to install it using composer.' ); - // Expose the protected RequestHandler::validateResponse() method. - $class = new \ReflectionClass('Drupal\jsonapi\Controller\RequestHandler'); - $validate_response = $class->getMethod('validateResponse'); + // Expose protected ResourceResponseSubscriber::validateResponse() method. + $object = new \ReflectionObject($resource_response_subscriber); + $validate_response = $object->getMethod('validateResponse'); $validate_response->setAccessible(TRUE); // Test validation failure: no "type" in "data". @@ -50,7 +51,7 @@ EOD; $response = new ResourceResponse(); $response->setContent($json); $this->assertFalse( - $validate_response->invoke(NULL, $response), + $validate_response->invoke($resource_response_subscriber, $response), 'Response validation failed to flag an invalid response.' ); @@ -71,7 +72,7 @@ EOD; $response = new ResourceResponse(); $response->setContent($json); $this->assertFalse( - $validate_response->invoke(NULL, $response), + $validate_response->invoke($resource_response_subscriber, $response), 'Response validation failed to flag an invalid response.' ); @@ -90,18 +91,17 @@ EOD; EOD; $response->setContent($json); $this->assertTrue( - $validate_response->invoke(NULL, $response), + $validate_response->invoke($resource_response_subscriber, $response), 'Response validation flagged a valid response.' ); // Test validation of an empty response passes. $response = new ResourceResponse(); $this->assertTrue( - $validate_response->invoke(NULL, $response), + $validate_response->invoke($resource_response_subscriber, $response), 'Response validation flagged a valid empty response.' ); } - }