Commit 21a74534 authored by Matt Glaman's avatar Matt Glaman
Browse files

Issue #3160511 by nikolay.sh, mglaman: Prevent recursive rendering

parent 68a914ed
Loading
Loading
Loading
Loading
+44 −2
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
@@ -24,6 +25,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 */
class EntityBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * The number of times this block allows rendering the same entity.
   *
   * @var int
   */
  const RECURSIVE_RENDER_LIMIT = 3;

  /**
   * The name of our entity type.
   *
@@ -59,10 +67,24 @@ class EntityBlock extends BlockBase implements ContainerFactoryPluginInterface {
   */
  protected $view_mode_options;

  /**
   * An array of counters for the recursive rendering protection.
   *
   * @var array
   */
  protected static $recursiveRenderDepth = [];

  /**
   * The logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerFactory;

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entityTypeManager, EntityDisplayRepositoryInterface $entityDisplayRepository) {
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entityTypeManager, EntityDisplayRepositoryInterface $entityDisplayRepository, LoggerChannelFactoryInterface $logger_factory) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);

    // Determine what entity type we are referring to.
@@ -82,6 +104,7 @@ class EntityBlock extends BlockBase implements ContainerFactoryPluginInterface {
    }

    $this->view_mode_options = $entityDisplayRepository->getViewModeOptions($this->entityTypeName);
    $this->loggerFactory = $logger_factory;
  }

  /**
@@ -91,7 +114,8 @@ class EntityBlock extends BlockBase implements ContainerFactoryPluginInterface {
    return new static(
      $configuration, $plugin_id, $plugin_definition,
      $container->get('entity_type.manager'),
      $container->get('entity_display.repository')
      $container->get('entity_display.repository'),
      $container->get('logger.factory')
    );
  }

@@ -169,6 +193,24 @@ class EntityBlock extends BlockBase implements ContainerFactoryPluginInterface {
   */
  public function build() {
    if ($entity = $this->getEntity()) {
      $recursive_render_id = $entity->getEntityTypeId() . ':' . $entity->id();
      if (isset(static::$recursiveRenderDepth[$recursive_render_id])) {
        static::$recursiveRenderDepth[$recursive_render_id]++;
      }
      else {
        static::$recursiveRenderDepth[$recursive_render_id] = 1;
      }

      // Protect recursive rendering.
      if (static::$recursiveRenderDepth[$recursive_render_id] > static::RECURSIVE_RENDER_LIMIT) {
        $this->loggerFactory->get('entity')->error('Recursive rendering detected when rendering embedded entity %entity_type: %entity_id. Aborting rendering.', [
          '%entity_type' => $entity->getEntityTypeId(),
          '%entity_id' => $entity->id(),
        ]);

//        return [];
      }

      $render_controller = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId());
      $view_mode = $this->configuration['view_mode'] ?? 'default';

+34 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ final class EntityBlockTest extends EntityKernelTestBase {
    $entity = EntityTest::create([
      'name' => $this->randomString(),
    ]);
    $entity->save();
    $block = Block::create([
      'id' => strtolower($this->randomMachineName()),
      'theme' => 'stark',
@@ -50,4 +51,37 @@ final class EntityBlockTest extends EntityKernelTestBase {
    $this->assertConfigSchemaByName($block->getConfigDependencyName());
  }

  public function testBuild(): void {
    $entity = EntityTest::create([
      'name' => $this->randomString(),
    ]);
    $entity->save();
    $block = Block::create([
      'id' => strtolower($this->randomMachineName()),
      'theme' => 'stark',
      'weight' => 0,
      'status' => TRUE,
      'region' => 'content',
      'plugin' => 'entity_block:entity_test',
      'settings' => [
        'label' => $this->randomString(),
        'provider' => 'entity_block',
        'label_display' => FALSE,
        'entity' => $entity->id(),
      ],
      'visibility' => [],
    ]);
    $block->save();

    $view_builder_build = $this->container->get('entity_type.manager')
      ->getViewBuilder('entity_test')
      ->view($entity, 'default');
    unset($view_builder_build['#entity_test']);

    $block_build = $block->getPlugin()->build();
    unset($block_build['#entity_test']);
    self::assertEquals($view_builder_build, $block_build);

  }

}