View source
<?php
namespace Drupal\hotjar;
use Drupal\Component\Utility\Html;
use Drupal\Core\Asset\AssetCollectionOptimizerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
class SnippetBuilder implements SnippetBuilderInterface, ContainerInjectionInterface {
use StringTranslationTrait;
protected $state;
protected $configFactory;
protected $settings;
protected $moduleHandler;
protected $jsCollectionOptimizer;
protected $messenger;
protected $fileSystem;
public function __construct(StateInterface $state, ConfigFactoryInterface $config_factory, HotjarSettingsInterface $settings, ModuleHandlerInterface $module_handler, AssetCollectionOptimizerInterface $js_collection_optimizer, MessengerInterface $messenger, FileSystemInterface $file_system) {
$this->state = $state;
$this->configFactory = $config_factory;
$this->settings = $settings;
$this->moduleHandler = $module_handler;
$this->jsCollectionOptimizer = $js_collection_optimizer;
$this->messenger = $messenger;
$this->fileSystem = $file_system;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('state'), $container
->get('config.factory'), $container
->get('hotjar.settings'), $container
->get('module_handler'), $container
->get('asset.js.collection_optimizer'), $container
->get('messenger'), $container
->get('file_system'));
}
public function pageAttachment(array &$attachments) {
if ($this->settings
->getSetting('attachment_mode') === HotjarSettingsInterface::ATTACHMENT_MODE_DRUPAL_SETTINGS) {
$this
->pageAttachmentDrupalSettings($attachments);
}
else {
$this
->pageAttachmentBuilt($attachments);
}
}
protected function pageAttachmentBuilt(array &$attachments) {
$uri = $this
->getSnippetPath();
$query_string = $this->state
->get('system.css_js_query_string') ?: '0';
$query_string_separator = strpos($uri, '?') !== FALSE ? '&' : '?';
$url = file_url_transform_relative(file_create_url($uri));
$attachments['#attached']['html_head'][] = [
[
'#type' => 'html_tag',
'#tag' => 'script',
'#attributes' => [
'src' => $url . $query_string_separator . $query_string,
],
],
'hotjar_script_tag',
];
}
protected function pageAttachmentDrupalSettings(array &$attachments) {
$clean_id = Html::escape((string) $this->settings
->getSetting('account'));
$clean_version = Html::escape($this->settings
->getSetting('snippet_version'));
$attachments['#attached']['drupalSettings']['hotjar']['account'] = $clean_id;
$attachments['#attached']['drupalSettings']['hotjar']['snippetVersion'] = $clean_version;
$attachments['#attached']['library'][] = 'hotjar/hotjar';
}
public function createAssets() {
$this->settings
->getSettings(TRUE);
$result = TRUE;
$directory = dirname($this
->getSnippetPath());
if (!is_dir($directory) || !is_writable($directory)) {
$result = $this->fileSystem
->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
}
if ($result) {
$result = $this
->saveSnippets();
}
else {
$this->messenger
->addWarning($this
->t('Failed to create or make writable the directory %directory, possibly due to a permissions problem. Make the directory writable.', [
'%directory' => $directory,
]));
}
return $result;
}
protected function saveSnippets() {
$snippet = $this
->buildSnippet();
$snippet_path = $this
->getSnippetPath();
if ($this->fileSystem
->realpath($snippet_path)) {
$this->fileSystem
->delete($snippet_path);
}
$dir = $this->fileSystem
->realpath(dirname($snippet_path));
$this->fileSystem
->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
$path = $this->fileSystem
->saveData($snippet, $snippet_path, FileSystemInterface::EXISTS_REPLACE);
if ($path === FALSE) {
$this->messenger
->addMessage($this
->t('An error occurred saving one or more snippet files. Please try again or contact the site administrator if it persists.'));
return FALSE;
}
$this->messenger
->addMessage($this
->t('Created snippet file based on configuration.'));
$this->jsCollectionOptimizer
->deleteAll();
_drupal_flush_css_js();
return TRUE;
}
public function buildSnippet() {
$id = $this->settings
->getSetting('account');
$clean_id = $this
->escapeValue($id);
$clean_version = $this
->escapeValue($this->settings
->getSetting('snippet_version'));
if ($id && $clean_id) {
$script = <<<HJ
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:{<span class="php-variable">$clean_id</span>},hjsv:{<span class="php-variable">$clean_version</span>}};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'//static.hotjar.com/c/hotjar-','.js?sv=');
HJ;
}
else {
$script = <<<HJ
// Empty HotjarID.
HJ;
}
$this->moduleHandler
->alter('hotjar_snippet', $script);
if ($this
->isJsPreprocessEnabled() || $this->moduleHandler
->moduleExists('advagg')) {
$script = str_replace([
"\n",
' ',
], '', $script);
}
return $script;
}
protected function escapeValue($value) {
return json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
}
protected function isJsPreprocessEnabled() {
$config = $this->configFactory
->get('system.performance');
$configured = $config
->get('js.preprocess');
if (!isset($configured)) {
$configured = TRUE;
}
return $configured === TRUE;
}
protected function getSnippetPath() {
return $this->settings
->getSetting('snippet_path');
}
}