Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
61.47% |
67 / 109 |
|
59.68% |
37 / 62 |
|
40.48% |
17 / 42 |
|
36.36% |
8 / 22 |
CRAP | |
0.00% |
0 / 1 |
| DisplayExtender | |
61.47% |
67 / 109 |
|
59.68% |
37 / 62 |
|
40.48% |
17 / 42 |
|
36.36% |
8 / 22 |
414.02 | |
0.00% |
0 / 1 |
| create | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getPrefix | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| buildOptionsForm | |
75.00% |
3 / 4 |
|
66.67% |
2 / 3 |
|
50.00% |
1 / 2 |
|
0.00% |
0 / 1 |
2.50 | |||
| submitOptionsForm | |
53.85% |
7 / 13 |
|
62.50% |
5 / 8 |
|
20.00% |
1 / 5 |
|
0.00% |
0 / 1 |
17.80 | |||
| optionsSummary | |
87.50% |
7 / 8 |
|
66.67% |
2 / 3 |
|
50.00% |
1 / 2 |
|
0.00% |
0 / 1 |
2.50 | |||
| preExecute | |
0.00% |
0 / 6 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| getContextRequirement | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getBuilderUrl | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| checkInstanceId | |
85.71% |
6 / 7 |
|
66.67% |
2 / 3 |
|
50.00% |
1 / 2 |
|
0.00% |
0 / 1 |
2.50 | |||
| getUrlFromInstanceId | |
75.00% |
3 / 4 |
|
66.67% |
2 / 3 |
|
50.00% |
1 / 2 |
|
0.00% |
0 / 1 |
2.50 | |||
| getDisplayUrlFromInstanceId | |
0.00% |
0 / 4 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| getProfile | |
87.50% |
7 / 8 |
|
80.00% |
4 / 5 |
|
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
3.33 | |||
| getInstanceId | |
66.67% |
2 / 3 |
|
66.67% |
2 / 3 |
|
50.00% |
1 / 2 |
|
0.00% |
0 / 1 |
2.50 | |||
| checkAccess | |
0.00% |
0 / 1 |
|
0.00% |
0 / 4 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| initInstanceIfMissing | |
100.00% |
5 / 5 |
|
100.00% |
3 / 3 |
|
50.00% |
1 / 2 |
|
100.00% |
1 / 1 |
2.50 | |||
| getInitialSources | |
100.00% |
4 / 4 |
|
100.00% |
3 / 3 |
|
50.00% |
1 / 2 |
|
100.00% |
1 / 1 |
2.50 | |||
| getInitialContext | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getSources | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| saveSources | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| buildThemeRegistryEntry | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| isApplicable | |
66.67% |
6 / 9 |
|
57.14% |
4 / 7 |
|
25.00% |
1 / 4 |
|
0.00% |
0 / 1 |
10.75 | |||
| getInstance | |
100.00% |
4 / 4 |
|
100.00% |
3 / 3 |
|
50.00% |
1 / 2 |
|
100.00% |
1 / 1 |
2.50 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Drupal\display_builder_views\Plugin\views\display_extender; |
| 6 | |
| 7 | use Drupal\Core\Access\AccessResult; |
| 8 | use Drupal\Core\Access\AccessResultInterface; |
| 9 | use Drupal\Core\Extension\ModuleExtensionList; |
| 10 | use Drupal\Core\Form\FormStateInterface; |
| 11 | use Drupal\Core\Plugin\Context\EntityContext; |
| 12 | use Drupal\Core\Session\AccountInterface; |
| 13 | use Drupal\Core\StringTranslation\TranslatableMarkup; |
| 14 | use Drupal\Core\Theme\Registry; |
| 15 | use Drupal\Core\Url; |
| 16 | use Drupal\display_builder\ConfigFormBuilderInterface; |
| 17 | use Drupal\display_builder\DisplayBuildableInterface; |
| 18 | use Drupal\display_builder\DisplayBuilderHelpers; |
| 19 | use Drupal\display_builder\InstanceInterface; |
| 20 | use Drupal\display_builder\ProfileInterface; |
| 21 | use Drupal\ui_patterns\Plugin\Context\RequirementsContext; |
| 22 | use Drupal\views\Attribute\ViewsDisplayExtender; |
| 23 | use Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase; |
| 24 | use Symfony\Component\DependencyInjection\ContainerInterface; |
| 25 | |
| 26 | /** |
| 27 | * Styles display extender plugin. |
| 28 | * |
| 29 | * @ingroup views_display_extender_plugins |
| 30 | */ |
| 31 | #[ViewsDisplayExtender( |
| 32 | id: 'display_builder', |
| 33 | title: new TranslatableMarkup('Display Builder'), |
| 34 | help: new TranslatableMarkup('Use display builder as output for this view.'), |
| 35 | no_ui: FALSE, |
| 36 | )] |
| 37 | final class DisplayExtender extends DisplayExtenderPluginBase implements DisplayBuildableInterface { |
| 38 | |
| 39 | /** |
| 40 | * The config form builder for Display Builder. |
| 41 | * |
| 42 | * @var \Drupal\display_builder\ConfigFormBuilderInterface |
| 43 | */ |
| 44 | protected $configFormBuilder; |
| 45 | |
| 46 | /** |
| 47 | * The entity type interface. |
| 48 | * |
| 49 | * @var \Drupal\Core\Entity\EntityTypeManagerInterface |
| 50 | */ |
| 51 | protected $entityTypeManager; |
| 52 | |
| 53 | /** |
| 54 | * The theme registry. |
| 55 | */ |
| 56 | protected Registry $themeRegistry; |
| 57 | |
| 58 | /** |
| 59 | * The list of modules. |
| 60 | */ |
| 61 | protected ModuleExtensionList $modules; |
| 62 | |
| 63 | /** |
| 64 | * The loaded display builder instance. |
| 65 | */ |
| 66 | protected ?InstanceInterface $instance; |
| 67 | |
| 68 | /** |
| 69 | * {@inheritdoc} |
| 70 | */ |
| 71 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self { |
| 72 | $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); |
| 73 | $instance->configFormBuilder = $container->get('display_builder.config_form_builder'); |
| 74 | $instance->entityTypeManager = $container->get('entity_type.manager'); |
| 75 | $instance->themeRegistry = $container->get('theme.registry'); |
| 76 | $instance->modules = $container->get('extension.list.module'); |
| 77 | |
| 78 | return $instance; |
| 79 | } |
| 80 | |
| 81 | /** |
| 82 | * {@inheritdoc} |
| 83 | */ |
| 84 | public static function getPrefix(): string { |
| 85 | return 'views__'; |
| 86 | } |
| 87 | |
| 88 | /** |
| 89 | * {@inheritdoc} |
| 90 | */ |
| 91 | public function buildOptionsForm(&$form, FormStateInterface $form_state): void { |
| 92 | if ($form_state->get('section') !== 'display_builder') { |
| 93 | return; |
| 94 | } |
| 95 | |
| 96 | $form['#title'] .= $this->t('Display Builder'); |
| 97 | $form[ConfigFormBuilderInterface::PROFILE_PROPERTY] = $this->configFormBuilder->build($this, FALSE); |
| 98 | } |
| 99 | |
| 100 | /** |
| 101 | * {@inheritdoc} |
| 102 | */ |
| 103 | public function submitOptionsForm(&$form, FormStateInterface $form_state): void { |
| 104 | if ($form_state->get('section') !== 'display_builder') { |
| 105 | return; |
| 106 | } |
| 107 | |
| 108 | // @todo we should have always a fallback. |
| 109 | $profile_id = $form_state->getValue(ConfigFormBuilderInterface::PROFILE_PROPERTY, 'default'); |
| 110 | $this->options[ConfigFormBuilderInterface::PROFILE_PROPERTY] = $profile_id; |
| 111 | |
| 112 | if (empty($profile_id)) { |
| 113 | // If no Display Builder selected, we delete the related instance. |
| 114 | // @todo Do we move that to the View's EntityInterface::delete() method? |
| 115 | // @todo Also, when the changed are canceled from UI leaving the View |
| 116 | // without Display Builder. |
| 117 | $storage = $this->entityTypeManager->getStorage('display_builder_instance'); |
| 118 | $storage->delete([$this->getInstance()]); |
| 119 | |
| 120 | return; |
| 121 | } |
| 122 | |
| 123 | $this->initInstanceIfMissing(); |
| 124 | |
| 125 | // Save the profile in the instance if changed. |
| 126 | $instance = $this->getInstance(); |
| 127 | |
| 128 | if ($instance && $instance->getProfile()->id() !== $profile_id) { |
| 129 | $instance->setProfile($profile_id); |
| 130 | $instance->save(); |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | /** |
| 135 | * {@inheritdoc} |
| 136 | */ |
| 137 | public function optionsSummary(&$categories, &$options): void { |
| 138 | if (!$this->isApplicable()) { |
| 139 | return; |
| 140 | } |
| 141 | |
| 142 | $options['display_builder'] = [ |
| 143 | 'category' => 'other', |
| 144 | 'title' => $this->t('Display Builder'), |
| 145 | 'desc' => $this->t('Use display builder as output for this view.'), |
| 146 | 'value' => $this->getProfile()?->label() ?? $this->t('Disabled'), |
| 147 | ]; |
| 148 | } |
| 149 | |
| 150 | /** |
| 151 | * {@inheritdoc} |
| 152 | */ |
| 153 | public function preExecute(): void { |
| 154 | if (!$this->getProfile()) { |
| 155 | return; |
| 156 | } |
| 157 | // We alter the registry here instead of implementing |
| 158 | // hook_theme_registry_alter in order keep the alteration specific to each |
| 159 | // view. |
| 160 | $view = $this->view; |
| 161 | // Theme hook suggestion of the current view display. |
| 162 | $suggestion = \implode('__', ['views_view', $view->id(), $view->getDisplay()->getPluginId()]); |
| 163 | $entry = $this->buildThemeRegistryEntry(); |
| 164 | $this->themeRegistry->getRuntime()->set($suggestion, $entry); |
| 165 | } |
| 166 | |
| 167 | /** |
| 168 | * {@inheritdoc} |
| 169 | */ |
| 170 | public static function getContextRequirement(): string { |
| 171 | // @see \Drupal\ui_patterns_views\Plugin\UiPatterns\Source\ViewRowsSource. |
| 172 | return 'views:style'; |
| 173 | } |
| 174 | |
| 175 | /** |
| 176 | * {@inheritdoc} |
| 177 | */ |
| 178 | public function getBuilderUrl(): Url { |
| 179 | $params = [ |
| 180 | 'view' => $this->view->id(), |
| 181 | 'display' => $this->view->current_display, |
| 182 | ]; |
| 183 | |
| 184 | return Url::fromRoute('display_builder_views.views.manage', $params); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * {@inheritdoc} |
| 189 | */ |
| 190 | public static function checkInstanceId(string $instance_id): ?array { |
| 191 | if (!\str_starts_with($instance_id, DisplayExtender::getPrefix())) { |
| 192 | return NULL; |
| 193 | } |
| 194 | [, $view, $display] = \explode('__', $instance_id); |
| 195 | |
| 196 | return [ |
| 197 | 'view' => $view, |
| 198 | 'display' => $display, |
| 199 | ]; |
| 200 | } |
| 201 | |
| 202 | /** |
| 203 | * {@inheritdoc} |
| 204 | */ |
| 205 | public static function getUrlFromInstanceId(string $instance_id): Url { |
| 206 | $params = self::checkInstanceId($instance_id); |
| 207 | |
| 208 | if (!$params) { |
| 209 | // Fallback to the list of instances. |
| 210 | return Url::fromRoute('entity.display_builder_instance.collection'); |
| 211 | } |
| 212 | |
| 213 | return Url::fromRoute('display_builder_views.views.manage', $params); |
| 214 | } |
| 215 | |
| 216 | /** |
| 217 | * {@inheritdoc} |
| 218 | */ |
| 219 | public static function getDisplayUrlFromInstanceId(string $instance_id): Url { |
| 220 | $params = self::checkInstanceId($instance_id); |
| 221 | |
| 222 | if (!$params) { |
| 223 | // Fallback to the list of instances. |
| 224 | return Url::fromRoute('entity.display_builder_instance.collection'); |
| 225 | } |
| 226 | |
| 227 | return Url::fromRoute('entity.view.edit_form', $params); |
| 228 | } |
| 229 | |
| 230 | /** |
| 231 | * {@inheritdoc} |
| 232 | */ |
| 233 | public function getProfile(): ?ProfileInterface { |
| 234 | if (!isset($this->options[ConfigFormBuilderInterface::PROFILE_PROPERTY])) { |
| 235 | return NULL; |
| 236 | } |
| 237 | $display_builder_id = $this->options[ConfigFormBuilderInterface::PROFILE_PROPERTY]; |
| 238 | |
| 239 | if (empty($display_builder_id)) { |
| 240 | return NULL; |
| 241 | } |
| 242 | $storage = $this->entityTypeManager->getStorage('display_builder_profile'); |
| 243 | |
| 244 | /** @var \Drupal\display_builder\ProfileInterface $display_builder */ |
| 245 | $display_builder = $storage->load($display_builder_id); |
| 246 | |
| 247 | return $display_builder; |
| 248 | } |
| 249 | |
| 250 | /** |
| 251 | * {@inheritdoc} |
| 252 | */ |
| 253 | public function getInstanceId(): ?string { |
| 254 | if (!$this->view) { |
| 255 | return NULL; |
| 256 | } |
| 257 | |
| 258 | return \sprintf('%s%s__%s', self::getPrefix(), $this->view->id(), $this->view->current_display); |
| 259 | } |
| 260 | |
| 261 | /** |
| 262 | * {@inheritdoc} |
| 263 | */ |
| 264 | public static function checkAccess(string $instance_id, AccountInterface $account): AccessResultInterface { |
| 265 | return $account->hasPermission('administer views') ? AccessResult::allowed() : AccessResult::forbidden(); |
| 266 | } |
| 267 | |
| 268 | /** |
| 269 | * {@inheritdoc} |
| 270 | */ |
| 271 | public function initInstanceIfMissing(): void { |
| 272 | /** @var \Drupal\display_builder\InstanceStorage $storage */ |
| 273 | $storage = $this->entityTypeManager->getStorage('display_builder_instance'); |
| 274 | |
| 275 | /** @var \Drupal\display_builder\InstanceInterface $instance */ |
| 276 | $instance = $storage->load($this->getInstanceId()); |
| 277 | |
| 278 | if (!$instance) { |
| 279 | $instance = $storage->createFromImplementation($this); |
| 280 | $instance->save(); |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | /** |
| 285 | * {@inheritdoc} |
| 286 | */ |
| 287 | public function getInitialSources(): array { |
| 288 | // Get the sources stored in config. |
| 289 | $sources = $this->getSources(); |
| 290 | |
| 291 | if (empty($sources)) { |
| 292 | // Fallback to a fixture mimicking the standard view layout. |
| 293 | $sources = DisplayBuilderHelpers::getFixtureDataFromExtension('display_builder_views', 'default_view'); |
| 294 | } |
| 295 | |
| 296 | return $sources; |
| 297 | } |
| 298 | |
| 299 | /** |
| 300 | * {@inheritdoc} |
| 301 | */ |
| 302 | public function getInitialContext(): array { |
| 303 | $contexts = []; |
| 304 | // Mark for usage with views. |
| 305 | $contexts = RequirementsContext::addToContext([self::getContextRequirement()], $contexts); |
| 306 | // Add view entity that we need in our sources or even UI Patterns Views |
| 307 | // sources. |
| 308 | $contexts['ui_patterns_views:view_entity'] = EntityContext::fromEntity($this->view->storage); |
| 309 | |
| 310 | return $contexts; |
| 311 | } |
| 312 | |
| 313 | /** |
| 314 | * {@inheritdoc} |
| 315 | */ |
| 316 | public function getSources(): array { |
| 317 | return $this->options[ConfigFormBuilderInterface::SOURCES_PROPERTY] ?? []; |
| 318 | } |
| 319 | |
| 320 | /** |
| 321 | * {@inheritdoc} |
| 322 | */ |
| 323 | public function saveSources(): void { |
| 324 | $sources = $this->getInstance()->getCurrentState(); |
| 325 | $displays = $this->view->storage->get('display'); |
| 326 | $display_id = $this->view->current_display; |
| 327 | // It is risky to alter a View like that. We need to be careful to not |
| 328 | // break the storage integrity, but we didn't find a better way. |
| 329 | $displays[$display_id]['display_options']['display_extenders']['display_builder']['sources'] = $sources; |
| 330 | $this->view->storage->set('display', $displays); |
| 331 | $this->view->storage->save(); |
| 332 | // @todo Test if we still need to invalidate the cache manually here. |
| 333 | $this->view->storage->invalidateCaches(); |
| 334 | } |
| 335 | |
| 336 | /** |
| 337 | * Build theme registry entry. |
| 338 | * |
| 339 | * @return array |
| 340 | * A theme registry entry. |
| 341 | */ |
| 342 | protected function buildThemeRegistryEntry(): array { |
| 343 | $theme_registry = $this->themeRegistry->get(); |
| 344 | // Identical to views_view with a specific path. |
| 345 | $entry = $theme_registry['views_view']; |
| 346 | $entry['path'] = $this->modules->getPath('display_builder_views') . '/templates'; |
| 347 | |
| 348 | return $entry; |
| 349 | } |
| 350 | |
| 351 | /** |
| 352 | * If display builder can be applied to this display. |
| 353 | * |
| 354 | * @return bool |
| 355 | * Applicable or not. |
| 356 | */ |
| 357 | private function isApplicable(): bool { |
| 358 | $display = $this->view->getDisplay(); |
| 359 | $display_definition = $display->getPluginDefinition(); |
| 360 | |
| 361 | if (!isset($display_definition['class'])) { |
| 362 | return FALSE; |
| 363 | } |
| 364 | |
| 365 | // Do not include with feed and entity reference, as they have no output to |
| 366 | // apply a display builder to. |
| 367 | if ($display_definition['class'] === 'Drupal\views\Plugin\views\display\Feed') { |
| 368 | return FALSE; |
| 369 | } |
| 370 | |
| 371 | if ($display_definition['class'] === 'Drupal\views\Plugin\views\display\EntityReference') { |
| 372 | return FALSE; |
| 373 | } |
| 374 | |
| 375 | // @todo safer to not allow third party display? |
| 376 | // phpcs:disable |
| 377 | // if (str_contains($display_definition['class'], 'Drupal\views\Plugin\views\display')) { |
| 378 | // return FALSE; |
| 379 | // } |
| 380 | // phpcs:enable |
| 381 | |
| 382 | return TRUE; |
| 383 | } |
| 384 | |
| 385 | /** |
| 386 | * Gets the Display Builder instance. |
| 387 | * |
| 388 | * @return \Drupal\display_builder\InstanceInterface|null |
| 389 | * A display builder instance entity. |
| 390 | */ |
| 391 | private function getInstance(): ?InstanceInterface { |
| 392 | if (!isset($this->instance)) { |
| 393 | /** @var \Drupal\display_builder\InstanceInterface|null $instance */ |
| 394 | $instance = $this->entityTypeManager->getStorage('display_builder_instance')->load($this->getInstanceId()); |
| 395 | $this->instance = $instance; |
| 396 | } |
| 397 | |
| 398 | return $this->instance; |
| 399 | } |
| 400 | |
| 401 | } |
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.
| 91 | public function buildOptionsForm(&$form, FormStateInterface $form_state): void { |
| 92 | if ($form_state->get('section') !== 'display_builder') { |
| 93 | return; |
| 96 | $form['#title'] .= $this->t('Display Builder'); |
| 97 | $form[ConfigFormBuilderInterface::PROFILE_PROPERTY] = $this->configFormBuilder->build($this, FALSE); |
| 98 | } |
| 343 | $theme_registry = $this->themeRegistry->get(); |
| 344 | // Identical to views_view with a specific path. |
| 345 | $entry = $theme_registry['views_view']; |
| 346 | $entry['path'] = $this->modules->getPath('display_builder_views') . '/templates'; |
| 347 | |
| 348 | return $entry; |
| 264 | public static function checkAccess(string $instance_id, AccountInterface $account): AccessResultInterface { |
| 265 | return $account->hasPermission('administer views') ? AccessResult::allowed() : AccessResult::forbidden(); |
| 265 | return $account->hasPermission('administer views') ? AccessResult::allowed() : AccessResult::forbidden(); |
| 265 | return $account->hasPermission('administer views') ? AccessResult::allowed() : AccessResult::forbidden(); |
| 265 | return $account->hasPermission('administer views') ? AccessResult::allowed() : AccessResult::forbidden(); |
| 190 | public static function checkInstanceId(string $instance_id): ?array { |
| 191 | if (!\str_starts_with($instance_id, DisplayExtender::getPrefix())) { |
| 192 | return NULL; |
| 194 | [, $view, $display] = \explode('__', $instance_id); |
| 195 | |
| 196 | return [ |
| 197 | 'view' => $view, |
| 198 | 'display' => $display, |
| 71 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self { |
| 72 | $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); |
| 73 | $instance->configFormBuilder = $container->get('display_builder.config_form_builder'); |
| 74 | $instance->entityTypeManager = $container->get('entity_type.manager'); |
| 75 | $instance->themeRegistry = $container->get('theme.registry'); |
| 76 | $instance->modules = $container->get('extension.list.module'); |
| 77 | |
| 78 | return $instance; |
| 180 | 'view' => $this->view->id(), |
| 181 | 'display' => $this->view->current_display, |
| 182 | ]; |
| 183 | |
| 184 | return Url::fromRoute('display_builder_views.views.manage', $params); |
| 172 | return 'views:style'; |
| 219 | public static function getDisplayUrlFromInstanceId(string $instance_id): Url { |
| 220 | $params = self::checkInstanceId($instance_id); |
| 221 | |
| 222 | if (!$params) { |
| 224 | return Url::fromRoute('entity.display_builder_instance.collection'); |
| 227 | return Url::fromRoute('entity.view.edit_form', $params); |
| 303 | $contexts = []; |
| 304 | // Mark for usage with views. |
| 305 | $contexts = RequirementsContext::addToContext([self::getContextRequirement()], $contexts); |
| 306 | // Add view entity that we need in our sources or even UI Patterns Views |
| 307 | // sources. |
| 308 | $contexts['ui_patterns_views:view_entity'] = EntityContext::fromEntity($this->view->storage); |
| 309 | |
| 310 | return $contexts; |
| 289 | $sources = $this->getSources(); |
| 290 | |
| 291 | if (empty($sources)) { |
| 293 | $sources = DisplayBuilderHelpers::getFixtureDataFromExtension('display_builder_views', 'default_view'); |
| 294 | } |
| 295 | |
| 296 | return $sources; |
| 296 | return $sources; |
| 392 | if (!isset($this->instance)) { |
| 394 | $instance = $this->entityTypeManager->getStorage('display_builder_instance')->load($this->getInstanceId()); |
| 395 | $this->instance = $instance; |
| 396 | } |
| 397 | |
| 398 | return $this->instance; |
| 398 | return $this->instance; |
| 254 | if (!$this->view) { |
| 255 | return NULL; |
| 258 | return \sprintf('%s%s__%s', self::getPrefix(), $this->view->id(), $this->view->current_display); |
| 85 | return 'views__'; |
| 234 | if (!isset($this->options[ConfigFormBuilderInterface::PROFILE_PROPERTY])) { |
| 235 | return NULL; |
| 237 | $display_builder_id = $this->options[ConfigFormBuilderInterface::PROFILE_PROPERTY]; |
| 238 | |
| 239 | if (empty($display_builder_id)) { |
| 240 | return NULL; |
| 242 | $storage = $this->entityTypeManager->getStorage('display_builder_profile'); |
| 243 | |
| 244 | /** @var \Drupal\display_builder\ProfileInterface $display_builder */ |
| 245 | $display_builder = $storage->load($display_builder_id); |
| 246 | |
| 247 | return $display_builder; |
| 317 | return $this->options[ConfigFormBuilderInterface::SOURCES_PROPERTY] ?? []; |
| 205 | public static function getUrlFromInstanceId(string $instance_id): Url { |
| 206 | $params = self::checkInstanceId($instance_id); |
| 207 | |
| 208 | if (!$params) { |
| 210 | return Url::fromRoute('entity.display_builder_instance.collection'); |
| 213 | return Url::fromRoute('display_builder_views.views.manage', $params); |
| 273 | $storage = $this->entityTypeManager->getStorage('display_builder_instance'); |
| 274 | |
| 275 | /** @var \Drupal\display_builder\InstanceInterface $instance */ |
| 276 | $instance = $storage->load($this->getInstanceId()); |
| 277 | |
| 278 | if (!$instance) { |
| 279 | $instance = $storage->createFromImplementation($this); |
| 280 | $instance->save(); |
| 281 | } |
| 282 | } |
| 282 | } |
| 358 | $display = $this->view->getDisplay(); |
| 359 | $display_definition = $display->getPluginDefinition(); |
| 360 | |
| 361 | if (!isset($display_definition['class'])) { |
| 362 | return FALSE; |
| 367 | if ($display_definition['class'] === 'Drupal\views\Plugin\views\display\Feed') { |
| 368 | return FALSE; |
| 371 | if ($display_definition['class'] === 'Drupal\views\Plugin\views\display\EntityReference') { |
| 372 | return FALSE; |
| 382 | return TRUE; |
| 137 | public function optionsSummary(&$categories, &$options): void { |
| 138 | if (!$this->isApplicable()) { |
| 139 | return; |
| 143 | 'category' => 'other', |
| 144 | 'title' => $this->t('Display Builder'), |
| 145 | 'desc' => $this->t('Use display builder as output for this view.'), |
| 146 | 'value' => $this->getProfile()?->label() ?? $this->t('Disabled'), |
| 147 | ]; |
| 148 | } |
| 154 | if (!$this->getProfile()) { |
| 155 | return; |
| 160 | $view = $this->view; |
| 161 | // Theme hook suggestion of the current view display. |
| 162 | $suggestion = \implode('__', ['views_view', $view->id(), $view->getDisplay()->getPluginId()]); |
| 163 | $entry = $this->buildThemeRegistryEntry(); |
| 164 | $this->themeRegistry->getRuntime()->set($suggestion, $entry); |
| 165 | } |
| 324 | $sources = $this->getInstance()->getCurrentState(); |
| 325 | $displays = $this->view->storage->get('display'); |
| 326 | $display_id = $this->view->current_display; |
| 327 | // It is risky to alter a View like that. We need to be careful to not |
| 328 | // break the storage integrity, but we didn't find a better way. |
| 329 | $displays[$display_id]['display_options']['display_extenders']['display_builder']['sources'] = $sources; |
| 330 | $this->view->storage->set('display', $displays); |
| 331 | $this->view->storage->save(); |
| 332 | // @todo Test if we still need to invalidate the cache manually here. |
| 333 | $this->view->storage->invalidateCaches(); |
| 334 | } |
| 103 | public function submitOptionsForm(&$form, FormStateInterface $form_state): void { |
| 104 | if ($form_state->get('section') !== 'display_builder') { |
| 105 | return; |
| 109 | $profile_id = $form_state->getValue(ConfigFormBuilderInterface::PROFILE_PROPERTY, 'default'); |
| 110 | $this->options[ConfigFormBuilderInterface::PROFILE_PROPERTY] = $profile_id; |
| 111 | |
| 112 | if (empty($profile_id)) { |
| 117 | $storage = $this->entityTypeManager->getStorage('display_builder_instance'); |
| 118 | $storage->delete([$this->getInstance()]); |
| 119 | |
| 120 | return; |
| 123 | $this->initInstanceIfMissing(); |
| 124 | |
| 125 | // Save the profile in the instance if changed. |
| 126 | $instance = $this->getInstance(); |
| 127 | |
| 128 | if ($instance && $instance->getProfile()->id() !== $profile_id) { |
| 128 | if ($instance && $instance->getProfile()->id() !== $profile_id) { |
| 129 | $instance->setProfile($profile_id); |
| 130 | $instance->save(); |
| 131 | } |
| 132 | } |
| 132 | } |