vendor/sonata-project/block-bundle/src/Block/BlockContextManager.php line 241

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 Doctrine\Common\Util\ClassUtils;
  13. use Psr\Log\LoggerInterface;
  14. use Sonata\BlockBundle\Model\BlockInterface;
  15. use Symfony\Component\OptionsResolver\Exception\ExceptionInterface;
  16. use Symfony\Component\OptionsResolver\OptionsResolver;
  17. use Symfony\Component\OptionsResolver\OptionsResolverInterface;
  18. /**
  19.  * @final since sonata-project/block-bundle 3.0
  20.  */
  21. class BlockContextManager implements BlockContextManagerInterface
  22. {
  23.     /**
  24.      * @var BlockLoaderInterface
  25.      */
  26.     protected $blockLoader;
  27.     /**
  28.      * @var BlockServiceManagerInterface
  29.      */
  30.     protected $blockService;
  31.     /**
  32.      * @var array
  33.      */
  34.     protected $settingsByType;
  35.     /**
  36.      * @var array
  37.      */
  38.     protected $settingsByClass;
  39.     /**
  40.      * @var array
  41.      */
  42.     protected $cacheBlocks;
  43.     /**
  44.      * @var LoggerInterface
  45.      */
  46.     protected $logger;
  47.     /**
  48.      * Used for deprecation check on {@link resolve} method.
  49.      * To be removed in 4.0 with BC system.
  50.      *
  51.      * @var array
  52.      */
  53.     private $reflectionCache;
  54.     public function __construct(BlockLoaderInterface $blockLoaderBlockServiceManagerInterface $blockService,
  55.         array $cacheBlocks = [], LoggerInterface $logger null
  56.     ) {
  57.         $this->blockLoader $blockLoader;
  58.         $this->blockService $blockService;
  59.         $this->cacheBlocks $cacheBlocks;
  60.         $this->logger $logger;
  61.         $this->reflectionCache = [];
  62.     }
  63.     public function addSettingsByType($type, array $settings$replace false)
  64.     {
  65.         $typeSettings = isset($this->settingsByType[$type]) ? $this->settingsByType[$type] : [];
  66.         if ($replace) {
  67.             $this->settingsByType[$type] = array_merge($typeSettings$settings);
  68.         } else {
  69.             $this->settingsByType[$type] = array_merge($settings$typeSettings);
  70.         }
  71.     }
  72.     public function addSettingsByClass($class, array $settings$replace false)
  73.     {
  74.         $classSettings = isset($this->settingsByClass[$class]) ? $this->settingsByClass[$class] : [];
  75.         if ($replace) {
  76.             $this->settingsByClass[$class] = array_merge($classSettings$settings);
  77.         } else {
  78.             $this->settingsByClass[$class] = array_merge($settings$classSettings);
  79.         }
  80.     }
  81.     /**
  82.      * Check if a given block type exists.
  83.      *
  84.      * @param string $type Block type to check for
  85.      *
  86.      * @return bool
  87.      */
  88.     public function exists($type)
  89.     {
  90.         return $this->blockLoader->exists($type);
  91.     }
  92.     public function get($meta, array $settings = [])
  93.     {
  94.         if (!$meta instanceof BlockInterface) {
  95.             $block $this->blockLoader->load($meta);
  96.             if (\is_array($meta) && isset($meta['settings'])) {
  97.                 // merge user settings
  98.                 $settings array_merge($meta['settings'], $settings);
  99.             }
  100.         } else {
  101.             $block $meta;
  102.         }
  103.         if (!$block instanceof BlockInterface) {
  104.             return false;
  105.         }
  106.         $originalSettings $settings;
  107.         try {
  108.             $settings $this->resolve($blockarray_merge($block->getSettings(), $settings));
  109.         } catch (ExceptionInterface $e) {
  110.             if ($this->logger) {
  111.                 $this->logger->error(sprintf(
  112.                     '[cms::blockContext] block.id=%s - error while resolving options - %s',
  113.                     $block->getId(),
  114.                     $e->getMessage()
  115.                 ));
  116.             }
  117.             $settings $this->resolve($block$settings);
  118.         }
  119.         $blockContext = new BlockContext($block$settings);
  120.         $this->setDefaultExtraCacheKeys($blockContext$originalSettings);
  121.         return $blockContext;
  122.     }
  123.     /**
  124.      * NEXT_MAJOR: remove this method.
  125.      *
  126.      * @deprecated since sonata-project/block-bundle 2.3, to be renamed in 4.0.
  127.      *             Use the method configureSettings instead
  128.      */
  129.     protected function setDefaultSettings(OptionsResolverInterface $optionsResolverBlockInterface $block)
  130.     {
  131.         if (__CLASS__ !== static::class) {
  132.             @trigger_error(
  133.                 'The '.__METHOD__.' is deprecated since version 2.3, to be renamed in 4.0.'
  134.                 .' Use '.__CLASS__.'::configureSettings instead.',
  135.                 E_USER_DEPRECATED
  136.             );
  137.         }
  138.         $this->configureSettings($optionsResolver$block);
  139.     }
  140.     protected function configureSettings(OptionsResolver $optionsResolverBlockInterface $block)
  141.     {
  142.         // defaults for all blocks
  143.         $optionsResolver->setDefaults([
  144.             'use_cache' => true,
  145.             'extra_cache_keys' => [],
  146.             'attr' => [],
  147.             'template' => false,
  148.             'ttl' => (int) $block->getTtl(),
  149.         ]);
  150.         $optionsResolver
  151.             ->addAllowedTypes('use_cache''bool')
  152.             ->addAllowedTypes('extra_cache_keys''array')
  153.             ->addAllowedTypes('attr''array')
  154.             ->addAllowedTypes('ttl''int')
  155.             ->addAllowedTypes('template', ['string''bool'])
  156.         ;
  157.         // add type and class settings for block
  158.         $class ClassUtils::getClass($block);
  159.         $settingsByType = isset($this->settingsByType[$block->getType()]) ? $this->settingsByType[$block->getType()] : [];
  160.         $settingsByClass = isset($this->settingsByClass[$class]) ? $this->settingsByClass[$class] : [];
  161.         $optionsResolver->setDefaults(array_merge($settingsByType$settingsByClass));
  162.     }
  163.     /**
  164.      * Adds context settings, to be able to rebuild a block context, to the
  165.      * extra_cache_keys.
  166.      */
  167.     protected function setDefaultExtraCacheKeys(BlockContextInterface $blockContext, array $settings)
  168.     {
  169.         if (!$blockContext->getSetting('use_cache') || $blockContext->getSetting('ttl') <= 0) {
  170.             return;
  171.         }
  172.         $block $blockContext->getBlock();
  173.         // type by block class
  174.         $class ClassUtils::getClass($block);
  175.         $cacheServiceId = isset($this->cacheBlocks['by_class'][$class]) ? $this->cacheBlocks['by_class'][$class] : false;
  176.         // type by block service
  177.         if (!$cacheServiceId) {
  178.             $cacheServiceId = isset($this->cacheBlocks['by_type'][$block->getType()]) ? $this->cacheBlocks['by_type'][$block->getType()] : false;
  179.         }
  180.         if (!$cacheServiceId) {
  181.             // no context cache needed
  182.             return;
  183.         }
  184.         // do not add cache settings to extra_cache_keys
  185.         unset($settings['use_cache'], $settings['extra_cache_keys'], $settings['ttl']);
  186.         $extraCacheKeys $blockContext->getSetting('extra_cache_keys');
  187.         // add context settings to extra_cache_keys
  188.         if (!isset($extraCacheKeys[self::CACHE_KEY])) {
  189.             $extraCacheKeys[self::CACHE_KEY] = $settings;
  190.             $blockContext->setSetting('extra_cache_keys'$extraCacheKeys);
  191.         }
  192.     }
  193.     /**
  194.      * @param array $settings
  195.      *
  196.      * @return array
  197.      */
  198.     private function resolve(BlockInterface $block$settings)
  199.     {
  200.         $optionsResolver = new \Sonata\BlockBundle\Util\OptionsResolver();
  201.         $this->configureSettings($optionsResolver$block);
  202.         $service $this->blockService->get($block);
  203.         // Caching method reflection
  204.         // NEXT_MAJOR: Remove everything here
  205.         $serviceClass = \get_class($service);
  206.         if (!isset($this->reflectionCache[$serviceClass])) {
  207.             $reflector = new \ReflectionMethod($service'setDefaultSettings');
  208.             $isOldOverwritten = \get_class($service) === $reflector->getDeclaringClass()->getName();
  209.             // Prevention for service classes implementing directly the interface and not extends the new base class
  210.             if (!method_exists($service'configureSettings')) {
  211.                 $isNewOverwritten false;
  212.             } else {
  213.                 $reflector = new \ReflectionMethod($service'configureSettings');
  214.                 $isNewOverwritten = \get_class($service) === $reflector->getDeclaringClass()->getName();
  215.             }
  216.             $this->reflectionCache[$serviceClass] = [
  217.                 'isOldOverwritten' => $isOldOverwritten,
  218.                 'isNewOverwritten' => $isNewOverwritten,
  219.             ];
  220.         }
  221.         // NEXT_MAJOR: Keep Only else case
  222.         if ($this->reflectionCache[$serviceClass]['isOldOverwritten'] && !$this->reflectionCache[$serviceClass]['isNewOverwritten']) {
  223.             @trigger_error(
  224.                 'The Sonata\BlockBundle\Block\BlockServiceInterface::setDefaultSettings() method is deprecated'
  225.                 .' since version 2.3 and will be removed in 4.0. Use configureSettings() instead.'
  226.                 .' This method will be added to the BlockServiceInterface with SonataBlockBundle 4.0.',
  227.                 E_USER_DEPRECATED
  228.             );
  229.             $service->setDefaultSettings($optionsResolver);
  230.         } else {
  231.             $service->configureSettings($optionsResolver);
  232.         }
  233.         return $optionsResolver->resolve($settings);
  234.     }
  235. }