Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OPENEUROPA-1414: Add support for multilingual aliases on Webtools Analytics rules. #27

Merged
merged 11 commits into from
Jan 16, 2019
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ oe_webtools_analytics_rules.webtools_analytics_rule.*:
section:
type: label
label: 'Section'
match_on_site_default_language:
type: boolean
label: 'Match on path alias for site default language'
regex:
type: string
label: Regex
uuid:
type: string
type: string
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ package: OpenEuropa Webtools
type: module
core: 8.x
dependencies:
- oe_webtools_analytics
- oe_webtools_analytics:oe_webtools_analytics
- drupal:path
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
services:
oe_webtools_analytics_rules.event_subscriber:
class: Drupal\oe_webtools_analytics_rules\EventSubscriber\WebtoolsAnalyticsEventSubscriber
arguments: ['@entity_type.manager', '@request_stack', '@cache.webtools_analytics_rules']
arguments: ['@entity_type.manager', '@path.current', '@path.alias_manager','@cache.webtools_analytics_rules', '@config.factory']
tags:
- { name: event_subscriber }
cache_context.webtools_analytics_section:
class: Drupal\oe_webtools_analytics_rules\OpenEuropaWebtoolsAnalyticsSiteSectionCacheContext
arguments: ['@oe_webtools_analytics_rules.event_subscriber']
tags:
- { name: cache.context }
cache.webtools_analytics_rules:
class: Drupal\Core\Cache\CacheBackendInterface
tags:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* entity_keys = {
* "id" = "id",
* "section" = "section",
* "match_on_site_default_language" = "match_on_site_default_language",
* "regex" = "regex",
* "uuid" = "uuid"
* },
Expand Down Expand Up @@ -57,6 +58,13 @@ class WebtoolsAnalyticsRule extends ConfigEntityBase implements WebtoolsAnalytic
*/
protected $section = '';

/**
* Indicates if the rule should be applied on the default site language alias.
*
* @var bool
*/
protected $match_on_site_default_language = FALSE;

