Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Migrate comes a long with a few great examples. They helped me enormously.
Unfortunately, there's nowhere information to be found on the process of creating stubs. Any chance someone can copy/paste some code on how this actually works? Haven't been able to wrap my head around it yet. Could also be used to fill up the documentation page on http://drupal.org/node/1013506.
Comments
Comment #1
tiyberius CreditAttribution: tiyberius commentedI second that motion! I read about it here: http://drupal.org/node/915102 but then when I went to do it, I realized I had no idea how to actually go about writing the code for it. An example of this would be greatly appreciated.
Comment #2
moshe weitzman CreditAttribution: moshe weitzman commentedThis is FAQ. We need some docs on it.
I could have sworn that stub nodes were created automatically by the nodereference integration in migrate module. I don't see that code anymore. Instead, there is an API where migrations can implement stub support. Start at Migration::handleSourceMigration method.
However, usually you don't need any stub nodes. If you are migrating music albums and tracks, you should simply import your albums and in a subsequent migration, import your tracks. That way, assuming the node reference points from track to album, your referenced nodes are guaranteed to already exist. Stub nodes come into play when you have a self-reference like when albums have a node reference called 'related albums'. You can't easily assure that all the related albums exist by the time you create a given album.
Hope this helps.
Comment #3
tiyberius CreditAttribution: tiyberius commentedThis is quite similar to my situation!
Thank you for pointing out Migration::handleSourceMigration. Unfortunately, it is not clear to me how to use it to create stub node(s). Are there plans to put an example in the documentation?
Comment #4
mikeryanYes, we will be filling out the documentation over time. The missing piece here is that you need to define a createStub() method in the destination migration (i.e., the migration corresponding to the sourceMigration() argument), to create the stub node and return its nid.
Comment #5
tiyberius CreditAttribution: tiyberius commentedPerfect. This is exactly what I was looking for. Many thanks!
Comment #6
rp7 CreditAttribution: rp7 commentedAwesome, thanks, it works! If it's OK by you, I will fill up the documentation a bit (once I find the time).
1 more question though (hope this is the correct place - it's about stubs).
I'm importing a node reference field which can reference nodes of various content types (TypeX, TypeY, TypeZ). See code below, which works (XML source btw - sourceid's of the to-reference nodes are XML attributes).
Stubs for nodes that haven't been imported yet are being created. The problem I'm currently facing is that the stubs are always of type 'TypeX' (handled by TypeXNode). How do you define wether the stub-create function in TypeXNode, TypeYNode or TypeZNode should be used?
Been digging in the code for some time now, no luck so far. Not giving up though!
Comment #7
moshe weitzman CreditAttribution: moshe weitzman commentedLooks like a bug to me. The Stub system has no way to know which source_migration won. From handleSourceMigration():
if ($destids = $source_migration->createStubWrapper(array($source_key), $migration)) {
Would be good if Mike confirmed this.
Comment #8
mikeryanIt's true, the handling of multiple sourceMigrations will call the first sourceMigration's createStubWrapper when the ID is not found in any of the map tables. I don't see how handleSourceMigration() can choose in a general way - presumably there is something in the outer migration's source query that indicates what destination type (and thus what sourceMigration) to use, but it's very likely that the value (if it is indeed a single field) is not the name of the desired sourceMigration.
So, how do we get the necessary information into handleSourceMigration? Perhaps the field mapping sourceMigration() method could have an optional second argument, $stub_migration_field - if present, then the value in the source row field of that name would be taken by handleSourceMigration as the name of the migration to call for creating stubs. With clever SQL you may be able to map your source data values into migration names, but more likely you would use prepareRow() to translate into that field. Let's see how this might look in practice:
Thoughts?
Comment #9
rp7 CreditAttribution: rp7 commentedLooks good to me!
Comment #10
q0rban CreditAttribution: q0rban commentedTo solve this problem, we filtered the source migrations based on the node type by implementing handleSourceMigration in our abstract migration class. We store the source node type in $this->sourceNodeType on each migration.
Comment #11
Corentor CreditAttribution: Corentor commentedHello everyone,
sorry for reopening this thread. I'm a brand newbie of Drupal AND Migrate and I've to say that these are really great softwares. I don't know if what I'm trying to do is possible but I thought it's a good place to post a question about it.
I'm dealing with a table in a database that references itself (e.g. a table of individuals that may reference other individuals). Till there, it's nothing new, and it has been covered widely here and there. Stubs do the job, and do it quite well, as long as records reference OTHER records in the table, but not THEMSELVES. As an example of use case, individuals may be insured by other individuals, or may be their own insurants.
I've noticed that with my naive implementation of a stub (taking simply the code sample given above or in the chicken and eggs page), self-referencing nodes usually do not reference themselves, but create a dummy stub that stay in the Drupal database (one dummy stub being created per self-referencing node). There is an exception to that though : it's when the self referencing node was already referenced by a previous node and doesn't need to create its stub. In that case, the self-referencing node seems to be built correctly.
I know that my use case may not very common and may seem a bit contrived, but if anyone has a solution for this, I would be very glad to hear about it.
Many thanks to everybody
Comment #12
Corentor CreditAttribution: Corentor commentedComment #13
Corentor CreditAttribution: Corentor commentedComment #14
mikeryanComment #15
mirsoft CreditAttribution: mirsoft commentedMy solution to the problem described in #8 with the minimalistic approach (though it may not be the nicest in the world..).
Assumption: in this example the source data are in some relational database outside Drupal (because of that I couldn't use solution in #10, because we don't have the information about source node type in source Drupal's node table). Each external source table contains data for one destination content type. Data from all these source tables shall be imported into one common Drupal Node Reference field, of course with remembering reference to correct Content Type.
In Migration class:
Now the implementation of handleSourceMigration() method to support this syntax is following (insert this method into your migration class or in abstract migration class):
Comment #16
rich.3po CreditAttribution: rich.3po commentedI had a very similar problem and the approach in #15 worked for me - ie overriding the handleSourceMigration() method and manually determining which source migration should be used for each source key. Thanks for the code, mirsoft.
Going forward it would be great if the framework supported use of a callback function to determine the source migration - for ultimate flexibility. This might be used in the following way:
..and it would be the responsibility of mymodule_determine_source_migration() to return the source migration machine name, given the source data
Cheers
Comment #17
nerdcore CreditAttribution: nerdcore commentedI am attempting to use migrate_d2d (https://drupal.org/project/migrate_d2d) to migrate Drupal 6 Menu Links into Drupal 7. Node migrations have been run first, but there are many of them, and some node types are not going to be migrated.
If a source menu link doesn't have a properly migrated node, I'd like to simply skip that link, perhaps with a message in the migrate_message_menulinks table. Unfortunately when a source node was encountered which had not been migrated, the whole thing blew up on me with this somewhat cryptic message:
After some debugging, I found that what was happening was that the handleSourceMigration() function, upon discovering that the node wasn't migrated in any one of a number of possible source migrations, tried to call createStub() on each of the source migrations, and immediately bailed on the first one. The migration stopped entirely with the above error.
In my case, I don't want a stub created. Ever. I just want the bulk of the menu links imported and if a few get missed that's okay with me - a message would be nice to track errors. This code stopped the migration dead in its tracks:
I'm unsure how to apprach this use case. Perhaps an argument to handleSourceMigration() to tell it not to create stubs, and if that argument is TRUE, skip this chunk of code and proceed directly to assigning the $default value?
Comment #18
wheatpenny CreditAttribution: wheatpenny commentedmirsoft, #15 was exactly what I needed. Thank you for sharing. You made my Saturday.
I had to make one small change to the handleSourceMigration function as I had a single value field give me the "Invalid argument supplied for foreach()" error that nerdcore mentioned. To account for that message, I also tested to make sure that $source_keys is an array.
Comment #19
mpdonadioI have a fairly sub-optimal workaround for this, but I think it hints at a possible solution.
In the site I am working on now, which is a D6-to-D7 migration, I ended up implementing
This prevents the stubs from being created, which also means that my pointer fields (entityreference) fields won't be populated. I then manually reset the highwater mark, and rerun the node migrations. In this case, the dependent nodes already exist, so my entityreference get set.
In my particular case, I tried something similar to
but had problems with this because the parent class calls this in the D2D hierarchy placed the new node in the wrong migration map, and I couldn't figure out how to get it into the right map.
I think this means (maybe for just the D2D case) two possibilities.
1. Decouple the maps from the migrations, and have a single map object (yay! a singleton!) manage the maps.
2. Add a parameter to ->sourceMigration to prevent stubs from being created, which will defer the field from being populated. When population is deferred, do the necessary bookkeeping so the destination will be updated the next time the migration runs. Otherwise, populate as normal.
I think #2 is the most straightforward, but I don't understand how the classes work well enough to propose a patch.
Comment #20
RoSk0Had the same issue like in #19 but for D7->D7 migration and the fix appears to be simple:
In simple words the createStub() was implemented only in base class for different bundles that is why no matter what source migrations was specified the first one was creating a stub with incorrect bundle.
Trying to figure out is there a way to avoid this query for each attempt to create stub?
Comment #21
milos.kroulik CreditAttribution: milos.kroulik commented#20 Were you using Migrate D2D when defining your migration? If so, how did you get
$source_id
parameter, when this method is defined as http://www.drupalcontrib.org/api/drupal/contributions!migrate_d2d!node.i... ? Thanks in advance.Comment #22
RoSk0Yeah, this is because I have applied patch from #2637350: Make DrupalNodeMigration::createStub() use all arguments from invocation.
Comment #23
tssarun CreditAttribution: tssarun commented@Rosk0
https://www.drupal.org/node/1096132#comment-10750874: Good tip, this solved my problem. I want to more optimize the create stub query. I have some 32 refer nids with 4 different bundle. If i execute it 32 extra query will execute(inside createStub). Need to understand how to solve this query optimization. Anyidea?
Thanks
tssarun