Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
83.62% |
97 / 116 |
|
80.33% |
49 / 61 |
|
31.25% |
15 / 48 |
|
52.63% |
10 / 19 |
CRAP | |
0.00% |
0 / 1 |
| LayoutSource | |
83.62% |
97 / 116 |
|
80.33% |
49 / 61 |
|
31.25% |
15 / 48 |
|
57.89% |
11 / 19 |
457.14 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| create | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| defaultSettings | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getPropValue | |
83.33% |
10 / 12 |
|
81.82% |
9 / 11 |
|
14.29% |
1 / 7 |
|
0.00% |
0 / 1 |
20.74 | |||
| settingsForm | |
100.00% |
8 / 8 |
|
100.00% |
3 / 3 |
|
50.00% |
1 / 2 |
|
100.00% |
1 / 1 |
2.50 | |||
| settingsSummary | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getChoices | |
100.00% |
14 / 14 |
|
100.00% |
9 / 9 |
|
16.67% |
1 / 6 |
|
100.00% |
1 / 1 |
13.26 | |||
| getChoiceSettings | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getChoice | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| calculateDependencies | |
100.00% |
21 / 21 |
|
91.67% |
11 / 12 |
|
8.33% |
1 / 12 |
|
100.00% |
1 / 1 |
24.26 | |||
| getSlotDefinitions | |
87.50% |
7 / 8 |
|
83.33% |
5 / 6 |
|
25.00% |
1 / 4 |
|
0.00% |
0 / 1 |
6.80 | |||
| getSlotValues | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getSlotValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setSlotValue | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setSlotRenderable | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getSlotPath | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| settingsFormPropsOnly | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getLayout | |
75.00% |
3 / 4 |
|
66.67% |
2 / 3 |
|
50.00% |
1 / 2 |
|
0.00% |
0 / 1 |
2.50 | |||
| getExtensionType | |
40.00% |
2 / 5 |
|
40.00% |
2 / 5 |
|
33.33% |
1 / 3 |
|
0.00% |
0 / 1 |
5.67 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Drupal\display_builder\Plugin\UiPatterns\Source; |
| 6 | |
| 7 | use Drupal\Component\Plugin\Definition\PluginDefinitionInterface; |
| 8 | use Drupal\Component\Render\MarkupInterface; |
| 9 | use Drupal\Core\Extension\ModuleHandlerInterface; |
| 10 | use Drupal\Core\Extension\ThemeHandlerInterface; |
| 11 | use Drupal\Core\Form\FormStateInterface; |
| 12 | use Drupal\Core\Layout\LayoutInterface; |
| 13 | use Drupal\Core\Layout\LayoutPluginManagerInterface; |
| 14 | use Drupal\Core\Plugin\Context\ContextRepositoryInterface; |
| 15 | use Drupal\Core\Plugin\PluginFormInterface; |
| 16 | use Drupal\Core\Routing\RouteMatchInterface; |
| 17 | use Drupal\Core\StringTranslation\TranslatableMarkup; |
| 18 | use Drupal\Core\Utility\Token; |
| 19 | use Drupal\display_builder\SourceWithSlotsInterface; |
| 20 | use Drupal\ui_patterns\Attribute\Source; |
| 21 | use Drupal\ui_patterns\Element\ComponentElementBuilder; |
| 22 | use Drupal\ui_patterns\Entity\SampleEntityGeneratorInterface; |
| 23 | use Drupal\ui_patterns\PropTypePluginManager; |
| 24 | use Drupal\ui_patterns\SourcePluginBase; |
| 25 | use Drupal\ui_patterns\SourcePluginManager; |
| 26 | use Drupal\ui_patterns\SourceWithChoicesInterface; |
| 27 | use Drupal\ui_patterns\UiPatternsNormalizerInterface; |
| 28 | use Symfony\Component\DependencyInjection\ContainerInterface; |
| 29 | |
| 30 | /** |
| 31 | * Plugin implementation of the source. |
| 32 | */ |
| 33 | #[Source( |
| 34 | id: 'layout', |
| 35 | label: new TranslatableMarkup('Layout'), |
| 36 | prop_types: ['slot'], |
| 37 | context_requirements: ['layout_discovery'], |
| 38 | )] |
| 39 | class LayoutSource extends SourcePluginBase implements SourceWithChoicesInterface, SourceWithSlotsInterface { |
| 40 | |
| 41 | /** |
| 42 | * {@inheritdoc} |
| 43 | */ |
| 44 | public function __construct( |
| 45 | array $configuration, |
| 46 | $plugin_id, |
| 47 | $plugin_definition, |
| 48 | PropTypePluginManager $propTypeManager, |
| 49 | ContextRepositoryInterface $contextRepository, |
| 50 | RouteMatchInterface $routeMatch, |
| 51 | SampleEntityGeneratorInterface $sampleEntityGenerator, |
| 52 | ModuleHandlerInterface $moduleHandler, |
| 53 | Token $token, |
| 54 | UiPatternsNormalizerInterface $normalizer, |
| 55 | protected ComponentElementBuilder $componentElementBuilder, |
| 56 | protected LayoutPluginManagerInterface $layoutManager, |
| 57 | protected SourcePluginManager $sourceManager, |
| 58 | protected ThemeHandlerInterface $themeHandler, |
| 59 | ) { |
| 60 | parent::__construct($configuration, $plugin_id, $plugin_definition, $propTypeManager, $contextRepository, $routeMatch, $sampleEntityGenerator, $moduleHandler, $token, $normalizer); |
| 61 | } |
| 62 | |
| 63 | /** |
| 64 | * {@inheritdoc} |
| 65 | */ |
| 66 | public static function create( |
| 67 | ContainerInterface $container, |
| 68 | array $configuration, |
| 69 | $plugin_id, |
| 70 | $plugin_definition, |
| 71 | ): static { |
| 72 | $instance = new static( |
| 73 | $configuration, |
| 74 | $plugin_id, |
| 75 | $plugin_definition, |
| 76 | $container->get('plugin.manager.ui_patterns_prop_type'), |
| 77 | $container->get('context.repository'), |
| 78 | $container->get('current_route_match'), |
| 79 | $container->get('ui_patterns.sample_entity_generator'), |
| 80 | $container->get('module_handler'), |
| 81 | $container->get('token'), |
| 82 | $container->get('ui_patterns.normalizer'), |
| 83 | $container->get('ui_patterns.component_element_builder'), |
| 84 | $container->get('plugin.manager.core.layout'), |
| 85 | $container->get('plugin.manager.ui_patterns_source'), |
| 86 | $container->get('theme_handler'), |
| 87 | ); |
| 88 | |
| 89 | return $instance; |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * {@inheritdoc} |
| 94 | */ |
| 95 | public function defaultSettings(): array { |
| 96 | $layout = $this->getLayout(); |
| 97 | |
| 98 | return [ |
| 99 | 'layout_id' => NULL, |
| 100 | 'settings' => $layout->defaultConfiguration() ?? [], |
| 101 | 'regions' => [], |
| 102 | ]; |
| 103 | } |
| 104 | |
| 105 | /** |
| 106 | * {@inheritdoc} |
| 107 | */ |
| 108 | public function getPropValue(): mixed { |
| 109 | $layout = $this->getLayout(); |
| 110 | |
| 111 | if (!$layout) { |
| 112 | return []; |
| 113 | } |
| 114 | |
| 115 | $regions = []; |
| 116 | |
| 117 | foreach ($this->configuration['settings']['regions'] ?? [] as $region_id => $region) { |
| 118 | foreach ($region as $source) { |
| 119 | $content = $this->componentElementBuilder->buildSource([], 'content', [], $source, $this->configuration['contexts'] ?? []) ?? []; |
| 120 | $content = $content['#slots']['content'][0] ?? []; |
| 121 | |
| 122 | // An empty render array is enough to cancel the rendering of the full |
| 123 | // layout plugins, so let's remove them from the renderable. |
| 124 | if (empty($content)) { |
| 125 | continue; |
| 126 | } |
| 127 | $regions[$region_id][] = $content; |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | return $layout->build($regions); |
| 132 | } |
| 133 | |
| 134 | /** |
| 135 | * {@inheritdoc} |
| 136 | */ |
| 137 | public function settingsForm(array $form, FormStateInterface $form_state): array { |
| 138 | // Careful with the configuration/settings/settings hierarchy where: |
| 139 | // - $this->configuration has everything UI Patterns needs to work properly |
| 140 | // (prop_id, prop_definition, contexts..) |
| 141 | // - $this->configuration['settings'] is the source data from the source |
| 142 | // tree |
| 143 | // - $this->configuration['settings']['settings'] is the layout plugin |
| 144 | // configuration. |
| 145 | $form = parent::settingsForm($form, $form_state); |
| 146 | $form['#tree'] = TRUE; |
| 147 | |
| 148 | // We are not implementing a slot sources form for $forms['regions'], |
| 149 | // because Display Builder doesn't need layout regions to be available in |
| 150 | // the component form. |
| 151 | // @todo However, for compatibility with UI Patterns ecosystem, it would be |
| 152 | // better to implement it anyway. It will be removed by |
| 153 | // ::settingsFormPropsOnly() anyway. |
| 154 | $form['regions'] = []; |
| 155 | $layout = $this->getLayout(); |
| 156 | |
| 157 | if ($layout instanceof PluginFormInterface) { |
| 158 | $form['settings'] = $layout->buildConfigurationForm($form, $form_state); |
| 159 | // Hide administrative label textfield. |
| 160 | $form['settings']['label']['#type'] = 'hidden'; |
| 161 | } |
| 162 | |
| 163 | return $form; |
| 164 | } |
| 165 | |
| 166 | /** |
| 167 | * {@inheritdoc} |
| 168 | */ |
| 169 | public function settingsSummary(): array { |
| 170 | // @todo settings summary |
| 171 | return []; |
| 172 | } |
| 173 | |
| 174 | /** |
| 175 | * {@inheritdoc} |
| 176 | */ |
| 177 | public function getChoices(): array { |
| 178 | $definitions = $this->layoutManager->getGroupedDefinitions(); |
| 179 | $choices = []; |
| 180 | |
| 181 | foreach ($definitions as $group_id => $group) { |
| 182 | foreach ($group as $layout_id => $definition) { |
| 183 | /** @var \Drupal\Core\Layout\LayoutDefinition $definition */ |
| 184 | $choice = [ |
| 185 | 'label' => $definition->getLabel(), |
| 186 | 'original_id' => $layout_id, |
| 187 | 'group' => $group_id, |
| 188 | 'provider' => $definition, |
| 189 | ]; |
| 190 | |
| 191 | if ($choice['label'] instanceof MarkupInterface) { |
| 192 | $choice['label'] = (string) $choice['label']; |
| 193 | } |
| 194 | $choices[$layout_id] = $choice; |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | return $choices; |
| 199 | } |
| 200 | |
| 201 | /** |
| 202 | * {@inheritdoc} |
| 203 | */ |
| 204 | public function getChoiceSettings(string $choice_id): array { |
| 205 | return [ |
| 206 | 'layout_id' => $choice_id, |
| 207 | ]; |
| 208 | } |
| 209 | |
| 210 | /** |
| 211 | * {@inheritdoc} |
| 212 | */ |
| 213 | public function getChoice(array $settings): string { |
| 214 | return $settings['layout_id'] ?? ''; |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * {@inheritdoc} |
| 219 | */ |
| 220 | public function calculateDependencies(): array { |
| 221 | $dependencies = parent::calculateDependencies(); |
| 222 | $layout = $this->getLayout(); |
| 223 | $provider = []; |
| 224 | |
| 225 | // 1. Dependency of plugin.manager.core.layout. |
| 226 | $provider['module'][] = 'layout_discovery'; |
| 227 | |
| 228 | // 2. Layout provider extension (module or theme) |
| 229 | $definition = $layout->getPluginDefinition(); |
| 230 | $provider = ($definition instanceof PluginDefinitionInterface) ? $definition->getProvider() : (string) ($definition['provider'] ?? ''); |
| 231 | $extension_type = $this->getExtensionType($provider); |
| 232 | $dependencies[$extension_type][] = $provider; |
| 233 | |
| 234 | // 3. Layout plugin dependencies. |
| 235 | SourcePluginBase::mergeConfigDependencies( |
| 236 | $dependencies, |
| 237 | $layout->calculateDependencies() |
| 238 | ); |
| 239 | |
| 240 | // 4. Sources in slots. |
| 241 | $slot_definition = ['ui_patterns' => ['type_definition' => $this->sourceManager->getSlotPropType()]]; |
| 242 | |
| 243 | foreach ($this->getSlotValues() as $slot_id => $slot) { |
| 244 | foreach ($slot as $source) { |
| 245 | if ($source = $this->sourceManager->getSource($slot_id, $slot_definition, $source, [])) { |
| 246 | SourcePluginBase::mergeConfigDependencies( |
| 247 | $dependencies, |
| 248 | $source->calculateDependencies() |
| 249 | ); |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | return $dependencies; |
| 255 | } |
| 256 | |
| 257 | /** |
| 258 | * {@inheritdoc} |
| 259 | */ |
| 260 | public function getSlotDefinitions(): array { |
| 261 | $slots = []; |
| 262 | $layout_id = $this->configuration['settings']['layout_id'] ?? NULL; |
| 263 | |
| 264 | if (!$layout_id) { |
| 265 | return []; |
| 266 | } |
| 267 | $definition = $this->layoutManager->getDefinition($layout_id); |
| 268 | |
| 269 | foreach ($definition->getRegions() as $region_id => $region) { |
| 270 | $slots[$region_id]['title'] = (string) $region['label']; |
| 271 | } |
| 272 | |
| 273 | return $slots; |
| 274 | } |
| 275 | |
| 276 | /** |
| 277 | * {@inheritdoc} |
| 278 | */ |
| 279 | public function getSlotValues(): array { |
| 280 | return $this->configuration['settings']['regions'] ?? []; |
| 281 | } |
| 282 | |
| 283 | /** |
| 284 | * {@inheritdoc} |
| 285 | */ |
| 286 | public function getSlotValue(string $slot_id): array { |
| 287 | return $this->configuration['settings']['regions'][$slot_id] ?? []; |
| 288 | } |
| 289 | |
| 290 | /** |
| 291 | * {@inheritdoc} |
| 292 | */ |
| 293 | public function setSlotValue(string $slot_id, array $slot): array { |
| 294 | $this->configuration['settings']['regions'][$slot_id] = $slot; |
| 295 | |
| 296 | return $this->configuration['settings']; |
| 297 | } |
| 298 | |
| 299 | /** |
| 300 | * {@inheritdoc} |
| 301 | */ |
| 302 | public function setSlotRenderable(array $build, string $slot_id, array $slot): array { |
| 303 | $build[$slot_id] = $slot; |
| 304 | |
| 305 | return $build; |
| 306 | } |
| 307 | |
| 308 | /** |
| 309 | * {@inheritdoc} |
| 310 | */ |
| 311 | public static function getSlotPath(string $slot_id): array { |
| 312 | return ['regions', $slot_id]; |
| 313 | } |
| 314 | |
| 315 | /** |
| 316 | * {@inheritdoc} |
| 317 | */ |
| 318 | public function settingsFormPropsOnly(array $form, FormStateInterface $form_state): array { |
| 319 | $form = $this->settingsForm($form, $form_state); |
| 320 | unset($form['regions']); |
| 321 | $layout = $this->getLayout(); |
| 322 | $form['layout_id'] = [ |
| 323 | '#type' => 'hidden', |
| 324 | '#value' => $layout->getPluginId(), |
| 325 | ]; |
| 326 | |
| 327 | return $form; |
| 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Get layout plugin. |
| 332 | * |
| 333 | * @return \Drupal\Core\Layout\LayoutInterface|null |
| 334 | * The layout plugin. |
| 335 | */ |
| 336 | private function getLayout(): ?LayoutInterface { |
| 337 | $layout_id = $this->configuration['settings']['layout_id'] ?? NULL; |
| 338 | |
| 339 | if (!$layout_id) { |
| 340 | return NULL; |
| 341 | } |
| 342 | |
| 343 | return $this->layoutManager->createInstance($layout_id, $this->configuration['settings']['settings'] ?? []); |
| 344 | } |
| 345 | |
| 346 | /** |
| 347 | * Get extension type (theme or module). |
| 348 | * |
| 349 | * @param string $extension |
| 350 | * Extension (module or theme) machine name. |
| 351 | * |
| 352 | * @return string |
| 353 | * Extension type. |
| 354 | */ |
| 355 | private function getExtensionType(string $extension): string { |
| 356 | if ($this->moduleHandler->moduleExists($extension)) { |
| 357 | return 'module'; |
| 358 | } |
| 359 | |
| 360 | if ($this->themeHandler->themeExists($extension)) { |
| 361 | return 'theme'; |
| 362 | } |
| 363 | |
| 364 | return ''; |
| 365 | } |
| 366 | |
| 367 | } |
Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not
necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once.
Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 45 | array $configuration, |
| 46 | $plugin_id, |
| 47 | $plugin_definition, |
| 48 | PropTypePluginManager $propTypeManager, |
| 49 | ContextRepositoryInterface $contextRepository, |
| 50 | RouteMatchInterface $routeMatch, |
| 51 | SampleEntityGeneratorInterface $sampleEntityGenerator, |
| 52 | ModuleHandlerInterface $moduleHandler, |
| 53 | Token $token, |
| 54 | UiPatternsNormalizerInterface $normalizer, |
| 55 | protected ComponentElementBuilder $componentElementBuilder, |
| 56 | protected LayoutPluginManagerInterface $layoutManager, |
| 57 | protected SourcePluginManager $sourceManager, |
| 58 | protected ThemeHandlerInterface $themeHandler, |
| 59 | ) { |
| 60 | parent::__construct($configuration, $plugin_id, $plugin_definition, $propTypeManager, $contextRepository, $routeMatch, $sampleEntityGenerator, $moduleHandler, $token, $normalizer); |
| 61 | } |
| 221 | $dependencies = parent::calculateDependencies(); |
| 222 | $layout = $this->getLayout(); |
| 223 | $provider = []; |
| 224 | |
| 225 | // 1. Dependency of plugin.manager.core.layout. |
| 226 | $provider['module'][] = 'layout_discovery'; |
| 227 | |
| 228 | // 2. Layout provider extension (module or theme) |
| 229 | $definition = $layout->getPluginDefinition(); |
| 230 | $provider = ($definition instanceof PluginDefinitionInterface) ? $definition->getProvider() : (string) ($definition['provider'] ?? ''); |
| 230 | $provider = ($definition instanceof PluginDefinitionInterface) ? $definition->getProvider() : (string) ($definition['provider'] ?? ''); |
| 230 | $provider = ($definition instanceof PluginDefinitionInterface) ? $definition->getProvider() : (string) ($definition['provider'] ?? ''); |
| 230 | $provider = ($definition instanceof PluginDefinitionInterface) ? $definition->getProvider() : (string) ($definition['provider'] ?? ''); |
| 231 | $extension_type = $this->getExtensionType($provider); |
| 232 | $dependencies[$extension_type][] = $provider; |
| 233 | |
| 234 | // 3. Layout plugin dependencies. |
| 235 | SourcePluginBase::mergeConfigDependencies( |
| 236 | $dependencies, |
| 237 | $layout->calculateDependencies() |
| 238 | ); |
| 239 | |
| 240 | // 4. Sources in slots. |
| 241 | $slot_definition = ['ui_patterns' => ['type_definition' => $this->sourceManager->getSlotPropType()]]; |
| 242 | |
| 243 | foreach ($this->getSlotValues() as $slot_id => $slot) { |
| 243 | foreach ($this->getSlotValues() as $slot_id => $slot) { |
| 243 | foreach ($this->getSlotValues() as $slot_id => $slot) { |
| 244 | foreach ($slot as $source) { |
| 244 | foreach ($slot as $source) { |
| 245 | if ($source = $this->sourceManager->getSource($slot_id, $slot_definition, $source, [])) { |
| 244 | foreach ($slot as $source) { |
| 245 | if ($source = $this->sourceManager->getSource($slot_id, $slot_definition, $source, [])) { |
| 246 | SourcePluginBase::mergeConfigDependencies( |
| 244 | foreach ($slot as $source) { |
| 243 | foreach ($this->getSlotValues() as $slot_id => $slot) { |
| 244 | foreach ($slot as $source) { |
| 243 | foreach ($this->getSlotValues() as $slot_id => $slot) { |
| 244 | foreach ($slot as $source) { |
| 245 | if ($source = $this->sourceManager->getSource($slot_id, $slot_definition, $source, [])) { |
| 246 | SourcePluginBase::mergeConfigDependencies( |
| 247 | $dependencies, |
| 248 | $source->calculateDependencies() |
| 249 | ); |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | return $dependencies; |
| 255 | } |
| 67 | ContainerInterface $container, |
| 68 | array $configuration, |
| 69 | $plugin_id, |
| 70 | $plugin_definition, |
| 71 | ): static { |
| 72 | $instance = new static( |
| 73 | $configuration, |
| 74 | $plugin_id, |
| 75 | $plugin_definition, |
| 76 | $container->get('plugin.manager.ui_patterns_prop_type'), |
| 77 | $container->get('context.repository'), |
| 78 | $container->get('current_route_match'), |
| 79 | $container->get('ui_patterns.sample_entity_generator'), |
| 80 | $container->get('module_handler'), |
| 81 | $container->get('token'), |
| 82 | $container->get('ui_patterns.normalizer'), |
| 83 | $container->get('ui_patterns.component_element_builder'), |
| 84 | $container->get('plugin.manager.core.layout'), |
| 85 | $container->get('plugin.manager.ui_patterns_source'), |
| 86 | $container->get('theme_handler'), |
| 87 | ); |
| 88 | |
| 89 | return $instance; |
| 90 | } |
| 96 | $layout = $this->getLayout(); |
| 97 | |
| 98 | return [ |
| 99 | 'layout_id' => NULL, |
| 100 | 'settings' => $layout->defaultConfiguration() ?? [], |
| 101 | 'regions' => [], |
| 102 | ]; |
| 103 | } |
| 213 | public function getChoice(array $settings): string { |
| 214 | return $settings['layout_id'] ?? ''; |
| 215 | } |
| 204 | public function getChoiceSettings(string $choice_id): array { |
| 205 | return [ |
| 206 | 'layout_id' => $choice_id, |
| 207 | ]; |
| 208 | } |
| 178 | $definitions = $this->layoutManager->getGroupedDefinitions(); |
| 179 | $choices = []; |
| 180 | |
| 181 | foreach ($definitions as $group_id => $group) { |
| 181 | foreach ($definitions as $group_id => $group) { |
| 181 | foreach ($definitions as $group_id => $group) { |
| 182 | foreach ($group as $layout_id => $definition) { |
| 182 | foreach ($group as $layout_id => $definition) { |
| 182 | foreach ($group as $layout_id => $definition) { |
| 183 | /** @var \Drupal\Core\Layout\LayoutDefinition $definition */ |
| 184 | $choice = [ |
| 185 | 'label' => $definition->getLabel(), |
| 186 | 'original_id' => $layout_id, |
| 187 | 'group' => $group_id, |
| 188 | 'provider' => $definition, |
| 189 | ]; |
| 190 | |
| 191 | if ($choice['label'] instanceof MarkupInterface) { |
| 192 | $choice['label'] = (string) $choice['label']; |
| 193 | } |
| 194 | $choices[$layout_id] = $choice; |
| 182 | foreach ($group as $layout_id => $definition) { |
| 183 | /** @var \Drupal\Core\Layout\LayoutDefinition $definition */ |
| 184 | $choice = [ |
| 185 | 'label' => $definition->getLabel(), |
| 186 | 'original_id' => $layout_id, |
| 187 | 'group' => $group_id, |
| 188 | 'provider' => $definition, |
| 189 | ]; |
| 190 | |
| 191 | if ($choice['label'] instanceof MarkupInterface) { |
| 192 | $choice['label'] = (string) $choice['label']; |
| 193 | } |
| 194 | $choices[$layout_id] = $choice; |
| 181 | foreach ($definitions as $group_id => $group) { |
| 182 | foreach ($group as $layout_id => $definition) { |
| 181 | foreach ($definitions as $group_id => $group) { |
| 182 | foreach ($group as $layout_id => $definition) { |
| 183 | /** @var \Drupal\Core\Layout\LayoutDefinition $definition */ |
| 184 | $choice = [ |
| 185 | 'label' => $definition->getLabel(), |
| 186 | 'original_id' => $layout_id, |
| 187 | 'group' => $group_id, |
| 188 | 'provider' => $definition, |
| 189 | ]; |
| 190 | |
| 191 | if ($choice['label'] instanceof MarkupInterface) { |
| 192 | $choice['label'] = (string) $choice['label']; |
| 193 | } |
| 194 | $choices[$layout_id] = $choice; |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | return $choices; |
| 199 | } |
| 355 | private function getExtensionType(string $extension): string { |
| 356 | if ($this->moduleHandler->moduleExists($extension)) { |
| 357 | return 'module'; |
| 360 | if ($this->themeHandler->themeExists($extension)) { |
| 361 | return 'theme'; |
| 364 | return ''; |
| 365 | } |
| 337 | $layout_id = $this->configuration['settings']['layout_id'] ?? NULL; |
| 338 | |
| 339 | if (!$layout_id) { |
| 340 | return NULL; |
| 343 | return $this->layoutManager->createInstance($layout_id, $this->configuration['settings']['settings'] ?? []); |
| 344 | } |
| 109 | $layout = $this->getLayout(); |
| 110 | |
| 111 | if (!$layout) { |
| 112 | return []; |
| 115 | $regions = []; |
| 116 | |
| 117 | foreach ($this->configuration['settings']['regions'] ?? [] as $region_id => $region) { |
| 117 | foreach ($this->configuration['settings']['regions'] ?? [] as $region_id => $region) { |
| 117 | foreach ($this->configuration['settings']['regions'] ?? [] as $region_id => $region) { |
| 118 | foreach ($region as $source) { |
| 118 | foreach ($region as $source) { |
| 119 | $content = $this->componentElementBuilder->buildSource([], 'content', [], $source, $this->configuration['contexts'] ?? []) ?? []; |
| 120 | $content = $content['#slots']['content'][0] ?? []; |
| 121 | |
| 122 | // An empty render array is enough to cancel the rendering of the full |
| 123 | // layout plugins, so let's remove them from the renderable. |
| 124 | if (empty($content)) { |
| 125 | continue; |
| 118 | foreach ($region as $source) { |
| 119 | $content = $this->componentElementBuilder->buildSource([], 'content', [], $source, $this->configuration['contexts'] ?? []) ?? []; |
| 120 | $content = $content['#slots']['content'][0] ?? []; |
| 121 | |
| 122 | // An empty render array is enough to cancel the rendering of the full |
| 123 | // layout plugins, so let's remove them from the renderable. |
| 124 | if (empty($content)) { |
| 125 | continue; |
| 126 | } |
| 127 | $regions[$region_id][] = $content; |
| 117 | foreach ($this->configuration['settings']['regions'] ?? [] as $region_id => $region) { |
| 118 | foreach ($region as $source) { |
| 117 | foreach ($this->configuration['settings']['regions'] ?? [] as $region_id => $region) { |
| 118 | foreach ($region as $source) { |
| 119 | $content = $this->componentElementBuilder->buildSource([], 'content', [], $source, $this->configuration['contexts'] ?? []) ?? []; |
| 120 | $content = $content['#slots']['content'][0] ?? []; |
| 121 | |
| 122 | // An empty render array is enough to cancel the rendering of the full |
| 123 | // layout plugins, so let's remove them from the renderable. |
| 124 | if (empty($content)) { |
| 125 | continue; |
| 126 | } |
| 127 | $regions[$region_id][] = $content; |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | return $layout->build($regions); |
| 132 | } |
| 261 | $slots = []; |
| 262 | $layout_id = $this->configuration['settings']['layout_id'] ?? NULL; |
| 263 | |
| 264 | if (!$layout_id) { |
| 265 | return []; |
| 267 | $definition = $this->layoutManager->getDefinition($layout_id); |
| 268 | |
| 269 | foreach ($definition->getRegions() as $region_id => $region) { |
| 269 | foreach ($definition->getRegions() as $region_id => $region) { |
| 269 | foreach ($definition->getRegions() as $region_id => $region) { |
| 269 | foreach ($definition->getRegions() as $region_id => $region) { |
| 270 | $slots[$region_id]['title'] = (string) $region['label']; |
| 271 | } |
| 272 | |
| 273 | return $slots; |
| 274 | } |
| 311 | public static function getSlotPath(string $slot_id): array { |
| 312 | return ['regions', $slot_id]; |
| 313 | } |
| 286 | public function getSlotValue(string $slot_id): array { |
| 287 | return $this->configuration['settings']['regions'][$slot_id] ?? []; |
| 288 | } |
| 280 | return $this->configuration['settings']['regions'] ?? []; |
| 281 | } |
| 302 | public function setSlotRenderable(array $build, string $slot_id, array $slot): array { |
| 303 | $build[$slot_id] = $slot; |
| 304 | |
| 305 | return $build; |
| 306 | } |
| 293 | public function setSlotValue(string $slot_id, array $slot): array { |
| 294 | $this->configuration['settings']['regions'][$slot_id] = $slot; |
| 295 | |
| 296 | return $this->configuration['settings']; |
| 297 | } |
| 137 | public function settingsForm(array $form, FormStateInterface $form_state): array { |
| 138 | // Careful with the configuration/settings/settings hierarchy where: |
| 139 | // - $this->configuration has everything UI Patterns needs to work properly |
| 140 | // (prop_id, prop_definition, contexts..) |
| 141 | // - $this->configuration['settings'] is the source data from the source |
| 142 | // tree |
| 143 | // - $this->configuration['settings']['settings'] is the layout plugin |
| 144 | // configuration. |
| 145 | $form = parent::settingsForm($form, $form_state); |
| 146 | $form['#tree'] = TRUE; |
| 147 | |
| 148 | // We are not implementing a slot sources form for $forms['regions'], |
| 149 | // because Display Builder doesn't need layout regions to be available in |
| 150 | // the component form. |
| 151 | // @todo However, for compatibility with UI Patterns ecosystem, it would be |
| 152 | // better to implement it anyway. It will be removed by |
| 153 | // ::settingsFormPropsOnly() anyway. |
| 154 | $form['regions'] = []; |
| 155 | $layout = $this->getLayout(); |
| 156 | |
| 157 | if ($layout instanceof PluginFormInterface) { |
| 158 | $form['settings'] = $layout->buildConfigurationForm($form, $form_state); |
| 159 | // Hide administrative label textfield. |
| 160 | $form['settings']['label']['#type'] = 'hidden'; |
| 161 | } |
| 162 | |
| 163 | return $form; |
| 163 | return $form; |
| 164 | } |
| 318 | public function settingsFormPropsOnly(array $form, FormStateInterface $form_state): array { |
| 319 | $form = $this->settingsForm($form, $form_state); |
| 320 | unset($form['regions']); |
| 321 | $layout = $this->getLayout(); |
| 322 | $form['layout_id'] = [ |
| 323 | '#type' => 'hidden', |
| 324 | '#value' => $layout->getPluginId(), |
| 325 | ]; |
| 326 | |
| 327 | return $form; |
| 328 | } |
| 171 | return []; |
| 172 | } |