I think MigrateDestinationFile should provide better control as to where a destination file is copied to.
For example, if my Migration was going to copy a file from URI http://example.com/folder1/folder2/foo.jpg
The current implementation would place the copied file here: $this->copyDestination/folder1/folder2/foo.jpg ($this->copyDestination is set to public://) by default.
The following code in MigrateDestinationFile, inside import() function implements this behavior
if ($this->copyFile) {
$path = trim(parse_url($file->uri, PHP_URL_PATH), '/');
$destination = $this->copyDestination . $path;
$dirname = drupal_dirname($destination);
if (file_prepare_directory($dirname, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
I would like to have an option for a fixed destination. For example:
if ($this->copyFile) {
if (!$this->fixedDestination) {
$path = trim(parse_url($file->uri, PHP_URL_PATH), '/');
$destination = $this->copyDestination . $path;
$dirname = drupal_dirname($destination);
} else {
$destination = $this->copyDestination;
$dirname = drupal_dirname($destination);
}
if (file_prepare_directory($dirname, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
This would allow a migration to put all migrated files into a common directory. For example you could set copyDestination = "public://migrated/"
and then http://example.com/folder1/folder2/foo.jpg would be migrated to public://migrated/foo.jpg
| Comment | File | Size | Author |
|---|---|---|---|
| #8 | migrate-flatten-paths-1120136.patch | 922 bytes | twod |
Comments
Comment #1
moshe weitzman commentedThe intent of the file handler is to migrate into a file Field. Each file field has a configured destination already. I'm not clear why you would want to migrate into some other destination. If you really want that, just copy it yourself in a prepare hook.
Comment #2
myname.com commentedI'm working on migrating an old forum into drupal forum. In the old forum software, each user could upload or link to an external image for their avatar. My initial thought was to copy in all of the users' avatar files into public://pictures/ using MigrateDestinationFile and then link the picture to their drupal user account via user table picture field (a foreign key to files_managed table).
Do you have a different model for doing this sort of thing?
My current solution is to create a sub-class of MigrateDestinationFile and and override the import() method.
Comment #3
moshe weitzman commentedThe most native Drupal way is to enable user pictures and then import right into that. An alternative is to put an Image field on the user entity or on a new profile entity (see Profile2 module).
You can go with a custom picture implementation like you describe but then you have to build own UI and code for add/edit/delete
Comment #4
myname.com commentedThanks for your suggestions. I'm pretty sure that what I'm doing is what you described as "enable user pictures and then import right into that"
The result of my migration is that for each avatar in the old forum system, I am copying the file to public://pictures/ and adding a row to the files_managed table for this image. Then I am updating the user table 'picture' column to have the file id from files_managed.
My only request is the copy operation in MigrateDestinationFile allow an option to not mirror the path from the source URI into public://pictures/
For example if user 1 in the old forum system had his avatar stored at http://example.com/foo/bar/pic.jpg
and user 2 had his avatar stored at http://example2.com/dir1/dir2/pic2.jpg
Then using the MigrateDestinationFile class distributed with Migrate module, the end result is that the following directory structure is created in my public://pictures/ directory
/pictures/foo/bar
/pictures/dir1/dir2
Apply this over 1000's of users and the public/pictures directory just became a major mess. I would rather put all of the imported avatars into one directory.
Here is a sample of my migrate code to give you a feel for what I'm doing
Comment #5
mikeryanOK, so what you would like is an option to flatten the file hierarchy on import, correct?
Comment #6
myname.com commentedYes, thanks!
Comment #7
Fidelix commentedmyname.com, can you share what you've done, please?
Comment #8
twodI'm having a similar problem with MigrateFileFieldHandler when my Migrate class downloads files from FTP to /tmp/mypics/filename.jpg (in prepareRow) and then map them to an image field. Since the files are no longer remote I use the 'file_move' operation to let the field handler move things into public://myphotos (set as the image field's destination).
Since I know no filenames will collide, I would have expected all files to end up as www.example.com/sites/default/files/myphotos/filename.jpg. (public:// is pointing to sites/default/files)
But, all filenames are modified so the path ends up like this: www.example.com/sites/default/files/myphotos/-tmp-mypics-filename.jpg.
This is a bit of a problem since I want the filenames to stay intact.
My field mapping looks like this.
I traced it back to fields.inc (around line 320 in 7.x-2.1, which is what I'm using):
Why is
basename()never used for local files?Could we add an argument to tell the file handler to apply
basename()even if the file is local?I put together a simple patch for 7.x-2.x which does what I need, but it hasn't had much testing with alternate setups yet.
Comment #9
darksnowI'm in almost exactly the same boat as myname.com
I'm importing an old forum, with user avatars. I've chosen to import from a http:// uri and have supplied the path from web root to the location of the files.
In the SQL source, I have a file name. In order for migrate to find the file, I'm prepending the full URL to the file name giving me something like http://example.com/images/avatars/upload/filename.ext
I've set the migrate destination like this:
Which gets the set path for user pictures (public://pictures/)
The result is, I get files in:
public://pictures/images/avatars/upload/filename.extWhere as, I would like them to be:
public://pictures/filename.extThis would give me consistency with any new avatars uploaded after the migration.
It seems to me a option to only use the basename of the migrated file would be exactly what I need.
Comment #10
mototribe commentedas a workaround I just downloaded the files on my local drive and then imported from there. The advantage is that the import is now faster, I can remove the extra folder structure, can rename the filenames and keep a backup copy, just in case ;-)
Comment #11
twodI've got ~5000 images to import from FTP in one go, then there's maybe up to 40 new images each day, separated across hundreds of directories and subdirectories...
Comment #12
mototribe commentedI just write PHP scripts to curl the files. I'm downloading 100,000+ images and videos. I'm glad TB harddrives are cheap and comcast hasn't throttled my Internet connection (yet) ;-)
I just noticed that I migrated some node images (from remote url) and they got saved in the "sites/default/files" directory even though the remote url has 4 or 5 folders.
I used this code:
Comment #13
twodI don't know how many files each imported item has beforehand, I just know the naming scheme - based on item id - and in which folder they should exist (sorted into subdirs by item group and then by image number). Using the same folder hierarchy on the site's server makes no sense, which is why this patch is important to me.
@mototribe, I'll probably approach those numbers when my client switches data provider, but I've got a 30s execution time limit to battle too, so that's not likely an option for me.
Comment #14
StuartDH commentedI'm finding that MigrateDestinationFile maintains folder structures, which is what I need for my project
However, when I then use the MigrateFileFieldHandler the folders are flattened...which is the opposite of what I need
See this issue http://drupal.org/node/1436838
Comment #15
mikeryanSee also #1436838: copy folder structure bug. Both fall under #1240928: META: Refactoring of file destination/field handlers, which we plan on addressing for Migrate 2.4.
Comment #16
mikeryanComment #17
mikeryanThis is dealt with in #1240928: META: Refactoring of file destination/field handlers - by default, the hierarchy will be flattened, but by setting destination_file to the hierarchy you want you can preserve it.