Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
0.00% |
0 / 61 |
|
0.00% |
0 / 39 |
|
0.00% |
0 / 27 |
|
0.00% |
0 / 16 |
CRAP | |
0.00% |
0 / 1 |
| PageLayout | |
0.00% |
0 / 57 |
|
0.00% |
0 / 39 |
|
0.00% |
0 / 27 |
|
0.00% |
0 / 16 |
702 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 7 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| checkInstanceId | |
0.00% |
0 / 6 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| getBuilderUrl | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| checkAccess | |
0.00% |
0 / 1 |
|
0.00% |
0 / 4 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| getUrlFromInstanceId | |
0.00% |
0 / 4 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| getDisplayUrlFromInstanceId | |
0.00% |
0 / 4 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| getProfile | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getSources | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| saveSources | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| collectInstances | |
0.00% |
0 / 10 |
|
0.00% |
0 / 4 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| getInstanceId | |
0.00% |
0 / 3 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| getRuntimeContexts | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getInitializationMessage | |
0.00% |
0 / 3 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| getInitialSources | |
0.00% |
0 / 6 |
|
0.00% |
0 / 6 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
| converter | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| pluginCacheClearer | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Drupal\display_builder_page_layout\Plugin\display_builder\Buildable; |
| 6 | |
| 7 | use Drupal\Core\Access\AccessResult; |
| 8 | use Drupal\Core\Access\AccessResultInterface; |
| 9 | use Drupal\Core\Plugin\CachedDiscoveryClearerInterface; |
| 10 | use Drupal\Core\Session\AccountInterface; |
| 11 | use Drupal\Core\StringTranslation\TranslatableMarkup; |
| 12 | use Drupal\Core\Url; |
| 13 | use Drupal\display_builder\Attribute\DisplayBuildable; |
| 14 | use Drupal\display_builder\DisplayBuildablePluginBase; |
| 15 | use Drupal\display_builder\Entity\ProfileInterface; |
| 16 | use Drupal\display_builder_page_layout\BuilderDataConverter; |
| 17 | use Drupal\display_builder_page_layout\Entity\PageLayout as PageLayoutEntity; |
| 18 | use Drupal\display_builder_page_layout\PageLayoutInterface; |
| 19 | use 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 | )] |
| 29 | final 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 | } |
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.
| 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; |
| 54 | $this->entity = PageLayoutEntity::load($configuration['entity_id']); |
| 55 | } |
| 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(); |
| 82 | return $account->hasPermission('administer page_layout') ? AccessResult::allowed() : AccessResult::forbidden(); |
| 83 | } |
| 60 | public static function checkInstanceId(string $instance_id): ?array { |
| 61 | if (!\str_starts_with($instance_id, self::getPrefix())) { |
| 62 | return NULL; |
| 64 | [, $page_layout] = \explode('__', $instance_id); |
| 65 | |
| 66 | return [ |
| 67 | 'page_layout' => $page_layout, |
| 68 | ]; |
| 69 | } |
| 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) { |
| 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 | } |
| 221 | return \Drupal::service('display_builder_page_layout.builder_data_converter'); |
| 222 | } |
| 75 | return Url::fromRoute('entity.page_layout.display_builder', ['page_layout' => $this->entity->id()]); |
| 76 | } |
| 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'); |
| 110 | return Url::fromRoute('entity.page_layout.edit_form', $params); |
| 111 | } |
| 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]; |
| 207 | $sources = \array_is_list($sources) ? $sources : [$sources]; |
| 208 | $this->initialDataSource = 'theme'; |
| 209 | } |
| 210 | |
| 211 | return $sources; |
| 211 | return $sources; |
| 212 | } |
| 191 | if ($this->initialDataSource === 'theme') { |
| 192 | return $this->t('Import display from Block Layout configuration'); |
| 195 | return $this->t('Initialize display from existing Page Layout configuration'); |
| 196 | } |
| 170 | if ($this->entity->isNew()) { |
| 171 | return NULL; |
| 174 | return \sprintf('%s%s', self::getPrefix(), $this->entity->id()); |
| 175 | } |
| 117 | return $this->entity?->getProfile(); |
| 118 | } |
| 180 | public function getRuntimeContexts(array $unqualified_context_ids): array { |
| 181 | $contexts = []; |
| 182 | $contexts = RequirementsContext::addToContext(['page'], $contexts); |
| 183 | |
| 184 | return $contexts; |
| 185 | } |
| 126 | $entity = $this->entityTypeManager->getStorage('page_layout')->load($this->entity->id()); |
| 127 | $this->entity = $entity; |
| 128 | |
| 129 | return $this->entity->getSources(); |
| 130 | } |
| 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'); |
| 96 | return Url::fromRoute('entity.page_layout.display_builder', $params); |
| 97 | } |
| 231 | return \Drupal::service('plugin.cache_clearer'); |
| 232 | } |
| 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 | } |