opigno_dashboard-8.x-1.8/src/BlockService.php

src/BlockService.php
<?php

namespace Drupal\opigno_dashboard;

use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Block\BlockManagerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\HttpFoundation\JsonResponse;

/**
 * The dashboard block manager service definition.
 */
class BlockService implements BlockServiceInterface {

  use StringTranslationTrait;

  /**
   * The block manager service.
   *
   * @var \Drupal\Core\Block\BlockManagerInterface
   */
  protected BlockManagerInterface $blockManager;

  /**
   * The renderer service.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected RendererInterface $renderer;

  /**
   * The current user account.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected AccountInterface $currentUser;

  /**
   * The config factory service.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected ConfigFactoryInterface $configFactory;

  /**
   * The module handler service.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected ModuleHandlerInterface $moduleHandler;

  /**
   * The database connection service.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected Connection $database;

  /**
   * The block storage.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected EntityStorageInterface $blockStorage;

  /**
   * Logger.
   *
   * @var \Drupal\Core\Logger\LoggerChannel
   */
  protected $logger;

  /**
   * BlockService constructor.
   *
   * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
   *   The block manager service.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer service.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user account.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory service.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler service.
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   An entity type manager service.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger service.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   */
  public function __construct(
    BlockManagerInterface $block_manager,
    RendererInterface $renderer,
    AccountInterface $account,
    ConfigFactoryInterface $config_factory,
    ModuleHandlerInterface $module_handler,
    Connection $database,
    EntityTypeManagerInterface $entity_type_manager,
    LoggerChannelFactoryInterface $logger_factory,
  ) {
    $this->blockManager = $block_manager;
    $this->renderer = $renderer;
    $this->currentUser = $account;
    $this->configFactory = $config_factory;
    $this->moduleHandler = $module_handler;
    $this->database = $database;
    $this->blockStorage = $entity_type_manager->getStorage('block');
    $this->logger = $logger_factory->get('opigno_dashboard_exception');
  }

  /**
   * {@inheritdoc}
   */
  public function getAllBlocks(): array {
    return $this->blockManager->getDefinitions();
  }

  /**
   * {@inheritdoc}
   */
  public function getAvailableBlocks(): array {
    $blocks = $this->getAllBlocks();
    $availables = $this->configFactory->get('opigno_dashboard.settings')->get('blocks');
    $account_roles = $this->currentUser->getRoles();

    foreach ($blocks as $key1 => &$block) {
      if (!isset($availables[$key1])
      || (isset($availables[$key1]) && !$availables[$key1]['available'])
      ) {
        unset($blocks[$key1]);
        continue;
      }
      // Check access first.
      $block_real = $this->blockStorage->load($this->sanitizeId($key1));
      if (!$block_real) {
        // Try to load old version of block.
        $block_real = $this->blockStorage->load($this->sanitizeIdOld($key1));
      }

      $role_access = TRUE;
      if (!empty($block_real)) {
        $block_visibility = $block_real->getVisibility();

        if (isset($block_visibility['user_role']) && !empty($block_visibility['user_role'])) {
          $role_access = FALSE;

          foreach ($block_visibility['user_role']['roles'] as $block_role) {
            if (in_array($block_role, $account_roles)) {
              $role_access = TRUE;
            }
          }
        }
      }

      if (!$role_access) {
        unset($blocks[$key1]);
        continue;
      }

      foreach ($block as &$value) {
        if (is_object($value)) {
          $value = $value->render();
        }
      }

      $blocks[$key1]['id'] = $key1;

      unset(
        $blocks[$key1]['config_dependencies'],
        $blocks[$key1]['class'],
        $blocks[$key1]['provider'],
        $blocks[$key1]['category'],
        $blocks[$key1]['deriver'],
        $blocks[$key1]['context']
      );
    }

    return array_values($blocks);
  }

  /**
   * {@inheritdoc}
   */
  public function getDashboardBlocksContents($need_render = TRUE): array {
    $blocks = $this->getAvailableBlocks();

    $data = [
      'blocks' => [],
      'attachments' => [],
    ];
    foreach ($blocks as $block) {
      $id = $block['id'];

      try {
        $block = $this->blockManager->createInstance($id);
      }
      catch (PluginException $exception) {
        $this->logger->error($exception);
        continue;
      }

      if (!$block instanceof BlockBase) {
        continue;
      }

      try {
        $render = $block->build();
      }
      catch (\Exception $exception) {
        $this->logger->warning('No required context for the block: ' . $id);
        $render = [];
      }

      $data['blocks'][$id] = $need_render ? $this->renderer->renderRoot($render) : $render;
      $attachments = $render['#attached'] ?? [];
      $data['attachments'] = array_merge_recursive($data['attachments'], $attachments);
    }

    // Get only unique libraries.
    if (isset($data['attachments']['library'])) {
      $data['attachments']['library'] = array_unique($data['attachments']['library']);
    }

    return $data;
  }

