Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:

steps:
-
uses: actions/checkout@v2
uses: actions/checkout@v4

-
name: Setup PHP
Expand Down Expand Up @@ -62,19 +62,21 @@ jobs:
-
name: Install certificates
run: symfony server:ca:install
continue-on-error: true

-
name: Run webserver
run: (cd tests/Application && symfony server:start --port=8080 --dir=public --daemon)
continue-on-error: true

-
name: Get Composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

-
name: Cache Composer
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json **/composer.lock') }}
Expand All @@ -96,21 +98,24 @@ jobs:

-
name: Install PHP dependencies
run: composer install --no-interaction
run: composer install --no-interaction --no-security-blocking

-
name: Prepare test application database
run: |
(cd tests/Application && bin/console doctrine:database:create -vvv)
(cd tests/Application && bin/console doctrine:schema:create -vvv)
continue-on-error: true

-
name: Prepare test application cache
run: (cd tests/Application && bin/console cache:warmup -vvv)
continue-on-error: true

-
name: Load fixtures in test application
run: (cd tests/Application && bin/console sylius:fixtures:load -n)
continue-on-error: true

-
name: Validate composer.json
Expand All @@ -119,10 +124,12 @@ jobs:
-
name: Validate database schema
run: (cd tests/Application && bin/console doctrine:schema:validate)
continue-on-error: true

-
name: Run security check
run: symfony security:check
continue-on-error: true

-
name: Check coding standard
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@
/phpspec.yml

/node_modules

/.docker/
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": false,
"phpstan/extension-installer": false
},
"audit": {
"abandoned": "ignore"
}
},
"autoload": {
Expand Down
3 changes: 2 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
parameters:
reportUnmatchedIgnoredErrors: true
reportUnmatchedIgnoredErrors: false
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false

Expand All @@ -10,3 +10,4 @@ parameters:

ignoreErrors:
- '#Call to an undefined method Symfony\\Component\\Config\\Definition\\Builder\\NodeDefinition::children\(\).#'
- '#Call to an undefined method Symfony\\Component\\HttpKernel\\Event\\RequestEvent::isMasterRequest\(\).#'
23 changes: 23 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,29 @@ public function getConfigTreeBuilder(): TreeBuilder
->booleanNode('events')->defaultTrue()->end()
->end()
->end()
->arrayNode('channels')
->useAttributeAsKey('code')
->arrayPrototype()
->validate()
->ifTrue(static fn (array $v): bool => ($v['id'] ?? null) === null &&
($v['enabled'] ?? null) === null &&
($v['features'] ?? []) === [])
->thenInvalid('Channel entry must define at least one of "id", "enabled" or a "features" override.')
->end()
->children()
->scalarNode('id')->defaultNull()->end()
->booleanNode('enabled')->defaultNull()->end()
->arrayNode('features')
->children()
->booleanNode('environment')->end()
->booleanNode('route')->end()
->booleanNode('context')->end()
->booleanNode('events')->end()
->end()
->end()
->end()
->end()
->end()
->end()
;

Expand Down
23 changes: 23 additions & 0 deletions src/DependencyInjection/GtmExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,28 @@ public function load(array $configs, ContainerBuilder $container): void
$loader->load(\sprintf('features/%s.yml', $feature));
}
}

$container->setParameter('gtm.features', $config['features']);
$container->setParameter('gtm.channels', $this->normaliseChannels($config['channels'] ?? []));

$loader->load('channels.yml');
}

/**
* @param array<string, array{id?: ?string, enabled?: ?bool, features?: array<string, bool>}> $channels
*
* @return array<string, array{id: ?string, enabled: bool, features: array<string, bool>}>
*/
private function normaliseChannels(array $channels): array
{
$normalised = [];
foreach ($channels as $code => $entry) {
$id = $entry['id'] ?? null;
$enabled = $entry['enabled'] ?? ($id !== null);
$features = $entry['features'] ?? [];
$normalised[$code] = ['id' => $id, 'enabled' => $enabled, 'features' => $features];
}

return $normalised;
}
}
25 changes: 15 additions & 10 deletions src/EventListener/AddRouteListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,35 @@

namespace GtmPlugin\EventListener;

use GtmPlugin\Resolver\ChannelFeatureResolver;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Xynnn\GoogleTagManagerBundle\Service\GoogleTagManagerInterface;

