adunblock/server-tag-symfony
Symfony bundle that fetches script URLs from a remote endpoint and renders them via a Twig server_tag() function. Uses Symfony HttpClient, optional caching with configurable TTL, safe HTML escaping, and graceful error handling. Compatible with Symfony 5–8.
Installation:
composer require adunblock/server-tag-symfony:^1.0
Enable in config/bundles.php:
AdUnblock\ServerTag\Symfony\AdunblockServerTagBundle::class => ['all' => true],
First Use Case:
Inject the server_tag() Twig function in a template:
{{ server_tag('https://example.com/remote-script.js') }}
This fetches and renders the remote script with default caching (1 hour).
Where to Look First:
server_tag() in templates.config/packages/adunblock_server_tag.yaml (auto-generated).adunblock_server_tag.client (customizable HTTP client).Dynamic Script Injection: Use Twig to fetch scripts dynamically (e.g., A/B testing, feature flags):
{% if user.is_premium %}
{{ server_tag('https://cdn.premium.example.com/analytics') }}
{% endif %}
Caching Strategies:
{{ server_tag('https://ad-network.example.com/tag', 300) }} {# 5-minute TTL #}
{{ server_tag('https://static.example.com/lib.js', 86400) }} {# 1-day TTL #}
Integration with Symfony Services: Extend the bundle’s HTTP client via dependency injection:
# config/services.yaml
services:
adunblock_server_tag.client:
class: Symfony\Contracts\HttpClient\HttpClientInterface
factory: ['App\Service\CustomHttpClientFactory', 'create']
Conditional Rendering:
Combine with Twig’s if for environment-specific tags:
{% if app.environment == 'prod' %}
{{ server_tag('https://prod-cdn.example.com/script') }}
{% else %}
{{ server_tag('https://dev-cdn.example.com/script') }}
{% endif %}
Tag Grouping: Use Twig loops to render multiple tags with shared caching:
{% for url in remoteScripts %}
{{ server_tag(url, 3600) }}
{% endfor %}
Fallback Logic: Provide default content if the remote script fails:
{% set tag = server_tag('https://failing.example.com/tag', 60) %}
{% if tag is empty %}
<script>console.log('Fallback: Remote tag failed');</script>
{% endif %}
Custom Cache Keys: Override cache keys via configuration (e.g., include query params):
# config/packages/adunblock_server_tag.yaml
adunblock_server_tag:
cache_key_generator: 'App\Cache\CustomKeyGenerator'
Cache Invalidation:
?v=2 in URLs).XSS Risks:
HTTP Client Failures:
config/packages/adunblock_server_tag.yaml:
adunblock_server_tag:
http_client_options:
max_retries: 3
timeout: 10
Twig Function Scope:
server_tag() fails if Twig’s environment isn’t properly initialized (e.g., CLI commands).$client = $container->get('adunblock_server_tag.client');
$response = $client->request('GET', 'https://example.com/tag');
Log Remote Responses:
Enable debug mode in config/packages/adunblock_server_tag.yaml:
adunblock_server_tag:
debug: true
Logs responses to var/log/dev.log.
Cache Inspection: Check cached responses with:
php bin/console cache:pool:list
php bin/console debug:cache
HTTP Client Mocking: For testing, mock the HTTP client:
$this->container->set('adunblock_server_tag.client', $this->createMock(HttpClientInterface::class));
Custom Cache Adapter:
Replace the default CacheInterface:
# config/services.yaml
services:
adunblock_server_tag.cache:
class: Symfony\Component\Cache\Adapter\FilesystemAdapter
arguments: ['custom_cache_dir']
Response Transformers: Modify fetched content before rendering:
// src/EventSubscriber/ServerTagSubscriber.php
use AdUnblock\ServerTag\Event\ServerTagEvent;
class ServerTagSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [ServerTagEvent::PRE_RENDER => 'onPreRender'];
}
public function onPreRender(ServerTagEvent $event) {
$event->setContent(str_replace('old', 'new', $event->getContent()));
}
}
Async Loading:
Defer script loading with async/defer attributes:
{% set tag = server_tag('https://example.com/script') %}
<script async>{{ tag }}</script>
Environment-Specific URLs: Use Symfony’s parameter bag to switch URLs:
{% set url = app.parameters.remote_scripts[app.environment] %}
{{ server_tag(url) }}
How can I help you explore Laravel packages today?