g2-8.x-1.x-dev/src/RefererTracker.php

src/RefererTracker.php
<?php

namespace Drupal\g2;

use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityInterface;
use Drupal\path_alias\AliasManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Tracks navigation to G2 entries anonymously.
 */
class RefererTracker {

  /**
   * The core database service.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected Connection $db;

  /**
   * The core path_alias.manager service.
   *
   * @var \Drupal\path_alias\AliasManagerInterface
   */
  protected AliasManagerInterface $pathAliasManager;

  /**
   * The core request_stack service.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected RequestStack $requestStack;

  /**
   * Service constructor.
   *
   * @param \Drupal\Core\Database\Connection $db
   *   The core database service.
   * @param \Drupal\path_alias\AliasManagerInterface $pathAliasManager
   *   The core path_alias.manager service.
   * @param \Symfony\Component\HttpFoundation\RequestStack $stack
   *   The core request_stack service.
   */
  public function __construct(
    Connection $db,
    AliasManagerInterface $pathAliasManager,
    RequestStack $stack,
  ) {
    $this->db = $db;
    $this->pathAliasManager = $pathAliasManager;
    $this->requestStack = $stack;
  }

  /**
   * Log a hit from a referrer.
   *
   * Note that this does not work on cached nodes, and will log hits from all
   * pages linking to a g2_entry, even if it is only from a block, not just
   * from
   * the main content.
   *
   * @param \Drupal\Core\Entity\EntityInterface $node
   *   The node being viewed.
   *
   * @throws \Exception
   *
   * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
   */
  public function upsertReferer(EntityInterface $node): void {
    $req = $this->requestStack->getCurrentRequest();
    if (empty($req)) {
      return;
    }
    $referer = $req->headers->get('referer');
    // Ignore both missing headers and Safari >= 13.1 empty Referer headers.
    if (empty($referer)) {
      return;
    }
    $base = $req->getSchemeAndHttpHost();

    // For now, we do not handle non-local referers, which have become less
    // available over time since IE8 introduced X-Frame-Options anyway.
    if (!str_starts_with($referer, "$base/")) {
      return;
    }

    // Extract local path, possibly aliased.
    $path = mb_substr($referer, mb_strlen($base));
    // Unalias it.
    $canonical = $this->pathAliasManager->getPathByAlias($path);
    // Sanitize it.
    $escaped = Html::escape($canonical);

    // We cannot use the Upsert() method because this table has a composite PK.
    $updated = $this->db->update(G2::TBL_REFERER)
      ->condition('nid', (string) $node->id())
      ->condition('referer', $escaped)
      ->expression('incoming', 'incoming+1')
      ->execute();
    if (!empty($updated)) {
      return;
    }
    // Update found no row to update: insert one.
    $this->db->insert(G2::TBL_REFERER)
      ->fields(['nid', 'referer', 'incoming'])
      ->values(['nid' => $node->id(), 'referer' => $escaped, 'incoming' => 1])
      ->execute();
  }

  /**
   * Erase the referer counts on g2 entries.
   *
   * @param int $nid
   *   Node from which to erase referers, or 0 to erase all g2 referers.
   */
  public function wipe(int $nid = 0): void {
    $tags = ["node_list:" . G2::BUNDLE];
    if (empty($nid)) {
      $this->db
        ->truncate(G2::TBL_REFERER)
        ->execute();
      Cache::invalidateTags($tags);
      return;
    }

    $tags[] = "node:$nid";
    $this->db
      ->delete(G2::TBL_REFERER)
      ->condition('nid', (string) $nid)
      ->execute();
    Cache::invalidateTags($tags);
  }

}

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

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