arch-8.x-1.x-dev/modules/product/modules/downloadable/src/Controller/ProductDownloadController.php

modules/product/modules/downloadable/src/Controller/ProductDownloadController.php
<?php

namespace Drupal\arch_downloadable_product\Controller;

use Drupal\arch_downloadable_product\ProductFileAccessInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Product download controller.
 *
 * @package Drupal\arch_downloadable_product\Controller
 */
class ProductDownloadController extends ControllerBase {

  /**
   * Product file access.
   *
   * @var \Drupal\arch_downloadable_product\ProductFileAccessInterface
   */
  protected $productFileAccess;

  /**
   * Product storage.
   *
   * @var \Drupal\arch_product\Entity\Storage\ProductStorageInterface
   */
  protected $productStorage;

  /**
   * File storage.
   *
   * @var \Drupal\file\FileStorageInterface
   */
  protected $fileStorage;

  /**
   * Current request.
   *
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $currentRequest;

  /**
   * ProductDownloadController constructor.
   *
   * @param \Drupal\arch_downloadable_product\ProductFileAccessInterface $product_file_access
   *   Product file access.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   Entity type manager.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   Request stack.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   Current user.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function __construct(
    ProductFileAccessInterface $product_file_access,
    EntityTypeManagerInterface $entity_type_manager,
    RequestStack $request_stack,
    AccountInterface $current_user,
  ) {
    $this->productFileAccess = $product_file_access;
    $this->productStorage = $entity_type_manager->getStorage('product');
    $this->fileStorage = $entity_type_manager->getStorage('file');
    $this->currentUser = $entity_type_manager->getStorage('user')->load($current_user->id());

    $this->currentRequest = $request_stack->getCurrentRequest();
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('downloadable_product.access'),
      $container->get('entity_type.manager'),
      $container->get('request_stack'),
      $container->get('current_user')
    );
  }

  /**
   * Access callback.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   Account.
   * @param int $product_id
   *   Product ID.
   * @param string $file_uuid
   *   File UUID.
   * @param string $user_uuid
   *   User UUID.
   *
   * @return \Drupal\Core\Access\AccessResultAllowed|\Drupal\Core\Access\AccessResultForbidden
   *   Access check result.
   */
  public function downloadAccess(AccountInterface $account, $product_id, $file_uuid, $user_uuid) {
    if (
      $account->isAnonymous()
      || $user_uuid !== $this->currentUser->uuid()
    ) {
      return AccessResult::forbidden();
    }

    $request_token = $this->currentRequest->query->get('pdtok');
    if (!$this->productFileAccess->checkByIdsWithToken($product_id, $file_uuid, $user_uuid, $request_token)) {
      return AccessResult::forbidden();
    }

    return AccessResult::allowed();
  }

  /**
   * Handles private file transfers.
   *
   * Call modules that implement hook_file_download() to find out if a file is
   * accessible and what headers it should be transferred with. If one or more
   * modules returned headers the download will start with the returned headers.
   * If a module returns -1 an AccessDeniedHttpException will be thrown. If the
   * file exists but no modules responded an AccessDeniedHttpException will be
   * thrown. If the file does not exist a NotFoundHttpException will be thrown.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request object.
   * @param int $product_id
   *   Product ID.
   * @param string $file_uuid
   *   File UUID.
   * @param string $user_uuid
   *   User UUID.
   *
   * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
   *   The transferred file as response.
   *
   * @see hook_file_download()
   *
   * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
   *   Thrown when the requested file does not exist.
   * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
   *   Thrown when the user does not have access to the file.
   */
  public function download(Request $request, $product_id, $file_uuid, $user_uuid) {
    $file = $this->loadFileByUuid($file_uuid);
    if (!$file) {
      throw new NotFoundHttpException();
    }

    $uri = $file->getFileUri();
    if (!file_exists($uri)) {
      throw new NotFoundHttpException();
    }

    $hooks = [
      'product_file_download',
      'file_download',
    ];

    $headers = [];
    foreach ($hooks as $hook) {
      // Let other modules provide headers and controls access to the file.
      $headers = $this->moduleHandler()->invokeAll($hook, [$uri]);
      foreach ($headers as $result) {
        if ($result == -1) {
          throw new AccessDeniedHttpException();
        }
        $headers[] = $result;
      }
    }

    if (count($headers)) {
      // \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond()
      // sets response as not cacheable if the Cache-Control header is not
      // already modified. We pass in FALSE for non-private schemes for the
      // $public parameter to make sure we don't change the headers.
      return new BinaryFileResponse($uri, 200, $headers, FALSE);
    }

    throw new AccessDeniedHttpException();
  }

  /**
   * Load file by UUID.
   *
   * @param string $file_uuid
   *   File UUID.
   *
   * @return \Drupal\file\FileInterface|null
   *   File instance or NULL on failure.
   */
  protected function loadFileByUuid($file_uuid) {
    /** @var \Drupal\file\FileInterface[] $files */
    $files = $this->fileStorage->loadByProperties([
      'uuid' => $file_uuid,
    ]);
    if (empty($files)) {
      return NULL;
    }

    return current($files);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc