xandeadx.ru Блог музицирующего веб-девелопера

Drupal → Использование виджета AJAX загрузки файлов в своих формах

Я как-то упустил из виду, что помимо стандартного способа загрузки файлов в своих формах можно использовать AJAX виджет поля File:

Поле загрузки файлов
Результат загрузки файла

Пример использования:

/**
 * Form builder.
 */
function mymodule_myform($form) {
  $form['file'] = array(
    '#type' => 'managed_file',
    '#title' => 'Картинка',
    '#description' => 'Выберите файл с расширением jpg, jpeg, png или gif',
    '#upload_location' => 'public://',
    '#upload_validators' => array(
      'file_validate_is_image' => array(),
      'file_validate_extensions' => array('png gif jpg jpeg'),
      'file_validate_size' => array(1 * 1024 * 1024),
    ),
    '#default_value' => variable_get('mymodule_myfilefid'),
  );
 
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Отправить',
  );
 
  return $form;
}
 
/**
 * Form submit callback.
 */
function mymodule_myform_submit($form, &$form_state) {
  // Delete old file
  $old_file_fid = variable_get('mymodule_myfilefid');
  if ($old_file_fid && $old_file_fid != $form_state['values']['file']) {
    $old_file = file_load($old_file_fid);
    file_usage_delete($old_file, 'mymodule');
    file_delete($old_file);
  }
 
  // Save new file
  $file = file_load($form_state['values']['file']);
  $file->status = FILE_STATUS_PERMANENT;
  file_save($file);
  file_usage_add($file, 'mymodule', 'mymodule', 0);
  variable_set('mymodule_myfilefid', $file->fid);
 
  drupal_set_message('Картинка загружена');
}

Об удалении файла надо заботиться самостоятельно.

Документация.
Модуль для загрузки картинок и отображения их превьюшек.

Написанное актуально для Drupal 7
Похожие записи

Комментарии RSS

Спасибо за пример!
Скажите как загрузить несколько файлов? т.е. при выборе одного файла появлялось форма для загрузки еще одного и т.д.

Спасибо за пример!
Не совсем понял для чего нужна функция mymodule_myform_submit? Файл и без нее загружается на сервер или файл при такой загрузке в друпале имеет состояние "временного" и ему нужно присвоить статус "постоянного".

А можно в этом виджете указать диалоговому окну маску разрешенных расширения для открытия или такое не предусмотрено?

Если файл уже был когда-то загружен, как передать виджету что файл уже есть и надо просто вывести имя файла и кнопку Remove (т.е. привести к состоянию как на 2-м скриншоте)?

заполнить #default_value

Павел, FILE_STATUS_PERMANENT вам ни о чем не говорит?

А не подскажите как сделать, если мне необходимо загрузить больше одного изображения?

создайте больше одного элемента формы ;)

нее, мне необходима что-то вроде массовой загрузки файлов. Например если мне нужно загрузить 100 изображений - эт не вариант делать 100 элементов форм.

из коробки способов нет

Хотел написать на этой странице http://xandeadx.ru/blog/drupal/4, но там 6 ветка. Решил тут, хоть немного не в тему.

Может кто-то сталкивался с модулем AJAX Comments для семерки и добавлял к комментарию дополнительное поле типа file?

Добавил поле с возможностью добавления одного файла. После нажатия на кнопку ответить и после загрузки формы комментария, пытаюсь загрузить файл, Выскакивает ошибка и события не срабатывают. Начал разбираться и нашел причину - отсутствие уникального враппера для виджета, везде один id="edit-field-comment-image-und-0-ajax-wrapper" во всех раскрытых формах.

И выходит, что при аплоаде файла и отработки $commands[] = ajax_command_replace(NULL, $output, $settings); в функции file_ajax_upload(), данные вставляются во все формы.

Решил вопрос загрузки таким способом.
function MODULE_NAME_menu_alter(&$items) {
$items['file/ajax']['page callback'] = 'MODULE_NAME_file_ajax_upload_custom';
}
Т.е. переопределил callback и скопировал содержимое file_ajax_upload в свою функцию.
И немного изменил ретерн:

  $selector_='';
  if(isset($form_state['storage']['ajax_comments_form_id'])){
    $setting_ajax = array_shift($settings['ajax']);
    $selector_='#'.$form_state['storage']['ajax_comments_form_id'].' #'.$setting_ajax['wrapper'];
  }
  $commands[] = ajax_command_replace($selector_, $output, $settings);
  return array('#type' => 'ajax', '#commands' => $commands);

И все заработало! НО!!! Еще же есть кнопка удалить? И с ней та же проблема вышла. Только как ее оформить в враппер, не понял.

Буду благодарен за любой совет. Может я сильно "заморачиваюсь" и уже есть решение этой проблемы?

Насколько правильно, не знаю. Убрал решение выше.
В hook_form_alter:

if($form_id=='comment_node_TYPE_form'){
    if(isset($form_state['storage']['ajax_comments_form_id'])){
      $new_wrap_image_id=preg_replace("/[^0-9]/", '', $form_state['storage']['ajax_comments_form_id']);
      $field_image_temp = $form['field_IMAGE_NAME']['und'][0];
      unset($form['field_IMAGE_NAME']['und'][0]);
      $form['field_IMAGE_NAME']['und'][$new_wrap_image_id] = $field_image_temp;
      $form['field_IMAGE_NAME']['und'][$new_wrap_image_id]['#file_upload_delta'] = $new_wrap_image_id;
    }
}

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании