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 / 37
0.00% covered (danger)
0.00%
0 / 26
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 / 50
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 16
650
0.00% covered (danger)
0.00%
0 / 1
 __construct
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
 getContextRequirement
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
 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 / 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
 saveSources
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
 collectInstances
0.00% covered (danger)
0.00%
0 / 11
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
 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
 getInitialContext
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
 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
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\Entity\EntityTypeManagerInterface;
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\ProfileInterface;
16use Drupal\display_builder_page_layout\BuilderDataConverter;
17use Drupal\display_builder_page_layout\PageLayoutInterface;
18use Drupal\ui_patterns\Plugin\Context\RequirementsContext;
19
20/**
21 * Plugin implementation of the display_buildable.
22 */
23#[DisplayBuildable(
24  id: 'page_layout',
25  label: new TranslatableMarkup('Page layout'),
26  instance_prefix: 'page_layout__',
27)]
28final class PageLayout extends DisplayBuildablePluginBase {
29
30  /**
31   * The page layout entity storing the display.
32   */
33  public ?PageLayoutInterface $entity = NULL;
34
35  /**
36   * {@inheritdoc}
37   */
38  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
39    parent::__construct($configuration, $plugin_id, $plugin_definition);
40    $this->entity = $configuration['entity'];
41  }
42
43  /**
44   * {@inheritdoc}
45   */
46  public static function getContextRequirement(): string {
47    return 'page';
48  }
49
50  /**
51   * {@inheritdoc}
52   */
53  public static function checkInstanceId(string $instance_id): ?array {
54    if (!\str_starts_with($instance_id, self::getPrefix())) {
55      return NULL;
56    }
57    [, $page_layout] = \explode('__', $instance_id);
58
59    return [
60      'page_layout' => $page_layout,
61    ];
62  }
63
64  /**
65   * {@inheritdoc}
66   */
67  public function getBuilderUrl(): Url {
68    return Url::fromRoute('entity.page_layout.display_builder', ['page_layout' => $this->entity->id()]);
69  }
70
71  /**
72   * {@inheritdoc}
73   */
74  public static function checkAccess(string $instance_id, AccountInterface $account): AccessResultInterface {
75    return $account->hasPermission('administer page_layout') ? AccessResult::allowed() : AccessResult::forbidden();
76  }
77
78  /**
79   * {@inheritdoc}
80   */
81  public static function getUrlFromInstanceId(string $instance_id): Url {
82    $params = self::checkInstanceId($instance_id);
83
84    if (!$params) {
85      // Fallback to the list of instances.
86      return Url::fromRoute('entity.display_builder_instance.collection');
87    }
88
89    return Url::fromRoute('entity.page_layout.display_builder', $params);
90  }
91
92  /**
93   * {@inheritdoc}
94   */
95  public static function getDisplayUrlFromInstanceId(string $instance_id): Url {
96    $params = self::checkInstanceId($instance_id);
97
98    if (!$params) {
99      // Fallback to the list of instances.
100      return Url::fromRoute('entity.display_builder_instance.collection');
101    }
102
103    return Url::fromRoute('entity.page_layout.edit_form', $params);
104  }
105
106  /**
107   * {@inheritdoc}
108   */
109  public function getProfile(): ?ProfileInterface {
110    return $this->entity->getProfile();
111  }
112
113  /**
114   * {@inheritdoc}
115   */
116  public function getSources(): array {
117    return $this->entity->getSources();
118  }
119
120  /**
121   * {@inheritdoc}
122   */
123  public function saveSources(): void {
124    $this->entity->setSources($this->getInstance()->getCurrentState());
125    $this->entity->save();
126  }
127
128  /**
129   * {@inheritdoc}
130   */
131  public static function collectInstances(?EntityTypeManagerInterface $entityTypeManager = NULL): array {
132    $entityTypeManager = \Drupal::service('entity_type.manager');
133    $instance_storage = $entityTypeManager->getStorage('display_builder_instance');
134    $instances = [];
135    $displayBuildableManager = \Drupal::service('plugin.manager.display_buildable');
136    $storage = $entityTypeManager->getStorage('page_layout');
137    $entities = $storage->loadMultiple();
138
139    foreach ($entities as $page_layout) {
140      /** @var \Drupal\display_builder_page_layout\PageLayoutInterface $page_layout */
141      /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
142      $buildable = $displayBuildableManager->createInstance('page_layout', ['entity' => $page_layout]);
143      $instance_id = $buildable->getInstanceId();
144      // We are OK with keeping the null values if the instance entity
145      // doesn't exists in storage. So the caller can decide to create
146      // the missing Instance entities.
147      $instances[$instance_id] = $instance_storage->load($instance_id);
148    }
149
150    return $instances;
151  }
152
153  /**
154   * {@inheritdoc}
155   */
156  public function getInstanceId(): ?string {
157    // Usually an entity is new if no ID exists for it yet.
158    if ($this->entity->isNew()) {
159      return NULL;
160    }
161
162    return \sprintf('%s%s', self::getPrefix(), $this->entity->id());
163  }
164
165  /**
166   * {@inheritdoc}
167   */
168  protected function getInitializationMessage(): TranslatableMarkup {
169    if ($this->initialDataSource === 'theme') {
170      return $this->t('Import from Block Layout configuration.');
171    }
172
173    return $this->t('Initialization from existing Page Layout configuration.');
174  }
175
176  /**
177   * {@inheritdoc}
178   */
179  protected function getInitialSources(): array {
180    $sources = $this->getSources();
181
182    if (empty($sources)) {
183      $sources = $this->converter()->convertPage();
184      // Sources root is always a list of source data structures.
185      $sources = \array_is_list($sources) ? $sources : [$sources];
186      $this->initialDataSource = 'theme';
187    }
188
189    return $sources;
190  }
191
192  /**
193   * {@inheritdoc}
194   */
195  protected function getInitialContext(): array {
196    $contexts = [];
197    $contexts = RequirementsContext::addToContext([self::getContextRequirement()], $contexts);
198
199    return $contexts;
200  }
201
202  /**
203   * Gets the builder data converter.
204   *
205   * @return \Drupal\display_builder_page_layout\BuilderDataConverter
206   *   The converter service.
207   */
208  private function converter(): BuilderDataConverter {
209    return \Drupal::service('display_builder_page_layout.builder_data_converter');
210  }
211
212}