Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
PageLayoutSource
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 12
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 create
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPropValue
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 calculateDependencies
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
30
 getSlotDefinitions
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getSlotValues
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSlotValue
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setSlotValue
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setSlotRenderable
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSlotPath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 settingsFormPropsOnly
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 systemRegionList
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder_page_layout\Plugin\UiPatterns\Source;
6
7use Drupal\Core\Config\ConfigFactoryInterface;
8use Drupal\Core\Extension\ModuleHandlerInterface;
9use Drupal\Core\Form\FormStateInterface;
10use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
11use Drupal\Core\Routing\RouteMatchInterface;
12use Drupal\Core\StringTranslation\TranslatableMarkup;
13use Drupal\Core\Utility\Token;
14use Drupal\display_builder\SourceWithSlotsInterface;
15use Drupal\ui_patterns\Attribute\Source;
16use Drupal\ui_patterns\Element\ComponentElementBuilder;
17use Drupal\ui_patterns\Entity\SampleEntityGeneratorInterface;
18use Drupal\ui_patterns\PropTypePluginManager;
19use Drupal\ui_patterns\SourcePluginBase;
20use Drupal\ui_patterns\SourcePluginManager;
21use Drupal\ui_patterns\UiPatternsNormalizerInterface;
22use Symfony\Component\DependencyInjection\ContainerInterface;
23
24/**
25 * Plugin implementation of the source.
26 */
27#[Source(
28  id: 'page_layout',
29  label: new TranslatableMarkup('Page layout (from active theme)'),
30  prop_types: ['slot'],
31  context_requirements: ['page'],
32  context_definitions: []
33)]
34class PageLayoutSource extends SourcePluginBase implements SourceWithSlotsInterface {
35
36  /**
37   * {@inheritdoc}
38   */
39  public function __construct(
40    array $configuration,
41    $plugin_id,
42    $plugin_definition,
43    PropTypePluginManager $propTypeManager,
44    ContextRepositoryInterface $contextRepository,
45    RouteMatchInterface $routeMatch,
46    SampleEntityGeneratorInterface $sampleEntityGenerator,
47    ModuleHandlerInterface $moduleHandler,
48    Token $token,
49    UiPatternsNormalizerInterface $normalizer,
50    protected ComponentElementBuilder $componentElementBuilder,
51    protected SourcePluginManager $sourceManager,
52    protected ConfigFactoryInterface $configFactory,
53  ) {
54    parent::__construct($configuration, $plugin_id, $plugin_definition, $propTypeManager, $contextRepository, $routeMatch, $sampleEntityGenerator, $moduleHandler, $token, $normalizer);
55  }
56
57  /**
58   * {@inheritdoc}
59   */
60  public static function create(
61    ContainerInterface $container,
62    array $configuration,
63    $plugin_id,
64    $plugin_definition,
65  ): static {
66    $instance = new static(
67      $configuration,
68      $plugin_id,
69      $plugin_definition,
70      $container->get('plugin.manager.ui_patterns_prop_type'),
71      $container->get('context.repository'),
72      $container->get('current_route_match'),
73      $container->get('ui_patterns.sample_entity_generator'),
74      $container->get('module_handler'),
75      $container->get('token'),
76      $container->get('ui_patterns.normalizer'),
77      $container->get('ui_patterns.component_element_builder'),
78      $container->get('plugin.manager.ui_patterns_source'),
79      $container->get('config.factory'),
80    );
81
82    return $instance;
83  }
84
85  /**
86   * {@inheritdoc}
87   */
88  public function getPropValue(): mixed {
89    /** @var array<string, mixed> $page */
90    $page = [
91      '#type' => 'page',
92    ];
93
94    foreach ($this->getSlotValues() as $region_id => $region) {
95      $region_content = [];
96
97      foreach ($region as $source) {
98        $content = $this->componentElementBuilder->buildSource([], 'content', [], $source, $this->configuration['contexts'] ?? []) ?? [];
99        $content = $content['#slots']['content'][0] ?? [];
100        $region_content[] = $content;
101      }
102
103      $page[(string) $region_id] = $region_content;
104    }
105
106    return $page;
107  }
108
109  /**
110   * {@inheritdoc}
111   */
112  public function calculateDependencies(): array {
113    $dependencies = parent::calculateDependencies();
114    $slot_definition = ['ui_patterns' => ['type_definition' => $this->sourceManager->getSlotPropType()]];
115
116    foreach ($this->getSlotValues() as $slot_id => $slot) {
117      // A slot is a list of source data.
118      $slot = \array_is_list($slot) ? $slot : [$slot];
119
120      foreach ($slot as $source) {
121        if ($source = $this->sourceManager->getSource($slot_id, $slot_definition, $source, [])) {
122          SourcePluginBase::mergeConfigDependencies(
123            $dependencies,
124            $source->calculateDependencies()
125          );
126        }
127      }
128    }
129
130    return $dependencies;
131  }
132
133  /**
134   * {@inheritdoc}
135   */
136  public function getSlotDefinitions(): array {
137    $slots = [];
138    $theme_name = $this->configFactory->get('system.theme')->get('default');
139    $regions = $this->systemRegionList($theme_name);
140
141    foreach ($regions as $region => $title) {
142      $slots[$region]['title'] = (string) $title;
143    }
144
145    return $slots;
146  }
147
148  /**
149   * {@inheritdoc}
150   */
151  public function getSlotValues(): array {
152    return $this->configuration['settings']['regions'] ?? [];
153  }
154
155  /**
156   * {@inheritdoc}
157   */
158  public function getSlotValue(string $slot_id): array {
159    return $this->configuration['settings']['regions'][$slot_id] ?? [];
160  }
161
162  /**
163   * {@inheritdoc}
164   */
165  public function setSlotValue(string $slot_id, array $slot): array {
166    $this->configuration['settings']['regions'][$slot_id] = $slot;
167
168    return $this->configuration['settings'];
169  }
170
171  /**
172   * {@inheritdoc}
173   */
174  public function setSlotRenderable(array $build, string $slot_id, array $slot): array {
175    $build[$slot_id] = $slot;
176
177    return $build;
178  }
179
180  /**
181   * {@inheritdoc}
182   */
183  public static function getSlotPath(string $slot_id): array {
184    return ['regions', $slot_id];
185  }
186
187  /**
188   * {@inheritdoc}
189   */
190  public function settingsFormPropsOnly(array $form, FormStateInterface $form_state): array {
191    return $form;
192  }
193
194  /**
195   * Lists a theme's visible regions.
196   *
197   * @param string $theme
198   *   The machine name of the theme.
199   *
200   * @return array
201   *   An array of region names and their human readable labels.
202   */
203  private function systemRegionList(string $theme): array {
204    return \Drupal::service('theme_handler')->getTheme($theme)->listVisibleRegions(); // @phpcs:ignore
205  }
206
207}