marketo_ma-8.x-2.x-dev/src/PageAttachment.php

src/PageAttachment.php
<?php

namespace Drupal\marketo_ma;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\marketo_ma\Service\MarketoMaMunchkinInterface;
use Drupal\marketo_ma\Service\MarketoMaServiceInterface;
use Drupal\path_alias\AliasManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Page attachment service to attach munchkin tracking and related actions.
 */
class PageAttachment {

  /**
   * Configuration service.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * Current user account.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

  /**
   * Route matching service.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface
   */
  protected $routeMatch;

  /**
   * Path matching service.
   *
   * @var \Drupal\Core\Path\PathMatcherInterface
   */
  protected $pathMatcher;

  /**
   * Munchkin service.
   *
   * @var \Drupal\marketo_ma\Service\MarketoMaMunchkinInterface
   */
  protected $munchkin;

  /**
   * Temporary storage service.
   *
   * @var \Drupal\Core\TempStore\PrivateTempStoreFactory
   */
  protected $tempStoreFactory;

  /**
   * Optional path alias manager for resolving aliases.
   *
   * @var \Drupal\path_alias\AliasManagerInterface|null
   */
  protected $pathAliasManager;

  /**
   * Current path.
   *
   * @var \Drupal\Core\Path\CurrentPathStack
   */
  protected $currentPath;

  /**
   * Request stack service.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * Calculated page match to avoid re-calculation.
   *
   * @var bool|null
   */
  private $pageMatchCache;

  /**
   * Marketo settings.
   *
   * @var \Drupal\Core\Config\ImmutableConfig|null
   */
  private $config;

  /**
   * Creates the Marketo MA core service..
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   The current user.
   * @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
   *   The path matcher service.
   * @param \Drupal\marketo_ma\Service\MarketoMaMunchkinInterface $munchkin
   *   The munchkin service.
   * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
   *   Temporary storage service for holding lead data until delivery.
   * @param \Drupal\Core\Path\CurrentPathStack $currentPath
   *   The current path.
   * @param \Symfony\Component\HttpFoundation\RequestStack|null $requestStack
   *   Request stack service.
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    AccountInterface $current_user,
    PathMatcherInterface $path_matcher,
    MarketoMaMunchkinInterface $munchkin,
    PrivateTempStoreFactory $temp_store_factory,
    CurrentPathStack $currentPath,
    RequestStack $requestStack = NULL
  ) {
    $this->configFactory = $config_factory;
    $this->currentUser = $current_user;
    $this->pathMatcher = $path_matcher;
    $this->munchkin = $munchkin;
    $this->tempStoreFactory = $temp_store_factory;
    $this->currentPath = $currentPath;
    $this->requestStack = $requestStack;
  }

  /**
   * Set the alias manager is path_alias is installed.
   *
   * @param \Drupal\path_alias\AliasManagerInterface $aliasManager
   *   The path alias manager services.
   */
  public function setAliasManager(AliasManagerInterface $aliasManager) {
    $this->pathAliasManager = $aliasManager;
  }

  /**
   * The current tracking method.
   *
   * \Drupal\marketo_ma\Service\MarketoMaMunchkinInterface::MARKETO_TRACKING_*
   *
   * @return string
   *   On of the defined tracking methods.
   */
  private function trackingMethod() {
    return $this->config()->get('tracking_method');
  }

  /**
   * Helper for loading marketo settings out of config.
   *
   * @return \Drupal\Core\Config\ImmutableConfig
   *   The current marketo settings.
   */
  private function config() {
    // Load config if not already loaded.
    if (!isset($this->config)) {
      $this->config = $this->configFactory->get(MarketoMaServiceInterface::MARKETO_MA_CONFIG_NAME);
    }
    return $this->config;
  }

  /**
   * Handles `hook_page_attachments` for the marketo_ma module.
   */
  public function pageAttachments(&$page) {
    // Check whether we should track via the Munchkin.
    if ($this->shouldTrackCurrentRequest()) {
      // Add marketo ma to the page..
      if (!empty($this->munchkin->getAccountId())) {
        // Add the library and settings for tracking the page.
        $page['#attached']['library'][] = 'marketo_ma/marketo-ma';
        $page['#attached']['drupalSettings']['marketo_ma'] = [
          'track' => TRUE,
          'key' => $this->munchkin->getAccountId(),
          'initParams' => $this->munchkin->getInitParams(),
          'library' => $this->munchkin->getLibrary(),
        ];
      }

      // Get the Lead data from temporary user storage.
      $lead = $this->getUserData();

      // Check for the munchkin option and that the munchkin api is configured.
      if ($lead
        && $this->trackingMethod() == MarketoMaServiceInterface::TRACKING_METHOD_MUNCHKIN
        && $this->munchkin->isConfigured()
        && !empty($lead->getEmail())
      ) {
        // Set drupalSettings so JS will do the lead association.
        $page['#attached']['drupalSettings']['marketo_ma']['actions'][] = $this->munchkin->getAction(
          MarketoMaMunchkinInterface::ACTION_ASSOCIATE_LEAD,
          $lead
        );
        // Set the associated flag so we are not associating on every request.
        $this->resetUserData();
      }
    }
  }

