I am trying to write a module that will automatically set up a storage class and container when it is installed, and use hook_field_default_field_bases_alter() to enable it on certain fields in my site.
So far, the creation of the class and container works, and I can set the files I want to use the storage URI schemes I want.
The only thing I'm having trouble with is enabling my custom storage class on the field base definition. I'm setting the "class_id" parameter (using the code below) - but when I open up the field settings afterwards, the class is still set to "Everything" (the default class set up by Storage API itself).
In hook_field_default_field_bases_alter():
// Set the storage class of the field base.
$my_class_id = 2;
$data['field_farm_files']['settings']['storage_class'] = array(
'class_id' => $my_class_id,
);
If I then go and manually configure the field to use the new class (via the UI), it works, and I notice that it is also storing a "current_class_id" property.
Do I need to set that property on the field base as well, in order for it to work?
Comment | File | Size | Author |
---|---|---|---|
#13 | storage_api_create_selector-2604380-1.patch | 808 bytes | m.stenta |
Comments
Comment #2
Perignon CreditAttribution: Perignon commentedMy suggestion would be to export the field with features to see what code is created with Features. Reason I say this is I have moved code around with Features that have fields backed by Storage API.
I have not wrote a custom module with a field using Storage API yet so I cannot be of much assistance.
Comment #3
m.stentaWhelp - just answered my own question... no. Adding "current_class_id" does NOT work.
This is what I tried:
So I'm not really sure how to do this correctly... :-/
Comment #4
m.stentaI actually do have the fields stored in features already - and I'm trying to enable storage on them from a separate module (so that it can be turned on/off on some sites).
It seems like it needs more than just the field base definition to set the storage class... or something... I'm digging into it now to try to figure out what's up.
Comment #5
Perignon CreditAttribution: Perignon commentedYes there are changes in the Storage API tables that has to be made.
Comment #6
m.stentaAh ok! I think I see what you're referring to... in the {storage_selector} table?
Do you know if there's a helper function to populate that? Or should I just do some straight queries to set those up?
Comment #7
Perignon CreditAttribution: Perignon commentedHonestly I cannot say. I am just a co-maintainer here and I jumped into a rat's nest of a module :-D
Comment #8
m.stentaGot it!
You were right about the {storage_selector} table - it needed to have the class set there too.
Here is the final hook implementation that works for me (generalized for the purpose of sharing):
Not sure if that's the "correct" way to do it (there may be helper functions in the Storage module that do the same thing in a more consistent way - I didn't dig deep enough to rule that out)... but hopefully this helps anyone who's looking to do the same thing!
Comment #9
jonhattanThere's API for that. See for example http://cgit.drupalcode.org/storage_api/tree/core_bridge/storage_core_bri...
Comment #10
m.stentaAwesome! Thanks @jonhattan! I had a feeling there would be...
Question...
In the selector->create() method, it looks like it always performs a database INSERT into the {storage_selector} table.
In my code, I was performing an UPDATE, because there is already a record in the {storage_selector} table using the "Everything" class by default. But I want to change the class... not add another one... I think.
Why does the {storage_selector} table allow multiple records per storage_id? The primary key of the table is
array('storage_id, 'class_id')
- which indicates that storing multiple combinations is OK. I don't understand the purpose of this - do you? I think I haven't fully wrapped my head around what a "selector" is.Comment #11
jonhattanIt does an insert, because it *creates* a selector. Problem is that your approaching with a _alter, that runs always. You want to check first if a storage selector already exists.
A selector is the interface to manage storage api files. A selector is related to a storage class.... and this relation can safely be changed (in the UI), and storage api migrate files from one class to another. Files continue attached to the same selector, but moved to any other class/containers.
storage_core_bridge creates a selector and a stream wrapper for each field. storage_api_stream_wrapper also works with selectors and stream wrappers, but in a different way.
Comment #12
Perignon CreditAttribution: Perignon commentedYeah pretty crappy I don't know this module that well.
Comment #13
m.stentaThanks @jonhattan.
The function
storage_core_bridge_field_selector_create($field_name)
lacks any way of setting the class_id that you want to assign. If you trace the logic into the selector->create() method it just grabs the first one it finds (which in all cases will be the "Everything" class - since that's the first one created automatically by the Storage module).Line 27 of selector.inc:
So I guess the best solution would be to add an optional
$class_id
parameter to thestorage_core_bridge_field_selector_create()
function.Attached is a patch for review!
Comment #14
m.stentaI just tested that patch - and that alone does not solve my problem.
That allows me to add additional rows to the {storage_selector} table for my custom "My Files" class, alongside the existing ones for the "Everything" class. But if I go to the field UI and look at the configuration, they are using "Everything" instead of "My Files".
If I use the UPDATE query I described in #8, it works perfectly - because it overwrites the "Everything" class in the {storage_selector} so that ONLY "My Files" is used in that table.
I'm not sure if this is possible with the current API functions... is it?
Comment #15
m.stentaPS: Here is the code I tested in my hook_field_default_field_bases_alter():
That works to add additional rows to the {storage_selector} table - but it does not fix the fact the all my fields are defaulting to using the "Everything" class.
Comment #16
jonhattanI agree StorageSelector::create() could check for existance before db_insert. Perhaps with a db_merge - https://www.drupal.org/node/310085