Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
0.00% |
0 / 225 |
|
0.00% |
0 / 57 |
|
0.00% |
0 / 70 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
| ProfileForm | |
0.00% |
0 / 225 |
|
0.00% |
0 / 57 |
|
0.00% |
0 / 70 |
|
0.00% |
0 / 7 |
930 | |
0.00% |
0 / 1 |
| form | |
0.00% |
0 / 92 |
|
0.00% |
0 / 8 |
|
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
| submitForm | |
0.00% |
0 / 6 |
|
0.00% |
0 / 6 |
|
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
| save | |
0.00% |
0 / 16 |
|
0.00% |
0 / 11 |
|
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
42 | |||
| buildIslandTypeTable | |
0.00% |
0 / 29 |
|
0.00% |
0 / 7 |
|
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
20 | |||
| buildIslandRow | |
0.00% |
0 / 73 |
|
0.00% |
0 / 16 |
|
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
72 | |||
| copyFormValuesToEntity | |
0.00% |
0 / 8 |
|
0.00% |
0 / 8 |
|
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
| moduleExtensionList | |
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\Form; |
| 6 | |
| 7 | use Drupal\Component\Utility\Html; |
| 8 | use Drupal\Component\Utility\NestedArray; |
| 9 | use Drupal\Core\DependencyInjection\AutowireTrait; |
| 10 | use Drupal\Core\Entity\EntityForm; |
| 11 | use Drupal\Core\Entity\EntityInterface; |
| 12 | use Drupal\Core\Entity\EntityWithPluginCollectionInterface; |
| 13 | use Drupal\Core\Extension\ModuleExtensionList; |
| 14 | use Drupal\Core\Form\FormStateInterface; |
| 15 | use Drupal\Core\Plugin\PluginFormInterface; |
| 16 | use Drupal\display_builder\Entity\Profile; |
| 17 | use Drupal\display_builder\IslandInterface; |
| 18 | use Drupal\display_builder\IslandType; |
| 19 | use Drupal\display_builder\IslandTypeViewDisplay; |
| 20 | use Drupal\display_builder\ProfileInterface; |
| 21 | use Drupal\user\RoleInterface; |
| 22 | |
| 23 | /** |
| 24 | * Display builder form. |
| 25 | */ |
| 26 | final class ProfileForm extends EntityForm { |
| 27 | |
| 28 | use AutowireTrait; |
| 29 | |
| 30 | /** |
| 31 | * Module extension list. |
| 32 | */ |
| 33 | protected ModuleExtensionList $moduleExtensionList; |
| 34 | |
| 35 | /** |
| 36 | * {@inheritdoc} |
| 37 | */ |
| 38 | public function form(array $form, FormStateInterface $form_state): array { |
| 39 | $form = parent::form($form, $form_state); |
| 40 | /** @var \Drupal\display_builder\ProfileInterface $entity */ |
| 41 | $entity = $this->entity; |
| 42 | |
| 43 | $form['label'] = [ |
| 44 | '#type' => 'textfield', |
| 45 | '#title' => $this->t('Label'), |
| 46 | '#maxlength' => 255, |
| 47 | '#default_value' => $entity->label(), |
| 48 | '#required' => TRUE, |
| 49 | ]; |
| 50 | |
| 51 | $form['id'] = [ |
| 52 | '#type' => 'machine_name', |
| 53 | '#default_value' => $this->entity->id(), |
| 54 | '#machine_name' => [ |
| 55 | 'exists' => [Profile::class, 'load'], |
| 56 | ], |
| 57 | '#disabled' => !$entity->isNew(), |
| 58 | ]; |
| 59 | |
| 60 | $form['description'] = [ |
| 61 | '#type' => 'textarea', |
| 62 | '#title' => $this->t('Description'), |
| 63 | '#default_value' => $entity->get('description'), |
| 64 | ]; |
| 65 | |
| 66 | // Add user role access selection. Not available at creation because the |
| 67 | // permissions are not set yet by ProfilePermissions. |
| 68 | if (!$entity->isNew()) { |
| 69 | $roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple(); |
| 70 | \ksort($roles); |
| 71 | $form['roles'] = [ |
| 72 | '#type' => 'checkboxes', |
| 73 | '#title' => $this->t('Roles'), |
| 74 | '#options' => \array_map(static fn (RoleInterface $role) => Html::escape((string) $role->label()), $roles), |
| 75 | '#default_value' => \array_keys($entity->getRoles()), |
| 76 | ]; |
| 77 | } |
| 78 | |
| 79 | // Inform on two time save for the island specific configurations. |
| 80 | if ($this->entity->isNew()) { |
| 81 | $form['islands_notice'] = [ |
| 82 | '#prefix' => '<div class="messages messages--warning">', |
| 83 | '#markup' => $this->t('Island configuration will be available only after saving this form.'), |
| 84 | '#suffix' => '</div>', |
| 85 | ]; |
| 86 | } |
| 87 | |
| 88 | $path = $this->moduleExtensionList()->getPath('display_builder'); |
| 89 | $form['islands_intro'] = [ |
| 90 | [ |
| 91 | '#type' => 'html_tag', |
| 92 | '#tag' => 'label', |
| 93 | '#value' => $this->t('Islands'), |
| 94 | '#attributes' => [ |
| 95 | 'class' => ['form-item__label'], |
| 96 | ], |
| 97 | ], |
| 98 | [ |
| 99 | '#type' => 'html_tag', |
| 100 | '#tag' => 'img', |
| 101 | '#attributes' => [ |
| 102 | 'src' => base_path() . $path . '/assets/images/islands-regions.png', |
| 103 | 'width' => '1200', |
| 104 | ], |
| 105 | '#prefix' => '<div style="text-align: center;">', |
| 106 | '#suffix' => '</div>', |
| 107 | ], |
| 108 | ]; |
| 109 | |
| 110 | $form['islands'] = [ |
| 111 | '#type' => 'vertical_tabs', |
| 112 | ]; |
| 113 | |
| 114 | $island_configuration = $entity->get('islands') ?? []; |
| 115 | |
| 116 | /** @var \Drupal\display_builder\IslandPluginManagerInterface $islandPluginManager */ |
| 117 | $islandPluginManager = \Drupal::service('plugin.manager.db_island'); // phpcs:ignore |
| 118 | $island_by_types = $islandPluginManager->getIslandsByTypes(); |
| 119 | $labels = [ |
| 120 | 'view' => $this->t('View panels'), |
| 121 | 'button' => $this->t('Toolbar buttons'), |
| 122 | 'contextual' => $this->t('Contextual panels'), |
| 123 | 'library' => $this->t('Library panels'), |
| 124 | 'menu' => $this->t('Menu items'), |
| 125 | ]; |
| 126 | // Sort the types according to the labels. |
| 127 | $island_by_types = \array_merge($labels, $island_by_types); |
| 128 | |
| 129 | foreach ($island_by_types as $type => $islands) { |
| 130 | $form['islands'][$type] = [ |
| 131 | '#type' => 'details', |
| 132 | '#title' => $labels[$type] ?? $type, |
| 133 | '#description' => IslandType::description($type), |
| 134 | '#group' => 'islands', |
| 135 | 'content' => $this->buildIslandTypeTable(IslandType::from($type), $islands, $island_configuration), |
| 136 | ]; |
| 137 | } |
| 138 | |
| 139 | $form['debug'] = [ |
| 140 | '#type' => 'checkbox', |
| 141 | '#title' => $this->t('Debug mode'), |
| 142 | '#description' => $this->t('Enable verbose JavaScript and error logs.'), |
| 143 | '#default_value' => $entity->get('debug'), |
| 144 | ]; |
| 145 | |
| 146 | $form['status'] = [ |
| 147 | '#type' => 'checkbox', |
| 148 | '#title' => $this->t('Enabled'), |
| 149 | '#default_value' => $entity->status(), |
| 150 | ]; |
| 151 | |
| 152 | return $form; |
| 153 | } |
| 154 | |
| 155 | /** |
| 156 | * {@inheritdoc} |
| 157 | */ |
| 158 | public function submitForm(array &$form, FormStateInterface $form_state): ProfileInterface { |
| 159 | parent::submitForm($form, $form_state); |
| 160 | |
| 161 | // Save user permissions. |
| 162 | /** @var \Drupal\display_builder\ProfileInterface $entity */ |
| 163 | $entity = $this->entity; |
| 164 | |
| 165 | if ($permission = $entity->getPermissionName()) { |
| 166 | foreach ($form_state->getValue('roles') ?? [] as $rid => $enabled) { |
| 167 | user_role_change_permissions($rid, [$permission => $enabled]); |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | return $entity; |
| 172 | } |
| 173 | |
| 174 | /** |
| 175 | * {@inheritdoc} |
| 176 | */ |
| 177 | public function save(array $form, FormStateInterface $form_state): int { |
| 178 | $result = parent::save($form, $form_state); |
| 179 | |
| 180 | // Clear the plugin cache so changes are applied on front theme builder. |
| 181 | /** @var \Drupal\Core\Plugin\CachedDiscoveryClearerInterface $pluginCacheClearer */ |
| 182 | $pluginCacheClearer = \Drupal::service('plugin.cache_clearer'); // phpcs:ignore |
| 183 | $pluginCacheClearer->clearCachedDefinitions(); |
| 184 | |
| 185 | $message_args = ['%label' => $this->entity->label()]; |
| 186 | $this->messenger()->addStatus( |
| 187 | match ($result) { |
| 188 | SAVED_NEW => $this->t('Created new display builder config %label.', $message_args), |
| 189 | SAVED_UPDATED => $this->t('Updated display builder config %label.', $message_args), |
| 190 | default => '', |
| 191 | } |
| 192 | ); |
| 193 | |
| 194 | // Set the initial default configuration and stay on the form to allow |
| 195 | // islands configuration. |
| 196 | if ($result === SAVED_NEW) { |
| 197 | $form_state->setRedirect('entity.display_builder_profile.edit_form', ['display_builder_profile' => $this->entity->id()]); |
| 198 | } |
| 199 | elseif ($result === SAVED_UPDATED) { |
| 200 | $form_state->setRedirect('entity.display_builder_profile.collection'); |
| 201 | } |
| 202 | |
| 203 | return $result; |
| 204 | } |
| 205 | |
| 206 | /** |
| 207 | * Build island type table. |
| 208 | * |
| 209 | * @param \Drupal\display_builder\IslandType $type |
| 210 | * Island type from IslandType enum. |
| 211 | * @param array $islands |
| 212 | * List of island plugins. |
| 213 | * @param array $configuration |
| 214 | * Configuration of all islands from this type. |
| 215 | * |
| 216 | * @return array |
| 217 | * A renderable array. |
| 218 | */ |
| 219 | protected function buildIslandTypeTable(IslandType $type, array $islands, array $configuration): array { |
| 220 | $type = $type->value; |
| 221 | $table = [ |
| 222 | '#type' => 'table', |
| 223 | '#header' => [ |
| 224 | 'drag' => '', |
| 225 | 'status' => $this->t('Enabled'), |
| 226 | 'name' => $this->t('Island'), |
| 227 | 'summary' => $this->t('Configuration'), |
| 228 | 'region' => ($type === IslandType::View->value) ? $this->t('Region') : '', |
| 229 | 'actions' => $this->t('Actions'), |
| 230 | 'weight' => $this->t('Weight'), |
| 231 | ], |
| 232 | '#attributes' => ['id' => 'db-islands-' . $type], |
| 233 | '#tabledrag' => [ |
| 234 | [ |
| 235 | 'action' => 'order', |
| 236 | 'relationship' => 'sibling', |
| 237 | 'group' => 'draggable-weight-' . $type, |
| 238 | ], |
| 239 | ], |
| 240 | // We don't want to submit the island type level. We already know the |
| 241 | // type of each islands thanks to IslandInterface::getTypeId() so let's |
| 242 | // keep the storage flat. |
| 243 | '#parents' => ['islands'], |
| 244 | ]; |
| 245 | |
| 246 | foreach ($islands as $id => $island) { |
| 247 | $table[$id] = $this->buildIslandRow($island, $configuration[$id] ?? []); |
| 248 | } |
| 249 | |
| 250 | // Order rows by weight. |
| 251 | \uasort($table, static function ($a, $b) { |
| 252 | if (isset($a['#weight'], $b['#weight'])) { |
| 253 | return (int) $a['#weight'] - (int) $b['#weight']; |
| 254 | } |
| 255 | }); |
| 256 | |
| 257 | return $table; |
| 258 | } |
| 259 | |
| 260 | /** |
| 261 | * Build island row. |
| 262 | * |
| 263 | * @param \Drupal\display_builder\IslandInterface $island |
| 264 | * Island plugin. |
| 265 | * @param array $configuration |
| 266 | * Configuration of this specific island. |
| 267 | * |
| 268 | * @return array |
| 269 | * A renderable array. |
| 270 | */ |
| 271 | protected function buildIslandRow(IslandInterface $island, array $configuration): array { |
| 272 | $id = $island->getPluginId(); |
| 273 | $definition = (array) $island->getPluginDefinition(); |
| 274 | $type = $island->getTypeId(); |
| 275 | /** @var \Drupal\display_builder\IslandPluginManagerInterface $islandPluginManager */ |
| 276 | $islandPluginManager = \Drupal::service('plugin.manager.db_island'); // phpcs:ignore |
| 277 | /** @var \Drupal\display_builder\IslandConfigurationFormInterface $instance */ |
| 278 | $instance = $islandPluginManager->createInstance($id, $configuration); |
| 279 | $weight = isset($configuration['weight']) ? (string) $configuration['weight'] : '0'; |
| 280 | |
| 281 | $row = []; |
| 282 | $row['#attributes']['class'] = ['draggable']; |
| 283 | $row['#weight'] = (int) $weight; |
| 284 | |
| 285 | $row[''] = []; |
| 286 | $row['status'] = [ |
| 287 | '#type' => 'checkbox', |
| 288 | '#title' => $this->t('Enabled'), |
| 289 | '#title_display' => 'invisible', |
| 290 | '#default_value' => $configuration['status'] ?? $definition['enabled_by_default'] ?? FALSE, |
| 291 | ]; |
| 292 | $row['name'] = [ |
| 293 | '#type' => 'inline_template', |
| 294 | '#template' => '<strong >{{ name }}</strong><br>{{ description }}', |
| 295 | '#context' => [ |
| 296 | 'name' => $definition['label'] ?? '', |
| 297 | 'description' => $definition['description'] ?? '', |
| 298 | ], |
| 299 | ]; |
| 300 | $row['summary'] = [ |
| 301 | '#markup' => \implode('<br>', $instance->configurationSummary()), |
| 302 | ]; |
| 303 | |
| 304 | if ($type === IslandType::View->value) { |
| 305 | // If new, only library is on sidebar by default. |
| 306 | // @todo move this position option to Island configuration. |
| 307 | if ($id !== 'library' && !isset($configuration['region']) && isset($definition['enabled_by_default'])) { |
| 308 | $region = IslandTypeViewDisplay::Main->value; |
| 309 | } |
| 310 | else { |
| 311 | $region = $configuration['region'] ?? NULL; |
| 312 | } |
| 313 | $row['region'] = [ |
| 314 | '#type' => 'radios', |
| 315 | '#title' => $this->t('Display'), |
| 316 | '#title_display' => 'invisible', |
| 317 | '#options' => IslandTypeViewDisplay::regions(), |
| 318 | '#default_value' => $region, |
| 319 | ]; |
| 320 | } |
| 321 | else { |
| 322 | $row['region'] = []; |
| 323 | } |
| 324 | |
| 325 | if ($island instanceof PluginFormInterface && !$this->entity->isNew()) { |
| 326 | $row['actions'] = [ |
| 327 | '#type' => 'link', |
| 328 | '#title' => $this->t('Configure'), |
| 329 | '#url' => $this->entity->toUrl('edit-plugin-form', [ |
| 330 | 'island_id' => $id, |
| 331 | 'query' => [ |
| 332 | 'destination' => $this->entity->toUrl()->toString(), |
| 333 | ], |
| 334 | ]), |
| 335 | '#attributes' => [ |
| 336 | 'class' => ['use-ajax', 'button', 'button--small'], |
| 337 | 'data-dialog-type' => 'modal', |
| 338 | 'data-dialog-options' => \json_encode([ |
| 339 | 'width' => 700, |
| 340 | ]), |
| 341 | ], |
| 342 | '#states' => [ |
| 343 | 'visible' => [ |
| 344 | 'input[name="islands[' . $id . '][status]"]' => ['checked' => TRUE], |
| 345 | ], |
| 346 | ], |
| 347 | ]; |
| 348 | } |
| 349 | else { |
| 350 | $row['actions'] = ['#markup' => '']; |
| 351 | } |
| 352 | |
| 353 | $row['weight'] = [ |
| 354 | '#type' => 'weight', |
| 355 | '#default_value' => $weight, |
| 356 | '#title' => $this->t('Weight'), |
| 357 | '#title_display' => 'invisible', |
| 358 | '#attributes' => [ |
| 359 | 'class' => ['draggable-weight-' . $type], |
| 360 | ], |
| 361 | ]; |
| 362 | |
| 363 | return $row; |
| 364 | } |
| 365 | |
| 366 | /** |
| 367 | * {@inheritdoc} |
| 368 | */ |
| 369 | protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state): void { |
| 370 | $values = $form_state->getValues(); |
| 371 | |
| 372 | /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */ |
| 373 | $entity = $entity; |
| 374 | |
| 375 | if ($this->entity instanceof EntityWithPluginCollectionInterface) { |
| 376 | // Do not manually update values represented by plugin collections. |
| 377 | $values = \array_diff_key($values, $this->entity->getPluginCollections()); |
| 378 | } |
| 379 | |
| 380 | foreach ($values as $key => $value) { |
| 381 | if ($key === 'islands') { |
| 382 | $value = NestedArray::mergeDeep($entity->get('islands'), $value); |
| 383 | } |
| 384 | $entity->set($key, $value); |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | /** |
| 389 | * Wraps the module extension list service repository service. |
| 390 | * |
| 391 | * @return \Drupal\Core\Extension\ModuleExtensionList |
| 392 | * The module extension list service. |
| 393 | */ |
| 394 | protected function moduleExtensionList(): ModuleExtensionList { |
| 395 | return $this->moduleExtensionList ??= \Drupal::service('extension.list.module'); // phpcs:ignore |
| 396 | } |
| 397 | |
| 398 | } |
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.
| 271 | protected function buildIslandRow(IslandInterface $island, array $configuration): array { |
| 272 | $id = $island->getPluginId(); |
| 273 | $definition = (array) $island->getPluginDefinition(); |
| 274 | $type = $island->getTypeId(); |
| 275 | /** @var \Drupal\display_builder\IslandPluginManagerInterface $islandPluginManager */ |
| 276 | $islandPluginManager = \Drupal::service('plugin.manager.db_island'); // phpcs:ignore |
| 277 | /** @var \Drupal\display_builder\IslandConfigurationFormInterface $instance */ |
| 278 | $instance = $islandPluginManager->createInstance($id, $configuration); |
| 279 | $weight = isset($configuration['weight']) ? (string) $configuration['weight'] : '0'; |
| 279 | $weight = isset($configuration['weight']) ? (string) $configuration['weight'] : '0'; |
| 279 | $weight = isset($configuration['weight']) ? (string) $configuration['weight'] : '0'; |
| 279 | $weight = isset($configuration['weight']) ? (string) $configuration['weight'] : '0'; |
| 280 | |
| 281 | $row = []; |
| 282 | $row['#attributes']['class'] = ['draggable']; |
| 283 | $row['#weight'] = (int) $weight; |
| 284 | |
| 285 | $row[''] = []; |
| 286 | $row['status'] = [ |
| 287 | '#type' => 'checkbox', |
| 288 | '#title' => $this->t('Enabled'), |
| 289 | '#title_display' => 'invisible', |
| 290 | '#default_value' => $configuration['status'] ?? $definition['enabled_by_default'] ?? FALSE, |
| 291 | ]; |
| 292 | $row['name'] = [ |
| 293 | '#type' => 'inline_template', |
| 294 | '#template' => '<strong >{{ name }}</strong><br>{{ description }}', |
| 295 | '#context' => [ |
| 296 | 'name' => $definition['label'] ?? '', |
| 297 | 'description' => $definition['description'] ?? '', |
| 298 | ], |
| 299 | ]; |
| 300 | $row['summary'] = [ |
| 301 | '#markup' => \implode('<br>', $instance->configurationSummary()), |
| 302 | ]; |
| 303 | |
| 304 | if ($type === IslandType::View->value) { |
| 307 | if ($id !== 'library' && !isset($configuration['region']) && isset($definition['enabled_by_default'])) { |
| 307 | if ($id !== 'library' && !isset($configuration['region']) && isset($definition['enabled_by_default'])) { |
| 307 | if ($id !== 'library' && !isset($configuration['region']) && isset($definition['enabled_by_default'])) { |
| 307 | if ($id !== 'library' && !isset($configuration['region']) && isset($definition['enabled_by_default'])) { |
| 308 | $region = IslandTypeViewDisplay::Main->value; |
| 311 | $region = $configuration['region'] ?? NULL; |
| 312 | } |
| 313 | $row['region'] = [ |
| 314 | '#type' => 'radios', |
| 304 | if ($type === IslandType::View->value) { |
| 305 | // If new, only library is on sidebar by default. |
| 306 | // @todo move this position option to Island configuration. |
| 307 | if ($id !== 'library' && !isset($configuration['region']) && isset($definition['enabled_by_default'])) { |
| 308 | $region = IslandTypeViewDisplay::Main->value; |
| 309 | } |
| 310 | else { |
| 311 | $region = $configuration['region'] ?? NULL; |
| 312 | } |
| 313 | $row['region'] = [ |
| 314 | '#type' => 'radios', |
| 322 | $row['region'] = []; |
| 323 | } |
| 324 | |
| 325 | if ($island instanceof PluginFormInterface && !$this->entity->isNew()) { |
| 325 | if ($island instanceof PluginFormInterface && !$this->entity->isNew()) { |
| 325 | if ($island instanceof PluginFormInterface && !$this->entity->isNew()) { |
| 325 | if ($island instanceof PluginFormInterface && !$this->entity->isNew()) { |
| 326 | $row['actions'] = [ |
| 327 | '#type' => 'link', |
| 350 | $row['actions'] = ['#markup' => '']; |
| 351 | } |
| 352 | |
| 353 | $row['weight'] = [ |
| 354 | '#type' => 'weight', |
| 354 | '#type' => 'weight', |
| 355 | '#default_value' => $weight, |
| 356 | '#title' => $this->t('Weight'), |
| 357 | '#title_display' => 'invisible', |
| 358 | '#attributes' => [ |
| 359 | 'class' => ['draggable-weight-' . $type], |
| 360 | ], |
| 361 | ]; |
| 362 | |
| 363 | return $row; |
| 219 | protected function buildIslandTypeTable(IslandType $type, array $islands, array $configuration): array { |
| 220 | $type = $type->value; |
| 221 | $table = [ |
| 222 | '#type' => 'table', |
| 223 | '#header' => [ |
| 224 | 'drag' => '', |
| 225 | 'status' => $this->t('Enabled'), |
| 226 | 'name' => $this->t('Island'), |
| 227 | 'summary' => $this->t('Configuration'), |
| 228 | 'region' => ($type === IslandType::View->value) ? $this->t('Region') : '', |
| 228 | 'region' => ($type === IslandType::View->value) ? $this->t('Region') : '', |
| 228 | 'region' => ($type === IslandType::View->value) ? $this->t('Region') : '', |
| 228 | 'region' => ($type === IslandType::View->value) ? $this->t('Region') : '', |
| 229 | 'actions' => $this->t('Actions'), |
| 230 | 'weight' => $this->t('Weight'), |
| 231 | ], |
| 232 | '#attributes' => ['id' => 'db-islands-' . $type], |
| 233 | '#tabledrag' => [ |
| 234 | [ |
| 235 | 'action' => 'order', |
| 236 | 'relationship' => 'sibling', |
| 237 | 'group' => 'draggable-weight-' . $type, |
| 238 | ], |
| 239 | ], |
| 240 | // We don't want to submit the island type level. We already know the |
| 241 | // type of each islands thanks to IslandInterface::getTypeId() so let's |
| 242 | // keep the storage flat. |
| 243 | '#parents' => ['islands'], |
| 244 | ]; |
| 245 | |
| 246 | foreach ($islands as $id => $island) { |
| 246 | foreach ($islands as $id => $island) { |
| 246 | foreach ($islands as $id => $island) { |
| 246 | foreach ($islands as $id => $island) { |
| 247 | $table[$id] = $this->buildIslandRow($island, $configuration[$id] ?? []); |
| 248 | } |
| 249 | |
| 250 | // Order rows by weight. |
| 251 | \uasort($table, static function ($a, $b) { |
| 252 | if (isset($a['#weight'], $b['#weight'])) { |
| 253 | return (int) $a['#weight'] - (int) $b['#weight']; |
| 254 | } |
| 255 | }); |
| 256 | |
| 257 | return $table; |
| 369 | protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state): void { |
| 370 | $values = $form_state->getValues(); |
| 371 | |
| 372 | /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */ |
| 373 | $entity = $entity; |
| 374 | |
| 375 | if ($this->entity instanceof EntityWithPluginCollectionInterface) { |
| 377 | $values = \array_diff_key($values, $this->entity->getPluginCollections()); |
| 378 | } |
| 379 | |
| 380 | foreach ($values as $key => $value) { |
| 380 | foreach ($values as $key => $value) { |
| 380 | foreach ($values as $key => $value) { |
| 380 | foreach ($values as $key => $value) { |
| 381 | if ($key === 'islands') { |
| 382 | $value = NestedArray::mergeDeep($entity->get('islands'), $value); |
| 383 | } |
| 384 | $entity->set($key, $value); |
| 380 | foreach ($values as $key => $value) { |
| 381 | if ($key === 'islands') { |
| 382 | $value = NestedArray::mergeDeep($entity->get('islands'), $value); |
| 383 | } |
| 384 | $entity->set($key, $value); |
| 380 | foreach ($values as $key => $value) { |
| 381 | if ($key === 'islands') { |
| 382 | $value = NestedArray::mergeDeep($entity->get('islands'), $value); |
| 383 | } |
| 384 | $entity->set($key, $value); |
| 385 | } |
| 386 | } |
| 38 | public function form(array $form, FormStateInterface $form_state): array { |
| 39 | $form = parent::form($form, $form_state); |
| 40 | /** @var \Drupal\display_builder\ProfileInterface $entity */ |
| 41 | $entity = $this->entity; |
| 42 | |
| 43 | $form['label'] = [ |
| 44 | '#type' => 'textfield', |
| 45 | '#title' => $this->t('Label'), |
| 46 | '#maxlength' => 255, |
| 47 | '#default_value' => $entity->label(), |
| 48 | '#required' => TRUE, |
| 49 | ]; |
| 50 | |
| 51 | $form['id'] = [ |
| 52 | '#type' => 'machine_name', |
| 53 | '#default_value' => $this->entity->id(), |
| 54 | '#machine_name' => [ |
| 55 | 'exists' => [Profile::class, 'load'], |
| 56 | ], |
| 57 | '#disabled' => !$entity->isNew(), |
| 58 | ]; |
| 59 | |
| 60 | $form['description'] = [ |
| 61 | '#type' => 'textarea', |
| 62 | '#title' => $this->t('Description'), |
| 63 | '#default_value' => $entity->get('description'), |
| 64 | ]; |
| 65 | |
| 66 | // Add user role access selection. Not available at creation because the |
| 67 | // permissions are not set yet by ProfilePermissions. |
| 68 | if (!$entity->isNew()) { |
| 69 | $roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple(); |
| 70 | \ksort($roles); |
| 71 | $form['roles'] = [ |
| 72 | '#type' => 'checkboxes', |
| 73 | '#title' => $this->t('Roles'), |
| 74 | '#options' => \array_map(static fn (RoleInterface $role) => Html::escape((string) $role->label()), $roles), |
| 75 | '#default_value' => \array_keys($entity->getRoles()), |
| 76 | ]; |
| 77 | } |
| 78 | |
| 79 | // Inform on two time save for the island specific configurations. |
| 80 | if ($this->entity->isNew()) { |
| 80 | if ($this->entity->isNew()) { |
| 82 | '#prefix' => '<div class="messages messages--warning">', |
| 83 | '#markup' => $this->t('Island configuration will be available only after saving this form.'), |
| 84 | '#suffix' => '</div>', |
| 85 | ]; |
| 86 | } |
| 87 | |
| 88 | $path = $this->moduleExtensionList()->getPath('display_builder'); |
| 88 | $path = $this->moduleExtensionList()->getPath('display_builder'); |
| 89 | $form['islands_intro'] = [ |
| 90 | [ |
| 91 | '#type' => 'html_tag', |
| 92 | '#tag' => 'label', |
| 93 | '#value' => $this->t('Islands'), |
| 94 | '#attributes' => [ |
| 95 | 'class' => ['form-item__label'], |
| 96 | ], |
| 97 | ], |
| 98 | [ |
| 99 | '#type' => 'html_tag', |
| 100 | '#tag' => 'img', |
| 101 | '#attributes' => [ |
| 102 | 'src' => base_path() . $path . '/assets/images/islands-regions.png', |
| 103 | 'width' => '1200', |
| 104 | ], |
| 105 | '#prefix' => '<div style="text-align: center;">', |
| 106 | '#suffix' => '</div>', |
| 107 | ], |
| 108 | ]; |
| 109 | |
| 110 | $form['islands'] = [ |
| 111 | '#type' => 'vertical_tabs', |
| 112 | ]; |
| 113 | |
| 114 | $island_configuration = $entity->get('islands') ?? []; |
| 115 | |
| 116 | /** @var \Drupal\display_builder\IslandPluginManagerInterface $islandPluginManager */ |
| 117 | $islandPluginManager = \Drupal::service('plugin.manager.db_island'); // phpcs:ignore |
| 118 | $island_by_types = $islandPluginManager->getIslandsByTypes(); |
| 119 | $labels = [ |
| 120 | 'view' => $this->t('View panels'), |
| 121 | 'button' => $this->t('Toolbar buttons'), |
| 122 | 'contextual' => $this->t('Contextual panels'), |
| 123 | 'library' => $this->t('Library panels'), |
| 124 | 'menu' => $this->t('Menu items'), |
| 125 | ]; |
| 126 | // Sort the types according to the labels. |
| 127 | $island_by_types = \array_merge($labels, $island_by_types); |
| 128 | |
| 129 | foreach ($island_by_types as $type => $islands) { |
| 129 | foreach ($island_by_types as $type => $islands) { |
| 129 | foreach ($island_by_types as $type => $islands) { |
| 129 | foreach ($island_by_types as $type => $islands) { |
| 130 | $form['islands'][$type] = [ |
| 131 | '#type' => 'details', |
| 132 | '#title' => $labels[$type] ?? $type, |
| 133 | '#description' => IslandType::description($type), |
| 134 | '#group' => 'islands', |
| 135 | 'content' => $this->buildIslandTypeTable(IslandType::from($type), $islands, $island_configuration), |
| 136 | ]; |
| 137 | } |
| 138 | |
| 139 | $form['debug'] = [ |
| 140 | '#type' => 'checkbox', |
| 141 | '#title' => $this->t('Debug mode'), |
| 142 | '#description' => $this->t('Enable verbose JavaScript and error logs.'), |
| 143 | '#default_value' => $entity->get('debug'), |
| 144 | ]; |
| 145 | |
| 146 | $form['status'] = [ |
| 147 | '#type' => 'checkbox', |
| 148 | '#title' => $this->t('Enabled'), |
| 149 | '#default_value' => $entity->status(), |
| 150 | ]; |
| 151 | |
| 152 | return $form; |
| 395 | return $this->moduleExtensionList ??= \Drupal::service('extension.list.module'); // phpcs:ignore |
| 177 | public function save(array $form, FormStateInterface $form_state): int { |
| 178 | $result = parent::save($form, $form_state); |
| 179 | |
| 180 | // Clear the plugin cache so changes are applied on front theme builder. |
| 181 | /** @var \Drupal\Core\Plugin\CachedDiscoveryClearerInterface $pluginCacheClearer */ |
| 182 | $pluginCacheClearer = \Drupal::service('plugin.cache_clearer'); // phpcs:ignore |
| 183 | $pluginCacheClearer->clearCachedDefinitions(); |
| 184 | |
| 185 | $message_args = ['%label' => $this->entity->label()]; |
| 186 | $this->messenger()->addStatus( |
| 187 | match ($result) { |
| 188 | SAVED_NEW => $this->t('Created new display builder config %label.', $message_args), |
| 189 | SAVED_UPDATED => $this->t('Updated display builder config %label.', $message_args), |
| 189 | SAVED_UPDATED => $this->t('Updated display builder config %label.', $message_args), |
| 188 | SAVED_NEW => $this->t('Created new display builder config %label.', $message_args), |
| 189 | SAVED_UPDATED => $this->t('Updated display builder config %label.', $message_args), |
| 190 | default => '', |
| 190 | default => '', |
| 191 | } |
| 192 | ); |
| 193 | |
| 194 | // Set the initial default configuration and stay on the form to allow |
| 195 | // islands configuration. |
| 196 | if ($result === SAVED_NEW) { |
| 196 | if ($result === SAVED_NEW) { |
| 197 | $form_state->setRedirect('entity.display_builder_profile.edit_form', ['display_builder_profile' => $this->entity->id()]); |
| 199 | elseif ($result === SAVED_UPDATED) { |
| 200 | $form_state->setRedirect('entity.display_builder_profile.collection'); |
| 201 | } |
| 202 | |
| 203 | return $result; |
| 203 | return $result; |
| 158 | public function submitForm(array &$form, FormStateInterface $form_state): ProfileInterface { |
| 159 | parent::submitForm($form, $form_state); |
| 160 | |
| 161 | // Save user permissions. |
| 162 | /** @var \Drupal\display_builder\ProfileInterface $entity */ |
| 163 | $entity = $this->entity; |
| 164 | |
| 165 | if ($permission = $entity->getPermissionName()) { |
| 166 | foreach ($form_state->getValue('roles') ?? [] as $rid => $enabled) { |
| 166 | foreach ($form_state->getValue('roles') ?? [] as $rid => $enabled) { |
| 166 | foreach ($form_state->getValue('roles') ?? [] as $rid => $enabled) { |
| 166 | foreach ($form_state->getValue('roles') ?? [] as $rid => $enabled) { |
| 167 | user_role_change_permissions($rid, [$permission => $enabled]); |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | return $entity; |
| 171 | return $entity; |
| 251 | \uasort($table, static function ($a, $b) { |
| 252 | if (isset($a['#weight'], $b['#weight'])) { |
| 252 | if (isset($a['#weight'], $b['#weight'])) { |
| 253 | return (int) $a['#weight'] - (int) $b['#weight']; |
| 255 | }); |
| 74 | '#options' => \array_map(static fn (RoleInterface $role) => Html::escape((string) $role->label()), $roles), |