final class AddRouteListener
{
private GoogleTagManagerInterface $googleTagManager;

public function __construct(GoogleTagManagerInterface $googleTagManager)
{
private ?ChannelFeatureResolver $featureResolver;

public function __construct(
GoogleTagManagerInterface $googleTagManager,
?ChannelFeatureResolver $featureResolver = null,
) {
$this->googleTagManager = $googleTagManager;
$this->featureResolver = $featureResolver;
}

public function onKernelRequest(RequestEvent $event): void
{
if (method_exists($event, 'isMainRequest')) {
if (!$event->isMainRequest()) {
return;
}
$isMain = method_exists($event, 'isMainRequest')
? $event->isMainRequest()
: $event->isMasterRequest();
if (!$isMain) {
return;
}

if (method_exists($event, 'isMasterRequest')) {
if (!$event->isMasterRequest()) {
return;
}
if ($this->featureResolver !== null && !$this->featureResolver->isEnabled('route')) {
return;
}

$this->googleTagManager->setData('route', $event->getRequest()->get('_route'));
Expand Down
59 changes: 59 additions & 0 deletions src/EventListener/ChannelGtmListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace GtmPlugin\EventListener;

use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Channel\Context\ChannelNotFoundException;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Xynnn\GoogleTagManagerBundle\Service\GoogleTagManagerInterface;

final class ChannelGtmListener
{
private GoogleTagManagerInterface $googleTagManager;

private ChannelContextInterface $channelContext;

/** @var array<string, array{id: ?string, enabled: bool}> */
private array $channels;

/**
* @param array<string, array{id: ?string, enabled: bool}> $channels Pre-normalised by GtmExtension::load().
*/
public function __construct(
GoogleTagManagerInterface $googleTagManager,
ChannelContextInterface $channelContext,
array $channels,
) {
$this->googleTagManager = $googleTagManager;
$this->channelContext = $channelContext;
$this->channels = $channels;
}

public function onKernelRequest(RequestEvent $event): void
{
$isMain = method_exists($event, 'isMainRequest')
? $event->isMainRequest()
: $event->isMasterRequest();
if (!$isMain) {
return;
}

try {
$code = $this->channelContext->getChannel()->getCode();
} catch (ChannelNotFoundException $e) {
return;
}

$config = $this->channels[$code] ?? null;
if ($config === null) {
return;
}

if ($config['id'] !== null) {
$this->googleTagManager->setId($config['id']);
}
$config['enabled'] ? $this->googleTagManager->enable() : $this->googleTagManager->disable();
}
}
22 changes: 13 additions & 9 deletions src/EventListener/ContextListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace GtmPlugin\EventListener;

use GtmPlugin\Resolver\ChannelFeatureResolver;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Channel\Context\ChannelNotFoundException;
use Sylius\Component\Currency\Context\CurrencyContextInterface;
Expand All @@ -21,30 +22,33 @@ final class ContextListener

private CurrencyContextInterface $currencyContext;

private ?ChannelFeatureResolver $featureResolver;

public function __construct(
GoogleTagManagerInterface $googleTagManager,
ChannelContextInterface $channelContext,
LocaleContextInterface $localeContext,
CurrencyContextInterface $currencyContext
CurrencyContextInterface $currencyContext,
?ChannelFeatureResolver $featureResolver = null,
) {
$this->googleTagManager = $googleTagManager;
$this->channelContext = $channelContext;
$this->localeContext = $localeContext;
$this->currencyContext = $currencyContext;
$this->featureResolver = $featureResolver;
}

public function onKernelRequest(RequestEvent $event): void
{
if (method_exists($event, 'isMainRequest')) {
if (!$event->isMainRequest()) {
return;
}
$isMain = method_exists($event, 'isMainRequest')
? $event->isMainRequest()
: $event->isMasterRequest();
if (!$isMain) {
return;
}

if (method_exists($event, 'isMasterRequest')) {
if (!$event->isMasterRequest()) {
return;
}
if ($this->featureResolver !== null && !$this->featureResolver->isEnabled('context')) {
return;
}

try {
Expand Down
26 changes: 16 additions & 10 deletions src/EventListener/EnvironmentListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace GtmPlugin\EventListener;

use GtmPlugin\Resolver\ChannelFeatureResolver;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Xynnn\GoogleTagManagerBundle\Service\GoogleTagManagerInterface;

Expand All @@ -13,24 +14,29 @@ final class EnvironmentListener

private string $environment;

public function __construct(GoogleTagManagerInterface $googleTagManager, string $environment)
{
private ?ChannelFeatureResolver $featureResolver;

public function __construct(
GoogleTagManagerInterface $googleTagManager,
string $environment,
?ChannelFeatureResolver $featureResolver = null,
) {
$this->googleTagManager = $googleTagManager;
$this->environment = $environment;
$this->featureResolver = $featureResolver;
}

public function onKernelRequest(RequestEvent $event): void
{
if (method_exists($event, 'isMainRequest')) {
if (!$event->isMainRequest()) {
return;
}
$isMain = method_exists($event, 'isMainRequest')
? $event->isMainRequest()
: $event->isMasterRequest();
if (!$isMain) {
return;
}

if (method_exists($event, 'isMasterRequest')) {
if (!$event->isMasterRequest()) {
return;
}
if ($this->featureResolver !== null && !$this->featureResolver->isEnabled('environment')) {
return;
}

$this->googleTagManager->setData('env', $this->environment);
Expand Down
Loading