From b989298986d3fc1aaa01d2b70acfb7d254af9c00 Mon Sep 17 00:00:00 2001 From: Dave Reid Date: Tue, 10 Jun 2014 14:03:24 -0500 Subject: [PATCH 1/3] Adds EntityEmbedPostRenderCache service class. --- entity_embed.services.yml | 3 + src/EntityEmbedPostRenderCache.php | 121 ++++++++++++++++++++++++ src/Plugin/Filter/EntityEmbedFilter.php | 69 +------------- 3 files changed, 125 insertions(+), 68 deletions(-) create mode 100644 src/EntityEmbedPostRenderCache.php diff --git a/entity_embed.services.yml b/entity_embed.services.yml index 1ac4fff4..00de00bc 100644 --- a/entity_embed.services.yml +++ b/entity_embed.services.yml @@ -2,3 +2,6 @@ services: plugin.manager.entity_embed.display: class: Drupal\entity_embed\EntityEmbedDisplay\EntityEmbedDisplayManager arguments: ['@container.namespaces', '@cache.discovery', '@language_manager', '@module_handler', '@string_translation'] + entity_embed.post_render_cache: + class: Drupal\entity_embed\EntityEmbedPostRenderCache + arguments: ['@entity.manager', '@module_handler', '@plugin.manager.entity_embed.display'] \ No newline at end of file diff --git a/src/EntityEmbedPostRenderCache.php b/src/EntityEmbedPostRenderCache.php new file mode 100644 index 00000000..24d9442e --- /dev/null +++ b/src/EntityEmbedPostRenderCache.php @@ -0,0 +1,121 @@ +setEntityManager($entity_manager); + $this->moduleHandler = $module_handler; + $this->pluginManager = $plugin_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity.manager'), + $container->get('module_handler'), + $container->get('plugin.manager.entity_embed.display') + ); + } + + /** + * #post_render_cache callback; renders an embedded entity. + * + * Replaces the #post_render_cache placeholder with an embedded entity. + * + * @param array $element + * The renderable array that contains the to be replaced placeholder. + * @param array $context + * An array with the following keys: + * - entity-type: The entity type. + * - entity-id: The entity ID. + * - token: The placeholder token generated in buildPlaceholder(). + * + * @return array + * A renderable array representing the placeholder replaced with the + * rendered entity. + */ + public function renderEmbed(array $element, array $context) { + $callback = 'entity_embed.post_render_cache:renderEmbed'; + $placeholder = drupal_render_cache_generate_placeholder($callback, $context); + + // Do not bother rendering the entity if the placeholder cannot be found. + if (strpos($element['#markup'], $placeholder) === FALSE) { + return $element; + } + + $entity_output = ''; + try { + // Protect ourselves from recursive rendering. + static $depth = 0; + $depth++; + if ($depth > 20) { + throw new RecursiveRenderingException(format_string('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $this->entity->getEntityTypeId(), '@entity_id' => $this->entity->id()))); + } + + if ($entity = $this->loadEntity($context['entity-type'], $context['entity-id'])) { + // Allow modules to alter the entity prior to display rendering. + $this->moduleHandler->invokeAll('entity_preembed', array($entity, $context)); + // Build the display plugin. + $display = $this->pluginManager->createInstance($context['entity-embed-display'], $context['entity-embed-settings']); + $display->setContextValue('entity', $entity); + $display->setAttributes($context); + // Check if the display plugin is accessible. This also checks entity + // access, which is why we never call $entity->access() here. + if ($display->access()) { + $build = $display->build(); + // Allow modules to alter the rendered embedded entity. + $this->moduleHandler->alter('entity_embed', $build, $display); + $entity_output = drupal_render($build); + } + } + + $depth--; + } + catch (\Exception $e) { + watchdog_exception('entity_embed', $e); + } + + $element['#markup'] = str_replace($placeholder, $entity_output, $element['#markup']); + return $element; + } +} \ No newline at end of file diff --git a/src/Plugin/Filter/EntityEmbedFilter.php b/src/Plugin/Filter/EntityEmbedFilter.php index 024b38bc..49b401e6 100644 --- a/src/Plugin/Filter/EntityEmbedFilter.php +++ b/src/Plugin/Filter/EntityEmbedFilter.php @@ -13,7 +13,6 @@ use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\entity_embed\EntityHelperTrait; -use Drupal\entity_embed\RecursiveRenderingException; use Drupal\filter\FilterProcessResult; use Drupal\filter\Plugin\FilterBase; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -173,7 +172,7 @@ public function tips($long = FALSE) { * drupal_render_cache_generate_placeholder(). */ public function buildPlaceholder(EntityInterface $entity, FilterProcessResult $result, array $context = array()) { - $callback = get_called_class() . '::postRender'; + $callback = 'entity_embed.post_render_cache:renderEmbed'; $context += array( 'entity-type' => $entity->getEntityTypeId(), 'entity-id' => $entity->id(), @@ -197,72 +196,6 @@ public function buildPlaceholder(EntityInterface $entity, FilterProcessResult $r return $placeholder; } - /** - * #post_render_cache callback; renders an embedded entity. - * - * Replaces the #post_render_cache placeholder with an embedded entity. - * - * @param array $element - * The renderable array that contains the to be replaced placeholder. - * @param array $context - * An array with the following keys: - * - entity-type: The entity type. - * - entity-id: The entity ID. - * - token: The placeholder token generated in buildPlaceholder(). - * - * @return array - * A renderable array representing the placeholder replaced with the - * rendered entity. - */ - public static function postRender(array $element, array $context) { - $callback = get_called_class() . '::postRender'; - $placeholder = drupal_render_cache_generate_placeholder($callback, $context); - - // Do not bother rendering the entity if the placeholder cannot be found. - if (strpos($element['#markup'], $placeholder) === FALSE) { - return $element; - } - - $entity_output = ''; - try { - // Protect ourselves from recursive rendering. - static $depth = 0; - $depth++; - if ($depth > 20) { - throw new RecursiveRenderingException(format_string('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $this->entity->getEntityTypeId(), '@entity_id' => $this->entity->id()))); - } - - if ($entity = entity_load($context['entity-type'], $context['entity-id'])) { - // @todo, This direct usage can be replaced with injection following - // https://drupal.org/node/2247779 . - // @see https://drupal.org/node/2281487 . - // Allow modules to alter the entity prior to display rendering. - \Drupal::moduleHandler()->invokeAll('entity_preembed', array($entity, $context)); - // Build the display plugin. - $manager = \Drupal::service('plugin.manager.entity_embed.display'); - $display = $manager->createInstance($context['entity-embed-display'], $context['entity-embed-settings']); - $display->setContextValue('entity', $entity); - $display->setAttributes($context); - // Check if the display plugin is accessible. This also checks entity - // access, which is why we never call $entity->access() here. - if ($display->access()) { - $build = $display->build(); - // Allow modules to alter the rendered embedded entity. - \Drupal::moduleHandler()->alter('entity_embed', $build, $display); - $entity_output = drupal_render($build); - } - } - - $depth--; - } - catch (\Exception $e) { - watchdog_exception('entity_embed', $e); - } - - $element['#markup'] = str_replace($placeholder, $entity_output, $element['#markup']); - return $element; - } - /** * Replace the contents of a DOMNode. * From 193c0bc14efbe760596fd9bdd611c7e3ad3b20ef Mon Sep 17 00:00:00 2001 From: Dave Reid Date: Tue, 10 Jun 2014 14:04:43 -0500 Subject: [PATCH 2/3] Added docs for core patch. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c74d39b9..b568554e 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ ## Requirements -* Drupal 8 core must have a current patch from https://drupal.org/node/2217877 - applied. +* Drupal 8 core must have a current patch from https://drupal.org/node/2247779 +* applied. ## Usage From 84f01a496d8796c3c3600fd064f720f53f6734f7 Mon Sep 17 00:00:00 2001 From: Dave Reid Date: Sat, 14 Jun 2014 06:01:29 -0500 Subject: [PATCH 3/3] Added EntityHelperTrait::renderEntityEmbedDisplayPlugin(). --- src/EntityEmbedPostRenderCache.php | 49 ++------- src/EntityHelperTrait.php | 126 +++++++++++++++++++++++- src/Plugin/Filter/EntityEmbedFilter.php | 11 +-- 3 files changed, 133 insertions(+), 53 deletions(-) diff --git a/src/EntityEmbedPostRenderCache.php b/src/EntityEmbedPostRenderCache.php index 24d9442e..13d63bd7 100644 --- a/src/EntityEmbedPostRenderCache.php +++ b/src/EntityEmbedPostRenderCache.php @@ -16,20 +16,6 @@ class EntityEmbedPostRenderCache { use EntityHelperTrait; - /** - * The Module Handler. - * - * @var \Drupal\Core\Extension\ModuleHandlerInterface. - */ - protected $moduleHandler; - - /** - * The display plugin manager. - * - * @var \Drupal\entity_embed\EntityEmbedDisplay\EntityEmbedDisplayManager. - */ - protected $pluginManager; - /** * Constructs a EntityEmbedPostRenderCache object. * @@ -42,8 +28,8 @@ class EntityEmbedPostRenderCache { */ public function __construct(EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, EntityEmbedDisplayManager $plugin_manager) { $this->setEntityManager($entity_manager); - $this->moduleHandler = $module_handler; - $this->pluginManager = $plugin_manager; + $this->setModuleHandler($module_handler); + $this->setDisplayPluginManager($plugin_manager); } /** @@ -85,31 +71,14 @@ public function renderEmbed(array $element, array $context) { $entity_output = ''; try { - // Protect ourselves from recursive rendering. - static $depth = 0; - $depth++; - if ($depth > 20) { - throw new RecursiveRenderingException(format_string('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $this->entity->getEntityTypeId(), '@entity_id' => $this->entity->id()))); - } - if ($entity = $this->loadEntity($context['entity-type'], $context['entity-id'])) { - // Allow modules to alter the entity prior to display rendering. - $this->moduleHandler->invokeAll('entity_preembed', array($entity, $context)); - // Build the display plugin. - $display = $this->pluginManager->createInstance($context['entity-embed-display'], $context['entity-embed-settings']); - $display->setContextValue('entity', $entity); - $display->setAttributes($context); - // Check if the display plugin is accessible. This also checks entity - // access, which is why we never call $entity->access() here. - if ($display->access()) { - $build = $display->build(); - // Allow modules to alter the rendered embedded entity. - $this->moduleHandler->alter('entity_embed', $build, $display); - $entity_output = drupal_render($build); - } + $entity_output = $this->renderEntityEmbedDisplayPlugin( + $entity, + $context['entity-embed-display'], + $context['entity-embed-settings'], + $context + ); } - - $depth--; } catch (\Exception $e) { watchdog_exception('entity_embed', $e); @@ -118,4 +87,4 @@ public function renderEmbed(array $element, array $context) { $element['#markup'] = str_replace($placeholder, $entity_output, $element['#markup']); return $element; } -} \ No newline at end of file +} diff --git a/src/EntityHelperTrait.php b/src/EntityHelperTrait.php index 18c4682e..e2ddab1f 100644 --- a/src/EntityHelperTrait.php +++ b/src/EntityHelperTrait.php @@ -10,7 +10,9 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityStorageException; +use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Session\AccountInterface; +use Drupal\entity_embed\EntityEmbedDisplay\EntityEmbedDisplayManager; /** * Wrapper methods for entity loading and rendering. @@ -29,6 +31,20 @@ trait EntityHelperTrait { */ protected $entityManager; + /** + * The module handler service. + * + * @var \Drupal\Core\Extension\ModuleHandlerInterface. + */ + protected $moduleHandler; + + /** + * The display plugin manager. + * + * @var \Drupal\entity_embed\EntityEmbedDisplay\EntityEmbedDisplayManager. + */ + protected $displayPluginManager; + /** * Loads an entity from the database. * @@ -112,6 +128,56 @@ protected function renderEntity(EntityInterface $entity, $view_mode, $langcode = return $render_controller->view($entity, $view_mode, $langcode); } + /** + * Renders an entity using an EntityEmbedDisplay plugin. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity to be rendered. + * @param string $plugin_id + * The EntityEmbedDisplay plugin ID. + * @param array $plugin_configuration + * (optional) Array of plugin configuration values. + * @param array $context + * (optional) Array of additional context values, usually the embed HTML + * tag's attributes. + * + * @return string + * The HTML of the entity rendered with the display plugin. + * + * @throws \Drupal\entity_embed\RecursiveRenderingException; + */ + protected function renderEntityEmbedDisplayPlugin(EntityInterface $entity, $plugin_id, array $plugin_configuration = array(), array $context = array()) { + // Protect ourselves from recursive rendering. + static $depth = 0; + $depth++; + if ($depth > 20) { + throw new RecursiveRenderingException(format_string('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $entity->getEntityTypeId(), '@entity_id' => $entity->id()))); + } + + // Allow modules to alter the entity prior to display rendering. + $this->moduleHandler()->invokeAll('entity_preembed', array($entity, $context)); + + // Build the display plugin. + $display = $this->displayPluginManager()->createInstance($plugin_id, $plugin_configuration); + $display->setContextValue('entity', $entity); + $display->setAttributes($context); + + // Check if the display plugin is accessible. This also checks entity + // access, which is why we never call $entity->access() here. + if (!$display->access()) { + return ''; + } + + // Build and render the display plugin, allowing modules to alter the + // result before rendering. + $build = $display->build(); + $this->moduleHandler()->alter('entity_embed', $build, $display); + $entity_output = drupal_render($build); + + $depth--; + return $entity_output; + } + /** * Check access to an entity. * @@ -126,7 +192,7 @@ protected function renderEntity(EntityInterface $entity, $view_mode, $langcode = * @return bool|null * self::ALLOW, self::DENY, or self::KILL. */ - protected function accessEntity(EntityInterface $entity, $operation = 'view', AccountInterface $account = NULL) { + protected function accessEntity(EntityInterface $entity, $op = 'view', AccountInterface $account = NULL) { switch ($entity->getEntityTypeId()) { case 'file': // Due to issues with access checking with file entities in core, @@ -142,7 +208,7 @@ protected function accessEntity(EntityInterface $entity, $operation = 'view', Ac case 'private': case 'temporary': - $headers = \Drupal::moduleHandler()->invokeAll('file_download', array($uri)); + $headers = $this->moduleHandler()->invokeAll('file_download', array($uri)); foreach ($headers as $result) { if ($result == -1) { return FALSE; @@ -156,7 +222,7 @@ protected function accessEntity(EntityInterface $entity, $operation = 'view', Ac } default: - return $entity->access('view', $account); + return $entity->access($op, $account); } } @@ -168,7 +234,7 @@ protected function accessEntity(EntityInterface $entity, $operation = 'view', Ac */ protected function entityManager() { if (!isset($this->entityManager)) { - $this->entityManager = \Drupal::service('entity.manager'); + $this->entityManager = \Drupal::entityManager(); } return $this->entityManager; } @@ -185,4 +251,56 @@ public function setEntityManager(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; return $this; } + + /** + * Returns the module handler. + * + * @return \Drupal\Core\Extension\ModuleHandlerInterface + * The module handler. + */ + protected function moduleHandler() { + if (!isset($this->moduleHandler)) { + $this->moduleHandler = \Drupal::moduleHandler(); + } + return $this->moduleHandler; + } + + /** + * Sets the module handler service. + * + * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler + * The module handler service. + * + * @return self + */ + public function setModuleHandler(ModuleHandlerInterface $moduleHandler) { + $this->moduleHandler = $moduleHandler; + return $this; + } + + /** + * Returns the display plugin manager. + * + * @return \Drupal\entity_embed\EntityEmbedDisplay\EntityEmbedDisplayManager + * The display plugin manager. + */ + protected function displayPluginManager() { + if (!isset($this->displayPluginManager)) { + $this->displayPluginManager = \Drupal::service('plugin.manager.entity_embed.display'); + } + return $this->displayPluginManager; + } + + /** + * Sets the display plugin manager service. + * + * @param \Drupal\entity_embed\EntityEmbedDisplay\EntityEmbedDisplayManager $displayPluginManager + * The display plugin manager service. + * + * @return self + */ + public function setDisplayPluginManager(EntityEmbedDisplayManager $displayPluginManager) { + $this->displayPluginManager = $displayPluginManager; + return $this; + } } diff --git a/src/Plugin/Filter/EntityEmbedFilter.php b/src/Plugin/Filter/EntityEmbedFilter.php index 49b401e6..2828d1bd 100644 --- a/src/Plugin/Filter/EntityEmbedFilter.php +++ b/src/Plugin/Filter/EntityEmbedFilter.php @@ -30,13 +30,6 @@ class EntityEmbedFilter extends FilterBase implements ContainerFactoryPluginInterface { use EntityHelperTrait; - /** - * The Module Handler. - * - * @var \Drupal\Core\Extension\ModuleHandlerInterface. - */ - protected $moduleHandler; - /** * Constructs a EntityEmbedFilter object. * @@ -54,7 +47,7 @@ class EntityEmbedFilter extends FilterBase implements ContainerFactoryPluginInte public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->setEntityManager($entity_manager); - $this->moduleHandler = $module_handler; + $this->setModuleHandler($module_handler); } /** @@ -182,7 +175,7 @@ public function buildPlaceholder(EntityInterface $entity, FilterProcessResult $r ); // Allow modules to alter the context. - $this->moduleHandler->alter('entity_embed_context', $context, $callback, $entity); + $this->moduleHandler()->alter('entity_embed_context', $context, $callback, $entity); $placeholder = drupal_render_cache_generate_placeholder($callback, $context);