I have written an import that uses migration. The import brings in the data correctly, but I can never get prepareRow() to work. It gets called but errors out saying that the fields are undefined. Here is the error:
Undefined property: stdClass::$topicid File /home/tracksadmin/support.trackssoftware.com/html/sites/all/modules/migrate/migrate_hmanual/migrate_hmanual.migrate.inc, line 93
I get that error once for each record imported. I have a very simple prepareRow() here which matches the example code as far as I could tell, but nothing happens.
Here is the code for my import:
class hmanualXMLMigration extends XMLMigration {
public function __construct() {
parent::__construct();
$this->description = t('XML feed from Help and Manual ');
$this->map = new MigrateSQLMap($this->machineName,
array(
'sourcename' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE
)
),
MigrateDestinationNode::getKeySchema()
);
$xml_folder = 'xxx';
$item_url = $xml_folder . ':id';
$this->source = new MigrateSourceList(
new MigrateListFiles( array(
'xxxx'),
'xxx',
'/(.*\.xml$)/i'),
new MigrateItemXML($item_url),
$this->fields()
);
$this->destination = new MigrateDestinationNode('book');
$this->addFieldMapping('title', 'topictitle')
->xpath('/topic/topictitle');
$this->addFieldMapping('body', 'topicbody')
->arguments(array('summary' => 'test summary', 'format' => 'full_html'))
->xpath('/topic/topicbody');
$this->addFieldMapping('field_help_context', 'helpcontext')
->callbacks(array($this, 'fixHelpContact'))
->xpath('/topic/helpcontext');
$this->addFieldMapping('field_topic_id', 'topicid')
->xpath('/topic/topicid');
}
/* Help context is an integer, but it may be blank in the source. In that case we default it to 0 */
protected function fixHelpContact($help_context) {
return '0' . $help_context;
}
/* Ignore files without a topicid */
function prepareRow($row) {
$row->topicid = 'test' . $row->topicid; // << this is the line it doesn't like.
}
function fields() {
return array(
'topicid' => 'Topic ID',
'helpcontext' => 'Context ID',
'title' => 'Title',
'topicbody' => 'Body'
);
}
}
Comments
Comment #1
mikeryanYou need to use prepare() rather than prepareRow(), or pull the values from the XML object yourself. For XML sources, the fields are not populated yet in prepareRow() - the xpaths which pull them out of the XML are attached to the field mappings, which are processed in applyMappings(), which is a later stage.
The "Row" in prepareRow() may be a little misleading, maybe prepareData() would be better - this method is called from a source plugin as soon as the raw data is retrieved, and it gives you an opportunity to deal with it in its raw form before any mappings are applied. For SQL sources, of course, the raw data is already in nice shape, but for XML sources you've only got a SimpleXMLObject at that stage.
Comment #2
JeremyFrench commentedThis also means that
prepareRow()can't be used to override fields for XML sources. Found that out the hard way.Comment #3
bjalford commentedyou can access the data by casting to string e.g.
$desc = (String) $row->xml->description;
Comment #4
oddible commentedThis should really desperately be in the documentation. The number of hours I spent before I found this post.
To clarify, $row is stdClass which could probably be cast to SimpleXMLObject.
$row->xml is a SimpleXMLElement.
Comment #5
eclipsegc commentedSo, I know I'm late to this party, but since I was looking for the answer to this myself, I thought I'd share my results.
SimpleXMLObject can be rendered via casting it to a string. Likewise it can be set by simply doing an $object = $value; The elements of $current_row->xml are SimpleXMLObjects so you CAN prepare the values here. What follows is something you might do in order to change pubDate in an rss feed into a unix timestamp.
I hope this helps.
Eclipse
PS: I extracted this code from a more generic solution that I confirmed was working, but I did not confirm this code directly. Nevertheless, something along these lines should basically work.
Comment #6
jlongbottom commentedHow would you skip certain XML records based on the data, if it is not available in prepareRow()?
UPDATE:
I was able to use xpath to read the XML data, and skip rows based on that.