diff --git a/src/Element/ComponentElementAlter.php b/src/Element/ComponentElementAlter.php index 1e39bb6e5b8c7820efca8c0b8c220abdc0ee21fa..3a405d38654d95feea7c1b6a33b68354a6d0a911 100644 --- a/src/Element/ComponentElementAlter.php +++ b/src/Element/ComponentElementAlter.php @@ -124,7 +124,7 @@ class ComponentElementAlter implements TrustedCallbackInterface { * @return bool * Returns true for empty. */ - public static function isSlotEmpty(array $slot, int $max_level = 2, int $level = 0): bool { + public static function isSlotEmpty(array $slot, int $max_level = 5, int $level = 0): bool { if (is_array($slot) && empty($slot)) { return TRUE; } @@ -160,6 +160,10 @@ class ComponentElementAlter implements TrustedCallbackInterface { unset($slot[$key]); } } + if (isset($slot['#access']) && is_string($slot['#access'])) { + // This fix is for isVisibleElement() to work properly. + $slot['#access'] = (bool) $slot['#access']; + } if (Element::isEmpty($slot) || Element::isVisibleElement($slot) === FALSE) { return TRUE; } diff --git a/src/Plugin/UiPatterns/Source/BlockSource.php b/src/Plugin/UiPatterns/Source/BlockSource.php index 245df061635e5a35bda82bece2e0817576b1f58f..dad2a61a9e56755e3a636f82920622160c2ce647 100644 --- a/src/Plugin/UiPatterns/Source/BlockSource.php +++ b/src/Plugin/UiPatterns/Source/BlockSource.php @@ -37,6 +37,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; prop_types: ['slot'] )] class BlockSource extends SourcePluginBase { + /** * Block to be rendered. * @@ -88,13 +89,42 @@ class BlockSource extends SourcePluginBase { return $instance; } + /** + * Alter the element after the form is built. + * + * @param array $element + * The element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return array + * The altered element. + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public static function afterBuildBlockForm(array $element, FormStateInterface $form_state) : array { + $element_settings = $form_state->getValue($element['#parents']); + $plugin_id = $element_settings['plugin_id']; + if (!$plugin_id) { + return $element; + } + $form = $form_state->getCompleteForm(); + $subform_state = SubformState::createForSubform($element[$plugin_id], $form, $form_state); + $block = \Drupal::service('plugin.manager.block')->createInstance($plugin_id, []); + if ($block instanceof BlockPluginInterface) { + $block->submitConfigurationForm($element, $subform_state); + $configuration = $block->getConfiguration(); + $form_state->setValue(array_merge($element['#parents'], [$plugin_id]), $configuration); + } + return $element; + } + /** * {@inheritdoc} */ public function defaultSettings(): array { return [ 'plugin_id' => NULL, - 'settings' => [], ]; } @@ -107,17 +137,22 @@ class BlockSource extends SourcePluginBase { if (!$this->block) { return []; } - return $this->block->build(); + $build = $this->block->build(); + if (!is_array($build)) { + return []; + } + return $build; } /** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state): void { - $block = $this->getBlock($form_state->getValue('plugin_id')); + $plugin_id = $form_state->getValue('plugin_id'); + $block = $this->getBlock($plugin_id); if ($block) { - $subform_state = SubformState::createForSubform($form['settings'], $form, $form_state); - $this->getPluginForm($block)->validateConfigurationForm($form['settings'], $subform_state); + $subform_state = SubformState::createForSubform($form[$plugin_id], $form, $form_state); + $this->getPluginForm($block)->validateConfigurationForm($form[$plugin_id], $subform_state); } } @@ -155,7 +190,7 @@ class BlockSource extends SourcePluginBase { '#empty_option' => $this->t('- None -'), '#required' => FALSE, ]; - $form["settings"] = [ + $form[$plugin_id] = [ '#type' => 'container', '#attributes' => ["id" => $wrapper_id], "#tree" => TRUE, @@ -165,12 +200,23 @@ class BlockSource extends SourcePluginBase { // Create a block entity. $form['#tree'] = TRUE; // $form['#process'] = [ '::validateForm']; - $form['settings'] = []; - $subform_state = SubformState::createForSubform($form['settings'], $form, $form_state); - $form['settings'] = $this->getPluginForm($block)->buildConfigurationForm($form['settings'], $subform_state); - $form["settings"]['#tree'] = TRUE; - $form['settings']['#prefix'] = '<div id="' . $wrapper_id . '">' . ($form['settings']['#prefix'] ?? ''); - $form['settings']['#suffix'] = ($form['settings']['#suffix'] ?? '') . '</div>'; + $form[$plugin_id] = []; + $subform_state = SubformState::createForSubform($form[$plugin_id], $form, $form_state); + $form[$plugin_id] = $this->getPluginForm($block)->buildConfigurationForm($form[$plugin_id], $subform_state); + $form[$plugin_id]['#tree'] = TRUE; + $form[$plugin_id]['#prefix'] = '<div id="' . $wrapper_id . '">' . ($form[$plugin_id]['#prefix'] ?? ''); + $form[$plugin_id]['#suffix'] = ($form[$plugin_id]['#suffix'] ?? '') . '</div>'; + $hide_elements = [ + 'label', + 'label_display', + 'admin_label', + ]; + foreach ($hide_elements as $hide_element) { + if (isset($form[$plugin_id][$hide_element])) { + $form[$plugin_id][$hide_element]['#access'] = FALSE; + } + } + $form['#after_build'][] = [static::class, 'afterBuildBlockForm']; } } @@ -203,7 +249,7 @@ class BlockSource extends SourcePluginBase { if (!$plugin_id) { return NULL; } - $block_configuration = $this->getSetting('settings') ?? []; + $block_configuration = $this->getSetting($plugin_id) ?? []; $contexts = $this->context; /** @var \Drupal\Core\Block\BlockPluginInterface $plugin */ $plugin = $this->blockManager->createInstance($plugin_id, $block_configuration); @@ -251,7 +297,10 @@ class BlockSource extends SourcePluginBase { $subformKeys = $triggeringElement['#array_parents']; // Remove the triggering element itself and add the 'block' below key. array_pop($subformKeys); - $subformKeys[] = 'settings'; + $parents = $triggeringElement['#parents']; + array_pop($parents); + $plugin_id = $form_state->getValue($parents)['plugin_id']; + $subformKeys[] = $plugin_id; // Return the subform: $subform = NestedArray::getValue($form, $subformKeys); $form_state->setRebuild(); @@ -327,10 +376,7 @@ class BlockSource extends SourcePluginBase { // CacheableMetadata::createFromRenderArray($content) $cache = $element["#cache"] ?? []; - $element["#cache"] = array_merge($cache, [ - "max-age" => 0, - // "tags" => ['config:system.menu.' . $this->menuId], - ]); + $element["#cache"] = $cache; return $element; } diff --git a/tests/fixtures/block_tests.yml b/tests/fixtures/block_tests.yml index f3d973d10a557381b626e355e74341dbaa9fc4f3..118808810210bd03b52f98485c4e69b1f3ad32c6 100644 --- a/tests/fixtures/block_tests.yml +++ b/tests/fixtures/block_tests.yml @@ -9,7 +9,7 @@ block_1: source_id: 'block' source: plugin_id: 'ui_patterns_test_block' - settings: + 'ui_patterns_test_block': display_message: "value_text_X" entity: {} output: diff --git a/ui_patterns.module b/ui_patterns.module index 8cce89e038edb3e064c2077b027b17bcafa1955e..57c667035350039f5bb7fc6f2e3c3f63ee9be624 100644 --- a/ui_patterns.module +++ b/ui_patterns.module @@ -46,9 +46,8 @@ function ui_patterns_plugin_filter_block__ui_patterns_alter(array &$definitions, // Add a boolean marker '_ui_patterns_compatible' to all remaining definitions // Other modules can use the same hook to modify this value. // This allows to add or remove blocks. - $allowed_blocks = [ - "id" => ["search_form_block", "system_menu_block"], - "provider" => ["views"], + $forbidden_blocks = [ + "provider" => ["layout_builder", "ui_patterns_blocks"], ]; foreach ($definitions as $id => &$definition) { if (isset($definitions[$id]['_ui_patterns_compatible'])) { @@ -58,25 +57,8 @@ function ui_patterns_plugin_filter_block__ui_patterns_alter(array &$definitions, continue; } $compatibilityFlag = TRUE; - if (in_array($definition['provider'], $allowed_blocks["provider"]) || - in_array($definition["id"], $allowed_blocks["id"])) { - // The block stays accepted. - } - elseif (isset($definition['class'])) { - try { - $class_name = $definition['class']; - $reflector = new \ReflectionClass($class_name); - if ($reflector->hasMethod("blockSubmit") && ($reflector->getMethod("blockSubmit")->getDeclaringClass()->getName() === $class_name)) { - // Blocks having a custom implementation are discarded, - // because some blocks may store in their configuration - // a different structure than the form structure. - // We can't support this properly yet. - $compatibilityFlag = FALSE; - } - } - catch (\ReflectionException $e) { - // The block stays accepted. - } + if (in_array($definition['provider'], $forbidden_blocks["provider"])) { + $compatibilityFlag = FALSE; } // Filter out blocks with _block_ui_hidden ? $definitions[$id]['_ui_patterns_compatible'] = $compatibilityFlag;