vendor/sonata-project/block-bundle/src/Block/BlockRenderer.php line 61

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of the Sonata Project package.
  5.  *
  6.  * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace Sonata\BlockBundle\Block;
  12. use Psr\Log\LoggerInterface;
  13. use Sonata\BlockBundle\Exception\Strategy\StrategyManagerInterface;
  14. use Symfony\Component\HttpFoundation\Response;
  15. /**
  16.  * Handles the execution and rendering of a block.
  17.  *
  18.  * This function render a block and make sure the cacheable information are correctly retrieved
  19.  * and set to the upper response (container can have child blocks, so the smallest ttl from a child
  20.  * must be used in the container).
  21.  */
  22. final class BlockRenderer implements BlockRendererInterface
  23. {
  24.     /**
  25.      * This property hold the last response available from the child or sibling block
  26.      * The cacheable attributes must be cascaded to the parent.
  27.      */
  28.     private ?Response $lastResponse null;
  29.     /**
  30.      * @param BlockServiceManagerInterface $blockServiceManager      Block service manager
  31.      * @param StrategyManagerInterface     $exceptionStrategyManager Exception strategy manager
  32.      * @param LoggerInterface              $logger                   Logger class
  33.      */
  34.     public function __construct(
  35.         private BlockServiceManagerInterface $blockServiceManager,
  36.         private StrategyManagerInterface $exceptionStrategyManager,
  37.         private ?LoggerInterface $logger null
  38.     ) {
  39.     }
  40.     public function render(BlockContextInterface $blockContext, ?Response $response null): Response
  41.     {
  42.         $block $blockContext->getBlock();
  43.         if (null !== $this->logger) {
  44.             $this->logger->info(
  45.                 sprintf('[cms::renderBlock] block.id=%d, block.type=%s'$block->getId() ?? ''$block->getType() ?? '')
  46.             );
  47.         }
  48.         try {
  49.             $service $this->blockServiceManager->get($block);
  50.             $service->load($block);
  51.             $response $service->execute($blockContext$this->createResponse($blockContext$response));
  52.             $response $this->addMetaInformation($response$blockContext);
  53.         } catch (\Throwable $exception) {
  54.             if (null !== $this->logger) {
  55.                 $this->logger->error(sprintf(
  56.                     '[cms::renderBlock] block.id=%d - error while rendering block - %s',
  57.                     $block->getId() ?? '',
  58.                     $exception->getMessage()
  59.                 ), compact('exception'));
  60.             }
  61.             // reseting the state object
  62.             $this->lastResponse null;
  63.             $response $this->exceptionStrategyManager->handleException($exception$blockContext->getBlock(), $response);
  64.         }
  65.         return $response;
  66.     }
  67.     private function createResponse(BlockContextInterface $blockContext, ?Response $response null): Response
  68.     {
  69.         if (null === $response) {
  70.             $response = new Response();
  71.         }
  72.         // set the ttl from the block instance, this can be changed by the BlockService
  73.         if (($ttl $blockContext->getBlock()->getTtl()) > 0) {
  74.             $response->setTtl($ttl);
  75.         }
  76.         return $response;
  77.     }
  78.     /**
  79.      * This method is responsible to cascade ttl to the parent block.
  80.      */
  81.     private function addMetaInformation(Response $responseBlockContextInterface $blockContext): Response
  82.     {
  83.         // a response exists, use it
  84.         if (null !== $this->lastResponse && $this->lastResponse->isCacheable()) {
  85.             $lastResponseTtl $this->lastResponse->getTtl();
  86.             if (null !== $lastResponseTtl) {
  87.                 $response->setTtl($lastResponseTtl);
  88.             }
  89.             $response->setPublic();
  90.         } elseif (null !== $this->lastResponse) { // not cacheable
  91.             $response->setPrivate();
  92.             $response->setTtl(0);
  93.             $response->headers->removeCacheControlDirective('s-maxage');
  94.             $response->headers->removeCacheControlDirective('maxage');
  95.         }
  96.         // no more children available in the stack, reseting the state object
  97.         if (!$blockContext->getBlock()->hasParent()) {
  98.             $this->lastResponse null;
  99.         } else { // contains a parent so storing the response
  100.             $this->lastResponse $response;
  101.         }
  102.         return $response;
  103.     }
  104. }