I'm attempting to integrate Storage API with another module but there doesn't seem to be any documentation or examples on how to do so.
I'm trying to use BD as an example, but I'm having a hard time understanding the 'class selector' concept.
BD calls storage_api_new_selector_id to generate new selector id's but the code seems to assign the selector to the first class alphabetically.

What is the purpose of the abstraction between classes and selectors?
Is there a way to generate a selector for a particular class without manually querying/updating the db tables?

I apologize if I'm missing something really obvious.

Comments

jbrown’s picture

There is some documentation in Doxygen format in the source.

Class selectors exist to make it easier for a module to integrate with Storage API.

When a module adds a file it needs to be in a class. Typically the class will be selected by an admin in the module's configuration.

If an admin later changes the class, then the module would have to update every file that that configuration relates to to be in the new class.

The idea for the selector is that a file's selector never changes, but the class it points to can. This way a module does not need extra code to update all the file's classes when it is changed.

Just call storage_api_selector_submit() on the selector form item when it is submitted and Storage API will do all the heavy lifting.

A further feature of selectors is migration. When a selector is changed to point at a different class, it will actually point at both the old and new classes until all files have been fully migrated during cron.

As you point out, when a new selector is generated it defaults to point to the first class alphabetically. This is just so if the form is not submitted, the selector will still point at a class.

rfoote’s picture

Version: 6.x-1.1 » 7.x-1.0

Is there any documentation/examples available for the 7.x version? Trying to get my head around how to integrate Storage API with a custom module I'm developing, but not having much luck. In short, what I'm attempting to do is that I have a form created via Form API and it has a file upload field as one of its components. I'd like to use the benefits that the Storage API brings to the table to handle the file storage, but just can't quite figure out how to go about doing that. Any help/pointers to documentation or examples for 7.x would be appreciated.

rurri’s picture

+1

Started integrating with this module and gave up. I would suggest some basic integration instructions or example module that stores stuff with this module. My guesses on how this worked based on the source that my module was supposed to pick a selector name and create it with the selector.inc.

Once this was done, there was a convenience method on the selector that gives a FAPI array for use in asking the user which storage class they want. This FAPI element can then be passed along to the corresponding submit handler that took the result of the form and the selector name I made up and it will save the configuration in the db for me.

Once this is done I can use the Storage object in storage.inc to store and retrieve files.

This is all guesses, but I think this is the basic type of documentation needed. Assuming the above is even correct, I am left with the following questions:

1) How do I create a selector exactly?
2) How do I create a storage in a selector?
3) How do I retrieve a storage?
4) What is the proper way to get a URI for a storage?
5) Do I need to do anything special once I decide on a name for my selector? Do I need to save this somewhere? Should this be in my .install code? In the case of a specialized field object will I need to create a special selector for each of my fields?
6) What about notifying storage_api once I no longer use a selector. Is this required? What are the ramifications? Are all files contained in the field deleted? Can I remove a selector and keep the files?

Lastly, What about D7's new filesystem abstraction? Can this be used to abstract away the Storage_API? I feel like I should be able to simply use drupals existing file management functions give a uri such as storage_api://selector_id/filename and copy files to from, etc. Is there any plans for this? Does this already exist?

digitalwonk’s picture

+1

I would agree that the lack of an integration document is limiting others from creating other containers. I, too, have a need to create a custom container.

chicodasilva’s picture

+1

milovan’s picture

Hi, I am also interested what does "Serve by redirection" and "Serve source URL" do, maybe explained on S3 example. I assume it has to do with file links but couldn't find any kind of Storage API documentation or a single record in "Issues" about it.

scottpayne’s picture

Issue summary: View changes

I've just been picking my way through the code to answer this question for myself. I had to spike a little module to see how it all fit together. To save others pain, here's some example code to hopefully help out.

Note that this might be the wrong way to do things, but hopefully it's a starting point.

function storage_api_spike_menu() {
  $items = array();
  $items['admin/config/media/storage-test'] = array(
    'type' => MENU_NORMAL_ITEM,
    'title' => 'Storage API Spike',
    'page callback' => 'storage_api_spike_page',
    'access callback' => TRUE,
  );
}

function storage_api_spike_page() {
  return drupal_get_form("storage_api_spike_form");
}

function storage_api_spike_form($form, &$form_state) {
  $selector = storage_selector('storage_api_spike');
  $form['selector'] = $selector->formItem();
  $form['actions'] = array(
    '#type' => 'actions'
  );
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  return $form;
}

function storage_api_spike_form_submit($form, $form_state) {
  // update selector class
  $selector = storage_selector('storage_api_spike');
  $selector->submit($form_state['values']['selector']);

  // create a temporary file and save it
  $tempname = drupal_tempnam("temporary://", "abcde");
  if ($realtemp_name = file_unmanaged_save_data("This is a file on " . date("Y-m-d H:i:s"), $tempname, FILE_EXISTS_REPLACE)) {
    drupal_set_message(drupal_realpath($realtemp_name));
  } else {
    drupal_set_message("Couldn't write to file");
    return;
  }

  // we use the filename as the identifier, so keep track of it
  $storage_filename = 'storage_api_spike/' . drupal_basename($tempname);

  // add the file to storage api
  $selector->storageAdd(array(
    'source_uri' => $tempname,
    'filename' => $storage_filename,
  ));

  // find the file by filename
  $query = db_select('storage', 's');
  $query->fields('s', array('storage_id'));
  $query->addJoin('INNER', 'storage_file', 'sf', 'sf.file_id = s.file_id');
  $query->condition("sf.filename", $storage_filename);
  $query->condition("s.selector_id", "storage_api_spike");
  $r = $query->execute();
  if ($r->rowCount() != 1) {
    drupal_set_message("Uh-oh! Should have found one and only one file with the name " . $storage_filename . "!", 'error');
    return;
  }

  // load the storage
  $storage_row = $r->fetchAssoc();
  $storage = storage_load($storage_row['storage_id']);

  // serve the file
  storage_serve($storage);  

}
Perignon’s picture

I would welcome help with this. The documentation for the module is lacking here on D.O and I would like to get that fixed. I'm doing all I can in my spare time but there is a lot of work here in Storage API land. Any help would be greatly appreciated!