class EntityRenderHandler in Acquia Lift Connector 8.4
Class EntityRenderHandler.
@package Drupal\acquia_lift_publisher\EventSubscriber\Cdf
Hierarchy
- class \Drupal\acquia_lift_publisher\EventSubscriber\Cdf\EntityRenderHandler implements \Symfony\Component\EventDispatcher\EventSubscriberInterface uses ContentPublishingSettingsTrait
Expanded class hierarchy of EntityRenderHandler
1 file declares its use of EntityRenderHandler
- EntityRenderHandlerTest.php in modules/
acquia_lift_publisher/ tests/ src/ Kernel/ EventSubscriber/ Cdf/ EntityRenderHandlerTest.php
1 string reference to 'EntityRenderHandler'
- acquia_lift_publisher.services.yml in modules/
acquia_lift_publisher/ acquia_lift_publisher.services.yml - modules/acquia_lift_publisher/acquia_lift_publisher.services.yml
1 service uses EntityRenderHandler
File
- modules/
acquia_lift_publisher/ src/ EventSubscriber/ Cdf/ EntityRenderHandler.php, line 32
Namespace
Drupal\acquia_lift_publisher\EventSubscriber\CdfView source
class EntityRenderHandler implements EventSubscriberInterface {
use ContentPublishingSettingsTrait;
/**
* The account switcher.
*
* @var \Drupal\Core\Session\AccountSwitcherInterface
*/
protected $accountSwitcher;
/**
* The origin uuid.
*
* @var string
*/
protected $origin;
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The Block Manager.
*
* @var \Drupal\Core\Block\BlockManagerInterface
*/
protected $blockManager;
/**
* The uuid generator.
*
* @var \Drupal\Component\Uuid\UuidInterface
*/
protected $uuidGenerator;
/**
* The rendered user.
*
* @var \Drupal\Core\Session\UserSession
*/
protected $renderUser;
/**
* The storage.
*
* @var array
*/
protected $storage = [];
/**
* The client factory.
*
* @var \Drupal\acquia_contenthub\Client\ClientFactory
*/
protected $clientFactory;
/**
* The language default service.
*
* @var \Drupal\Core\Language\LanguageDefault
*/
protected $languageDefault;
/**
* Translation manager.
*
* @var \Drupal\Core\StringTranslation\TranslationManager
*/
protected $translationManager;
/**
* EntityRenderHandler constructor.
*
* @param \Drupal\Core\Session\AccountSwitcherInterface $account_switcher
* The account switcher.
* @param \Drupal\Core\Config\ImmutableConfig $config
* The Acquia Lift publishing configuration object.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Block\BlockManagerInterface $block_manager
* The block manager.
* @param \Drupal\Component\Uuid\UuidInterface $uuid_generator
* The UUID generator.
* @param \Drupal\acquia_contenthub\Client\ClientFactory $client_factory
* The client factory.
*/
public function __construct(AccountSwitcherInterface $account_switcher, ImmutableConfig $config, RendererInterface $renderer, EntityTypeManagerInterface $entity_type_manager, BlockManagerInterface $block_manager, UuidInterface $uuid_generator, ClientFactory $client_factory, LanguageDefault $language_default, TranslationManager $translation_manager) {
$this->accountSwitcher = $account_switcher;
$this->publisherSettings = $config;
$this->clientFactory = $client_factory;
$this->origin = $client_factory
->getSettings()
->getUuid();
$this->renderer = $renderer;
$this->entityTypeManager = $entity_type_manager;
$this->blockManager = $block_manager;
$this->uuidGenerator = $uuid_generator;
$this->languageDefault = $language_default;
$this->translationManager = $translation_manager;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[AcquiaContentHubEvents::CREATE_CDF_OBJECT][] = [
'onCreateCdf',
100,
];
return $events;
}
/**
* Actions on create CDF.
*
* @param \Drupal\acquia_contenthub\Event\CreateCdfEntityEvent $event
* The create CDF entity event.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function onCreateCdf(CreateCdfEntityEvent $event) {
$entity = $event
->getEntity();
if (!$entity instanceof ContentEntityInterface) {
// @todo we should support config entity rendering too.
return;
}
if ($view_modes = $this
->getEntityViewModesSettingValue($entity)) {
$client = $this->clientFactory
->getClient();
if (!is_object($client)) {
return;
}
$document = $client
->getEntities([
$entity
->uuid(),
]);
$remote_entity = $document
->hasEntity($entity
->uuid()) ? $document
->getCDFEntity($entity
->uuid()) : FALSE;
$default_lang = $this->languageDefault
->get();
foreach (array_keys($view_modes) as $view_mode) {
// The preview image field setting is saved along side the view modes.
// Don't process it as one.
if ($view_mode == 'acquia_lift_preview_image') {
continue;
}
foreach ($entity
->getTranslationLanguages() as $language) {
$translation = $entity
->getTranslation($language
->getId());
if ($remote_entity instanceof CDFObject) {
$uuid = $this
->getRenderUuid($remote_entity, $view_mode, $language
->getId());
}
else {
$uuid = $this->uuidGenerator
->generate();
}
$cdf = new CDFObject('rendered_entity', $uuid, date('c'), date('c'), $this->origin);
$this->languageDefault
->set($language);
$this->translationManager
->setDefaultLangcode($language
->getId());
$standard_languages = LanguageManager::getStandardLanguageList();
if (isset($standard_languages[$language
->getId()][1])) {
$language_native_label = $standard_languages[$language
->getId()][1];
}
else {
$language_native_label = $language
->getName();
}
// Getting fake user account to give as context to the normalization.
$account = $this
->getRenderUser();
// Checking for entity access permission to this particular account.
$entity_access = $translation
->access('view', $account, TRUE);
// Switch to render account.
$this->accountSwitcher
->switchTo($account);
$elements = [];
if ($entity_access
->isAllowed()) {
$elements = $this
->getViewModeMinimalHtml($translation, $view_mode);
}
$html = $this->renderer
->renderPlain($elements);
// Restore user account.
$this->accountSwitcher
->switchBack();
$metadata['data'] = base64_encode($html);
$cdf
->addAttribute('content', CDFAttribute::TYPE_STRING, trim(preg_replace('/\\s+/', ' ', str_replace("\n", ' ', strip_tags($html)))));
$cdf
->addAttribute('source_entity', CDFAttribute::TYPE_STRING, $translation
->uuid());
$cdf
->addAttribute('label', CDFAttribute::TYPE_ARRAY_STRING, $translation
->label(), $translation
->language()
->getId());
$cdf
->addAttribute('language', CDFAttribute::TYPE_STRING, $language
->getId());
$cdf
->addAttribute('language_label', CDFAttribute::TYPE_STRING, $language_native_label);
$cdf
->addAttribute('view_mode', CDFAttribute::TYPE_STRING, $view_mode);
$cdf
->addAttribute('view_mode_label', CDFAttribute::TYPE_STRING, $view_mode);
$preview_src = $this
->buildPreviewImageAttributeSource($view_modes, 'acquia_lift_preview_image', 'acquia_lift_publisher_preview_image', $translation);
if (!empty($preview_src)) {
$cdf
->addAttribute('preview_image', CDFAttribute::TYPE_STRING, $preview_src);
}
$cdf
->setMetadata($metadata);
$event
->addCdf($cdf);
}
}
$this->languageDefault
->set($default_lang);
$this->translationManager
->setDefaultLangcode($default_lang
->getId());
}
}
/**
* Build a preview image attribute source.
*
* @param $view_modes
* View modes available to check.
* @param $preview_view_mode
* View mode that represents the preview image.
* @param $style
* Image style for the preview image.
* @param $translation
* Translation to use to build the source.
*
* @return string|null
* The source string returned or nothing.
*/
protected function buildPreviewImageAttributeSource($view_modes, $preview_view_mode, $style, $translation) {
// Does the view mode exist?
if (empty($view_modes[$preview_view_mode])) {
return NULL;
}
// Can we load this view mode?
$preview_image = $translation->{$view_modes[$preview_view_mode]}
->first();
if (empty($preview_image)) {
return NULL;
}
// Can we get a source url for the image style using the view mode?
$src = ImageStyle::load($style)
->buildUrl($preview_image->entity
->getFileUri());
if (empty($src)) {
return NULL;
}
return $src;
}
/**
* Get rendered user.
*
* @return \Drupal\acquia_contenthub\Session\ContentHubUserSession|\Drupal\Core\Session\UserSession
* The rendered user.
*/
protected function getRenderUser() {
if (!$this->renderUser) {
$this->renderUser = new ContentHubUserSession($this->publisherSettings
->get('render_role'));
}
return $this->renderUser;
}
/**
* Get view mode minimal HTML.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $object
* The content entity object.
* @param string $view_mode
* The view mode identifier.
*
* @return array
* The view mode minimal HTML.
*/
protected function getViewModeMinimalHtml(ContentEntityInterface $object, $view_mode) {
// Render View Mode.
$entity_type_id = $object
->getEntityTypeId();
// @todo allow different entity types to specify how to do this.
if ($entity_type_id === 'block_content') {
$build = $this
->getBlockMinimalBuildArray($object, $view_mode);
}
else {
$build = $this
->getViewMode($object, $view_mode);
}
return $build;
}
/**
* Renders block using BlockViewBuilder.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $object
* The Content Entity Object.
* @param string $view_mode
* The request view mode identifier.
*
* @return array
* Render array for the block.
*/
protected function getBlockMinimalBuildArray(ContentEntityInterface $object, $view_mode) {
/** @var \Drupal\block_content\Plugin\Block\BlockContentBlock $block */
$block = $this->blockManager
->createInstance('block_content:' . $object
->uuid());
$build = [
'#theme' => 'block',
'#attributes' => [],
'#contextual_links' => [],
'#weight' => 0,
'#configuration' => $block
->getConfiguration(),
'#plugin_id' => $block
->getPluginId(),
'#base_plugin_id' => $block
->getBaseId(),
'#derivative_plugin_id' => $block
->getDerivativeId(),
];
// Label controlled by the block__block_content__acquia_contenthub template
// (hidden by default). Override the template in your theme to render a
// block label.
if ($build['#configuration']['label'] === '') {
$build['#configuration']['label'] = $object
->label();
}
// Block entity itself doesn't have configuration.
$block
->setConfigurationValue('view_mode', $view_mode);
$build['#configuration']['view_mode'] = $view_mode;
// See \Drupal\block\BlockViewBuilder::preRender() for reference.
$content = $this
->getViewMode($object, $view_mode);
if ($content !== NULL && !Element::isEmpty($content)) {
foreach ([
'#attributes',
'#contextual_links',
] as $property) {
if (isset($content[$property])) {
$build[$property] += $content[$property];
unset($content[$property]);
}
}
}
$build['content'] = $content;
return $build;
}
/**
* Returns the applicable render array.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* The renderable entity.
* @param string $view_mode
* The view mode to render in.
*
* @return array
* The render array.
*/
protected function getViewMode(ContentEntityInterface $entity, string $view_mode) : array {
return $this->entityTypeManager
->getViewBuilder($entity
->getEntityTypeId())
->view($entity, $view_mode, $entity
->language()
->getId());
}
/**
* Get rendered content UUID for given source entity view mode and language.
*
* A render UUID will be created if one does not already exist in Content Hub
* for the provided view mode and language.
*
* @param \Acquia\ContentHubClient\CDF\CDFObject $source_entity_cdf
* The source entity CDF.
* @param string $view_mode
* The view mode identifier.
* @param string $langcode
* The language code.
*
* @return mixed
* The UUID.
*/
protected function getRenderUuid(CDFObject $source_entity_cdf, $view_mode, $langcode) {
$source_entity_uuid = $source_entity_cdf
->getUuid();
if ($this
->isStorageHit($source_entity_uuid, $langcode, $view_mode)) {
return $this
->getStorageItem($source_entity_uuid, $langcode, $view_mode);
}
// Warm up storage.
$this
->getAllRenderUuids($source_entity_uuid);
if (!$this
->isStorageHit($source_entity_uuid, $langcode, $view_mode)) {
$this
->setStorageItem($source_entity_uuid, $langcode, $view_mode, $this->uuidGenerator
->generate());
}
return $this
->getStorageItem($source_entity_uuid, $langcode, $view_mode);
}
/**
* Get all rendered content UUIDs for a given source entity.
*
* @param string $source_entity_uuid
* The source entity CDF.
*
* @return mixed
* The UUIDs.
*/
protected function getAllRenderUuids($source_entity_uuid) {
if (!$this
->storageIsAlreadyWarmedUp($source_entity_uuid)) {
$response = $this->clientFactory
->getClient()
->listEntities([
'type' => 'rendered_entity',
'origin' => $this->origin,
'fields' => 'language,view_mode,source_entity',
'filters' => [
'source_entity' => $source_entity_uuid,
],
]);
if (TRUE === $response['success'] && !empty($response['data'])) {
$this
->storageWarmUp($response['data'], $source_entity_uuid);
}
}
return $this
->getStorageAllItems($source_entity_uuid);
}
/**
* Get attribute value.
*
* @param array $attribute
* The attribute.
* @param string $key
* The key.
* @param string|null $default
* The default.
*
* @return mixed|null
* The und value or the default value.
*/
protected function getAttributeValue(array $attribute, string $key, ?string $default = NULL) {
return $attribute[$key][LanguageInterface::LANGCODE_NOT_SPECIFIED] ?? $default;
}
/**
* Check if the storage is a hit.
*
* @param string $uuid
* The UUID.
* @param string $langcode
* The language code.
* @param string $view_mode
* The view mode identifier.
*
* @return bool
* TRUE if storage hit; FALSE otherwise.
*/
protected function isStorageHit($uuid, $langcode, $view_mode) {
return isset($this->storage[$uuid][$langcode][$view_mode]);
}
/**
* Get storage item.
*
* @param string $uuid
* The UUID.
* @param string $langcode
* The language code.
* @param string $view_mode
* The view mode identifier.
*
* @return mixed
* The value.
*/
protected function getStorageItem($uuid, $langcode, $view_mode) {
return $this->storage[$uuid][$langcode][$view_mode];
}
/**
* Get all items from storage regardless of langcodes and view modes.
*
* @param string $uuid
* The UUID.
*
* @return mixed
* The value.
*/
protected function getStorageAllItems($uuid) {
return $this->storage[$uuid] ?? [];
}
/**
* Set storage item.
*
* @param string $uuid
* The UUID.
* @param string $langcode
* The language code.
* @param string $view_mode
* The view mode identifier.
* @param mixed $value
* The value.
*/
protected function setStorageItem($uuid, $langcode, $view_mode, $value) {
$this->storage[$uuid][$langcode][$view_mode] = $value;
}
/**
* Check if the storage is already warmed up.
*
* @param string $uuid
* The UUID.
*
* @return bool
* TRUE if the storage is already warmed up; FALSE otherwise.
*/
protected function storageIsAlreadyWarmedUp($uuid) {
return isset($this->storage[$uuid]);
}
/**
* Storage warm up action.
*
* @param array $data
* The array of data.
* @param string $source_uuid
* The source UUID.
*/
protected function storageWarmUp(array $data, $source_uuid) {
foreach ($data as $entity_info) {
// Ensure we discard any result that does not match exactly the source_uuid.
if ($this
->getAttributeValue($entity_info['attributes'], 'source_entity') === $source_uuid) {
$this
->setStorageItem($source_uuid, $this
->getAttributeValue($entity_info['attributes'], 'language'), $this
->getAttributeValue($entity_info['attributes'], 'view_mode'), $entity_info['uuid']);
}
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ContentPublishingSettingsTrait:: |
private | property | Acquia lift publisher configuration object. | |
ContentPublishingSettingsTrait:: |
protected | function | Returns the value of the entity view modes setting. | |
EntityRenderHandler:: |
protected | property | The account switcher. | |
EntityRenderHandler:: |
protected | property | The Block Manager. | |
EntityRenderHandler:: |
protected | property | The client factory. | |
EntityRenderHandler:: |
protected | property | The entity type manager. | |
EntityRenderHandler:: |
protected | property | The language default service. | |
EntityRenderHandler:: |
protected | property | The origin uuid. | |
EntityRenderHandler:: |
protected | property | The renderer. | |
EntityRenderHandler:: |
protected | property | The rendered user. | |
EntityRenderHandler:: |
protected | property | The storage. | |
EntityRenderHandler:: |
protected | property | Translation manager. | |
EntityRenderHandler:: |
protected | property | The uuid generator. | |
EntityRenderHandler:: |
protected | function | Build a preview image attribute source. | |
EntityRenderHandler:: |
protected | function | Get all rendered content UUIDs for a given source entity. | |
EntityRenderHandler:: |
protected | function | Get attribute value. | |
EntityRenderHandler:: |
protected | function | Renders block using BlockViewBuilder. | |
EntityRenderHandler:: |
protected | function | Get rendered user. | |
EntityRenderHandler:: |
protected | function | Get rendered content UUID for given source entity view mode and language. | |
EntityRenderHandler:: |
protected | function | Get all items from storage regardless of langcodes and view modes. | |
EntityRenderHandler:: |
protected | function | Get storage item. | |
EntityRenderHandler:: |
public static | function | Returns an array of event names this subscriber wants to listen to. | |
EntityRenderHandler:: |
protected | function | Returns the applicable render array. | |
EntityRenderHandler:: |
protected | function | Get view mode minimal HTML. | |
EntityRenderHandler:: |
protected | function | Check if the storage is a hit. | |
EntityRenderHandler:: |
public | function | Actions on create CDF. | |
EntityRenderHandler:: |
protected | function | Set storage item. | |
EntityRenderHandler:: |
protected | function | Check if the storage is already warmed up. | |
EntityRenderHandler:: |
protected | function | Storage warm up action. | |
EntityRenderHandler:: |
public | function | EntityRenderHandler constructor. |