src/EventSubscriber/DeferReadmoreScriptSubscriber.php line 41

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber;
  3. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  4. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  5. use Symfony\Component\HttpKernel\KernelEvents;
  6. /**
  7.  * EventSubscriber para optimizar la carga de readmore.js
  8.  *
  9.  * Este subscriber:
  10.  * 1. Intercepta la respuesta HTML antes de enviarla al navegador
  11.  * 2. Encuentra el script readmore.min.js en el head
  12.  * 3. Lo mueve al final del body o añade atributo defer
  13.  * 4. Mejora el rendimiento de carga de la página
  14.  *
  15.  * @package App\EventSubscriber
  16.  */
  17. class DeferReadmoreScriptSubscriber implements EventSubscriberInterface
  18. {
  19.     /**
  20.      * Registrar los eventos a los que se suscribe
  21.      *
  22.      * @return array
  23.      */
  24.     public static function getSubscribedEvents(): array
  25.     {
  26.         return [
  27.             // Ejecutar justo antes de enviar la respuesta al navegador
  28.             // Prioridad baja (-100) para ejecutar después de otros listeners
  29.             KernelEvents::RESPONSE => ['onKernelResponse', -100],
  30.         ];
  31.     }
  32.     /**
  33.      * Manipular la respuesta para optimizar readmore.js
  34.      *
  35.      * @param ResponseEvent $event
  36.      */
  37.     public function onKernelResponse(ResponseEvent $event): void
  38.     {
  39.         // Solo procesar la respuesta principal, no sub-requests
  40.         if (!$event->isMainRequest()) {
  41.             return;
  42.         }
  43.         $response $event->getResponse();
  44.         $contentType $response->headers->get('Content-Type');
  45.         // Solo procesar respuestas HTML
  46.         if (!$contentType || strpos($contentType'text/html') === false) {
  47.             return;
  48.         }
  49.         $content $response->getContent();
  50.         // Verificar si el contenido contiene readmore
  51.         if (strpos($content'readmore') === false) {
  52.             return;
  53.         }
  54.         // ============================================
  55.         // OPCIÓN 1: Añadir atributo defer (recomendado)
  56.         // ============================================
  57.         // Buscar todos los scripts que incluyan "readmore" y añadir defer
  58.         $content preg_replace_callback(
  59.             '/<script\s+([^>]*src=["\'][^"\']*readmore[^"\']*["\'][^>]*)>/i',
  60.             function ($matches) {
  61.                 $scriptTag $matches[0];
  62.                 // Si ya tiene defer o async, no hacer nada
  63.                 if (preg_match('/\s(defer|async)\s/i'$scriptTag)) {
  64.                     return $scriptTag;
  65.                 }
  66.                 // Añadir defer antes del cierre >
  67.                 return str_replace('>'' defer>'$scriptTag);
  68.             },
  69.             $content
  70.         );
  71.         // ============================================
  72.         // OPCIÓN 2: Mover scripts al final del body (alternativa)
  73.         // ============================================
  74.         // Descomentar este bloque si prefieres mover el script al final
  75.         /*
  76.         $readmoreScripts = [];
  77.         // Extraer scripts de readmore del head
  78.         $content = preg_replace_callback(
  79.             '/<script\s+[^>]*src=["\'][^"\']*readmore[^"\']*["\'][^>]*>.*?<\/script>/is',
  80.             function ($matches) use (&$readmoreScripts) {
  81.                 // Guardar el script para insertarlo después
  82.                 $readmoreScripts[] = $matches[0];
  83.                 // Remover del head
  84.                 return '';
  85.             },
  86.             $content
  87.         );
  88.         // Insertar los scripts justo antes de </body>
  89.         if (!empty($readmoreScripts)) {
  90.             $scriptsHtml = "\n    <!-- Readmore scripts movidos al final para mejor rendimiento -->\n    ";
  91.             $scriptsHtml .= implode("\n    ", $readmoreScripts);
  92.             $scriptsHtml .= "\n";
  93.             $content = str_replace('</body>', $scriptsHtml . '</body>', $content);
  94.         }
  95.         */
  96.         // ============================================
  97.         // OPCIÓN 3: Preload para mejorar aún más (opcional)
  98.         // ============================================
  99.         // Añadir preload en el head para que el navegador descargue el script
  100.         // pero sin bloquear el renderizado
  101.         /*
  102.         if (preg_match('/<head[^>]*>/i', $content)) {
  103.             $preloadLinks = [];
  104.             // Extraer todas las URLs de scripts readmore
  105.             preg_match_all('/<script\s+[^>]*src=["\']([^"\']*readmore[^"\']*)["\'][^>]*>/i', $content, $matches);
  106.             foreach ($matches[1] as $scriptUrl) {
  107.                 $preloadLinks[] = sprintf(
  108.                     '<link rel="preload" href="%s" as="script">',
  109.                     htmlspecialchars($scriptUrl, ENT_QUOTES, 'UTF-8')
  110.                 );
  111.             }
  112.             if (!empty($preloadLinks)) {
  113.                 $preloadHtml = "\n    " . implode("\n    ", $preloadLinks) . "\n";
  114.                 $content = preg_replace(
  115.                     '/(<head[^>]*>)/i',
  116.                     '$1' . $preloadHtml,
  117.                     $content,
  118.                     1
  119.                 );
  120.             }
  121.         }
  122.         */
  123.         // Actualizar el contenido de la respuesta
  124.         $response->setContent($content);
  125.     }
  126. }