<?php
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* EventSubscriber para optimizar la carga de readmore.js
*
* Este subscriber:
* 1. Intercepta la respuesta HTML antes de enviarla al navegador
* 2. Encuentra el script readmore.min.js en el head
* 3. Lo mueve al final del body o añade atributo defer
* 4. Mejora el rendimiento de carga de la página
*
* @package App\EventSubscriber
*/
class DeferReadmoreScriptSubscriber implements EventSubscriberInterface
{
/**
* Registrar los eventos a los que se suscribe
*
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
// Ejecutar justo antes de enviar la respuesta al navegador
// Prioridad baja (-100) para ejecutar después de otros listeners
KernelEvents::RESPONSE => ['onKernelResponse', -100],
];
}
/**
* Manipular la respuesta para optimizar readmore.js
*
* @param ResponseEvent $event
*/
public function onKernelResponse(ResponseEvent $event): void
{
// Solo procesar la respuesta principal, no sub-requests
if (!$event->isMainRequest()) {
return;
}
$response = $event->getResponse();
$contentType = $response->headers->get('Content-Type');
// Solo procesar respuestas HTML
if (!$contentType || strpos($contentType, 'text/html') === false) {
return;
}
$content = $response->getContent();
// Verificar si el contenido contiene readmore
if (strpos($content, 'readmore') === false) {
return;
}
// ============================================
// OPCIÓN 1: Añadir atributo defer (recomendado)
// ============================================
// Buscar todos los scripts que incluyan "readmore" y añadir defer
$content = preg_replace_callback(
'/<script\s+([^>]*src=["\'][^"\']*readmore[^"\']*["\'][^>]*)>/i',
function ($matches) {
$scriptTag = $matches[0];
// Si ya tiene defer o async, no hacer nada
if (preg_match('/\s(defer|async)\s/i', $scriptTag)) {
return $scriptTag;
}
// Añadir defer antes del cierre >
return str_replace('>', ' defer>', $scriptTag);
},
$content
);
// ============================================
// OPCIÓN 2: Mover scripts al final del body (alternativa)
// ============================================
// Descomentar este bloque si prefieres mover el script al final
/*
$readmoreScripts = [];
// Extraer scripts de readmore del head
$content = preg_replace_callback(
'/<script\s+[^>]*src=["\'][^"\']*readmore[^"\']*["\'][^>]*>.*?<\/script>/is',
function ($matches) use (&$readmoreScripts) {
// Guardar el script para insertarlo después
$readmoreScripts[] = $matches[0];
// Remover del head
return '';
},
$content
);
// Insertar los scripts justo antes de </body>
if (!empty($readmoreScripts)) {
$scriptsHtml = "\n <!-- Readmore scripts movidos al final para mejor rendimiento -->\n ";
$scriptsHtml .= implode("\n ", $readmoreScripts);
$scriptsHtml .= "\n";
$content = str_replace('</body>', $scriptsHtml . '</body>', $content);
}
*/
// ============================================
// OPCIÓN 3: Preload para mejorar aún más (opcional)
// ============================================
// Añadir preload en el head para que el navegador descargue el script
// pero sin bloquear el renderizado
/*
if (preg_match('/<head[^>]*>/i', $content)) {
$preloadLinks = [];
// Extraer todas las URLs de scripts readmore
preg_match_all('/<script\s+[^>]*src=["\']([^"\']*readmore[^"\']*)["\'][^>]*>/i', $content, $matches);
foreach ($matches[1] as $scriptUrl) {
$preloadLinks[] = sprintf(
'<link rel="preload" href="%s" as="script">',
htmlspecialchars($scriptUrl, ENT_QUOTES, 'UTF-8')
);
}
if (!empty($preloadLinks)) {
$preloadHtml = "\n " . implode("\n ", $preloadLinks) . "\n";
$content = preg_replace(
'/(<head[^>]*>)/i',
'$1' . $preloadHtml,
$content,
1
);
}
}
*/
// Actualizar el contenido de la respuesta
$response->setContent($content);
}
}