View source  
  <?php
namespace Drupal\layout_builder_restrictions_by_region\Form;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseModalDialogCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Layout\LayoutPluginManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\Renderer;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\Url;
use Drupal\layout_builder_restrictions\Traits\PluginHelperTrait;
use Drupal\layout_builder_restrictions_by_region\Traits\LayoutBuilderRestrictionsByRegionHelperTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class AllowedBlocksForm extends FormBase {
  use PluginHelperTrait;
  use LayoutBuilderRestrictionsByRegionHelperTrait;
  
  protected $requestStack;
  
  protected $layoutManager;
  
  protected $entityTypeManager;
  
  protected $privateTempStoreFactory;
  
  protected $messenger;
  
  protected $renderer;
  
  protected $allowedBlockCategories;
  
  protected $tempData;
  
  protected $whitelistedBlocks;
  
  protected $blacklistedBlocks;
  
  protected $restrictedCategories;
  
  protected $layoutPluginId;
  
  protected $regionId;
  
  protected $staticId;
  
  public function __construct(RequestStack $request_stack, LayoutPluginManagerInterface $layout_manager, EntityTypeManager $entity_type_manager, PrivateTempStoreFactory $private_temp_store_factory, MessengerInterface $messenger, Renderer $renderer) {
    $this->requestStack = $request_stack;
    $this->layoutManager = $layout_manager;
    $this->entityTypeManager = $entity_type_manager;
    $this->privateTempStoreFactory = $private_temp_store_factory;
    $this->messenger = $messenger;
    $this->renderer = $renderer;
    
    $current_request = $this->requestStack
      ->getCurrentRequest();
    $entity_view_display_id = $current_request->query
      ->get('entity_view_display_id');
    $display = $this->entityTypeManager
      ->getStorage('entity_view_display')
      ->load($entity_view_display_id);
    $this->layoutPluginId = $current_request->query
      ->get('layout_plugin');
    $this->regionId = $current_request->query
      ->get('region_id');
    $this->allowedBlockCategories = $display
      ->getThirdPartySetting('layout_builder_restrictions', 'allowed_block_categories', []);
    $third_party_settings = $display
      ->getThirdPartySetting('layout_builder_restrictions', 'entity_view_mode_restriction_by_region', []);
    $this->whitelistedBlocks = isset($third_party_settings['whitelisted_blocks'][$this->layoutPluginId][$this->regionId]) ? $third_party_settings['whitelisted_blocks'][$this->layoutPluginId][$this->regionId] : [];
    $this->blacklistedBlocks = isset($third_party_settings['blacklisted_blocks'][$this->layoutPluginId][$this->regionId]) ? $third_party_settings['blacklisted_blocks'][$this->layoutPluginId][$this->regionId] : [];
    $this->restrictedCategories = isset($third_party_settings['restricted_categories'][$this->layoutPluginId][$this->regionId]) ? $third_party_settings['restricted_categories'][$this->layoutPluginId][$this->regionId] : [];
  }
  
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('request_stack'), $container
      ->get('plugin.manager.core.layout'), $container
      ->get('entity_type.manager'), $container
      ->get('tempstore.private'), $container
      ->get('messenger'), $container
      ->get('renderer'));
  }
  
  public function getFormId() {
    return 'layout_builder_by_region_allowed_blocks';
  }
  
  public function buildForm(array $form, FormStateInterface $form_state) {
    $current_request = $this->requestStack
      ->getCurrentRequest();
    $static_id = $current_request->query
      ->get('static_id');
    $entity_view_display_id = $current_request->query
      ->get('entity_view_display_id');
    $layout_plugin = $current_request->query
      ->get('layout_plugin');
    $region_id = $current_request->query
      ->get('region_id');
    $display = $this->entityTypeManager
      ->getStorage('entity_view_display')
      ->load($entity_view_display_id);
    
    $tempstore = $this->privateTempStoreFactory;
    $store = $tempstore
      ->get('layout_builder_restrictions_by_region');
    $temp_data = $store
      ->get($static_id . ':' . $layout_plugin . ':' . $region_id);
    $layout_definition = $this->layoutManager
      ->getDefinition($layout_plugin);
    $regions = $layout_definition
      ->getRegions();
    $regions['all_regions'] = [
      'label' => $this
        ->t('All regions'),
    ];
    $region_label = $regions[$region_id]['label']
      ->render();
    $layout_label = $layout_definition
      ->getLabel();
    $form['config_context_markup'] = [
      '#markup' => $this
        ->t('<strong>Layout:</strong> @layout_label<br><strong>Region:</strong> @region_label', [
        '@layout_label' => $layout_label,
        '@region_label' => $region_label,
      ]),
    ];
    foreach ($this
      ->getBlockDefinitions($display) as $category => $data) {
      $title = $data['label'];
      if (!empty($data['translated_label'])) {
        $title = $data['translated_label'];
      }
      $category_form = [
        '#type' => 'fieldset',
        '#title' => $title,
      ];
      $category_form['restriction_behavior'] = [
        '#type' => 'radios',
        '#options' => [
          "all" => $this
            ->t('Allow all existing & new %category blocks.', [
            '%category' => $data['label'],
          ]),
          "restrict_all" => $this
            ->t('Restrict all existing & new %category blocks.', [
            '%category' => $data['label'],
          ]),
          "whitelisted" => $this
            ->t('Allow specific %category blocks:', [
            '%category' => $data['label'],
          ]),
          "blacklisted" => $this
            ->t('Restrict specific %category blocks:', [
            '%category' => $data['label'],
          ]),
        ],
        '#parents' => [
          'allowed_blocks',
          $category,
          'restriction',
        ],
      ];
      $category_form['restriction_behavior']['#default_value'] = $this
        ->getCategoryBehavior($category, $temp_data);
      $category_form['allowed_blocks'] = [
        '#type' => 'container',
        '#states' => [
          'invisible' => [
            [
              ':input[name="allowed_blocks[' . $category . '][restriction]"]' => [
                'value' => "all",
              ],
            ],
            [
              ':input[name="allowed_blocks[' . $category . '][restriction]"]' => [
                'value' => "restrict_all",
              ],
            ],
          ],
        ],
      ];
      foreach ($data['definitions'] as $block_id => $block) {
        $category_form['allowed_blocks'][$block_id] = [
          '#type' => 'checkbox',
          '#title' => $block['admin_label'],
          '#default_value' => $this
            ->getBlockDefault($block_id, $category, $temp_data),
          '#parents' => [
            'allowed_blocks',
            $category,
            'allowed_blocks',
            $block_id,
          ],
        ];
      }
      if ($category == 'Custom blocks' || $category == 'Custom block types') {
        $category_form['description'] = [
          '#type' => 'container',
          '#children' => $this
            ->t('<p>In the event both <em>Custom Block Types</em> and <em>Custom Blocks</em> restrictions are enabled, <em>Custom Block Types</em> restrictions are disregarded.</p>'),
          '#states' => [
            'visible' => [
              ':input[name="allowed_blocks[' . $category . '][restriction]"]' => [
                'value' => "restricted",
              ],
            ],
          ],
        ];
      }
      $form['allowed_blocks'][$category] = $category_form;
    }
    $form['static_id'] = [
      '#type' => 'hidden',
      '#value' => $static_id,
    ];
    $form['layout_plugin'] = [
      '#type' => 'hidden',
      '#value' => $layout_plugin,
    ];
    $form['region_id'] = [
      '#type' => 'hidden',
      '#value' => $region_id,
    ];
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Save'),
      '#ajax' => [
        'callback' => '::ajaxSubmit',
        'event' => 'click',
        'url' => Url::fromRoute("layout_builder_restrictions_by_region.{$display->getTargetEntityTypeId()}_allowed_blocks", [
          'static_id' => $static_id,
          'entity_view_display_id' => $entity_view_display_id,
          'layout_plugin' => $layout_plugin,
          'region_id' => $region_id,
        ]),
        'options' => [
          'query' => [
            FormBuilderInterface::AJAX_FORM_REQUEST => TRUE,
          ],
        ],
      ],
    ];
    return $form;
  }
  
  public function ajaxSubmit(array &$form, FormStateInterface $form_state) {
    $values = $form_state
      ->getValues();
    $static_id = $values['static_id'];
    $layout_plugin = $values['layout_plugin'];
    $region_id = $values['region_id'];
    $categories = $values['allowed_blocks'];
    $block_restrictions = [];
    if (!empty($categories)) {
      foreach ($categories as $category => $category_setting) {
        $restriction_type = $category_setting['restriction'];
        $block_restrictions[$category]['restriction_type'] = $restriction_type;
        if (in_array($restriction_type, [
          'whitelisted',
          'blacklisted',
        ])) {
          foreach ($category_setting['allowed_blocks'] as $block_id => $block_setting) {
            if ($block_setting == '1') {
              
              $block_restrictions[$category]['restrictions'][$block_id] = $block_setting;
            }
          }
        }
      }
    }
    
    $tempstore = $this->privateTempStoreFactory;
    $store = $tempstore
      ->get('layout_builder_restrictions_by_region');
    $store
      ->set($static_id . ':' . $layout_plugin . ':' . $region_id, $block_restrictions);
    $response = new AjaxResponse();
    if ($form_state
      ->getErrors()) {
      
    }
    else {
      $command = new CloseModalDialogCommand();
      $response
        ->addCommand($command);
      $this->messenger
        ->addWarning($this
        ->t('There is unsaved Layout Builder Restrictions configuration.'));
      $status_messages = [
        '#type' => 'status_messages',
      ];
      $messages = $this->renderer
        ->renderRoot($status_messages);
      $messages = '<div id="layout-builder-restrictions-messages">' . $messages . '</div>';
      if (!empty($messages)) {
        $response
          ->addCommand(new ReplaceCommand('#layout-builder-restrictions-messages', $messages));
      }
      $region_status = $this
        ->RegionRestrictionStatusString($layout_plugin, $region_id, $static_id, NULL);
      $response
        ->addCommand(new ReplaceCommand('#restriction-status--' . $layout_plugin . '--' . $region_id . ' .data', '<span class="data">' . $region_status . '</span>'));
    }
    return $response;
  }
  
  public function validateForm(array &$form, FormStateInterface $form_state) {
  }
  
  public function submitForm(array &$form, FormStateInterface $form_state) {
  }
  
  protected function getCategoryBehavior($category, $temp_data) {
    
    $category_is_restricted = !empty($this->allowedBlockCategories) && !in_array($category, $this->allowedBlockCategories);
    
    if (!is_null($temp_data[$category]['restriction_type'])) {
      return $temp_data[$category]['restriction_type'];
    }
    else {
      if (isset($this->whitelistedBlocks) && in_array($category, array_keys($this->whitelistedBlocks))) {
        return "whitelisted";
      }
      elseif (isset($this->blacklistedBlocks) && in_array($category, array_keys($this->blacklistedBlocks))) {
        return "blacklisted";
      }
      elseif (in_array($category, $this->restrictedCategories)) {
        return 'restrict_all';
      }
      elseif ($category_is_restricted) {
        
        return "restrict_all";
      }
      else {
        return 'all';
      }
    }
  }
  
  protected function getBlockDefault($block_id, $category, $temp_data) {
    
    if (!is_null($temp_data)) {
      if (isset($temp_data[$category]['restrictions'])) {
        return in_array($block_id, array_keys($temp_data[$category]['restrictions']));
      }
      else {
        return FALSE;
      }
    }
    else {
      if (isset($this->whitelistedBlocks[$category])) {
        return in_array($block_id, $this->whitelistedBlocks[$category]);
      }
      if (isset($this->blacklistedBlocks[$category])) {
        return in_array($block_id, $this->blacklistedBlocks[$category]);
      }
      else {
        return FALSE;
      }
    }
    return FALSE;
  }
}