View source
<?php
namespace Drupal\acquia_lift_publisher\EventSubscriber\Cdf;
use Acquia\ContentHubClient\CDFAttribute;
use Acquia\ContentHubClient\CDF\CDFObject;
use Drupal\acquia_contenthub\AcquiaContentHubEvents;
use Drupal\acquia_contenthub\Client\ClientFactory;
use Drupal\acquia_contenthub\Event\CreateCdfEntityEvent;
use Drupal\acquia_contenthub\Session\ContentHubUserSession;
use Drupal\acquia_lift_publisher\Form\ContentPublishingSettingsTrait;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Block\BlockManagerInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Language\LanguageDefault;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountSwitcherInterface;
use Drupal\Core\StringTranslation\TranslationManager;
use Drupal\image\Entity\ImageStyle;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class EntityRenderHandler implements EventSubscriberInterface {
use ContentPublishingSettingsTrait;
protected $accountSwitcher;
protected $origin;
protected $renderer;
protected $entityTypeManager;
protected $blockManager;
protected $uuidGenerator;
protected $renderUser;
protected $storage = [];
protected $clientFactory;
protected $languageDefault;
protected $translationManager;
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;
}
public static function getSubscribedEvents() {
$events[AcquiaContentHubEvents::CREATE_CDF_OBJECT][] = [
'onCreateCdf',
100,
];
return $events;
}
public function onCreateCdf(CreateCdfEntityEvent $event) {
$entity = $event
->getEntity();
if (!$entity instanceof ContentEntityInterface) {
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) {
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();
}
$account = $this
->getRenderUser();
$entity_access = $translation
->access('view', $account, TRUE);
$this->accountSwitcher
->switchTo($account);
$elements = [];
if ($entity_access
->isAllowed()) {
$elements = $this
->getViewModeMinimalHtml($translation, $view_mode);
}
$html = $this->renderer
->renderPlain($elements);
$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());
}
}
protected function buildPreviewImageAttributeSource($view_modes, $preview_view_mode, $style, $translation) {
if (empty($view_modes[$preview_view_mode])) {
return NULL;
}
$preview_image = $translation->{$view_modes[$preview_view_mode]}
->first();
if (empty($preview_image)) {
return NULL;
}
$src = ImageStyle::load($style)
->buildUrl($preview_image->entity
->getFileUri());
if (empty($src)) {
return NULL;
}
return $src;
}
protected function getRenderUser() {
if (!$this->renderUser) {
$this->renderUser = new ContentHubUserSession($this->publisherSettings
->get('render_role'));
}
return $this->renderUser;
}
protected function getViewModeMinimalHtml(ContentEntityInterface $object, $view_mode) {
$entity_type_id = $object
->getEntityTypeId();
if ($entity_type_id === 'block_content') {
$build = $this
->getBlockMinimalBuildArray($object, $view_mode);
}
else {
$build = $this
->getViewMode($object, $view_mode);
}
return $build;
}
protected function getBlockMinimalBuildArray(ContentEntityInterface $object, $view_mode) {
$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(),
];
if ($build['#configuration']['label'] === '') {
$build['#configuration']['label'] = $object
->label();
}
$block
->setConfigurationValue('view_mode', $view_mode);
$build['#configuration']['view_mode'] = $view_mode;
$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;
}
protected function getViewMode(ContentEntityInterface $entity, string $view_mode) : array {
return $this->entityTypeManager
->getViewBuilder($entity
->getEntityTypeId())
->view($entity, $view_mode, $entity
->language()
->getId());
}
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);
}
$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);
}
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);
}
protected function getAttributeValue(array $attribute, string $key, ?string $default = NULL) {
return $attribute[$key][LanguageInterface::LANGCODE_NOT_SPECIFIED] ?? $default;
}
protected function isStorageHit($uuid, $langcode, $view_mode) {
return isset($this->storage[$uuid][$langcode][$view_mode]);
}
protected function getStorageItem($uuid, $langcode, $view_mode) {
return $this->storage[$uuid][$langcode][$view_mode];
}
protected function getStorageAllItems($uuid) {
return $this->storage[$uuid] ?? [];
}
protected function setStorageItem($uuid, $langcode, $view_mode, $value) {
$this->storage[$uuid][$langcode][$view_mode] = $value;
}
protected function storageIsAlreadyWarmedUp($uuid) {
return isset($this->storage[$uuid]);
}
protected function storageWarmUp(array $data, $source_uuid) {
foreach ($data as $entity_info) {
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']);
}
}
}
}