cms_content_sync-3.0.x-dev/modules/cms_content_sync_views/src/Plugin/views/field/SyncState.php
modules/cms_content_sync_views/src/Plugin/views/field/SyncState.php
<?php
namespace Drupal\cms_content_sync_views\Plugin\views\field;
use Drupal\cms_content_sync\Controller\Embed;
use Drupal\cms_content_sync\Entity\EntityStatus;
use Drupal\cms_content_sync\PushIntent;
use Drupal\cms_content_sync\SyncCoreInterface\DrupalApplication;
use Drupal\cms_content_sync\SyncIntent;
use Drupal\Core\Entity\EntityChangedInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;
/**
* Views Field handler to check if a entity is pulled.
*
* @ingroup views_field_handlers
*
* @ViewsField("cms_content_sync_sync_state")
*/
class SyncState extends FieldPluginBase {
/**
* {@inheritdoc}
*/
public function query() {
// Leave empty to avoid a query on this field.
}
/**
* Provide the options form.
*
* @param mixed $form
* The Drupal form object.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The Drupal form state interface.
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
}
/**
*
*/
public static function getPushLink(EntityInterface $entity, EntityStatus $status, $deleted = FALSE) {
$translatable = $entity instanceof TranslatableInterface;
$push_changes_route_parameters = [
'flow_id' => $status->getFlow()->id(),
'entity_id' => $entity->id(),
'entity_type' => $entity->getEntityTypeId(),
];
if ($deleted) {
$push_changes_url = Url::fromRoute(
'cms_content_sync.publish_changes_confirm_deleted_translation',
$push_changes_route_parameters,
['query' => ['destination' => Url::fromRoute('<current>')->toString()]]
);
}
elseif ($translatable) {
$push_changes_url = Url::fromRoute(
'cms_content_sync.publish_changes_confirm_translation',
$push_changes_route_parameters + ['language' => $entity->language()->getId()],
['query' => ['destination' => Url::fromRoute('<current>')->toString()]]
);
}
else {
$push_changes_url = Url::fromRoute(
'cms_content_sync.publish_changes_confirm',
$push_changes_route_parameters,
['query' => ['destination' => Url::fromRoute('<current>')->toString()]]
);
}
$push_changes = Link::fromTextAndUrl(_cms_content_sync_push_label(), $push_changes_url);
$push_changes = $push_changes->toRenderable();
return \Drupal::service('renderer')->render($push_changes);
}
/**
* {@inheritdoc}
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*
* @return \Drupal\Component\Render\MarkupInterface|string|TranslatableMarkup|ViewsRenderPipelineMarkup
* The rendered sync state view.
*/
public function render(ResultRow $values) {
$messages = [];
// Disable rendering if the user agent is set to "Ghost Inspector" to
// improve the Drupal integration test performance.
if (str_contains($_SERVER['HTTP_USER_AGENT'], 'Ghost Inspector')) {
$messages['disabled'] = $this->t('Disabled');
$update_status = '';
}
else {
$entity = $values->_entity;
// Get the status entity.
$entity_status = EntityStatus::getInfosForEntity($entity->getEntityTypeId(), $entity->uuid());
$only_embedded = TRUE;
// @todo Refactor to have rending of output in separated methods to allow
// overwriting per entity type.
foreach ($entity_status as $status) {
// Take care of translations.
$entity_type_id = $entity->getEntityTypeId();
$field_data_langcode = empty($values->{$entity_type_id . '_field_data_langcode'}) ? NULL : $values->{$entity_type_id . '_field_data_langcode'};
if (!is_null($field_data_langcode)) {
$entity = $entity->getTranslation($field_data_langcode);
}
$language = $entity instanceof TranslatableInterface ? $entity->language()->getId() : NULL;
$embedded = ($status->getLastPush($language) && $status->wasPushedEmbedded()) || ($status->getLastPull() && $status->wasPulledEmbedded());
if (!$embedded) {
$only_embedded = FALSE;
}
$pool = $status->getPool();
// "Pulled from ... at ..."
// We are checking on LastPull and not on the source entity
// since we also will have an "pulled" date when it comes to cross sync.
if (!is_null($status->getLastPull($language))) {
$source_url = $status->getSourceUrl();
if (!is_null($source_url)) {
$url = Url::fromUri($source_url);
$link = Link::fromTextAndUrl(t('here'), $url);
$link = $link->toRenderable();
$link['#attributes'] = ['target' => '_blank'];
$link_render = \Drupal::service('renderer')->render($link);
$messages['pulled_from'] = $this->t('Pulled from @link (%pool) at @date.', [
'%pool' => $pool ? $pool->label() : $status->get('pool')->value,
'@link' => $link_render,
'@date' => \Drupal::service('date.formatter')->format($status->getLastPull($language)),
]);
}
}
if ($status->getLastPush($language)) {
if ($embedded) {
$parent = $status->getParentEntity();
$parent_link = $parent && $parent->hasLinkTemplate('canonical') ? $parent->toLink()->toRenderable() : NULL;
$messages['pushed_on'] = $this->t('Pushed embedded on @date to %pool through @parent.', [
'@date' => \Drupal::service('date.formatter')->format($status->getLastPush($language)),
'%pool' => $pool ? $pool->label() : $status->get('pool')->value,
'@parent' => $parent ? ($parent_link ? \Drupal::service('renderer')->render($parent_link) : $parent->label() . "") : $this->t('(parent entity not found)'),
]);
}
else {
$messages['pushed_on'] = $this->t('Pushed on @date to %pool.', [
'@date' => \Drupal::service('date.formatter')->format($status->getLastPush($language)),
'%pool' => $pool ? $pool->label() : $status->get('pool')->value,
]);
}
if ($deleted_translations = $status->translationDeletionRequiresPush()) {
$flow = $status->getFlow();
if ($flow->getController()->canPushEntity($entity, PushIntent::PUSH_MANUALLY, SyncIntent::ACTION_CREATE) && $flow->getController()->canPushEntity($entity, PushIntent::PUSH_MANUALLY, SyncIntent::ACTION_DELETE)) {
$messages['translation_deletion_requires_push'] = $this->t('Translation %translation deleted locally - @push.', [
'%translation' => implode(', ', $deleted_translations),
'@push' => $this->getPushLink($entity, $status, TRUE),
]);
}
}
$last_pull = EntityStatus::getLastPullForEntity($entity, $language);
if ($entity instanceof EntityChangedInterface && $status->getLastPush($language) < $entity->getChangedTime() && $status->wasPushedManually() && (!$last_pull || $last_pull < $entity->getChangedTime())) {
$messages['update_waiting'] = $this->t('Update waiting to be pushed - @push_changes.', [
'@push_changes' => $this->getPushLink($entity, $status),
]);
}
}
elseif ($status->getLastPushTrigger($language)) {
$messages['pushed_triggered_on'] = $this->t('Push triggered on @date to %pool.', [
'@date' => \Drupal::service('date.formatter')->format($status->getLastPushTrigger($language)),
'%pool' => $pool ? $pool->label() : $status->get('pool')->value,
]);
}
// "Overridden locally".
if ($status->isOverriddenLocally()) {
$messages['overridden_locally'] = $this->t('Overridden locally.');
}
}
$update_status = NULL;
if (empty($messages)) {
if (PushIntent::isPushing($entity->getEntityTypeId(), $entity->uuid())) {
$messages['pushed_on'] = $this->t('Pushed just now.');
}
else {
$messages['not_syndicated'] = $this->t('<em>Local content.</em>');
}
}
if (empty($messages['not_syndicated']) && DrupalApplication::get()->getSiteUuid()) {
static $embed = NULL;
if (!$embed) {
$embed = Embed::create(\Drupal::getContainer());
}
$update_status = $embed->updateStatusBox($entity, $status->getLastPushTrigger($language) && $status->getLastPushTrigger($language) > time() - 5);
if ('node' === $entity->getEntityTypeId()) {
$link = Link::createFromRoute('Sync status', 'cms_content_sync.content_sync_status', ['node' => $entity->id()])->toString();
$messages['view_status'] = $link;
}
elseif ('media' === $entity->getEntityTypeId()) {
$link = Link::createFromRoute('Sync status', 'cms_content_sync.media_sync_status', ['media' => $entity->id()])->toString();
$messages['view_status'] = $link;
}
elseif ('block_content' === $entity->getEntityTypeId()) {
$link = Link::createFromRoute('Sync status', 'cms_content_sync.block_content_sync_status', ['block_content' => $entity->id()])->toString();
$messages['view_status'] = $link;
}
elseif ('taxonomy_term' === $entity->getEntityTypeId()) {
$link = Link::createFromRoute('Sync status', 'cms_content_sync.taxonomy_term_sync_status', ['taxonomy_term' => $entity->id()])->toString();
$messages['view_status'] = $link;
}
elseif ('menu_link_content' === $entity->getEntityTypeId()) {
$link = Link::createFromRoute('Sync status', 'cms_content_sync.menu_link_content_sync_status', ['menu_link_content' => $entity->id()])->toString();
$messages['view_status'] = $link;
}
elseif ('paragraphs_library_item' === $entity->getEntityTypeId()) {
$link = Link::createFromRoute('Sync status', 'cms_content_sync.paragraphs_library_item_sync_status', ['paragraphs_library_item' => $entity->id()])->toString();
$messages['view_status'] = $link;
}
}
// Allow other modules to extend the messages.
\Drupal::moduleHandler()->invokeAll('cms_content_sync_views_sync_state_alter', [&$entity, &$messages]);
}
$renderable = [
'#theme' => 'sync_status',
'#messages' => $messages,
'#update_status' => $update_status,
'#cache' => [
'max-age' => 0,
],
];
return \Drupal::service('renderer')->render($renderable);
}
/**
* Define the available options.
*
* @return array
* Returns the available options.
*/
protected function defineOptions() {
return parent::defineOptions();
}
}