  /**
   * Checks if the request should be tracked.
   */
  public function shouldTrackCurrentRequest() {
    return $this->checkPageVisibility() && $this->checkRoleVisibility($this->currentUser);
  }

  /**
   * Sets temporary user data for this session.
   *
   * @param \Drupal\marketo_ma\Lead $lead
   *   The marketo lead.
   *
   * @return $this
   *   The current object for chaining.
   */
  public function setUserData(Lead $lead) {
    // Make sure we have a real user before trying to access user data.
    if ($this->sessionAvailable()) {
      $this->temporaryStorage()->set('user_data', $lead);
    }
    return $this;
  }

  /**
   * Gets temporary user data for the current session.
   *
   * @return \Drupal\marketo_ma\Lead|null
   *   The temporary user data.
   */
  public function getUserData() {
    return $this->temporaryStorage()->get('user_data');
  }

  /**
   * Resets (deletes) the temporary user data for the current session.
   *
   * @return $this
   *   The current object for chaining.
   */
  public function resetUserData() {
    // Make sure we have a real user before trying to access user data.
    if ($this->sessionAvailable()) {
      $this->temporaryStorage()->delete('user_data');
    }
    return $this;
  }

  /**
   * Determines whether the current session contains any temporary user data.
   *
   * @return bool
   *   If there is lead data to be delivered.
   */
  public function hasUserData() {
    return !empty($this->getUserData());
  }

  /**
   * Check whether user data is available for the current user.
   *
   * @return bool
   *   If there is a session available.
   */
  protected function sessionAvailable() {
    return ($this->currentUser->id() || $this->requestStack->getCurrentRequest()->hasSession());
  }

  /**
   * Gets the private temporary storage for the marketo_ma module.
   *
   * @return \Drupal\Core\TempStore\PrivateTempStore
   *   Temporary storage for holding lead data until its able to be delivered.
   */
  protected function temporaryStorage() {
    return $this->tempStoreFactory->get('marketo_ma');
  }

  /**
   * Tracking visibility check for pages.
   *
   * Based on visibility setting this function returns TRUE if JS code should
   * be added to the current page and otherwise FALSE.
   *
   * @todo it would be nice if this used condition plugins.
   * @see \Drupal\block\BlockAccessControlHandler
   *
   * @return bool
   *   True if the page should be tracked by visibility rules.
   */
  protected function checkPageVisibility() {
    // Cache visibility result if function is called more than once.
    if (!isset($this->pageMatchCache)) {
      $config = $this->config();
      $visibility_request_path_mode = $config->get('tracking.request_path.mode');
      $visibility_request_path_pages = $config->get('tracking.request_path.pages');

      // Match path if necessary.
      if (!empty($visibility_request_path_pages)) {
        if ($visibility_request_path_mode < 2) {
          // Convert path to lowercase. This allows comparison of the same path
          // with different case. Ex: /Page, /page, /PAGE.
          $pages = mb_strtolower($visibility_request_path_pages);
          // Compare the lowercase path alias (if any) and internal path.
          $path_alias = $path = $this->currentPath->getPath();
          if (isset($this->pathAliasManager)) {
            $path_alias = mb_strtolower($this->pathAliasManager->getAliasByPath($path));
          }
          $match = $this->pathMatcher->matchPath(
              $path_alias,
              $pages
            ) || (($path != $path_alias) && $this->pathMatcher->matchPath($path, $pages));
          // When $visibility_request_path_mode has a value of 0, the tracking
          // code is displayed on all pages except those listed in $pages. When
          // set to 1, it is displayed only on those pages listed in $pages.
          $this->pageMatchCache = !($visibility_request_path_mode xor $match);
        }
        else {
          $this->pageMatchCache = FALSE;
        }
      }
      else {
        $this->pageMatchCache = TRUE;
      }
    }
    return $this->pageMatchCache;
  }

  /**
   * Tracking visibility check for user roles.
   *
   * Based on visibility setting this function returns TRUE if JS code should
   * be added for the current role and otherwise FALSE.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   A user object containing an array of roles to check.
   *
   * @return bool
   *   TRUE if JS code should be added for the current role and otherwise FALSE.
   */
  protected function checkRoleVisibility(AccountInterface $account) {
    $enabled = $visibility_user_role_mode = $this->config()->get('tracking.user_role.mode');
    $visibility_user_role_roles = $this->config()->get('tracking.user_role.roles');

    if (count($visibility_user_role_roles) > 0) {
      // One or more roles are selected.
      foreach (array_values($account->getRoles()) as $user_role) {
        // Is the current user a member of one of these roles?
        if (in_array($user_role, $visibility_user_role_roles)) {
          // Current user is a member of a role that should be tracked/excluded
          // from tracking.
          $enabled = !$visibility_user_role_mode;
          break;
        }
      }
    }
    else {
      // No role is selected, therefore all roles should be tracked.
      $enabled = TRUE;
    }

    return $enabled;
  }

}

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

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