toolshed-8.x-1.x-dev/modules/toolshed_media/src/Routing/MediaRedirectRequestSubscriber.php
modules/toolshed_media/src/Routing/MediaRedirectRequestSubscriber.php
<?php
namespace Drupal\toolshed_media\Routing;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\toolshed_media\Utility\FileHelper;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Exception\InvalidParameterException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
/**
* Event subscriber handler which redirects Media requests to file.
*
* By default the media entity canonical display page, points to fully rendered
* display page (entity display mode), but for most non-administrators, we
* tend want to redirect to the file directly.
*/
class MediaRedirectRequestSubscriber implements EventSubscriberInterface {
/**
* Route used to determine how the request needs to be handled.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected RouteMatchInterface $routeMatch;
/**
* The account to use when determining if the request should redirect.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected AccountInterface $account;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* Indicates if the media_entity_download module is available.
*
* This will provide an option to allow for using the media download to be
* used for the user redirect when configured. This has some benefits as
* it sets the header correctly for downloading, and provides other
* conveniences when loading media.
*
* @var bool
*/
protected bool $hasMediaDownload;
/**
* Generate a new MediaRedirectRequestSubscriber event listener.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The routing match interface to determine what route the request is
* acting on, and if it matches a media entity request.
* @param \Drupal\Core\Session\AccountInterface $account
* An account / session proxy representing the current user to evaluate
* the permissions and handling of the account retrieval.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
*/
public function __construct(RouteMatchInterface $route_match, AccountInterface $account, EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler) {
$this->routeMatch = $route_match;
$this->account = $account;
$this->entityTypeManager = $entity_type_manager;
$this->hasMediaDownload = $module_handler->moduleExists('media_entity_download');
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
return [
KernelEvents::REQUEST => 'onHandleRequest',
];
}
/**
* Respond to the Request, and redirect media pages if appropriate.
*
* Determine if the request is for the canonical media display page and
* decide if the page needs to get redirected to the media source file
* if the user access and media type settings call for it.
*
* @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
* The event information. This will contain the current kernel object and
* information about the request, since the event is responding to a
* KernelEvents::REQUEST event.
*/
public function onHandleRequest(RequestEvent $event): void {
// Ensure that the current route is for a media entity display, and
// get the media entity that is being requested.
$media = $this->routeMatch->getRouteName() === 'entity.media.canonical'
? $this->routeMatch->getParameter('media')
: NULL;
if ($media && !$media->access('update', $this->account)) {
/** @var \Drupal\media\MediaTypeInterface $mediaType */
$mediaType = $media->bundle->entity;
if (!$mediaType) {
return;
}
$settings = $mediaType->getThirdPartySettings('toolshed_media');
if (!empty($settings['redirect_to_file'])) {
if ($fileHelper = FileHelper::fromEntity($media)) {
$cacheMetadata = new CacheableMetadata();
try {
$dlRoute = 'media_entity_download.download';
$url = !$this->hasMediaDownload || empty($settings['use_download'])
? $fileHelper->buildRawUrl(FALSE)
: Url::fromRoute($dlRoute, ['media' => $media->id()])->toString($cacheMetadata);
}
catch (RouteNotFoundException | InvalidParameterException $e) {
$url = $fileHelper->buildRawUrl(FALSE);
}
$response = new TrustedRedirectResponse($url);
$cacheMetadata->addCacheableDependency($mediaType);
$cacheMetadata->addCacheableDependency($media);
$cacheMetadata->setCacheContexts(['user.permissions']);
$response->addCacheableDependency($cacheMetadata);
$event->setResponse($response);
}
else {
// Media referenced file is missing, return a 404.
throw new NotFoundHttpException();
}
}
}
}
}
