1

what hook gets called at the formation of a form.

I'm trying to add some additional mime types to form with id file_entity_add_upload but my hook_form_alter is getting called after these are validated, so attempts to upload them fails.

Update - added screenshot to illustrate the problem

screenshot to illustrate the problem

Update 2 the mime types list in file_entity_get_upload_validators function in file_entity.pages.inc dictates what can be uploaded - see this screenshot

uploader

Specifically, in, file_entity_get_upload_validators, the line that populates the valid mime types with hard-coded values is (my screenshot didn't completely show the line): $validators['file_validate_extensions'] = array(variable_get('file_entity_default_allowed_extensions', 'jpg jpeg gif png txt doc docx xls xlsx pdf ppt pptx pps ppsx odt ods odp'));

Update 3

It would appear that the actual checking of the mime type happens in core module "file", modules/file/file.js : if (!acceptableMatch.test(this.value)) { var error = Drupal.t("The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.", { I searched the error message shown in following screenshot in the code and file.js was a result - which looks like where the actual validation is taking place. error when upload

New error with Andy's answer - maybe it's me will look into it a little later. error when upload

Raised as an issue here: https://www.drupal.org/node/2295671

17
  • 1
    Sometimes the implemented hook is correct but it is being called too early or too late because of the relative weights of other modules that have implemented the same hook. In that case, check the weight of the module in the system table and if your implementation is called too early, increase the weight of your module; too late, decrease it.
    – keithm
    Jun 30, 2014 at 15:23
  • 1
    Can you post your current code? Are you using the media module as well as file_entity?
    – Andy
    Jun 30, 2014 at 15:25
  • +1 keithm - thanks for this idea. I couldn't really adjust the module weights but I know what you mean. It might be risky for my particular situation. +1 Andy yes I am using the media module as well as file_entity. The pain seems to be that file.entity determines the valid file extensions but they are hard coded in this module - it's not obvious how to extend to add more mime types. But I found out through debugging that file.entity is validating against an array of mime types as strings which the logic can derives from the form_state variable, if not present here, it uses the hard-coded ones. Jun 30, 2014 at 15:41
  • If you edit an individual file bundle (eg. image, document, etc.) via the UI you can define which mimetypes should be associated with it. Have you tried that?
    – Andy
    Jun 30, 2014 at 16:09
  • Thanks I think I have tried that already but this upload is to be within the wysiwyg editor via the media upload, so it appears that the settings used for that are different. I'll review what I've done though but I'm fairly sure I've tried most things in config but they are getting ignore. Jun 30, 2014 at 16:13

2 Answers 2

2

file_entity_add_upload is a three step form for uploading files when you have fieldable files.

function file_entity_add_upload($form, &$form_state, array $options = array()) {
  $step = (isset($form_state['step']) && in_array($form_state['step'], array(1, 2, 3))) ? $form_state['step'] : 1;
  $form['#step'] = $step;
  switch ($step) {
    case 1:
      return file_entity_add_upload_step_upload($form, $form_state, $options);
    case 2:
      return file_entity_add_upload_step_filetype($form, $form_state, $options);
    case 3:
      return file_entity_add_upload_step_fields($form, $form_state, $options);
  }
}
  1. Upload the file (validates extensions);
  2. Choose the file bundle (based on bundle mimetype associations);
  3. Fill out fields attached to that bundle.

As the extensions are validated in step 1, examine file_entity_add_upload_step_upload(). Of particular interest is the actual managed file element.

$form['upload'] = array(
  '#type' => 'managed_file', 
  '#title' => t('Upload a new file'), 
  '#upload_location' => file_entity_upload_destination_uri($options), 
  '#upload_validators' => file_entity_get_upload_validators($options), 
  '#progress_indicator' => 'bar', 
  '#required' => TRUE, 
  '#pre_render' => array('file_managed_file_pre_render', 'file_entity_upload_validators_pre_render'), 
  '#default_value' => isset($form_state['storage']['upload']) ? $form_state['storage']['upload'] : NULL,
);

The validators are added using a non-standard property #upload_validators to set the file validation callbacks and their arguments. In the form alter we can completely overwrite #upload_validators or just modify it, and that will affect the file's validation as you'd expect. However if you look in file_entity_get_upload_validators():

if (!empty($options['file_extensions'])) {
  $validators['file_validate_extensions'] = array($options['file_extensions']);
}
else {
  $validators['file_validate_extensions'] = array(variable_get('file_entity_default_allowed_extensions', 'jpg jpeg gif png txt doc docx xls xlsx pdf ppt pptx pps ppsx odt ods odp'));
}

You can see that the variable file_entity_default_allowed_extensions is used to specify which extensions to use by default (unless it's overridden by $options).

The managed_file element itself passes the extensions to JS for client-side validation in file_managed_file_process():

// Add the extension list to the page as JavaScript settings.
if (isset($element['#upload_validators']['file_validate_extensions'][0])) {
  $extension_list = implode(',', array_filter(explode(' ', $element['#upload_validators']['file_validate_extensions'][0])));
  $element['upload']['#attached']['js'] = array(
    array(
      'type' => 'setting',
      'data' => array('file' => array('elements' => array('#' . $element['#id'] . '-upload' => $extension_list))),
    ),
  );
}

As you can see from pcambra's neat illustration, processing happens after form alters are called, so any modifications you make will affect both client-side and server-side validation.

So to make a global change modify the variable file_entity_default_allowed_extensions: I'd suggest using drush or a hook_update_N().

To modify a subset of forms you can use a form alter. Here's an example:

/**
 * Implements hook_form_FORM_ID_alter() for file_entity_add_upload.
 *
 * Modifies the allowed extensions.
 */
function MYMODULE_form_file_entity_add_upload_alter(&$form, &$form_state) {

  // Check this is the file selection step.
  if ($form['#step'] != 1) {
    return;
  }

  $form['upload']['#upload_validators']['file_validate_extensions'][0] = 'png bmp';
}
8
  • +1 thank you very much for the comprehensive answer - Andy. Nearly there but getting error - i.stack.imgur.com/OxImi.png - have to pause on this for today and return tomorrow. Thanks for your help so far. Hoping to accept soon. Jul 1, 2014 at 13:09
  • P.S. I've used your code above to add mobi and epub to the mime types. I just created a small <2Mb text file and named it's extension as .mobi Jul 1, 2014 at 13:15
  • @therobyouknow grepping on that error it looks like the problem is The upload directory for the file field could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.
    – Andy
    Jul 1, 2014 at 13:15
  • I'll try to do my own digging, save you, when I next get a chance, you've done so much already. OK just got your last comment I'll come back a little later maybe end of today or tomorrow morning. Thanks so much so far, sorry I can't try out the further things re permissions / accessible, right now, will try that later. Jul 1, 2014 at 13:17
  • Once again thanks very much for this Andy. I will try to follow up on this today or tomorrow (Friday) and hopefully accept the answer. Jul 3, 2014 at 12:15
5

There's this brilliant image on the Form API Internal Workflow in drupal.org, you can see the build process and structure. You've got callbacks such as #process and #after_build that could be useful for your use case.

enter image description here

1
  • +1 Hey pcambra! thanks for this amazing diagram! I'll study it to see where I can get my code in early enough and hope to accept the answer. Jun 30, 2014 at 15:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.