/**
* The regular expression to be applied.
*
Expand All @@ -78,4 +86,11 @@ public function getRegex(): string {
return $this->regex;
}

/**
* {@inheritdoc}
*/
public function matchOnSiteDefaultLanguage(): bool {
return (bool) $this->match_on_site_default_language;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ interface WebtoolsAnalyticsRuleInterface extends ConfigEntityInterface {
*/
public function getSection(): string;

/**
* Indicates if the rule should be applied on the default site language alias.
*
* @return bool
* True if applies on the default site language alias.
*/
public function matchOnSiteDefaultLanguage(): bool;

/**
* Returns the regular expression.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

namespace Drupal\oe_webtools_analytics_rules\EventSubscriber;

use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Path\AliasManagerInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\oe_webtools_analytics\Event\AnalyticsEvent;
use Drupal\oe_webtools_analytics\AnalyticsEventInterface;
use Drupal\oe_webtools_analytics_rules\Entity\WebtoolsAnalyticsRuleInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
* Event subscriber for the Webtools Analytics event.
Expand All @@ -27,11 +28,18 @@ class WebtoolsAnalyticsEventSubscriber implements EventSubscriberInterface {
protected $entityTypeManager;

/**
* The request stack.
* The current path service.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
* @var \Drupal\Core\Path\CurrentPathStack
*/
protected $requestStack;
protected $currentPath;

/**
* The alias manager service.
*
* @var \Drupal\Core\Path\AliasManagerInterface
*/
protected $aliasManager;

/**
* A cache backend interface.
Expand All @@ -40,20 +48,33 @@ class WebtoolsAnalyticsEventSubscriber implements EventSubscriberInterface {
*/
protected $cache;

/**
* The configuration object.
*
* @var \Drupal\Core\Config\Config
*/
protected $siteConfig;

/**
* WebtoolsAnalyticsEventSubscriber constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager.
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
* The request stack.
* @param \Drupal\Core\Path\CurrentPathStack $currentPath
* The current path service.
* @param \Drupal\Core\Path\AliasManagerInterface $aliasManager
* The alias manager service.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* A cache backend used to store webtools rules for uris.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config
* The Config Factory service.
*/
public function __construct(EntityTypeManagerInterface $entityTypeManager, RequestStack $requestStack, CacheBackendInterface $cache) {
public function __construct(EntityTypeManagerInterface $entityTypeManager, CurrentPathStack $currentPath, AliasManagerInterface $aliasManager, CacheBackendInterface $cache, ConfigFactoryInterface $config) {
$this->entityTypeManager = $entityTypeManager;
$this->requestStack = $requestStack;
$this->currentPath = $currentPath;
$this->aliasManager = $aliasManager;
$this->cache = $cache;
$this->siteConfig = $config->get('system.site');
}

/**
Expand All @@ -63,51 +84,55 @@ public function __construct(EntityTypeManagerInterface $entityTypeManager, Reque
* Response event.
*/
public function analyticsEventHandler(AnalyticsEventInterface $event): void {
// We need to invalidate the render arrays if any rule changes.
$event->addCacheTags(['webtools_analytics_rule_list']);
$current_uri = $this->requestStack->getCurrentRequest()->getRequestUri();
if ($cache = $this->cache->get($current_uri)) {
$current_path = $this->currentPath->getPath();
$cache = $this->cache->get($current_path);
if ($cache && $cache->data === NULL) {
// If there is no cached data there is no section that applies to the uri.
if ($cache->data === NULL) {
return;
}
// Set site section from the cached data.
if (isset($cache->data['section'])) {
$event->setSiteSection($cache->data['section']);
return;
}
return;
}

try {
$storage = $this->entityTypeManager
->getStorage('webtools_analytics_rule');
}
// Because of the dynamic nature how entities work in Drupal the entity type
// manager can throw exceptions if an entity type is not available or
// invalid. However since we are using our very own entity type we can
// be certain that this is defined and valid. Convert the exceptions into
// unchecked runtime exceptions so they don't need to be documented all the
// way up the call stack.
catch (InvalidPluginDefinitionException $e) {
throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
if (isset($cache->data['section'])) {
$event->setSiteSection($cache->data['section']);
return;
}
catch (PluginNotFoundException $e) {
throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);

$rule = $this->getRuleByPath($current_path);
if ($rule instanceof WebtoolsAnalyticsRuleInterface) {
$event->setSiteSection($rule->getSection());
$this->cache->set($current_path, ['section' => $rule->getSection()], Cache::PERMANENT, $rule->getCacheTags());
return;
}

$rules = $storage->loadMultiple();
/** @var \Drupal\oe_webtools_analytics_rules\Entity\WebtoolsAnalyticsRuleInterface $rule */
// Cache NULL if there is no rule that applies to the uri.
$this->cache->set($current_path, NULL, Cache::PERMANENT, ['webtools_analytics_rule_list']);
}

/**
* Get a rule which related to current path.
*
* @param string $path
* Current path.
*
* @return \Drupal\oe_webtools_analytics_rules\Entity\WebtoolsAnalyticsRuleInterface|null
* Rule related to current path.
*/
protected function getRuleByPath(string $path): ?WebtoolsAnalyticsRuleInterface {
/** @var \Drupal\oe_webtools_analytics_rules\Entity\WebtoolsAnalyticsRuleInterface[] $rules */
$rules = $this->entityTypeManager->getStorage('webtools_analytics_rule')->loadMultiple();

foreach ($rules as $rule) {
if (preg_match($rule->getRegex(), $current_uri, $matches) === 1) {
$event->setSiteSection($rule->getSection());
$this->cache->set($current_uri, ['section' => $rule->getSection()], Cache::PERMANENT, $rule->getCacheTags());
// Currently there is no defined behavior for overlapping rules so we
// only take into account the first rule that applies.
return;
$current_path = $path;
if ($rule->matchOnSiteDefaultLanguage()) {
$current_path = $this->aliasManager->getAliasByPath($this->currentPath->getPath(), $this->siteConfig->get('default_langcode'));
}

if (preg_match($rule->getRegex(), $current_path) === 1) {
return $rule;
}
}
// Cache NULL if there is no rule that applies to the uri.
$this->cache->set($current_uri, NULL, Cache::PERMANENT, $storage->getEntityType()->getListCacheTags());

return NULL;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ public function form(array $form, FormStateInterface $form_state): array {
'#disabled' => !$rule->isNew(),
];

$form['match_on_site_default_language'] = [
'#type' => 'checkbox',
'#title' => $this->t('Match on path alias for site default language.'),
'#default_value' => $rule->matchOnSiteDefaultLanguage(),
'#description' => $this->t("If checked, the matching will be done on the path alias for the site default language. For example, if you have the /news/ regex value, the rule would be applied to the '/fr/nouvelles/*' as well as the /nl/nieuws/* paths."),
];

$form['regex'] = [
'#type' => 'textfield',
'#title' => $this->t('Regex'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class WebtoolsAnalyticsRuleListBuilder extends ConfigEntityListBuilder {
*/
public function buildHeader(): array {
$header['section'] = $this->t('Section');
$header['match_on_site_default_language'] = $this->t('Match on path alias for site default language');
$header['regex'] = $this->t('Regex');

return $header + parent::buildHeader();
Expand All @@ -27,6 +28,7 @@ public function buildHeader(): array {
*/
public function buildRow(EntityInterface $entity): array {
$row['section'] = $entity->getSection();
$row['match_on_site_default_language'] = $entity->matchOnSiteDefaultLanguage() ? $this->t('Yes') : $this->t('No');
$row['id'] = $entity->getRegex();

return $row + parent::buildRow($entity);
Expand Down

This file was deleted.

3 changes: 2 additions & 1 deletion runner.yml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ drupal:
- "./vendor/bin/drush en oe_webtools oe_webtools_analytics_rules -y"
- "./vendor/bin/drush en oe_webtools oe_webtools_laco_service -y"
- "./vendor/bin/drush en oe_webtools oe_webtools_laco_widget -y"
- "./vendor/bin/drush en language -y"
- "./vendor/bin/drush cr"
settings:
settings:
Expand All @@ -42,4 +43,4 @@ commands:
setup:phpunit:
- { task: "process", source: "phpunit.xml.dist", destination: "phpunit.xml" }
setup:behat:
- { task: "process", source: "behat.yml.dist", destination: "behat.yml" }
- { task: "process", source: "behat.yml.dist", destination: "behat.yml" }
2 changes: 1 addition & 1 deletion tests/Behat/WebtoolsAnalyticsMinkContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function analyticsJsonContainsParameter(string $parameter, string $value)
$json_value = json_decode($script->getText(), TRUE);
if (isset($json_value['utility']) && $json_value['utility'] == 'piwik') {
$json_found = TRUE;
Assert::assertEquals($value, $json_value[$parameter]);
Assert::assertEquals($value, $json_value[$parameter] ?? '');
}
}
if (!$json_found) {
Expand Down
Loading