Migrate module: migrating poll nodes
Currently the Migrate module doesn't support full migration of poll nodes. When the poll module is enabled, you can create a content set mapping for a poll node, but you are unable to set the poll status (active or closed) and, more importantly, you can't migrate the poll choices.
Using the hook_migrate_prepare_node()
and hook_migrate_complete_node()
hooks, I was able to migrate all choices for each node, along with all existing votes stored.
In the example below, I am migrating polls from a Joomla MySQL database and I am using a poll content set which handles the core node field mapping, including the question text.
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #FF8000">/**<br> * Implements hook_migrate_prepare_node().<br> */<br></span><span style="color: #007700">function </span><span style="color: #0000BB">mymodule_migrate_prepare_node</span><span style="color: #007700">(&</span><span style="color: #0000BB">$node</span><span style="color: #007700">, </span><span style="color: #0000BB">$tblinfo</span><span style="color: #007700">, &</span><span style="color: #0000BB">$row</span><span style="color: #007700">) {<br> </span><span style="color: #0000BB">$errors </span><span style="color: #007700">= array();<br> </span><span style="color: #FF8000">// Ensure we only work on a particular content set.<br> </span><span style="color: #007700">if (</span><span style="color: #0000BB">$tblinfo</span><span style="color: #007700">-></span><span style="color: #0000BB">machine_name </span><span style="color: #007700">== </span><span style="color: #DD0000">"my_poll_content_set" </span><span style="color: #007700">&& </span><span style="color: #0000BB">$node</span><span style="color: #007700">-></span><span style="color: #0000BB">type </span><span style="color: #007700">== </span><span style="color: #DD0000">"poll"</span><span style="color: #007700">) {<br> </span><span style="color: #0000BB">db_set_active</span><span style="color: #007700">(</span><span style="color: #DD0000">'joomla'</span><span style="color: #007700">); </span><span style="color: #FF8000">// Set active database to be the Joomla db.<br> </span><span style="color: #0000BB">$node</span><span style="color: #007700">-></span><span style="color: #0000BB">choice </span><span style="color: #007700">= array();<br> </span><span style="color: #0000BB">$node</span><span style="color: #007700">-></span><span style="color: #0000BB">active </span><span style="color: #007700">= </span><span style="color: #0000BB">$node</span><span style="color: #007700">-></span><span style="color: #0000BB">status</span><span style="color: #007700">; </span><span style="color: #FF8000">// Set the poll active/closed state to be the same status as the node.<br> </span><span style="color: #0000BB">$choices </span><span style="color: #007700">= </span><span style="color: #0000BB">db_query</span><span style="color: #007700">(</span><span style="color: #DD0000">"SELECT text, hits FROM {jos_poll_data} WHERE text != '' AND pollid = %d ORDER BY id"</span><span style="color: #007700">, </span><span style="color: #0000BB">$row</span><span style="color: #007700">-></span><span style="color: #0000BB">id</span><span style="color: #007700">);<br> while (</span><span style="color: #0000BB">$choice </span><span style="color: #007700">= </span><span style="color: #0000BB">db_fetch_object</span><span style="color: #007700">(</span><span style="color: #0000BB">$choices</span><span style="color: #007700">)) {<br> </span><span style="color: #0000BB">$node</span><span style="color: #007700">-></span><span style="color: #0000BB">choice</span><span style="color: #007700">[] = array(<br> </span><span style="color: #DD0000">'chtext' </span><span style="color: #007700">=> </span><span style="color: #0000BB">$choice</span><span style="color: #007700">-></span><span style="color: #0000BB">text</span><span style="color: #007700">,<br> </span><span style="color: #DD0000">'chvotes' </span><span style="color: #007700">=> </span><span style="color: #0000BB">$choice</span><span style="color: #007700">-></span><span style="color: #0000BB">hits</span><span style="color: #007700">,<br> );<br> }<br> </span><span style="color: #0000BB">db_set_active</span><span style="color: #007700">(</span><span style="color: #DD0000">'default'</span><span style="color: #007700">); </span><span style="color: #FF8000">// Restore active database setting to be the Drupal db.<br> </span><span style="color: #007700">}<br> return </span><span style="color: #0000BB">$errors</span><span style="color: #007700">;<br>}<br></span><span style="color: #0000BB">?></span></span>
The above implementation of hook_migrate_prepare_node()
first checks that we're operating on a specific content set which is identified by the machine name. This is the unique name you enter when creating the content set mapping. It then switches to the Joomla database, and fetches the configured choices for the poll record currently being migrated. Finally we just populate the $node->choice
array with this data, and the migration module takes care of the rest.
As the Joomla records I'm dealing with have no concept of being active or closed, I've manually set the poll status ($node->active
) to be the same as the node status ($node->status
). This may not apply to your own records, but if you don't set $node->active
somehow, it will default to closed.
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #FF8000">/**<br> * Implements hook_migrate_complete_node().<br> */<br></span><span style="color: #007700">function </span><span style="color: #0000BB">mymodule_migrate_complete_node</span><span style="color: #007700">(&</span><span style="color: #0000BB">$node</span><span style="color: #007700">, </span><span style="color: #0000BB">$tblinfo</span><span style="color: #007700">, &</span><span style="color: #0000BB">$row</span><span style="color: #007700">) {<br> </span><span style="color: #0000BB">$errors </span><span style="color: #007700">= array();<br> if (</span><span style="color: #0000BB">$tblinfo</span><span style="color: #007700">-></span><span style="color: #0000BB">machine_name </span><span style="color: #007700">== </span><span style="color: #DD0000">"my_poll_content_set" </span><span style="color: #007700">&& </span><span style="color: #0000BB">$node</span><span style="color: #007700">-></span><span style="color: #0000BB">type </span><span style="color: #007700">== </span><span style="color: #DD0000">"poll"</span><span style="color: #007700">) {<br> </span><span style="color: #FF8000">// Select across the two databases and match on poll id and choice text.<br> </span><span style="color: #0000BB">$votes </span><span style="color: #007700">= </span><span style="color: #0000BB">db_query</span><span style="color: #007700">(</span><span style="color: #DD0000">"SELECT p.chorder, jv.date FROM {poll_choices} p, joomla.jos_poll_data jc, joomla.jos_poll_date jv WHERE jc.text = p.chtext AND jc.pollid = jv.poll_id AND jv.vote_id = jc.id AND p.nid = %d AND jc.pollid = %d"</span><span style="color: #007700">, </span><span style="color: #0000BB">$node</span><span style="color: #007700">-></span><span style="color: #0000BB">nid</span><span style="color: #007700">, </span><span style="color: #0000BB">$row</span><span style="color: #007700">-></span><span style="color: #0000BB">id</span><span style="color: #007700">);<br> while (</span><span style="color: #0000BB">$vote </span><span style="color: #007700">= </span><span style="color: #0000BB">db_fetch_object</span><span style="color: #007700">(</span><span style="color: #0000BB">$votes</span><span style="color: #007700">)) {<br> </span><span style="color: #FF8000">// We have no user id or hostname to identify source of vote. <br> // However we need to store something in hostname field so record is unique - using<br> // vote date here.<br> </span><span style="color: #0000BB">db_query</span><span style="color: #007700">(</span><span style="color: #DD0000">"INSERT INTO {poll_votes} (nid, chorder, uid, hostname) VALUES (%d, %d, %d, '%s')"</span><span style="color: #007700">, </span><span style="color: #0000BB">$node</span><span style="color: #007700">-></span><span style="color: #0000BB">nid</span><span style="color: #007700">, </span><span style="color: #0000BB">$vote</span><span style="color: #007700">-></span><span style="color: #0000BB">chorder</span><span style="color: #007700">, </span><span style="color: #0000BB">0</span><span style="color: #007700">, </span><span style="color: #0000BB">$vote</span><span style="color: #007700">-></span><span style="color: #0000BB">date</span><span style="color: #007700">);<br> }<br> }<br> return </span><span style="color: #0000BB">$errors</span><span style="color: #007700">;<br>}<br></span><span style="color: #0000BB">?></span></span>
hook_migrate_complete_node()
is only needed if you have individual vote records to migrate in addition to the poll itself. Drupal expects to be able to store the poll id, poll choice id and details on the user who voted. If the user is anonymous, then Drupal will store the user's IP address instead. However in Joomla, no record of the user who voted is kept, but we do have an extra piece of information which is the date and time the vote was recorded. As Drupal's poll_votes
table has a primary key which enforces one vote per user (or one vote per anonymous user per IP address), we need to make our vote entries unique somehow. To get around this, I've stored the vote date in the hostname field. I suppose this is a bit "hacky" but it allows the votes to be migrated at least.
The other thing to note about the hook_migrate_complete_node()
implementation above is that in the hook_migrate_prepare_node()
I didn't store any mapping of a poll choice sourceid to a destid. This means that when pulling out the votes, I needed to join across the two databases in my SELECT and match up the records based on the poll id and the choice text. Again, not ideal, but I wasn't sure how to manage this mapping while in the middle of processing a separate content set.