Am working on a patch that would allow support for image_attach and bulk import of image nodes. I'm having trouble figuring out how to grab the particular value from a row. I've combed through the module a few times and just can't figure it out. What is the array that the key->value pairs are living? How do I address those?

I'd be so grateful for an answer on this.

Comments

Robrecht Jacques’s picture

I'll answer this here instead in the private emails you have sent (well I suppose you sent them, otherwise someone is busy with the same thing).

First email:

I've gone over the code for the last two days and I still cannot figure
out how to grab the value that is in a particular row of the tsv file I'm
importing. I figure they're stuck in a key-> value pair somewhere, but I'm
unsure of how to extract it. How do I get the value out of that one
particular column?

Second one:

Hi, think this may be quicker for you to answer...

On line 598, you have:

    foreach ($row as $i => $value) {
          if (!empty($match[$i])) {
            $fieldname = $match[$i];
            $node->$fieldname = $value;
          }

is $i numeric, or the key for the column header?

$i is numeric.

There is the $row array which contains the data as (column_number => string_value). There is the $match array which tells us what field each column is assigned to, so this is (column_number => fieldname). Lastly there is the $header array which contains the strings in the header row as (column_number => string_value).

So for example:
$header[0] = 'a header of a column, if you want automapping to work, one would set this to title';
$match[0] = 'title';
$row[0] = 'some title data';

The code above does:
$node->title = 'some title data';

So if I wanted to address the value in the column where 'imagename' is the
header, would I say:

    $imagename = $match[imagename];

?

You would not change node_import.module at all. Instead you would write a support file in supported/ directory.

Something like:

function imagefield_node_import_fields($type) {
  if ($type == 'some type that has imagefields') {
    return array(
      'some_cck_imagefield_fieldname' => t('Imagefield: XXX'),
    );
  }
}

This will make it so that the user is presented with a possibility to map one column to an "Imagefield: XXX". If there are multiple imagefields configured for a content type, then you probably need to add them all:

function imagefield_node_import_fields($type) {
  if ($type == 'some type that has imagefields') {
    return array(
      'imagefield_fieldname1' => t('Imagefield: fieldname1'),
      'imagefield_fieldname2' => t('Imagefield: fieldname2'),
    );
 }
}

Next is to do something with it, basically the code from your other email:

function imagefield_node_import_prepare(&$node, $preview = FALSE) {
  $errors = array();
  // In this function, $node->some_cck_imagefield_fieldname will contain the data from
  // the row. Eg, in this case, some filepath. So then you could do:

  if (!isset($node->some_cck_imagefield_fieldname)) {
    // If this is not set, then the user did not map any column to this imagefield.
    return;
  }

  // We probably also want to test other stuff, eg whether the string is empty.
  if (empty($node->some_cck_imagefield_fieldname)) {
    return;
  }

  $imagename = $node->some_cck_imagefield_fieldname;
  $imagepath = 'files/images/'. $imagename;

  // By convention we unset this, but it is not necessary.
  unset($node->some_cck_imagefield_fieldname);

  $result = db_result(db_query("SELECT nid from {files} WHERE filepath = '%s'", $imagepath));
  if ($result) {
    $iid = $result;
    $node->iid = $iid;
  }
  else {
     $errors[] = t('Could not find the image %path', array('%path' => $imagepath));
  }
  return $errors;
}
If they're not convenient key->value pairs, can I take the numeric key off
of $headings where it matches and stick it in as the key for the $match
array?

Try to look at the examples in the supported/ directory.

Basically you would just create a imagefield.inc file in the supported/cck directory. It will then be automatically included in node_import.module.

The $node object in hook_node_import_prepare() has the mappings already done, so all values show up as $node->some_field_name where 'some_field_name' is the key of the array you return in hook_node_import_fields().

Let me know if you need more help,
Robrecht

webslinger23’s picture

Thanks Robrecht!

This helps a lot! I really appreciate the time you took to post here.

I ran out of time and Imported the field as a textfield and mapped to that in node_import then added the path to the output in CCK. Way suboptimal. Will give this solution a try. I'm grateful.

konsumer’s picture

You can also do a

$new=array_combine($match, $row);

to get a nice associative array. This will allow you to do a

echo $new['title'];

for example

array_combine

This a PHP5 function, that's useful in a lot of situations. Here is how to make an emulator:


if (!function_exists('array_combine')){
function array_combine($arr1,$arr2) {
   $out = array();
   foreach($arr1 as $key1 => $value1)    {
    $out[$value1] = $arr2[$key1];
   }
   return $out
}
}

for your original issue, I implemented this, which might be useful:
http://drupal.org/node/143471#comment-679422

sethcohn’s picture

bump - any progress on this patch? - using image attach with node_import would be useful to me right now.

snarlydwarf’s picture

Since I needed image_attach support, I added it: it is actually very easy.

Save the below code into modules/node_import/supported/image_attach.inc

You may need to adjust the pathing which is hardcoded. And maybe you want to set the title of the image node to something else... but whatever. It should be easy enough to adapt to your needs.

[oops this code didnt really work, so yanking it to not confuse people]

I don't know if I should give credit to the image module itself (where 'image_create_node_from' is), or node_import for being so easy to work with.... but the above works fine for me.

snarlydwarf’s picture

oops, I am an idiot... the above doesn't work.

this does.


function image_attach_node_import_fields($type) {
    return array(
      'imageatt' => t('Image Attach Image'),
    );
}

/* nothing to prepare, we can do this all on post process (ie, creating the image
   node is easier after the main node is created... it makes linking easy).
   change path where imported files live as needed.  (it would be REALLY slick
   if I could shove urls in there, but it took an hour to transfer stuff from the
   evil MS-based proprietary CMS, so I don't want to think about doing that with
   apache and php timeouts).
 */

function image_attach_node_import_postprocess(&$node, $preview = FALSE, $any_errors=FALSE) {
  // no post-node-processing on preview.
  if ($preview) return;

  $imagename = $node->imageatt;
  $imagepath = 'files/temp/'. $imagename;

  $image = image_create_node_from($imagepath, $node->title);
  if ($image) {
    $image->new_file = TRUE;
    node_validate($image);
    $node->iid = $image->nid;
    $node->new_image = TRUE;
    db_query("INSERT INTO {image_attach} (nid, iid) VALUES (%d, %d)", $node->nid, $image->nid);
  }
}