The new #managed_file element provided by file.module is currently not documented on the Forms API reference page.

http://api.drupal.org/api/drupal/developer--topics--forms_api_reference....

CommentFileSizeAuthor
#7 750190.patch5.84 KBjgraham

Comments

jhodgdon’s picture

Status: Active » Postponed

I would like to postpone this until we decide to fix or not fix:
#100680: [meta] Make API module generate Form API documentation
because hopefully we'll be generating the Forms API reference automatically from comments in the code, instead of the current manual editing process.

rfay’s picture

Assigned: Unassigned » rfay
Status: Postponed » Active

I will try to take this on. We need to have all of the FAPI documented without waiting for dependencies that may or may not arrive.

rfay’s picture

@eojthebrave: If you can give me a quick set of pointers on how it's used, I'll write it up.

eojthebrave’s picture

Okay, here we go.

The element type is #managed_file and provides you with a complete ajax/progress aware widget for uploading a file and saving it to the {files} table.

By default you get a simple upload button, that allows you to choose a file to upload, once a file has been chosen you can click "Upload" and it will upload the file via ajax and display a progress meter. Your FAPI validate/submit callback will be given a file object ID that represents the ID of the new file in the {files} table.

The #managed_file element is expanded into a set of FAPI elements including two '#submit' buttons one for Upload one for Remove, a '#file' element and a handful of '#hidden' and '#markup' elements to handle progress indication and displaying of already uploaded files.

Note: New files are uploaded with a status of 0 and are treated as temporary files which are removed after 6 hours via cron. Your module is responsible for changing the $file objects status to FILE_STATUS_PERMANENT and saving the new status to the database. Something like the following within your submit handler should do the trick.

Once a file has been uploaded you can use the file objects fid as the #default_value for the form element. This will display an icon, a link to the file, and a remove button.

// Load the file via file.fid.
$file = file_load($form_state['values']['my_file_field']);
// Change status to permanent.
$file->status = FILE_STATUS_PERMANENT;
// Save.
file_save($file);

Clicking the remove button sets the value of the field to 0 and your module is responsible for actually removing the file from the files table and the file system. @see file_delete(). Off the top of my head I believe the $file object in question is stored somewhere in the $form_state array so you can access it without know the files fid. I guess if it isn't it probably should be. :)

Non-standard form element properties.

#progress_indicator options are 'none', 'bar', and 'throbber', default is 'throbber'.

#progress_message (string) Progress message to display along with progress meter while a file is being uploaded. Defaults to NULL.

#upload_validators (array) an array of callback functions to perform validation of uploaded files.

#upload_location (string) location on server where uploaded files should be stored. e.g.) 'public://files/my_files_director'

The image_example module provides a good example of basic usage in the image_example.pages.inc file.

Hope that helps, let me know if you have any questions or if any of that is unclear.

rfay’s picture

Status: Active » Needs review

I added this to D7 FAPI. Oh my goodness it's painful to add an element type.
Review is appreciated, http://api.drupal.org/api/drupal/developer--topics--forms_api_reference....

jhodgdon’s picture

Status: Needs review » Needs work

Looks pretty good Randy...

A couple of issues in the section http://api.drupal.org/api/drupal/developer--topics--forms_api_reference....

a) Missing the Properties: #access, etc. line.

b) " Something like the following within your submit handler should do the trick." -- missing the "following" code?

jgraham’s picture

StatusFileSize
new5.84 KB

Attached patch addresses the issues in comment 6 as well as providing an inline example like elsewhere in the doc

Note: New files are uploaded with a status of 0 and are treated as temporary files which are removed after 6 hours via cron. Your module is responsible for changing the $file objects status to FILE_STATUS_PERMANENT and saving the new status to the database. Something like the following within your submit handler should do the trick.

<?php
// Load the file via file.fid.
$file = file_load($form_state['values']['my_file_field']);
// Change status to permanent.
$file->status = FILE_STATUS_PERMANENT;
// Save.
file_save($file);
?>

Properties: #access, #after_build, #array_parents, #attached, #attributes, #description, #disabled, #element_validate, #parents, #post_render, #prefix, #pre_render,#process, #states, #suffix, #theme, #theme_wrappers, #title, #tree, #weight

Usage example (image_example.pages.inc.):

  // Use the #managed_file FAPI element to upload an image file.
  $form['image_example_image_fid'] = array(
    '#title' => t('Image'),
    '#type' => 'managed_file',
    '#description' => t('The uploaded image will be displayed on this page using the image style choosen below.'),
    '#default_value' => variable_get('image_example_image_fid', ''),
    '#upload_location' => 'public://image_example_images/',
  );
jgraham’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 750190.patch, failed testing.

rfay’s picture

Status: Needs work » Reviewed & tested by the community

Looks good to me. I sure appreciate you picking this up.

jgraham’s picture

Status: Reviewed & tested by the community » Fixed

committed to head

rfay’s picture

Thanks so much, jgraham!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

aaronelborg’s picture

Alright.........what am I missing here.

eojthebrave said:

Your FAPI validate/submit callback will be given a file object ID that represents the ID of the new file in the {files} table.

How does a validate and/or a submit handler get called when the upload button triggers an ajax call?

Thanks for any advice.

aaronelborg’s picture

Huh. Nothing?

Well here's what I ended up doing.

function MYMODULE_my_form($form, &$form_state) {
  $form['image'] = array(
    '#type' => 'managed_file',
    '#title' => 'File',
    '#upload_location' => 'public://my-files/',
    '#process' => array('MYMODULE_my_file_element_process')
  );

  return $form;
}

function MYMODULE_my_file_element_process($element, &$form_state, $form) {
  $element = file_managed_file_process($element, $form_state, $form);
  $element['upload_button']['#access'] = FALSE;
  return $element;
}
//  Disable the ajax submit button since it doesn't call my custom submit handler.  Why?
function MYMODULE_my_file_element_process($element, &$form_state, $form) {
  $element = file_managed_file_process($element, $form_state, $form);
  $element['upload_button']['#access'] = FALSE;
  return $element;
}

THEN.....my custom submit handler gets called and all is right within the world. (Except for the fact that this feels wicked-hacky.)

function MYMODULE_submit($form, &$form_state) {
  if (!empty($form_state['values']['thing'])){
    // Load the file via file.fid.
    $file = file_load($form_state['values']['thing']);
    // Change status to permanent.
    $file->status = FILE_STATUS_PERMANENT;
    // Save.
    file_save($file);
    //file_usage_add($file, 'user', 'user', $account->uid);
    drupal_set_message('Your file has been uploaded.');
  } else {
      form_set_error('thing', 'You didn\'t submit anything.');
    }
}