Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 61
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
PageLayout
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 16
702
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 checkInstanceId
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getBuilderUrl
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
 checkAccess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getUrlFromInstanceId
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getDisplayUrlFromInstanceId
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getProfile
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
 getSources
0.00% covered (danger)
0.00%
0 / 3
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
 saveSources
0.00% covered (danger)
0.00%
0 / 3
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
 collectInstances
0.00% covered (danger)
0.00%
0 / 10
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
 getInstanceId
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getRuntimeContexts
0.00% covered (danger)
0.00%
0 / 3
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
 getInitializationMessage
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getInitialSources
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 converter
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
 pluginCacheClearer
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\display_builder\Buildable;
6
7use Drupal\Core\Access\AccessResult;
8use Drupal\Core\Access\AccessResultInterface;
9use Drupal\Core\Plugin\CachedDiscoveryClearerInterface;
10use Drupal\Core\Session\AccountInterface;
11use Drupal\Core\StringTranslation\TranslatableMarkup;
12use Drupal\Core\Url;
13use Drupal\display_builder\Attribute\DisplayBuildable;
14use Drupal\display_builder\DisplayBuildablePluginBase;
15use Drupal\display_builder\Entity\ProfileInterface;
16use Drupal\display_builder_page_layout\BuilderDataConverter;
17use Drupal\display_builder_page_layout\Entity\PageLayout as PageLayoutEntity;
18use Drupal\display_builder_page_layout\PageLayoutInterface;
19use Drupal\ui_patterns\Plugin\Context\RequirementsContext;
20
21/**
22 * Plugin implementation of the display_buildable.
23 */
24#[DisplayBuildable(
25  id: 'page_layout',
26  label: new TranslatableMarkup('Page layout'),
27  instance_prefix: 'page_layout__',
28)]
29final class PageLayout extends DisplayBuildablePluginBase {
30
31  /**
32   * The page layout entity storing the display.
33   */
34  public ?PageLayoutInterface $entity = NULL;
35
36  /**
37   * {@inheritdoc}
38   */
39  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
40    parent::__construct($configuration, $plugin_id, $plugin_definition);
41
42    if (isset($configuration['entity'])) {
43      $this->entity = $configuration['entity'];
44      // Configuration to store in the Instance entity.
45      unset($this->configuration['entity']);
46      $this->configuration['entity_id'] = $this->entity->id();
47
48      return;
49    }
50
51    // Configuration stored in Instance entity:
52    // - entity_id (string): Page layout entity ID.
53    // No dependency injection in plugin constructors.
54    $this->entity = PageLayoutEntity::load($configuration['entity_id']);
55  }
56
57  /**
58   * {@inheritdoc}
59   */
60  public static function checkInstanceId(string $instance_id): ?array {
61    if (!\str_starts_with($instance_id, self::getPrefix())) {
62      return NULL;
63    }
64    [, $page_layout] = \explode('__', $instance_id);
65
66    return [
67      'page_layout' => $page_layout,
68    ];
69  }
70
71  /**
72   * {@inheritdoc}
73   */
74  public function getBuilderUrl(): Url {
75    return Url::fromRoute('entity.page_layout.display_builder', ['page_layout' => $this->entity->id()]);
76  }
77
78  /**
79   * {@inheritdoc}
80   */
81  public static function checkAccess(string $instance_id, AccountInterface $account): AccessResultInterface {
82    return $account->hasPermission('administer page_layout') ? AccessResult::allowed() : AccessResult::forbidden();
83  }
84
85  /**
86   * {@inheritdoc}
87   */
88  public static function getUrlFromInstanceId(string $instance_id): Url {
89    $params = self::checkInstanceId($instance_id);
90
91    if (!$params) {
92      // Fallback to the list of instances.
93      return Url::fromRoute('entity.display_builder_instance.collection');
94    }
95
96    return Url::fromRoute('entity.page_layout.display_builder', $params);
97  }
98
99  /**
100   * {@inheritdoc}
101   */
102  public static function getDisplayUrlFromInstanceId(string $instance_id): Url {
103    $params = self::checkInstanceId($instance_id);
104
105    if (!$params) {
106      // Fallback to the list of instances.
107      return Url::fromRoute('entity.display_builder_instance.collection');
108    }
109
110    return Url::fromRoute('entity.page_layout.edit_form', $params);
111  }
112
113  /**
114   * {@inheritdoc}
115   */
116  public function getProfile(): ?ProfileInterface {
117    return $this->entity?->getProfile();
118  }
119
120  /**
121   * {@inheritdoc}
122   */
123  public function getSources(): array {
124    // We reload because the Drupal cache is very strong on this data.
125    /** @var \Drupal\display_builder_page_layout\PageLayoutInterface $entity */
126    $entity = $this->entityTypeManager->getStorage('page_layout')->load($this->entity->id());
127    $this->entity = $entity;
128
129    return $this->entity->getSources();
130  }
131
132  /**
133   * {@inheritdoc}
134   */
135  public function saveSources(): void {
136    $this->entity->setSources($this->getInstance()->getCurrentState());
137    $this->entity->save();
138    // Clearing plugin cache seems enough to get the new layout.
139    // @todo It looks very costly. Check if it is still needed.
140    $this->pluginCacheClearer()->clearCachedDefinitions();
141  }
142
143  /**
144   * {@inheritdoc}
145   */
146  public static function collectInstances(): array {
147    $entityTypeManager = \Drupal::service('entity_type.manager');
148    $displayBuildableManager = \Drupal::service('plugin.manager.display_buildable');
149
150    $instances = [];
151    $entities = $entityTypeManager->getStorage('page_layout')->loadMultiple();
152
153    foreach ($entities as $page_layout) {
154      /** @var \Drupal\display_builder_page_layout\PageLayoutInterface $page_layout */
155      /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
156      $buildable = $displayBuildableManager->createInstance('page_layout', ['entity' => $page_layout]);
157      $buildable->initInstanceIfMissing();
158      $instance_id = $buildable->getInstanceId();
159      $instances[$instance_id] = $buildable->getInstance();
160    }
161
162    return $instances;
163  }
164
165  /**
166   * {@inheritdoc}
167   */
168  public function getInstanceId(): ?string {
169    // Usually an entity is new if no ID exists for it yet.
170    if ($this->entity->isNew()) {
171      return NULL;
172    }
173
174    return \sprintf('%s%s', self::getPrefix(), $this->entity->id());
175  }
176
177  /**
178   * {@inheritdoc}
179   */
180  public function getRuntimeContexts(array $unqualified_context_ids): array {
181    $contexts = [];
182    $contexts = RequirementsContext::addToContext(['page'], $contexts);
183
184    return $contexts;
185  }
186
187  /**
188   * {@inheritdoc}
189   */
190  protected function getInitializationMessage(): TranslatableMarkup {
191    if ($this->initialDataSource === 'theme') {
192      return $this->t('Import display from Block Layout configuration');
193    }
194
195    return $this->t('Initialize display from existing Page Layout configuration');
196  }
197
198  /**
199   * {@inheritdoc}
200   */
201  protected function getInitialSources(): array {
202    $sources = $this->getSources();
203
204    if (empty($sources)) {
205      $sources = $this->converter()->convertPage();
206      // Sources root is always a list of source data structures.
207      $sources = \array_is_list($sources) ? $sources : [$sources];
208      $this->initialDataSource = 'theme';
209    }
210
211    return $sources;
212  }
213
214  /**
215   * Gets the builder data converter.
216   *
217   * @return \Drupal\display_builder_page_layout\BuilderDataConverter
218   *   The converter service.
219   */
220  private function converter(): BuilderDataConverter {
221    return \Drupal::service('display_builder_page_layout.builder_data_converter');
222  }
223
224  /**
225   * Gets the builder data converter.
226   *
227   * @return \Drupal\Core\Plugin\CachedDiscoveryClearerInterface
228   *   The plugin cache clearer.
229   */
230  private function pluginCacheClearer(): CachedDiscoveryClearerInterface {
231    return \Drupal::service('plugin.cache_clearer');
232  }
233
234}

Paths

Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once. Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

PageLayout->__construct
39  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
40    parent::__construct($configuration, $plugin_id, $plugin_definition);
41
42    if (isset($configuration['entity'])) {
 
43      $this->entity = $configuration['entity'];
44      // Configuration to store in the Instance entity.
45      unset($this->configuration['entity']);
46      $this->configuration['entity_id'] = $this->entity->id();
47
48      return;
39  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
40    parent::__construct($configuration, $plugin_id, $plugin_definition);
41
42    if (isset($configuration['entity'])) {
 
54    $this->entity = PageLayoutEntity::load($configuration['entity_id']);
55  }
PageLayout->checkAccess
81  public static function checkAccess(string $instance_id, AccountInterface $account): AccessResultInterface {
82    return $account->hasPermission('administer page_layout') ? AccessResult::allowed() : AccessResult::forbidden();
 
82    return $account->hasPermission('administer page_layout') ? AccessResult::allowed() : AccessResult::forbidden();
 
82    return $account->hasPermission('administer page_layout') ? AccessResult::allowed() : AccessResult::forbidden();
83  }
81  public static function checkAccess(string $instance_id, AccountInterface $account): AccessResultInterface {
82    return $account->hasPermission('administer page_layout') ? AccessResult::allowed() : AccessResult::forbidden();
 
82    return $account->hasPermission('administer page_layout') ? AccessResult::allowed() : AccessResult::forbidden();
 
82    return $account->hasPermission('administer page_layout') ? AccessResult::allowed() : AccessResult::forbidden();
83  }
PageLayout->checkInstanceId
60  public static function checkInstanceId(string $instance_id): ?array {
61    if (!\str_starts_with($instance_id, self::getPrefix())) {
 
62      return NULL;
60  public static function checkInstanceId(string $instance_id): ?array {
61    if (!\str_starts_with($instance_id, self::getPrefix())) {
 
64    [, $page_layout] = \explode('__', $instance_id);
65
66    return [
67      'page_layout' => $page_layout,
68    ];
69  }
PageLayout->collectInstances
147    $entityTypeManager = \Drupal::service('entity_type.manager');
148    $displayBuildableManager = \Drupal::service('plugin.manager.display_buildable');
149
150    $instances = [];
151    $entities = $entityTypeManager->getStorage('page_layout')->loadMultiple();
152
153    foreach ($entities as $page_layout) {
 
153    foreach ($entities as $page_layout) {
 
153    foreach ($entities as $page_layout) {
154      /** @var \Drupal\display_builder_page_layout\PageLayoutInterface $page_layout */
155      /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
156      $buildable = $displayBuildableManager->createInstance('page_layout', ['entity' => $page_layout]);
 
153    foreach ($entities as $page_layout) {
 
153    foreach ($entities as $page_layout) {
154      /** @var \Drupal\display_builder_page_layout\PageLayoutInterface $page_layout */
155      /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
156      $buildable = $displayBuildableManager->createInstance('page_layout', ['entity' => $page_layout]);
157      $buildable->initInstanceIfMissing();
158      $instance_id = $buildable->getInstanceId();
159      $instances[$instance_id] = $buildable->getInstance();
160    }
161
162    return $instances;
163  }
147    $entityTypeManager = \Drupal::service('entity_type.manager');
148    $displayBuildableManager = \Drupal::service('plugin.manager.display_buildable');
149
150    $instances = [];
151    $entities = $entityTypeManager->getStorage('page_layout')->loadMultiple();
152
153    foreach ($entities as $page_layout) {
 
153    foreach ($entities as $page_layout) {
 
153    foreach ($entities as $page_layout) {
154      /** @var \Drupal\display_builder_page_layout\PageLayoutInterface $page_layout */
155      /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
156      $buildable = $displayBuildableManager->createInstance('page_layout', ['entity' => $page_layout]);
157      $buildable->initInstanceIfMissing();
158      $instance_id = $buildable->getInstanceId();
159      $instances[$instance_id] = $buildable->getInstance();
160    }
161
162    return $instances;
163  }
147    $entityTypeManager = \Drupal::service('entity_type.manager');
148    $displayBuildableManager = \Drupal::service('plugin.manager.display_buildable');
149
150    $instances = [];
151    $entities = $entityTypeManager->getStorage('page_layout')->loadMultiple();
152
153    foreach ($entities as $page_layout) {
 
153    foreach ($entities as $page_layout) {
154      /** @var \Drupal\display_builder_page_layout\PageLayoutInterface $page_layout */
155      /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
156      $buildable = $displayBuildableManager->createInstance('page_layout', ['entity' => $page_layout]);
157      $buildable->initInstanceIfMissing();
158      $instance_id = $buildable->getInstanceId();
159      $instances[$instance_id] = $buildable->getInstance();
160    }
161
162    return $instances;
163  }
PageLayout->converter
221    return \Drupal::service('display_builder_page_layout.builder_data_converter');
222  }
PageLayout->getBuilderUrl
75    return Url::fromRoute('entity.page_layout.display_builder', ['page_layout' => $this->entity->id()]);
76  }
PageLayout->getDisplayUrlFromInstanceId
102  public static function getDisplayUrlFromInstanceId(string $instance_id): Url {
103    $params = self::checkInstanceId($instance_id);
104
105    if (!$params) {
 
107      return Url::fromRoute('entity.display_builder_instance.collection');
102  public static function getDisplayUrlFromInstanceId(string $instance_id): Url {
103    $params = self::checkInstanceId($instance_id);
104
105    if (!$params) {
 
110    return Url::fromRoute('entity.page_layout.edit_form', $params);
111  }
PageLayout->getInitialSources
202    $sources = $this->getSources();
203
204    if (empty($sources)) {
 
205      $sources = $this->converter()->convertPage();
206      // Sources root is always a list of source data structures.
207      $sources = \array_is_list($sources) ? $sources : [$sources];
 
207      $sources = \array_is_list($sources) ? $sources : [$sources];
 
207      $sources = \array_is_list($sources) ? $sources : [$sources];
208      $this->initialDataSource = 'theme';
209    }
210
211    return $sources;
 
211    return $sources;
212  }
202    $sources = $this->getSources();
203
204    if (empty($sources)) {
 
205      $sources = $this->converter()->convertPage();
206      // Sources root is always a list of source data structures.
207      $sources = \array_is_list($sources) ? $sources : [$sources];
 
207      $sources = \array_is_list($sources) ? $sources : [$sources];
 
207      $sources = \array_is_list($sources) ? $sources : [$sources];
208      $this->initialDataSource = 'theme';
209    }
210
211    return $sources;
 
211    return $sources;
212  }
202    $sources = $this->getSources();
203
204    if (empty($sources)) {
 
211    return $sources;
212  }
PageLayout->getInitializationMessage
191    if ($this->initialDataSource === 'theme') {
 
192      return $this->t('Import display from Block Layout configuration');
191    if ($this->initialDataSource === 'theme') {
 
195    return $this->t('Initialize display from existing Page Layout configuration');
196  }
PageLayout->getInstanceId
170    if ($this->entity->isNew()) {
 
171      return NULL;
170    if ($this->entity->isNew()) {
 
174    return \sprintf('%s%s', self::getPrefix(), $this->entity->id());
175  }
PageLayout->getProfile
117    return $this->entity?->getProfile();
118  }
PageLayout->getRuntimeContexts
180  public function getRuntimeContexts(array $unqualified_context_ids): array {
181    $contexts = [];
182    $contexts = RequirementsContext::addToContext(['page'], $contexts);
183
184    return $contexts;
185  }
PageLayout->getSources
126    $entity = $this->entityTypeManager->getStorage('page_layout')->load($this->entity->id());
127    $this->entity = $entity;
128
129    return $this->entity->getSources();
130  }
PageLayout->getUrlFromInstanceId
88  public static function getUrlFromInstanceId(string $instance_id): Url {
89    $params = self::checkInstanceId($instance_id);
90
91    if (!$params) {
 
93      return Url::fromRoute('entity.display_builder_instance.collection');
88  public static function getUrlFromInstanceId(string $instance_id): Url {
89    $params = self::checkInstanceId($instance_id);
90
91    if (!$params) {
 
96    return Url::fromRoute('entity.page_layout.display_builder', $params);
97  }
PageLayout->pluginCacheClearer
231    return \Drupal::service('plugin.cache_clearer');
232  }
PageLayout->saveSources
136    $this->entity->setSources($this->getInstance()->getCurrentState());
137    $this->entity->save();
138    // Clearing plugin cache seems enough to get the new layout.
139    // @todo It looks very costly. Check if it is still needed.
140    $this->pluginCacheClearer()->clearCachedDefinitions();
141  }