Логика пользовательского интерфейса (
Код: Выделить всё
#statesЯ уже потратил много времени на отладку этого и буду признателен за рекомендации по правильному подходу Drupal для проверки встроенных блочных форм в Layout Builder.
Контекст:
Тип пользовательского блока:
Код: Выделить всё
v2_banner
- Если field_v2_is_full_clickable = TRUE
требуетсяКод: Выделить всё
field_v2_link
- обязателен
Код: Выделить всё
field_v2_buttons_x2
Код: Выделить всё
field_v2_titleИзначально я реализовал это с помощью Entity Constraints + Constraint Validators, но формы AJAX Layout Builder аварийно завершали работу:
Код: Выделить всё
Undefined array key "#parents"
Поэтому я переместил проверку в проверку Form API.
Хуки в .module
Код: Выделить всё
function my_custom_blocks_v2_banner_form_block_content_form_alter(
&$form,
FormStateInterface $form_state,
$form_id
) {
\Drupal::service(FormAlterHooks::class)
->bannerBlockFormAlter($form, $form_state, $form_id);
}
function my_custom_blocks_v2_banner_form_layout_builder_add_block_alter(
&$form,
FormStateInterface $form_state,
$form_id
) {
\Drupal::service(FormAlterHooks::class)
->bannerBlockFormAlter($form, $form_state, $form_id);
}
function my_custom_blocks_v2_banner_form_layout_builder_update_block_alter(
&$form,
FormStateInterface $form_state,
$form_id
) {
\Drupal::service(FormAlterHooks::class)
->bannerBlockFormAlter($form, $form_state, $form_id);
}
Код: Выделить всё
final class FormAlterHooks {
private function getFormEntityType(array $form, FormStateInterface $form_state): ?string {
$form_object = $form_state->getFormObject();
if ($form_object instanceof EntityFormInterface) {
$entity = $form_object->getEntity();
return "{$entity->getEntityType()->id()}:{$entity->bundle()}";
}
elseif ($form_object instanceof LayoutBuilderForm) {
if (empty($form['#block'])) {
return NULL;
}
$block = $form['#block'];
return "{$block->getEntityType()->id()}:{$block->bundle()}";
}
return NULL;
}
public function bannerBlockFormAlter(
&$form,
FormStateInterface $form_state,
$form_id
): void {
if ($this->getFormEntityType($form, $form_state) !== 'block_content:v2_banner') {
return;
}
// Validation callback.
if (!empty($form['settings']['block_form'])) {
$form['settings']['block_form']['#validate'][] = [
self::class,
'validateBannerForm'
];
}
else {
$form['#validate'][] = [
self::class,
'validateBannerForm'
];
}
// States logic works correctly.
$form['field_v2_link']['#states']['visible'] = [
':input[name="field_v2_is_fully_clickable[value]"]' => ['checked' => TRUE],
];
$form['field_v2_buttons_x2']['#states']['visible'] = [
':input[name="field_v2_is_fully_clickable[value]"]' => ['checked' => FALSE],
];
}
public static function validateBannerForm(
array &$form,
FormStateInterface $form_state
): void {
throw new \Exception('VALIDATION RUNNING');
}
}
- выполняется
Код: Выделить всё
hook_form_layout_builder_add_block_alter() - выполняется
Код: Выделить всё
hook_form_layout_builder_update_block_alter() - логика работает правильно
Код: Выделить всё
#states - form alter определенно работает
- Модальное окно Layout Builder загружается правильно
Обратный вызов проверки никогда не выполняется.
Даже это никогда триггеры:
Код: Выделить всё
throw new \Exception('VALIDATION RUNNING');
- нет ошибки AJAX
- нет журналов
- нет страницы исключений
Я также ранее пробовал:
- Ограничения сущности
- Валидаторы ограничений
Код: Выделить всё
->atPath()Код: Выделить всё
$form['#entity_builders']Код: Выделить всё
$form['#element_validate']
Основной вопрос
Каков правильный подход Drupal 10 для прикрепления пользовательской проверки к встроенным блочным формам Layout Builder?
В частности:
- куда следует прикреплять обратные вызовы проверки?
- должна ли проверка выполняться на:
корневой форме? - ?
Код: Выделить всё
settings[block_form] - Плагин подформы?
- форма сущности?
Любой рекомендации или примеры будут оценены по достоинству.
Мобильная версия