Problem/Motivation
The Commerce XLS Import Module has a UI that allows the user to set the fields that the import would use. A similar thing would be useful for migrations with a CSV source, provide a UI so that the mapping of migration source properties to CSV columns can be changed.
Proposed resolution
Make a new form as described and add a hook migration_plugin_alter to change the column_names in the source plugin configuration.
Use a temp private store to save the values for the hook to access.
The changes are stored in temp store so will only persist for the default length of time, which is 1 week.
The URL used is: /admin/structure/migrate/manage/{migration_group}/migrations/{migration}/source_csv
A screenshot of the form with a CSV source.

Screenshot of message displayed when the source plugin is not of the CSV class.

Remaining tasks
Decide on the URL for the form
Decide where to link to it
Review
Commit
User interface changes
Yes, a new form for modifying the column_name to source property association.
| Comment | File | Size | Author |
|---|---|---|---|
| #54 | 2942373-54.patch | 28.23 KB | heddn |
| #54 | interdiff_49-54.txt | 531 bytes | heddn |
Comments
Comment #2
quietone commentedHere is a start and it was working locally.
However, I don't know forms and there is no way to get there from the UI, you need to enter the URL, /admin/structure/migrate/manage/{migration_group}/migrations/{migration}/source_csv, which I found easiest to do by navigating to the View->Source for the migration and then modifying the URL. Obviously, this needs to be fixed. Ideas? Since I don't know forms a patch would be best or, at least, an example.
This does not change the migration in config, it does a hook alter, so the changes are not permanent.
Comment #3
heddnSomewhat related #2933919: Allow migrations with file sources to have the file uploaded through the UI.
Comment #5
quietone commentedThis add links so that you can get to the new edit form. Still needs work to fix the failing tests and it should only show the new edit form for CSV sources.
Comment #7
quietone commentedAdd a fix for the test as well as comments and code standard fixes.
Comment #8
quietone commentedIf the source plugin is not of class CSV then it is not editable and a message is now displayed. Testing found test code lying about and typos, all that is fixed now. And the SourceCsvForm:buildForm() is reworked so error cases are checked in the beginning.
Comment #9
quietone commentedComment #11
quietone commentedAdd another check in the plugin alter.
Started to add a test but stuck on schema errors.
Comment #12
quietone commentedUpdate the IS.
Ready for initial review and testing.
Comment #13
heddnPerhaps you can give #2913592: Missing schema a spin and see if that fixes your issues. Love what I'm seeing in the screenshots.
Comment #14
quietone commentedI switched to using the existing test migration in migrate_tools and just changing the source plugin and process. I don't yet know why the previous one failed. I might look at it one more time.
This patch adds a functional test and in making the test I discovered two errors. They aren't fixed yet, I want to see the failures here.
Comment #16
quietone commentedPerhaps it needs @requires.
Comment #17
quietone commentedComment #18
quietone commentedThe new test isn't running on the testbot. Anyone know why?
Comment #19
heddnI think we need to either 1) add a require --dev for drupal/migrate_source_csv to composer.json or 2) add a test_dependencies. Or both. This should be on the main migrate_tools project, not the test module.
Is this check of UID to see if authenticated? I think we can do that in a cleaner way, no? BTW, the drush user is always anonymous unless we do something special, so counting on an authenticated user is difficult.
I think the access should be tied to permission and a _module_dependencies route check on migrate_source_csv. See https://www.drupal.org/docs/8/api/routing-system/structure-of-routes
I think we can get the migration passed into the form directly using route parameters arguments. The benefit there is you don't have to do the error checking if the migration exists.
If we do an access check on the route, then this isn't necessary. When doing the access check, also check on the source. This will require a custom access check I think.
Can we delete things from the store? Wouldn't that be easier/cleaner?
I think when opening the file, we can limit the number of lines read in. Let's do that and use the header column config option. That way we don't open a full 10mb csv just to read the first line.
Comment #20
quietone commented1. migrate_source_csv added to composer.json
2. Yes, I was just responding to the errors. What is a better way?
3. Added +module_dependencies
4. Fixed and learned how to do that.
5. Haven't changed this because I prefer a helpful error message to access denied for these two cases.
6. No, because all the source configurations use the same key 'source_configurations'. Maybe that should change.
7. Maybe I'm not understanding this, when no length is given fgets will read until it reaches the end of the line.
Comment #22
heddn19/20 feedback:
2:
\Drupal::currentUser()->isAuthenticated(). However, depending on if a user flushes cache from drush or web UI, it won't work the way you expect. Because drush runs as anonymous. We'll have to think about this one. Because the alter runs at cache clear time I think, no?5: If you are building links and menu items using the drupal api for links, it will check access for you and hide the link if the access doesn't exist. This (I feel) is better than posterior printing a message that the url won't work for them. Just don't make it available in the first place. If someone starts playing with the URL themselves, they already know enough and wouldn't be surprised with a 403.
6: Maybe it should change. This seems unexpected and only supports a single migration at a time? Teach me what this is doing.
7: Ignore my comment. I hadn't read the code in question closely enough and my thought is nonsense.
Won't this result trying to print an object? Wouldn't it be better to use
$migration->label()This should not be listed here as a required dependency. Test dependency, yes.
Comment #23
quietone commented2. OK The alter runs after the cache clear. During test of the plugins alter I need to
drush cr, then do adrush msfor the alter to run and debug it, if necessary.5. I'll get back to you on this. This patch makes a small change, adding a module dependency in routing.yml and removing the corresponding code from the form.
6. Yes, it should change. It was just the first go. I want to improve this next.
7. NP
1. Here, $migration is the plugin id, it isn't bringing in the object.
2. Fixed.
This patch fixes the things that came up while I was writing the test. The test runs locally but not yet on the testbot but when it does hopefully it will pass.
Comment #24
quietone commentedDon't let the green fool you, the new test still isn't running.
#22.6 This changes to the key used for the store to the plugin_id. Passes tests locally so seems to be fine. It much simpler and the comments updated as well.
Comment #25
quietone commentedNow I remember the reason all the change migration information was stored in one key, source_configurations. It made it easy at the time for the alter to find the migrations that were changed. It would get the 'source_configuration' from the store, which had a key for each migration changed. Now that the changes are stored by migration_id, the alter has to loop through all migrations and check if the id is in the private store. Instead of that there is now a simple array of the changed migrations in the store.
Changed the index 'updated' to 'changed' throughout because I prefer it.
Still to do is #22.2 and #22.5.
Comment #26
quietone commented22.5 Should be fixed in this patch.
Comment #27
megachrizI haven't looked into this issue at all, but I saw the screenshot at the top of the page and I would say that it would be nice if the mapping UI was in multiple columns as is the case in Feeds:
Comment #28
megachrizI have some more UI designs here, though some may only make sense in Feeds context: #2917405: UI designs.
Comment #29
quietone commented@MegaChriz, thanks for stopping by and commenting. On a first look, having a source and a target column seems a better way to present this information. I haven't read through the UI designs issue yet, thanks for the link.
This patch has quite a few changes:
The test for the currentUser in migrate_tools.module has been removed. I guess the addition of the Access checking has eliminated the problem.
The URL is now '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/source/edit'. Before it didn't include 'edit'.
Fixed a typo in the name of the migration_changed key
Reworked the test module migration to work for a taxonomy vocabulary destination so that a migration can be executed and tested
Execute the migration twice in the test to verify different results are optioned when the aliases are changed.
Comment #30
heddn@quietone should we merge this and later improve the UI or attempt to make changes on the UI before landing it. The code itself looks pretty solid at this point. I'm sure I could pull out some nits, but wanted to know if we're at that point in the review cycle or if you are just wanting to see if tests pass on the testbot. Because tests still aren't running :(
Comment #31
quietone commentedYes, lets get this in and move the UI improvements to a follow up.
The work to do here is to get the new test running on the testbot and review, no more features/additions planned here.
To start, what is wrong with the test?
Comment #32
quietone commentedFollow up made #2954082: Improve CSV alias edit form
Comment #33
heddnLet's see how this is treated.
Comment #34
heddnComment #36
heddnComment #38
heddnYeah, tests are recognized now. On to fixing things. I'll leave that to you @quietone.
Comment #39
quietone commented@heddn, thank you.
The form needs the \SplFileObject object for the source CSV file in order to determine the things like the header row count etc. This is already being calculated in the CSV:setupFile protected method. If that was made public then the form would not have to duplicate that setup code. Is there any reason not to make CSV:setupFile public? It should be noted that setupFile is called from initializeIterator() which is public, but that won't work as it is not guaranteed to return an SplfileObject. In the case when the source plugin uses yeild it returns a Generator.
Can the form be used to pass the SplFileObject?
edit: add initializeIterator
Comment #40
quietone commentedA getter for the file in CSV class will work.
Comment #41
quietone commentedGetting closer now. Now gets the file with all the properties setup via the new getter in migrate_source_csv. I also added another try catch in the cancel function, to match the existing one, on this->store->set. Not sure how to handle those execptions. Maybe just display the returned error?
Comment #43
quietone commentedChange the version of migrate_source_csv in the test dependency to -dev. Add display of error message if TempStoreException is caught in the cancel method.
Comment #45
quietone commentedChange composer.json to use migrate_source_cs 2.x-dev
Comment #47
quietone commentedRemove the carat
Comment #48
quietone commentedYay, the test is running now. Boo, I found a typo.
The changes since #40 are to get the file properties initialized and then get the SplFileObject for the file. This is now down with the following code.
And to display any error messages if the actions on the store throw an exception during when the cancel button is clicked.
And to use the dev version of migrate_source_csv
Comment #49
quietone commentedthis should be tested by someone other than me.
Comment #50
irinaz commented@quietone, I am happy to test, but now sure what is setup. Should I apply patch 2942373-49.patch to Migrated tools module or do I need to make any other changes?
thanks, Irina
Comment #51
quietone commented@irinaz, thanks for the offer!
Yes, apply the patch. And you will need an existing migration that uses a CSV file for import. You may have one from a project or the example here should work, https://github.com/heddn/d8_custom_migrate. The process is to run the migration, verify the results, rollback the migration, change the column assignments, run the migration, verify the results. We need to be sure that the changes made to the column assignments really work.
I wrote this in steps to help make sure I didn't miss anything.
I hope that make sense. If you get stuck, ask here.
Comment #52
irinaz commented@heddn, thanks for pointing me to https://www.drupal.org/project/migrate_source_csv.
@quietone, I setup test site http://demo-drupal-8-content-migration.pantheonsite.io/admin/modules and added migrate-related modules, including CSV source migration.
In /admin/structure/migrate I see migrations that come from module migrate_example, but not from /modules/migrate_source_csv/tests/modules/migrate_source_csv_test. I plan to go into back end and configure this migration via drush, but I wanted to make sure that I am not missing something obvious in the web interface.
Thanks for your help with this!!!
Comment #53
quietone commented@irinaz, sorry I ddn't see this earlier. Ah, looks like a missing step which is to upload the csv. I am working from memory but on, /admin/structure/migrate, there should be a button in the upper right to upload your source file. Upload your source file first and then it should work.
Good luck!
Comment #54
heddnStill waiting on manual testing, or should we proceed with merging it? It still applies cleanly.
Can we pin this on a specific version now? Doing that now. See updated patch.
Comment #55
irinaz commentedIt looks good, let's merge, and if there are any conflicts after merge we can report them. Thanks for making this happen :)
Comment #56
heddnBased on #55, let's RTBC this thing.
Comment #58
heddnComment #59
joelpittetThese get() assume a set() and unfortunately with drush that throws an exception:
This could be exposing a core bug? getOwner doesn't check for null or start a session like it does in session for anonymous users.
How would you like to fix this? Try/Catch? Core bug report? Separate issue?
Comment #60
joelpittetActually starting the session seems to work... not sure if this is the right way though.
I added this for a quick fix:
#2865991: provide an API to forcibly start a session
Comment #61
heddnIt also seems there is #2860341: PrivateTempStore->getOwner Attempts to access possibly unset Request Session.
Comment #62
heddnI've opened #2976862: PrivateTempStore throws exception if session is not started (drush users) to work around this in migrate tools while we fix upstream.
Comment #64
yareckon commentedThis feature makes drupal 8.5 the base requirement, as tempstore.private doesn't exist in 8.4
Comment #65
heddnThat's probably OK, seeing as 8.4 has limited support at this point. But we could probably open a new issue to pin the version in composer.json to 8.5+.
Comment #66
batigolixIs this functionality available in the 5.x version of migrate_tools? It seems te be missing.