I'm importing files from a script, and i need to be able to set the user of the file to it's correct user.
We can change the $filepath parameter to accept a $file array of properties, or add an $account parameter. I like the idea of $file because it would allow more flexability, but it might get messy for other modules calling those hooks?
What say ye?
function field_file_save_file($filepath, $validators = array(), $dest = FALSE) {
global $user;
// Add in our check of the the file name length.
$validators['file_validate_name_length'] = array();
// Build the list of non-munged extensions.
// @todo: this should not be here. we need to figure out the right place.
$extensions = '';
foreach ($user->roles as $rid => $name) {
$extensions .= ' '. variable_get("upload_extensions_$rid",
variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp'));
}
// Begin building file object.
$file = new stdClass();
$file->uid = $user->uid;
$file->filename = basename($filepath);
$file->filepath = $filepath;
...
| Comment | File | Size | Author |
|---|---|---|---|
| #16 | field_file_save_file_user.patch | 2.29 KB | quicksketch |
Comments
Comment #1
quicksketchI think the reason this isn't a $file object is because it's sometimes used to move files from the temporary directory to a permanent location, in which case there isn't a file object available, because it hasn't yet been saved to the database.
I think adding an $account parameter is the best approach, though it's unfortunate that we used the $uid in #419616: filefield_widget_file_path is hardcoded to global $user, because in this function we actually need the full account object to get the list of roles. Either that or we load the user, but I don't like this because user_load() isn't cached at all. Then again, it's not too likely that you'll be doing multiple moves unless you're doing an import script, in which case you probably don't need to worry so much because you're usually running it with beefy hardware.
Comment #2
frankcarey commented#419616: filefield_widget_file_path is hardcoded to global $user takes the whole $account, not just uid, doesn't it?
Comment #3
frankcarey commentedIs there a way to set these values after the fact (after this function is called)?
I want to be able to set uid, description, title, alt and timestamp programatically.
Comment #4
quicksketchIt does! I don't know what I was thinking. That makes $account seem like the obvious choice.
You can always call field_file_load($fid), make any changes, then call field_file_save(), however this doesn't affect description, alt, or title, since these aren't actually properties of the file, they're just associated with the file by CCK. If you want to affect all the properties at the same time, changing them in hook_nodeapi($op = 'presave') is probably the best place. There you have access to all these properties, associated with node and the uploaded files.
Comment #5
deviantintegral commentedIf performance is an issue, use the Batch API to do the importing. It works quite well.
#419616: filefield_widget_file_path is hardcoded to global $user does take the whole account, so as well if performance is an issue I suppose your import script could cache user_load's locally as well.
In the custom module for one of my sites where I need to set the UID, I do the following:
I'm not sure I like this code (which is why ATM it's in the site custom module and not as a feature in the Skeleton module yet), but it seems to work fine. Operations like this should be much better in D7 with files being true objects, but for D6 I think the above is the closest you'll get.
Comment #6
frankcarey commentedok thanks
Comment #7
frankcarey commentedOK, I was able to just edit the returned $file object before i attached to the node and that seemed to work ok.
Comment #8
quicksketchIt still wouldn't hurt to make this suggested change, it doesn't feel right hard-coding the global $user in there.
Comment #9
frankcarey commentedSeems like loading the whole user object is a bit of overkill here to just get the uid. In the other function it's important because the destination may be based off of a number of tokens (username for instance). Maybe we can add a $file object instead? It would make it so much easier to change the file attributes that way, and it would make it easy to just drop in an existing file object, save it to a new destination, and get a new file object returned. What do you think?
I'm curious, was there any thought to going this direction completely? $filepath, validators, and destination could all be added to the $file object?
Comment #10
quicksketchMy response in #1:
Besides, we're not making drastic API changes, we're trying to keep changes as minimal as possible (we're "frozen" now, new APIs are for FileField 4.x, which probably won't ever happen since we'll just put FileField into core). So no, we're not going to make sweeping changes to the APIs. We'll add a simple $account parameter which simply swaps out the global $user if passed in.
Comment #11
frankcarey commentedif i'm belaboring the issue I apologize, feel free to ignore this.
the use case above isn't effected by:
..since the $file object here is optional. In fact you wouldn't need a complete $file object at all, you could just have $file properties act as overrides if they are present.
Note, I was wrong about only uid being needed, though. field_file_save_file has $user->roles as well, so either a full $account, or having to to use user_load() is needed.
Comment #12
quicksketchYep, a good reason for using the $account parameter IMO. I think this makes for the best scenario when we'll want to avoid unnecessary user_load() calls, since like I mentioned, user_load() isn't cached, so inserting 100 files by the same user would load the user object 100 times.
Comment #13
frankcarey commentedIn my quest to use migrate to do a 4.7 to 6.0 upgrade (cross module many times), I'm really learning the beauty of a good api that allows me the power to configure everything. I came across a similar solution from the privatemsg (6.1.dev). They have an $options parameter, and one of this things it holds is a user object, in additional to being able to override anything that is set with defaults. Maybe this would be a good compromise. You wouldn't have to run user_load() and I could still override any file properties.
Comment #14
quicksketchYes, good APIs are good. However, this should have been addressed during the 2 years the 3.0 version was in development. It's too late to make large changes now. If you'd like to see better APIs in the future, open an issue against Drupal 7 HEAD and request for the changes to be made there. I think adding $account is simply accounting for a bug in the API, not actually making a change.
Comment #15
frankcarey commentedsorry, i know i'm late to the party ;) You're right though, the place for this conversation is d7 core, thanks for listening. I'll try to patch it tomorrow, as you requested, with an $account param.
Comment #16
quicksketchI've committed the attached patch to overcome this limitation. I also removed the variable_get() lines dealing with upload extensions, since it turns out after this data was collected, nothing was ever done with it. It's been like that since the function was originally added in #289335: Add field_file_save_file() to create files from the filesystem. Since this function is intended to be used as an API, I don't think it important that we change it's functionality to make it match core's file_save_upload() and munge the filename when moving it. Added a few additional docs while we're in here.