acquia_vwo-1.0.x-dev/src/Service/Context/PageContext.php
src/Service/Context/PageContext.php
<?php
namespace Drupal\acquia_vwo\Service\Context;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Render\Markup;
use Drupal\node\NodeInterface;
use Symfony\Component\HttpFoundation\RequestStack;
// cspell:ignore data-cfasync
/**
* Page Context class.
*/
class PageContext implements CacheableDependencyInterface {
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageInterface
*/
protected $languageManager;
/**
* The entity repository service.
*
* @var \Drupal\Core\Entity\EntityRepositoryInterface
*/
protected $entityRepository;
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
private $configFactory;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Field mapping.
*
* @var array
*/
private $fieldMapping;
/**
* The current node.
*
* @var \Drupal\node\NodeInterface
*/
private $node;
/**
* The Visibility Context.
*
* @var \Drupal\acquia_vwo\Service\Context\VisibilityContext
*/
private $visibilityContext;
/**
* The Request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
private $requestStack;
/**
* Constructor for Acquia VWO class.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Entity type manager.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository service.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param \Drupal\acquia_vwo\Service\Context\VisibilityContext $visibility_context
* The visibility context service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module Handler Service.
*/
public function __construct(
ConfigFactoryInterface $config_factory,
EntityTypeManagerInterface $entity_type_manager,
EntityRepositoryInterface $entity_repository,
RequestStack $request_stack,
VisibilityContext $visibility_context,
LanguageManagerInterface $language_manager,
ModuleHandlerInterface $module_handler,
) {
$this->configFactory = $config_factory;
$this->entityRepository = $entity_repository;
$this->visibilityContext = $visibility_context;
$this->languageManager = $language_manager;
$this->moduleHandler = $module_handler;
$this->entityTypeManager = $entity_type_manager;
$this->requestStack = $request_stack;
}
/**
* Populates the script on the page.
*
* @param array $page
* The current page array.
*/
public function populate(&$page) {
$this->populateCacheContexts($page);
$this->populateCacheTags($page);
if (!$this->visibilityContext->shouldAttach()) {
return;
}
$this->populateHtmlHead($page['#attached']['html_head']);
}
/**
* Populate page's cache context.
*
* @param array $page
* The page that is to be populated.
*/
protected function populateCacheContexts(array &$page) {
$page['#cache']['contexts'] = Cache::mergeContexts($page['#cache']['contexts'], $this->getCacheContexts());
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return $this->getVwoConfigSettings()->getCacheContexts();
}
/**
* Populate page's cache tags.
*
* @param array $page
* The page that is to be populated.
*/
protected function populateCacheTags(array &$page) {
$page['#cache']['tags'] = Cache::mergeTags($page['#cache']['tags'] ?? [], $this->getCacheTags());
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
return $this->getVwoConfigSettings()->getCacheTags();
}
/**
* Populates the script on the page.
*
* @param array $htmlHead
* The head elements.
*/
protected function populateHtmlHead(&$htmlHead) {
$htmlHead[] = $this->getJavaScriptTagRenderArray();
}
/**
* Get the render array for a JavaScript tag.
*
* @return array
* The render array
*/
private function getJavaScriptTagRenderArray() {
// Load the VWO script.
$module_path = $this->moduleHandler->getModule('acquia_vwo')->getPath();
$vwo_script = file_get_contents("$module_path/js/vwo.min.js");
// Add VWO script.
$account_id = $this->getVwoConfigSettings()->get('id');
$timeout = $this->getVwoConfigSettings()->get('loading.timeout');
$script = "!acquiaVwoUserOptOut() && (window._vwo_code || (function () {
var account_id=$account_id,
version=2.1,
settings_tolerance=$timeout,
hide_element='body',
hide_element_style='opacity:0 !important;filter:alpha(opacity=0) !important;background:none !important',
$vwo_script)" . PHP_EOL;
// Add Acquia VWO script with field mapping.
$node_data = json_encode($this->getNodeData());
$script .= "window.VWO = window.VWO || [];
window.VWO.data = window.VWO.data || {};
window.VWO.data.acquia=$node_data" . PHP_EOL;
return [
[
'#tag' => 'script',
'#attributes' => [
'data-cfasync' => 'false',
'type' => 'text/javascript',
],
'#value' => Markup::create($script),
],
'acquia_vwo',
];
}
/**
* Helper to extract the node data for each of the field mappings.
*
* @return array
* The node data.
*/
private function getNodeData() {
$node_data = [];
$node = $this->getNode();
if (empty($node)) {
return $node_data;
}
// Get values for each item from the field mapping configuration.
foreach ($this->getFieldMapping() as $key => $field_name) {
if (empty($field_name) ||
!$node->hasField($field_name) ||
$node->get($field_name)->isEmpty()
) {
continue;
}
$term_ids = $node->get($field_name)->getValue();
$term_data = $this->getTermData($term_ids);
foreach ($term_data as $term_name) {
$node_data[$key][] = $term_name;
}
}
return [
'drupal' => [
'title' => $node->getTitle(),
'content_type' => $node->bundle(),
'taxonomy' => $node_data,
],
];
}
/**
* Getter for node.
*
* @return \Drupal\node\NodeInterface|null
* Returns the node or null.
*/
private function getNode() {
/** @var \Symfony\Component\HttpFoundation\Request $request */
$request = $this->requestStack->getCurrentRequest();
$node = $request->attributes->get('node');
if (!empty($node) && $node instanceof NodeInterface) {
$this->node = $node;
}
return $this->node ?? NULL;
}
/**
* Getter for field mapping.
*
* @return array
* The field mapping.
*/
private function getFieldMapping() {
return $this->getVwoConfigSettings()->get('field_mapping') ?? [];
}
/**
* Helper to get the term names from term ids.
*
* @param array $term_ids
* The term ids.
*
* @return array
* The term data.
*/
private function getTermData(array $term_ids) {
$term_data = [];
/** @var \Drupal\taxonomy\TermStorageInterface $taxonomy_storage */
$taxonomy_storage = $this->entityTypeManager->getStorage('taxonomy_term');
$terms = $taxonomy_storage->loadMultiple(array_column($term_ids, 'target_id'));
foreach ($terms as $term) {
$taxonomy_term_trans = $this->getTranslatedContent($term);
$term_data[] = $taxonomy_term_trans->getName();
}
return $term_data;
}
/**
* Helper to get translated version of the entity.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity.
*
* @return \Drupal\Core\Entity\EntityInterface|null
* The translated entity.
*/
private function getTranslatedContent(EntityInterface $entity) {
$lang_code = $this->getCurrentLangCode();
return $this->entityRepository->getTranslationFromContext($entity, $lang_code);
}
/**
* Helper to get the current lang code.
*
* @return string
* The lang code.
*/
private function getCurrentLangCode() {
return $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)
->getId();
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
return $this->getVwoConfigSettings()->getCacheMaxAge();
}
/**
* Get Acquia VWO config settings.
*
* @return \Drupal\Core\Config\Config
* The VWO Config Object.
*/
protected function getVwoConfigSettings() {
return $this->configFactory->get('acquia_vwo.settings');
}
}
