Browse Source
* Add media headers * Add and fix up tests * Rebase and code review * Remove ?_format=jsonld from edit-media linkpull/756/head
Jared Whiklo
7 years ago
committed by
Natkeeran
8 changed files with 322 additions and 92 deletions
@ -0,0 +1,124 @@
|
||||
<?php |
||||
|
||||
namespace Drupal\islandora\EventSubscriber; |
||||
|
||||
use Drupal\Core\Entity\EntityFieldManager; |
||||
use Drupal\Core\Routing\RouteMatchInterface; |
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; |
||||
use Symfony\Component\HttpKernel\KernelEvents; |
||||
|
||||
/** |
||||
* Class LinkHeaderSubscriber. |
||||
* |
||||
* @package Drupal\islandora\EventSubscriber |
||||
*/ |
||||
abstract class LinkHeaderSubscriber implements EventSubscriberInterface { |
||||
|
||||
/** |
||||
* The entity field manager. |
||||
* |
||||
* @var \Drupal\Core\Entity\EntityFieldManager |
||||
*/ |
||||
protected $entityFieldManager; |
||||
|
||||
/** |
||||
* The route match object. |
||||
* |
||||
* @var \Drupal\Core\Routing\RouteMatchInterface |
||||
*/ |
||||
protected $routeMatch; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* |
||||
* @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager |
||||
* The entity field manager. |
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match |
||||
* The route match object. |
||||
*/ |
||||
public function __construct( |
||||
EntityFieldManager $entity_field_manager, |
||||
RouteMatchInterface $route_match |
||||
) { |
||||
$this->entityFieldManager = $entity_field_manager; |
||||
$this->routeMatch = $route_match; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public static function getSubscribedEvents() { |
||||
// Run this early so the headers get cached. |
||||
$events[KernelEvents::RESPONSE][] = ['onResponse', 129]; |
||||
|
||||
return $events; |
||||
} |
||||
|
||||
/** |
||||
* Get the Node | Media | File. |
||||
* |
||||
* @param \Symfony\Component\HttpFoundation\Response $response |
||||
* The current response object. |
||||
* @param string $object_type |
||||
* The type of entity to look for. |
||||
* |
||||
* @return Drupal\Core\Entity\ContentEntityBase|bool |
||||
* A node or media entity or FALSE if we should skip out. |
||||
*/ |
||||
protected function getObject(Response $response, $object_type) { |
||||
if ($object_type != 'node' |
||||
&& $object_type != 'media' |
||||
) { |
||||
return FALSE; |
||||
} |
||||
|
||||
// Exit early if the response is already cached. |
||||
if ($response->headers->get('X-Drupal-Dynamic-Cache') == 'HIT') { |
||||
return FALSE; |
||||
} |
||||
|
||||
if (!$response->isOk()) { |
||||
return FALSE; |
||||
} |
||||
|
||||
// Hack the node out of the route. |
||||
$route_object = $this->routeMatch->getRouteObject(); |
||||
if (!$route_object) { |
||||
return FALSE; |
||||
} |
||||
|
||||
$methods = $route_object->getMethods(); |
||||
$is_get = in_array('GET', $methods); |
||||
$is_head = in_array('HEAD', $methods); |
||||
if (!($is_get || $is_head)) { |
||||
return FALSE; |
||||
} |
||||
|
||||
$route_contexts = $route_object->getOption('parameters'); |
||||
if (!$route_contexts) { |
||||
return FALSE; |
||||
} |
||||
if (!isset($route_contexts[$object_type])) { |
||||
return FALSE; |
||||
} |
||||
|
||||
$object = $this->routeMatch->getParameter($object_type); |
||||
|
||||
if (!$object) { |
||||
return FALSE; |
||||
} |
||||
|
||||
return $object; |
||||
} |
||||
|
||||
/** |
||||
* Adds resource-specific link headers to appropriate responses. |
||||
* |
||||
* @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event |
||||
* Event containing the response. |
||||
*/ |
||||
abstract public function onResponse(FilterResponseEvent $event); |
||||
|
||||
} |
@ -0,0 +1,96 @@
|
||||
<?php |
||||
|
||||
namespace Drupal\islandora\EventSubscriber; |
||||
|
||||
use Drupal\Core\Entity\EntityFieldManager; |
||||
use Drupal\Core\Entity\EntityTypeManagerInterface; |
||||
use Drupal\Core\Entity\FieldableEntityInterface; |
||||
use Drupal\Core\Routing\RouteMatchInterface; |
||||
use Drupal\Core\Url; |
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; |
||||
|
||||
/** |
||||
* Class MediaLinkHeaderSubscriber. |
||||
* |
||||
* @package Drupal\islandora\EventSubscriber |
||||
*/ |
||||
class MediaLinkHeaderSubscriber extends LinkHeaderSubscriber implements EventSubscriberInterface { |
||||
|
||||
/** |
||||
* Media storage interface. |
||||
* |
||||
* @var \Drupal\Core\Entity\EntityStorageInterface |
||||
*/ |
||||
protected $mediaBundleStorage; |
||||
|
||||
/** |
||||
* MediaLinkHeaderSubscriber constructor. |
||||
* |
||||
* @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager |
||||
* The entity field manager. |
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match |
||||
* The route match object. |
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager |
||||
* The entity type manager. |
||||
*/ |
||||
public function __construct( |
||||
EntityFieldManager $entity_field_manager, |
||||
RouteMatchInterface $route_match, |
||||
EntityTypeManagerInterface $entity_type_manager) { |
||||
$this->mediaBundleStorage = $entity_type_manager->getStorage('media_bundle'); |
||||
parent::__construct($entity_field_manager, $route_match); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function onResponse(FilterResponseEvent $event) { |
||||
$response = $event->getResponse(); |
||||
|
||||
$entity = $this->getObject($response, 'media'); |
||||
|
||||
if ($entity === FALSE) { |
||||
return; |
||||
} |
||||
|
||||
$media_bundle = $this->mediaBundleStorage->load($entity->bundle()); |
||||
|
||||
$type_configuration = $media_bundle->getTypeConfiguration(); |
||||
|
||||
if (!isset($type_configuration['source_field'])) { |
||||
return; |
||||
} |
||||
$source_field = $type_configuration['source_field']; |
||||
|
||||
if (empty($source_field) || |
||||
!$entity instanceof FieldableEntityInterface || |
||||
!$entity->hasField($source_field) |
||||
) { |
||||
return; |
||||
} |
||||
|
||||
// Collect file links for the media. |
||||
$links = []; |
||||
foreach ($entity->get($source_field)->referencedEntities() as $referencedEntity) { |
||||
if ($entity->access('view')) { |
||||
$file_url = $referencedEntity->url('canonical', ['absolute' => TRUE]); |
||||
$edit_media_url = Url::fromRoute('islandora.media_source_update', ['media' => $referencedEntity->id()]) |
||||
->setAbsolute() |
||||
->toString(); |
||||
$links[] = "<$file_url>; rel=\"describes\"; type=\"{$referencedEntity->getMimeType()}\""; |
||||
$links[] = "<$edit_media_url>; rel=\"edit-media\""; |
||||
} |
||||
} |
||||
|
||||
// Exit early if there aren't any. |
||||
if (empty($links)) { |
||||
return; |
||||
} |
||||
|
||||
// Add the link headers to the response. |
||||
$response->headers->set('Link', $links, FALSE); |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,38 @@
|
||||
<?php |
||||
|
||||
namespace Drupal\Tests\islandora\Functional; |
||||
|
||||
/** |
||||
* Tests the MediaLinkHeader event subscriber. |
||||
* |
||||
* @group islandora |
||||
*/ |
||||
class MediaLinkHeaderTest extends IslandoraFunctionalTestBase { |
||||
|
||||
/** |
||||
* @covers \Drupal\islandora\EventSubscriber\MediaLinkHeaderSubscriber |
||||
*/ |
||||
public function testMediaLinkHeaders() { |
||||
// Create a test user. |
||||
$account = $this->drupalCreateUser([ |
||||
'view media', |
||||
'create media', |
||||
'update media', |
||||
]); |
||||
$this->drupalLogin($account); |
||||
|
||||
$urls = $this->createThumbnailWithFile(); |
||||
|
||||
$this->drupalGet($urls['media'], [], ['Cache-Control: no-cache']); |
||||
|
||||
$this->assertTrue( |
||||
$this->validateLinkHeaderWithUrl('describes', $urls['file']['file'], '', 'image/png') == 1, |
||||
"Malformed 'describes' link header" |
||||
); |
||||
$this->assertTrue( |
||||
$this->validateLinkHeaderWithUrl('edit-media', $urls['file']['rest'], '', '') == 1, |
||||
"Malformed 'edit-media' link header" |
||||
); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue