странный баг с AHAH и file

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

Аватар пользователя imissyouso imissyouso 10 января 2012 в 3:26

Привет всем!
Бьюсь с проблемой уже день, силы иссякли, решил написать тут. Излагаю суть:
Пишу простенький модуль для создания галереи.
Создаю форму добавления картинки в текущую галерею, в ней же отображаю уже добавленные картинки выводя их из базы.
Здесь для каждой картинки создаётся кнопка-submit, у которой есть собственный обработчик mygallery_image_delete_submit, он удаляет. Также ниже вывода картинок есть поле типа file для выбора загружаемой картинки, и ещё одна кнопка submit для загрузки этой картинки, у неё тоже свой обработчик и валидатор.

function mygallery_upload_form($form_state,$gall_id) {

    //Выборка всех данных о изображениях галереи с айдишником $gall_id
    $query = db_query("SELECT * FROM {mygallery_gallerys} AS t1
                        LEFT JOIN {node} AS t2 ON t1.iid = t2.nid
                        LEFT JOIN {node_revisions} AS t3 ON t2.nid = t3.nid
                        LEFT JOIN {mygallery_images} AS t4 ON t1.iid = t4.nid
                        LEFT JOIN {files} AS t5 ON t4.fid = t5.fid
                        WHERE t1.gid = %d"
, $gall_id);

    global $base_url;
    //враппер для ahah
    $form['wrapper_start'] = array(
        '#value' => '<div id = "wrap_here">',
    );
    //выводим изображения
    while ($row = db_fetch_object($query)) {
        $form['images'][$row->fid] = array(
            '#theme' => 'gallery',
           
        );
        $form['images'][$row->fid]['remove'] = array(
            '#type' => 'submit',
            '#value' => '[x]',
            '#name' => 'remove_'.$row->fid,
           //'#src' => drupal_get_path('module', 'mygallery') . '/images/cross.png',
            '#ahah' => array(
                'path' => 'mygallery/image_upload/js',
                'wrapper' => 'wrap_here',
                'method' => 'replace',
            ),
            '#submit' => array('mygallery_image_delete_submit')
        );
        //получаем путь для уменьшенной копии изображения
        $small = substr($row->filepath, 0, (strlen($row->filepath) - strlen($row->filename) - 1));
        //путь для оригинала
        $form['images'][$row->fid]['bigimage'] = array(
            '#type' => 'hidden',
            '#value' => $base_url . '/' . $row->filepath,
        );
        //путь для уменьшенной копии
        $form['images'][$row->fid]['smallimage'] = array(
            '#type' => 'hidden',
            '#value' => $base_url . '/'. $small . '/small/' . $row->filename,
        );
        $form['images'][$row->fid]['title'] = array(
            '#type' => 'hidden',
            '#value' => $row->title,
        );
        $form['images'][$row->fid]['body'] = array(
            '#type' => 'hidden',
            '#value' => $row->body,
        );
    }
    //если нет картинок в галереи, выводим "нет изображений"
    if(!isset($form['images']))
    {
        $form['images'] = array(
            '#theme' => 'emptyfolder',
            '#value' => 'Нет изображений',
        );
    }
    //конец враппера для ahah
    $form['wrapper_end'] = array(
        '#value' => '</div>',
    );
    $form['upload_image'] = array(
        '#type' => 'fieldset',
        '#title' => t('Загрузка изображения в галерею'),
        '#collapsible' => TRUE,
        '#collapsed' => FALSE,
    );
    $form['upload_image']['imagefile'] = array(
        '#type' => 'file',
        '#title' => t('Добавить изображение'),
        '#size' => 40,
        '#description' => "поддерживаемые форматы jpeg png gif",
    );
    $form['upload_image']['title_image'] = array(
        '#type' => 'textfield',
        '#title' => "Название изображения",
        '#required' => FALSE,
    );
    $form['upload_image']['description']['body'] = array(
        '#type' => 'textarea',
        '#title' => 'Описание изображения',
        '#required' => FALSE
    );
    $form['upload_image']['imagesubmit'] = array(
        '#op' => 'myop',
        '#type' => 'submit',
        '#value' => t('Загрузить'),
        '#name' => 'picsubmit',
        '#ahah' => array(
            'path' => 'mygallery/image_upload/js',
            'wrapper' => 'wrap_here',
            'method' => 'replace',
            'progress' => array('type' => 'bar', 'message' => t('Пожалуйста подождите...')),
        ),
        '#submit' => array('mygallery_image_submit'),
        '#validate' => array('mygallery_image_validate'),
    );
        //скрытое поле содержит id текущей галереи
        $form['nid'] = array(
        '#type' => 'hidden',
        '#value' => $gall_id,
    );
    $form['#attributes']['enctype'] = 'multipart/form-data';

    return $form;
}

function mygallery_image_validate($form, &$form_state) {
 
....
бла бла бла много кода валидации добавления картинки
...

}

function mygallery_image_submit($form, &$form_state) {

бла бла бла много кода сабмита картинкиЮ тут добавляем её в базу....

}

function mygallery_image_delete_submit($form, &$form_state) {
...
бла бла бла сабмитер для удаления картинки
...
}

А вот ahah обработчик для кнопок

function mygallery_image_upload_js() {

    $form_state = array('storage' => NULL, 'submitted' => FALSE);
    $form_build_id = $_POST['form_build_id'];
    $form = form_get_cache($form_build_id, $form_state);

    $args = $form['#parameters'];
    $form_id = array_shift($args);
    $form['#post'] = $_POST;
    $form['#redirect'] = FALSE;
    $form['#programmed'] = FALSE;
    $form_state['post'] = $_POST;
    drupal_process_form($form_id, $form, $form_state);

    $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);

    $images = $form['images'];
  //  $javascript = drupal_add_js(NULL, NULL, 'header');
    print drupal_to_js(array(
        'status' => TRUE,
        'data' => theme('status_messages') . drupal_render($images),
      //  'settings' => call_user_func_array('array_merge_recursive', $javascript['setting'])
        ));
    exit();
}

всё это дело шикарно работает при отелючении ahah, картинки добавляются, правильно отображаются, удаляются! Класс!

Но вот беда, когда подключаю ahah, в обработчике не верно идентифицируется нажатая кнопка. То есть для того чтобы
drupal_process_form($form_id, $form, $form_state); адекватно распознала нажатую кнопку и поместила её в $form_state['clicked_button'] нужно чтобы от браузера приходил $_POST содержащий '#name' нажатой кнопки, обрабатывая этот пост drupal_process_form и понимает какая кнопка была нажата.
Всё чики пуки когда я наживаю на кнопку 'загрузить' при отсутствии выбранного файла (т.е. форма выбора файла пустая), обработчик ahah в таком случае получает правильный пост, с неймом кнопки, следовательно совершенно адекватно определяет clicked_button (нажал на загрузку или на удаление). ВОТ МАГИЯ НАЧИНАЕТСЯ ОТСЮДА! Стоит мне прикрепить файл и нажать на 'загрузить' как ahah обработчик получает Post без параметра '#name', в следствии clicked_button определяется не адекватно, и в недрах drupal_process_form (а именно в form_builder -> _form_builder_ie_cleanup),clicked_button получает самую первую найденную кнопку в форме. Как так то?

Если не устали читать, то пишу что нараследовал по этой теме.

дампил в ahah обработчике $_POST , $_FILES
$_FILES при прикреплённом файле содержит информацию о нём, т.е. загружается успешно. => не в $_FILES дело
дампил и находил закономерности $_POST, закономерность одна - при прикреплённом изображении $_POST содержит name кнопки, без прикреплённого файла НЕТ. Остальные атрибуты в POST не изменяются.

Далее, пытался найти объяснение этому, полез в ahah.js. Немного помучав его firebug'om выяснил что форма отправляется таким образом

  // Bind the ajaxSubmit function to the element event.
  $(element_settings.element).bind(element_settings.event, function() {
        console.log(options.data);
    $(element_settings.element).parents('form').ajaxSubmit(options);
    return false;
  });

где options набор параметров

 
  var ahah = this;
  var options = {
    url: ahah.url,
    data: ahah.button,
    beforeSubmit: function(form_values, element_settings, options) {
      return ahah.beforeSubmit(form_values, element_settings, options);
    },
    success: function(response, status) {
      // Sanity check for browser support (object expected).
      // When using iFrame uploads, responses must be returned as a string.
      if (typeof(response) == 'string') {
        response = Drupal.parseJson(response);
      }
      return ahah.success(response, status);
    },
    complete: function(response, status) {
      if (status == 'error' || status == 'parsererror') {
        return ahah.error(response, ahah.url);
      }
    },
    dataType: 'json',
    type: 'POST'
  };

как видим здесь у параметру data задаётся ahah.button. Ahah.button содержит связку name-value нажатой кнопки, и как показал фаер баг правильно её определяет во всех случаях! и с файлом без файла!

Проблема в том, что когда ajaxSubmit(options) отправляет форму ajax'ом в которой есть input type='file' он игнорирует параметр data, и нихрена не передаёт.(следил за отправлеными post'ами через фаербаг) Отсюда то и ясно почему name кнопки не доходит постом до моего ahah обработчика на сервере, он просто не отсылается.

Вот тут я и застрял, как быть, что делать? Извиняюсь за большое количество текста, накипело. Спасибо заранее за помощь.

Комментарии

Аватар пользователя Shok211 Shok211 10 января 2012 в 12:37

Через ajax только в html 5 можно отправить файл все остальные способы frame-transport. Это не баг. В Drupal 6 этого 99% не реализоъвано

Аватар пользователя imissyouso imissyouso 10 января 2012 в 14:06

файл то отправляется и принимается/сохраняется без проблем, просто параметр нажатой кнопки отправки теряется