hn-8.x-1.x-dev/modules/hn_cache_session/src/EventSubscriber/EventSubscriber.php

modules/hn_cache_session/src/EventSubscriber/EventSubscriber.php
<?php

namespace Drupal\hn_cache_session\EventSubscriber;

use Drupal\Component\Uuid\UuidInterface;
use Drupal\hn\Event\HnResponseEvent;
use Drupal\user\SharedTempStoreFactory;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Class DefaultSubscriber.
 */
class EventSubscriber implements EventSubscriberInterface {

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {

    return [
      HnResponseEvent::PRE_SEND => 'alterResponseData',
    ];

  }

  const DONT_CACHE_KEYS = ['__hn'];

  /**
   * The storage that will be used to get and set data to.
   *
   * @var \Drupal\user\SharedTempStore
   */
  private $session;

  /**
   * The session factory that is used to get and set previous requests.
   *
   * @var \Drupal\user\SharedTempStoreFactory
   */
  private $sessionFactory;

  /**
   * The UUID Generator.
   *
   * @var \Drupal\Component\Uuid\UuidInterface
   */
  private $uuid;

  /**
   * Creates a new EventSubscriber.
   */
  public function __construct(SharedTempStoreFactory $sharedTempStoreFactory, UuidInterface $uuid) {
    $this->uuid = $uuid;
    $this->sessionFactory = $sharedTempStoreFactory;
  }

  /**
   * Alters the response data.
   *
   * @param \Drupal\hn\Event\HnResponseEvent $event
   *   The event that was dispatched.
   */
  public function alterResponseData(HnResponseEvent $event) {

    // Get or generate a user ID, where all requests are stored.
    // We don't use the PHP session because of issue #2743931 and so it is
    // easier to pass the user id when pre-rendering on the server.
    $user = \Drupal::request()->query->get('_hn_user') ?: $this->uuid->generate();
    $this->session = $this->sessionFactory->get('hn_cache_session.' . $user, $user);

    $responseData = $event->getResponseData();

    // First, parse the ?_hn_verify and transfer requests from unverified to
    // verified.
    $this->verifyRequests();

    // Remove all fields from requests that are already verified.
    $verifiedRequests = $this->getVerifiedRequests();
    foreach ($verifiedRequests as $data_key => $data_fields) {
      if (!empty($responseData['data'][$data_key])) {
        foreach ($data_fields as $field) {
          unset($responseData['data'][$data_key][$field]);
        }
        // Remove the data key if all properties are removed.
        // See issue #2918729.
        if (empty($responseData['data'][$data_key])) {
          unset($responseData['data'][$data_key]);
        }
      }
    }

    // Save the current request to the session for all next requests.
    $token = $this->saveCurrentRequest($responseData);

    // Add the user and token to the response so the client can send them with
    // their next request.
    $responseData['__hn']['request']['user'] = $user;
    $responseData['__hn']['request']['token'] = $token;

    $event->setResponseData($responseData);

  }

  /**
   * Verify all requests that are passed by the user.
   *
   * All requests are saved. To make sure the user has actually received the
   * request, it must sent all non-verified request tokens with the next
   * request. This way the tokens will be verified, and the entities that
   * were in that request aren't sent again.
   */
  private function verifyRequests() {

    // Get all the verifies provided by the user. The keys are the tokens.
    $verify = \Drupal::request()->query->get('_hn_verify');

    // Verify should be an array or string. If it isn't, don't verify anything.
    if (empty($verify) || !is_array($verify)) {
      if (is_string($verify)) {
        $verify = [$verify];
      }
      else {
        return;
      }
    }

    $verify = array_flip($verify);

    // Get all stored requests that aren't verified.
    $unverifiedRequests = $this->getUnverifiedRequests();

    // Intersect both arrays to get all requests that can be verified.
    $requestsToVerify = array_intersect_key($unverifiedRequests, $verify);

    // Only continue if there are requests to verify.
    if (empty($requestsToVerify)) {
      return;
    }

    $this->setUnverifiedRequests(array_diff_key($unverifiedRequests, $requestsToVerify));

    $verifiedRequests = $this->getVerifiedRequests();

    foreach ($requestsToVerify as $request) {
      foreach ($request as $data_key => $data) {
        if (!isset($verifiedRequests[$data_key])) {
          $verifiedRequests[$data_key] = [];
        }
        $verifiedRequests[$data_key] = array_merge($data, $verifiedRequests[$data_key] ?: []);
      }
    }

    $this->setVerifiedRequests($verifiedRequests);
  }

  /**
   * Saves the current request to the session, and returns the token.
   *
   * @param $responseData
   *
   * @return mixed
   */
  private function saveCurrentRequest($responseData) {

    /** @var \Drupal\Component\Uuid\UuidInterface $uuidService */
    $uuidService = \Drupal::service('uuid');
    $uuid = $uuidService->generate();

    $unverifiedRequest = [];
    foreach ($responseData['data'] as $key => $data) {
      $unverifiedRequest[$key] = array_values(array_diff(array_keys($data), self::DONT_CACHE_KEYS));
    }

    $this->setUnverifiedRequests($this->getUnverifiedRequests() + [$uuid => $unverifiedRequest]);

    return $uuid;
  }

  /**
   *
   */
  private function getUnverifiedRequests() {
    return $this->session->get('requests.unverified') ?: [];
  }

  /**
   *
   */
  private function setUnverifiedRequests(array $requests) {
    $this->session->set('requests.unverified', $requests);
  }

  /**
   *
   */
  private function getVerifiedRequests() {
    return $this->session->get('requests.verified') ?: [];
  }

  /**
   *
   */
  private function setVerifiedRequests(array $requests) {
    $this->session->set('requests.verified', $requests);
  }

}

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

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