display_builder-1.0.x-dev/modules/display_builder_devel/src/Controller/DisplayBuilderDevelController.php
modules/display_builder_devel/src/Controller/DisplayBuilderDevelController.php
<?php
declare(strict_types=1);
namespace Drupal\display_builder_devel\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\display_builder\DisplayBuilderHelpers;
use Drupal\display_builder\StateManager\StateManagerInterface;
use Drupal\display_builder_entity_view\Event\DisplayBuilderEntityViewEventsSubscriber;
use Drupal\display_builder_page_layout\DisplayBuilderPageLayout;
use Drupal\display_builder_views\DisplayBuilderViewsManager;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Returns responses for Display Builder ui routes.
*/
class DisplayBuilderDevelController extends ControllerBase {
public function __construct(
private readonly StateManagerInterface $stateManager,
) {}
/**
* Generate a simple index of saved display.
*
* @return array
* A render array.
*/
public function index(): array {
$build = [];
$build['display_builder_table'] = [
'#theme' => 'table',
'#header' => [
'id' => ['data' => $this->t('Id')],
'type' => ['data' => $this->t('Type')],
'display_builder_config' => ['data' => $this->t('Config')],
'updated' => ['data' => $this->t('Updated')],
'log' => ['data' => $this->t('Last log')],
'operations' => ['data' => $this->t('Operations')],
],
];
foreach (array_keys($this->stateManager->loadAll()) as $builder_id) {
$build['display_builder_table']['#rows'][$builder_id] = $this->buildRow($builder_id, $this->stateManager->load($builder_id));
}
$build['pager'] = ['#type' => 'pager'];
return $build;
}
/**
* Provides a generic title callback for a display.
*
* @param string $builder_id
* The uniq display id.
*
* @return \Drupal\Core\StringTranslation\TranslatableMarkup|null
* The title for the display page, if found.
*/
public function title(string $builder_id): ?TranslatableMarkup {
if (empty($builder_id)) {
return $this->t('Display builder');
}
return $this->t('Display builder: @id', ['@id' => $builder_id]);
}
/**
* Load a display builder demo by id.
*
* @param string $builder_id
* The display builder demo id.
*
* @return array
* The display build.
*/
public function view(string $builder_id): array {
// \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();
// \Drupal::service('page_cache_kill_switch')->trigger();
$display_builder_id = $this->stateManager->getEntityConfigId($builder_id);
$storage = $this->entityTypeManager()->getStorage('display_builder');
/** @var \Drupal\display_builder\DisplayBuilderInterface $displayBuilderConfig */
$displayBuilderConfig = $storage->load($display_builder_id);
if ($displayBuilderConfig) {
// @todo no contexts as it's a generic loader, but can fail if calling a
// display with context.
// $builder = $displayBuilderConfig->build($builder_id);
// $builder['#cache']['max-age'] = 0;
// return $builder;
return $displayBuilderConfig->build($builder_id);
}
return [
'#plain_text' => $this->t('Missing @builder_id config.', ['@builder_id' => $display_builder_id]),
];
}
/**
* Delete a sample entity generated by UI Patterns.
*
* @param string $entity_type_id
* The entity type id.
* @param string $bundle
* The bundle id.
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* A message and redirect.
*/
public function deleteSample(string $entity_type_id, string $bundle): RedirectResponse {
/** @var \Drupal\ui_patterns\Entity\SampleEntityGenerator $sample */
$sample = \Drupal::service('ui_patterns.sample_entity_generator'); // phpcs:ignore
$sample->delete($entity_type_id, $bundle);
$params = ['@entity_type_id' => $entity_type_id, '@bundle' => $bundle];
$this->messenger()->addStatus($this->t('Sample @entity_type_id @bundle deleted!', $params));
$redirect = $this->redirect('display_builder_devel.collection');
$redirect->send();
return $redirect;
}
/**
* Redirect to user DB demo.
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* A message and redirect.
*/
public function viewUserDemo(): RedirectResponse {
$user = \Drupal::currentUser(); // phpcs:ignore
$builder_id = \Drupal::state()->get(\sprintf('db_demo_user_%s', $user->id()), NULL); // phpcs:ignore
if (!$builder_id) {
$this->messenger()->addError($this->t('No display builder demo found for you!'));
$redirect = $this->redirect('<front>');
$redirect->send();
return $redirect;
}
$redirect = $this->redirect('display_builder_devel.view', ['builder_id' => $builder_id]);
$redirect->send();
return $redirect;
}
/**
* Delete associated user DB for demo.
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* A message and redirect.
*
* @see modules/display_builder_devel/src/Hook/DisplayBuilderDevelHooks.php
*/
public function resetUserDb(): RedirectResponse {
$user = \Drupal::currentUser(); // phpcs:ignore
$builder_id = \Drupal::state()->get(\sprintf('db_demo_user_%s', $user->id()), NULL); // phpcs:ignore
if (!$builder_id) {
$this->messenger()->addError($this->t('No display builder demo found for you!'));
$redirect = $this->redirect('<front>');
$redirect->send();
return $redirect;
}
$contexts = $this->stateManager->getContexts($builder_id);
$this->stateManager->delete($builder_id);
$builder_data = DisplayBuilderHelpers::getFixtureDataFromModule('display_builder_devel', '', 'ui_suite_bootstrap_demo');
$this->stateManager->create(
$builder_id,
'demo',
$builder_data,
$contexts,
);
$this->messenger()->addStatus($this->t('Display builder demo reset successfully!'));
$redirect = $this->redirect('display_builder_devel.view', ['builder_id' => $builder_id]);
$redirect->send();
return $redirect;
}
/**
* Builds a table row for a display builder.
*
* @param string $builder_id
* The builder id.
* @param array $builder
* An builder to display.
*
* @return array
* A table row.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function buildRow(string $builder_id, array $builder): array {
$row = [];
$route_name = 'display_builder_devel.view';
$route_params = ['builder_id' => $builder_id];
$type = $this->t('None');
$extra_links = [];
// Simple switch to url based on context.
if (class_exists('Drupal\display_builder_views\DisplayBuilderViewsManager') && $this->stateManager->hasSaveContextsRequirement($builder_id, DisplayBuilderViewsManager::VIEWS_CONTEXT_REQUIREMENT)) {
$route_name = 'display_builder_views.views.manage';
$type = $this->t('Views');
}
elseif (class_exists('Drupal\display_builder_page_layout\DisplayBuilderPageLayout') && $this->stateManager->hasSaveContextsRequirement($builder_id, DisplayBuilderPageLayout::PAGE_LAYOUT_CONTEXT_REQUIREMENT)) {
$route_name = 'display_builder_page_layout.manage';
$type = $this->t('Page layout');
}
elseif (class_exists('Drupal\display_builder_entity_view\Event\DisplayBuilderEntityViewEventsSubscriber') && $this->stateManager->hasSaveContextsRequirement($builder_id, DisplayBuilderEntityViewEventsSubscriber::CONTEXT_REQUIREMENT)) {
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $builder['contexts']['entity']->getContextValue();
$entity_type_id = $entity->getEntityTypeId();
$route_name = \sprintf('display_builder.%s.view', $entity_type_id);
$bundle = $builder['contexts']['bundle']->getContextValue();
$route_params[$entity->getEntityType()->getBundleEntityType()] = $bundle;
$route_params['view_mode_name'] = $builder['contexts']['view_mode']->getContextValue();
$type = $this->t('Entity');
$extra_links['refresh_sample'] = [
'title' => $this->t('Refresh sample'),
'url' => Url::fromRoute('display_builder_devel.delete_sample', [
'entity_type_id' => $entity_type_id,
'bundle' => $bundle,
]),
];
}
elseif (class_exists('Drupal\display_builder_page_layout\DisplayBuilderPageLayout') && $this->stateManager->hasSaveContextsRequirement($builder_id, DisplayBuilderPageLayout::PAGE_MANAGER_CONTEXT_REQUIREMENT)) {
$route_name = 'display_builder_page_layout.page_manager.manage';
$type = $this->t('Page manager');
}
// If related module is disabled, use devel default view.
try {
$url = Url::fromRoute($route_name, $route_params);
}
catch (\Throwable $th) {
$url = Url::fromRoute('display_builder_devel.view', $route_params);
}
$row['id']['data'] = [
'#type' => 'link',
'#title' => $builder_id,
'#url' => $url,
];
$row['type']['data'] = $type;
$row['display_builder_config']['data'] = $builder['entity_config_id'];
$present = $builder['present'];
if (!$present) {
$present = ['time' => NULL, 'log' => NULL];
}
$row['updated']['data'] = $present['time'] ?? '-';
if (isset($present['log']) && $present['log'] instanceof TranslatableMarkup) {
$row['log']['data'] = $this->formatLog($present['log']);
}
else {
$row['log']['data'] = '-';
}
$links = $this->getOperationLinks($builder_id, $extra_links);
if (\count($links) > 0) {
$row['operations']['data']['operations'] = [
'#type' => 'operations',
'#links' => $links,
];
}
return ['data' => $row];
}
/**
* Format the log.
*
* @param \Drupal\Core\StringTranslation\TranslatableMarkup $log
* The log to format.
*
* @return string
* The formatted log.
*/
private function formatLog(TranslatableMarkup $log): string {
return $log->render();
}
/**
* Operations for a display builder instance.
*
* @param string $builder_id
* The display builder id.
* @param array $extra
* Some more specific links.
*
* @return array
* The operation links
*/
private function getOperationLinks(string $builder_id, array $extra): array {
$links = [
'import' => [
'title' => $this->t('Import'),
'url' => Url::fromRoute('display_builder_devel.import', [
'builder_id' => $builder_id,
]),
],
'export' => [
'title' => $this->t('Export'),
'url' => Url::fromRoute('display_builder_devel.export', [
'builder_id' => $builder_id,
]),
],
'edit' => [
'title' => $this->t('Edit'),
'url' => Url::fromRoute('display_builder_devel.edit', [
'builder_id' => $builder_id,
]),
],
'delete' => [
'title' => $this->t('Delete'),
'url' => Url::fromRoute('display_builder_devel.delete', [
'builder_id' => $builder_id,
]),
],
];
return array_merge($links, $extra);
}
}
