In #1421974: Allow messages to be saved in prepareRow() the queue message options was added, but as far I can tell this doesn't work for rows skipped via prepareRow(). I think that inside MigrateSource::prepareRow() we need to clean the existing messages (wipe old messages) and save the queued ones before setting currentRow and currentKey to NULL.
Right now the queued message are saved inside Migration::import(), but skipped records don't go that far into processing (they are skipped inside MigrationSource::next() function).
This is the code I have inside MyMigration::prepareRow() and doesn't work. The messages are saved after a valid row is found with the id of the valid row.
function prepareRow() {
// ...
if (!$this->hasAllMandatoryFields()) {
$this->queueMessage(t('Row skipped because is missing essential information'), MigrationBase::MESSAGE_INFORMATIONAL);
return FALSE;
}
// ...
}
Right now I fixed by adding changing Migration::saveQueuedMessages():
/**
* Save any messages we've queued up to the message table.
*
* @param $wipe
* Boolean value indicating if the old messages should be wiped before save.
*/
public function saveQueuedMessages($wipe = FALSE) {
if ($wipe) {
$this->map->delete($this->currentSourceKey(), TRUE);
}
foreach ($this->queuedMessages as $queued_message) {
$this->saveMessage($queued_message['message'], $queued_message['level']);
}
$this->queuedMessages = array();
}
And calling it inside MigrationSource::prepareRow():
/**
* Give the calling migration a shot at manipulating, and possibly rejecting,
* the source row.
*
* @return bool
* FALSE if the row is to be skipped.
*/
protected function prepareRow($row) {
migrate_instrument_start(get_class($this->activeMigration) . ' prepareRow');
$return = $this->activeMigration->prepareRow($row);
migrate_instrument_stop(get_class($this->activeMigration) . ' prepareRow');
// We're explicitly skipping this row - keep track in the map table
if ($return === FALSE) {
$this->activeMigration->getMap()->saveIDMapping($row, array(),
MigrateMap::STATUS_IGNORED, $this->activeMigration->rollbackAction);
$this->activeMigration->saveQueuedMessages(TRUE); // Save queued messages
$this->numIgnored++;
$this->currentRow = NULL;
$this->currentKey = NULL;
}
else {
$return = TRUE;
}
$this->numProcessed++;
return $return;
}
Comments
Comment #1
LuxianAdding the patch with the code I use right now
Comment #2
mikeryanWhen submitting a patch, please set the status to "needs review".
Comment #4
LuxianI didn't want to send the patch for testing before getting a confirmation that I'm not doing anything work with my approach. Maybe this patch would work.
Comment #6
mikeryanLooks like you're deleting the map table row rather than messages?
Comment #7
LuxianLet's try it like this. I changed the order a little bit: saveQueuedMessages() is called before saveIDMapping() and should be no problem even if the mapping gets deleted.
Comment #9
mikeryan#7: migrate-queued_message_issue_for_rejected_row-1982564-7.patch queued for re-testing.
Comment #11
mikeryanHere's a simpler approach, does this work for you?
Comment #13
LuxianUnfortunately the messages are not saved with your patch. Rows that are skipped in prepareRow() are not processed in migration.inc. Messages can be saved only inside source.inc (prepareRow() or next() functions).
I'll post a new patch. This time I didn't change much inside migrate.inc (made the function saveQueuedMessages() public instead of protected) and called map->delete() straight from source -> prepareRow().
I tried to run the tests on my local and I don't have the error reported by testbot. Maybe is something wrong with automatic tests.
Comment #15
mikeryanTagging for Migrate 2.6.
Comment #16
mikeryan#13: migrate-preserve_prepareRow_messages-1982564-13.patch queued for re-testing.
Comment #18
mikeryanIgnore the failed tests, nothing to do with this...
I've committed a simplified version of the patch, thanks!