Странное поведение АНАН

Главные вкладки

Аватар пользователя vic vic 6 октября 2009 в 9:07

Разрабатываю формы с возможностью динамического добавления новых полей. Новые поля обязательны для заполнения (#required). И вот такая происходит интересная ситуация. Добавляю я новое поле, но не заполняю его. Затем пытаюсь сохранить форму. Естественно, вылазит form_set_error, что поле не заполнено. Пока все работает корректно. Затем, заполняю это поле и еще раз сохраняю форму. Форма сохраняется, но почему та после сабмита меня перебрасывает на адрес site.ru/my_module/js, то есть тот путь, который я использую как коллбэк для AHAH. Почему так происходит?

Комментарии

Аватар пользователя vic vic 6 октября 2009 в 10:03

Это коллбэк для AHAH

<?php
function rent_room_js() {
  include_once 
'modules/node/node.pages.inc';
  
$form_state = array('storage' => NULL'submitted' => FALSE);
  
$form_build_id $_POST['form_build_id'];
  
// Get the form from the cache.
  
$form form_get_cache($form_build_id$form_state);
  
$args $form['#parameters'];
  
$form_id array_shift($args);
  
// We will run some of the submit handlers so we need to disable redirecting.
  
$form['#redirect'] = FALSE;
  
// We need to process the form, prepare for that by setting a few internals
  // variables.
  
$form['#post'] = $_POST;
  
$form['#programmed'] = FALSE;
  
$form_state['post'] = $_POST;
  
// Build, validate and if possible, submit the form.
  
drupal_process_form($form_id$form$form_state);
  
// This call recreates the form relying solely on the form_state that the
  // drupal_process_form set up.
  
$form drupal_rebuild_form($form_id$form_state$args$form_build_id);
  
// Render the new output.
  
$rent_rooms $form['rooms'];
  unset(
$rent_rooms['#prefix'], $rent_rooms['#suffix']); // Prevent duplicate wrappers.
  
$output theme('status_messages') . drupal_render($rent_rooms);

  

drupal_json(array('status' => TRUE'data' => $output));
}
?>

Это кнопка добавления нового поля

<?php
$form
['add_room'] = array(
    
'#type' => 'submit',
    
'#value' => 'Добавить комнату',
    
'#submit' => array('rent_add_room_submit'),
    
'#ahah' => array(
      
'path' => 'rent/js',
      
'wrapper' => 'rent-rooms',
      
'method' => 'replace',
      
'effect' => 'fade',
    ),
  );
?>

Обработчик кнопки:

<?php
function rent_add_room_submit($form, &$form_state) {
  
node_form_submit_build_node($form$form_state);
  unset(
$form_state['storage']['del_room']); //убиваем флаг удаления комнаты комнаты
  
$form_state['storage']['add_room'] = TRUE;
}
?>

А это валидатор всей формы

<?php
function rent_my_validator($form, &$form_state) {
  unset(
$form_state['storage']);
}
?>
Аватар пользователя Stutzer Stutzer 6 октября 2009 в 18:17

Известный баг.
Лечится путем явного задания свойства #action у формы

<?php

  

// Force action to FIX AHAH bug that redirects to AHAH callback uri
  
$type node_get_types('type'$node);
  
$action '/node/add/'$type->type;
  if (
$node->nid) {
    
$action '/node/'$node->nid'/edit';
  }
  
$form['#action'] = $action;

?>
Аватар пользователя vic vic 7 октября 2009 в 4:24

"vic" wrote:
Лечится путем явного задания свойства #action у формы

Что то не помогло! А где можно подробнее прочитать про этот баг?

Аватар пользователя Stutzer Stutzer 7 октября 2009 в 14:43

У вас довольно нетипичный код в колбэке AHAH.

Во всех статьях по ахаху мне попадался один и тот же код, приведенный ниже:

<?php

  

// The form is generated in an include file which we need to include manually.
  
include_once 'modules/node/node.pages.inc';
  
  
// We're starting in step #3, preparing for #4.
  //$form_state = array('storage' => NULL, 'submitted' => FALSE);   
  
$form_state = array('storage' => NULL'rebuild' => TRUE);  // Поскольку мне критично было не сабмитить форму каждый раз при срабатывании этой фунцкии, предыдущая строка заменена на текущую
  
$form_build_id $_POST['form_build_id'];
  
  
// Step #4.
  
$form form_get_cache($form_build_id$form_state);
  
  
// Preparing for #5.
  
$args $form['#parameters'];
  
$form_id array_shift($args);
  
$form_state['post'] = $form['#post'] = $_POST;
  
$form['#programmed'] = $form['#redirect'] = FALSE;
  
  
// Step #5.
  //$form_state['submitted'] = TRUE;
  
drupal_process_form($form_id$form$form_state);
  
// Unset errors
  
unset($_SESSION['messages']['error']);
  
  
// Step #6 and #7 and #8.
  
$form drupal_rebuild_form($form_id$form_state$args$form_build_id);
  
  
// Step #9.
  
$form_element_collection $form['fieldset_model']['collection'];
  
$output /* vd($form_state) . */theme('status_messages') .  drupal_render($form_element_collection);

  

// Final rendering callback.
  
drupal_json(array('status' => TRUE'data' => $output));
  exit;
?>
Аватар пользователя vic vic 7 октября 2009 в 18:02

"Stutzer" wrote:
У вас довольно нетипичный код в колбэке AHAH.

Код как раз таки типичный - практически без изменений из модуля poll
И все-таки, про этот баг где почитать!?

Аватар пользователя bratello bratello 31 января 2011 в 12:09

Удалось ли разобраться с этим багом и понять как вылечить его? У меня такая же ситуация, альтерирую форму добавляя в нее комбик с AHAH callback, после пары колбеков и ошибочных сабмитов (которые обламываются на валидации) на клиентскую сторону приходит форма с неверным action. Продибагировал чуток, оказывается AHAH постит всю форму с ahah callback path, видимо она сохраняется в кеше и на следующем полном сабмите возвращается форма из кеша, даже не перестраивается, она даже до валидации может не доползти, просто системный валидатор обязательного поля ее обламает и вернет из кеша то что было до того (форму из последнего ahah). Пока что из кода вижу что менять нужно action в алтер хуке, потому что после этого произойдет ребилд и сохранение формы в кеше, в альтер у нас форма передаётся по ссылке.

Короче, все на то смахивает что AHAH это один большой костыль над FAPI.

Аватар пользователя bratello bratello 31 января 2011 в 12:24

В принципе у меня костыль с $form['#action'] в альтер хуке лечит ситуацию, кажется побочных проблем не возникает. Для тех кто захочет воспользоваться костылем, action формы нужно поменять до того как будет вызван drupal_rebuild_form, в противном случае в кеше сохранится форма с AHAH action. Кстати, советую поменять название темы на что то типа "AHAH callback изменяет action формы", чтобы потом проще было другим найти эту ветку.

Аватар пользователя Stutzer Stutzer 31 января 2011 в 17:15

мне как-то пришлось использовать вот такой вот уродливый костыль для формы редактирования ноды:

  // Uglu hack, but I have no time to dig it
  if (!empty($node->nid)) {
    $form['#action'] = url("node/{$node->nid}/edit");
  }
  else {
    $form['#action'] = url('node/add/estate');
  }