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

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.     private BlockServiceManagerInterface $blockServiceManager;
  25.     private StrategyManagerInterface $exceptionStrategyManager;
  26.     private ?LoggerInterface $logger;
  27.     /**
  28.      * This property hold the last response available from the child or sibling block
  29.      * The cacheable attributes must be cascaded to the parent.
  30.      */
  31.     private ?Response $lastResponse null;
  32.     /**
  33.      * @param BlockServiceManagerInterface $blockServiceManager      Block service manager
  34.      * @param StrategyManagerInterface     $exceptionStrategyManager Exception strategy manager
  35.      * @param LoggerInterface              $logger                   Logger class
  36.      */
  37.     public function __construct(
  38.         BlockServiceManagerInterface $blockServiceManager,
  39.         StrategyManagerInterface $exceptionStrategyManager,
  40.         ?LoggerInterface $logger null
  41.     ) {
  42.         $this->blockServiceManager $blockServiceManager;
  43.         $this->exceptionStrategyManager $exceptionStrategyManager;
  44.         $this->logger $logger;
  45.     }
  46.     public function render(BlockContextInterface $blockContext, ?Response $response null): Response
  47.     {
  48.         $block $blockContext->getBlock();
  49.         if (null !== $this->logger) {
  50.             $this->logger->info(
  51.                 sprintf('[cms::renderBlock] block.id=%d, block.type=%s'$block->getId() ?? ''$block->getType() ?? '')
  52.             );
  53.         }
  54.         try {
  55.             $service $this->blockServiceManager->get($block);
  56.             $service->load($block);
  57.             $response $service->execute($blockContext$this->createResponse($blockContext$response));
  58.             $response $this->addMetaInformation($response$blockContext);
  59.         } catch (\Throwable $exception) {
  60.             if (null !== $this->logger) {
  61.                 $this->logger->error(sprintf(
  62.                     '[cms::renderBlock] block.id=%d - error while rendering block - %s',
  63.                     $block->getId() ?? '',
  64.                     $exception->getMessage()
  65.                 ), compact('exception'));
  66.             }
  67.             // reseting the state object
  68.             $this->lastResponse null;
  69.             $response $this->exceptionStrategyManager->handleException($exception$blockContext->getBlock(), $response);
  70.         }
  71.         return $response;
  72.     }
  73.     private function createResponse(BlockContextInterface $blockContext, ?Response $response null): Response
  74.     {
  75.         if (null === $response) {
  76.             $response = new Response();
  77.         }
  78.         // set the ttl from the block instance, this can be changed by the BlockService
  79.         if (($ttl $blockContext->getBlock()->getTtl()) > 0) {
  80.             $response->setTtl($ttl);
  81.         }
  82.         return $response;
  83.     }
  84.     /**
  85.      * This method is responsible to cascade ttl to the parent block.
  86.      */
  87.     private function addMetaInformation(Response $responseBlockContextInterface $blockContext): Response
  88.     {
  89.         // a response exists, use it
  90.         if (null !== $this->lastResponse && $this->lastResponse->isCacheable()) {
  91.             $lastResponseTtl $this->lastResponse->getTtl();
  92.             if (null !== $lastResponseTtl) {
  93.                 $response->setTtl($lastResponseTtl);
  94.             }
  95.             $response->setPublic();
  96.         } elseif (null !== $this->lastResponse) { // not cacheable
  97.             $response->setPrivate();
  98.             $response->setTtl(0);
  99.             $response->headers->removeCacheControlDirective('s-maxage');
  100.             $response->headers->removeCacheControlDirective('maxage');
  101.         }
  102.         // no more children available in the stack, reseting the state object
  103.         if (!$blockContext->getBlock()->hasParent()) {
  104.             $this->lastResponse null;
  105.         } else { // contains a parent so storing the response
  106.             $this->lastResponse $response;
  107.         }
  108.         return $response;
  109.     }
  110. }