  /**
   * {@inheritdoc}
   */
  public function createBlocksInstances(): void {
    $items = $this->getAvailableBlocks();
    $theme = $this->configFactory->get('opigno_dashboard.settings')->get('theme');

    foreach ($items as $item) {
      $id = $this->sanitizeId($item['id']);

      if (!$this->blockStorage->load($id)) {
        $settings = [
          'plugin' => $item['id'],
          'region' => 'content',
          'id' => $id,
          'theme' => $theme ?? $this->configFactory->get('system.theme')->get('default'),
          'label' => $this->t('Dashboard: @label', ['@label' => $item['admin_label'] ?? '']),
          'visibility' => [
            'request_path' => [
              'id' => 'request_path',
              'pages' => '<front>',
              'negate' => FALSE,
              'context_mapping' => [],
            ],
          ],
          'weight' => 0,
        ];

        $values = [];
        foreach (['region', 'id', 'theme', 'plugin', 'weight', 'visibility'] as $key) {
          $values[$key] = $settings[$key];
          // Remove extra values that do not belong in the settings array.
          unset($settings[$key]);
        }
        foreach ($values['visibility'] as $id => $visibility) {
          $values['visibility'][$id]['id'] = $id;
        }
        $values['settings'] = $settings;
        $block = $this->blockStorage->create($values);

        try {
          $block->save();
        }
        catch (EntityStorageException $e) {
          $this->logger->error($e);
        }
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function sanitizeId(string $id): string {
    return 'dashboard_' . str_replace([':', '-'], ['_', '_'], $id);
  }

  /**
   * {@inheritdoc}
   */
  public function sanitizeIdOld(string $id): string {
    return 'dashboard_' . str_replace(':', '_', $id);
  }

  /**
   * {@inheritdoc}
   */
  public function isSocialFeatureEnabled(): bool {
    $socials_enabled = $this->configFactory->get('opigno_class.socialsettings')->get('enable_social_features') ?? FALSE;
    return $this->moduleHandler->moduleExists('opigno_social') && $socials_enabled;
  }

  /**
   * {@inheritdoc}
   */
  public function getDefaultDashboardConfig(): string {
    // Return the default dashboard layout depending on whether Opigno Social
    // module is enabled or not.
    return $this->isSocialFeatureEnabled()
      ? '{"1":[{"admin_label":"User statistics","context_definitions":[],"id":"opigno_user_stats_block"},{"admin_label":"User connections","context_definitions":[],"id":"opigno_user_connections_block"}],"2":[{"admin_label":"Recent posts","context_definitions":[],"id":"opigno_social_wall_block"},{"admin_label":"Training in progress","id":"views_block:latest_active_trainings-block","mandatory":false}],"3":[{"admin_label":"Opigno calendar block","id":"views_block:opigno_calendar-month_block","mandatory":false}]}'
      : '{"1":[{"admin_label":"Training in progress","id":"views_block:latest_active_trainings-block"}, {"admin_label":"Recent messages","id":"views_block:private_message-block_dashboard"}],"2":[{"admin_label":"Opigno calendar block","id":"views_block:opigno_calendar-month_block"}],"3":[]}';
  }

  /**
   * {@inheritdoc}
   */
  public function getDefaultLayoutId(): int {
    // Return 3-column layout in case if social features enabled, 2-column
    // otherwise.
    return $this->isSocialFeatureEnabled() ? 5 : 3;
  }

  /**
   * {@inheritdoc}
   */
  public function getPositioning($uid = NULL, bool $default = FALSE, bool $user_default = FALSE) {
    if (empty($uid)) {
      $uid = $this->currentUser->id();
    }

    $availables = $this->getAvailableBlocks();
    // Get default configuration.
    $config_default = $this->configFactory->get('opigno_dashboard.default.settings');
    $default_positions = json_decode($config_default->get('positions'), TRUE);
    $default_columns = $config_default->get('columns');

    if ($default) {
      $positions = $default_positions;
      $columns = $default_columns;
    }
    else {
      $query = $this->database->select('opigno_dashboard_positioning', 'p')
        ->fields('p', ['columns', 'positions'])
        ->condition('p.uid', $uid);

      $result = $query->execute()->fetchObject();
      $positions = FALSE;
      if (!empty($result->positions)) {
        $positions = json_decode($result->positions, TRUE);
      }
      $columns = $result->columns ?? $this->getDefaultLayoutId();
    }

    if (!$positions) {
      if (!empty($default_positions)) {
        $positions = $default_positions;
        $columns = $default_columns;
      }
      else {
        $positions = json_decode($this->getDefaultDashboardConfig(), TRUE);
        $columns = $this->getDefaultLayoutId();
      }
    }

    // Get mandatory blocks.
    $mandatory_blocks = $this->configFactory->get('opigno_dashboard.settings')->get('blocks');
    if (!empty($mandatory_blocks)) {
      $mandatory_blocks = array_filter($mandatory_blocks, function ($block) {
        return $block['available'] && $block['mandatory'];
      });
    }
    // Keep all mandatory blocks.
    $mandatory = $mandatory_blocks ?? [];

    // Remove blocks that are not available.
    $available_keys = [];
    foreach ($availables as $available) {
      $available_id = $available['id'] ?? '';
      if ($available_id) {
        $available_keys[$available_id] = $available_id;
      }
    }
    foreach ($positions as $key1 => $column) {
      foreach ($column as $key2 => $row) {
        if (!isset($row['id'])) {
          continue;
        }
        if (!in_array($row['id'], $available_keys)) {
          unset($positions[$key1][$key2]);
          continue;
        }
        // Filter unused mandatory blocks.
        if (!empty($mandatory_blocks) && isset($mandatory_blocks[$row['id']])) {
          unset($mandatory_blocks[$row['id']]);
        }
        // Add mandatory property to positions blocks.
        $positions[$key1][$key2]['mandatory'] = $mandatory && array_key_exists($row['id'], $mandatory);
      }
    }

    // Remove block already used.
    foreach ($availables as $key => $value) {
      foreach ($positions as $column) {
        foreach ($column as $row) {
          if (isset($row['id']) && isset($value['id']) && ($row['id'] == $value['id'])) {
            unset($availables[$key]);
          }
        }
      }
      // Save mandatory blocks key from "availables" array.
      if (!empty($mandatory_blocks) && array_key_exists($value['id'], $mandatory_blocks)) {
        $mandatory_blocks[$value['id']]['availables_key'] = $key;
      }
    }

    if (!$user_default) {
      $available_values = array_values($availables);
      $entities = array_merge([$available_values], $positions);
      $positions = $entities ?: array_merge([$available_values], [[], [], []]);
    }

    // Add unused mandatory blocks.
    if (!empty($mandatory_blocks)) {
      foreach ($mandatory_blocks as $id => $mandatory_block) {
        if (!empty($mandatory_block['availables_key'])) {
          array_unshift($positions[1], [
            'admin_label' => $availables[$mandatory_block['availables_key']]['admin_label'] ?? '',
            'id' => $id,
            'mandatory' => TRUE,
          ]);
        }
      }
    }

    $columns = $columns ?? $this->getDefaultLayoutId();

    $this->clearEmptyPositions($positions, $available_keys);
    if ($default) {
      return [
        'positions' => $positions,
        'columns' => $columns,
      ];
    }
    else {
      return new JsonResponse([
        'positions' => $positions,
        'columns' => $columns,
      ]);
    }
  }

  /**
   * Clear empty positions.
   *
   * @param array $positions
   *   Blocks positioning.
   * @param array $available_keys
   *   The list of available keys.
   */
  private function clearEmptyPositions(array &$positions, array $available_keys) {
    foreach ($positions as $c_key => $columns) {
      if (!is_array($columns)) {
        continue;
      }
      foreach ($columns as $key => $position) {
        if (!is_array($columns)) {
          continue;
        }
        // Unset empty arrays and removed blocks.
        if (!isset($position['id']) || (isset($position['id']) && !in_array($position['id'], $available_keys))) {
          unset($positions[$c_key][$key]);
        }
      }
      // Reset array keys.
      $positions[$c_key] = array_values($positions[$c_key]);
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc