0

I'm triggering a Feeds import in a custom module I made. I need to set a value of a blank source in that code because that value is not in the source file (in this case is a xml). Is it possible to do this?

Below is the code I have.

$path = $url . '/path_to_my_file/myfile.xml';
$feeds_source = feeds_source($feeds_importer);
$feeds_config = $feeds_source->getConfigFor($feeds_source->importer->fetcher);

$file_exists = get_headers($path, 1);

# check if file exists:     
if ($file_exists[0] == 'HTTP/1.1 200 OK') {
    $feeds_config['source'] = $path;

    $config = array(
        'process_in_background' => TRUE,
    );

    $feeds_source->setConfigFor($feeds_source->importer->fetcher, $feeds_config);
    $feeds_source->importer->addConfig($config);
    $feeds_source->save();
    $feeds_source->startImport();

    while (FEEDS_BATCH_COMPLETE != $feeds_source->import());
}

UPDATE:

Below is a more complete code. I have 3 functions. The first one is the original but one. Notice tha I get the $VALUETOPASS variable from the function arguments.

The other 2 functions are the ones rooby suggested. The problem is how to have the $VALUETOPASS in the last function. At this moment I only need that.

function MYMODULE_CustomImport($VALUETOPASS) {
  $path = $url . '/path_to_my_file/myfile.xml';
  $feeds_source = feeds_source($feeds_importer);
  $feeds_config = $feeds_source->getConfigFor($feeds_source->importer->fetcher);

  $file_exists = get_headers($path, 1);

  # check if file exists:       
  if ($file_exists[0] == 'HTTP/1.1 200 OK') {
    $feeds_config['source'] = $path;

    $config = array(
        'process_in_background' => TRUE,
    );

    $feeds_source->setConfigFor($feeds_source->importer->fetcher, $feeds_config);
    $feeds_source->importer->addConfig($config);
    $feeds_source->save();
    $feeds_source->startImport();

    while (FEEDS_BATCH_COMPLETE != $feeds_source->import());
  }

function MYMODULE_feeds_processor_targets_alter(array &$targets, $entity_type, $bundle) {
  // Set a custom value setter callback for the my field on my node type.
  if ($entity_type == 'node' && $bundle == 'my_bundle') {
    if (isset($targets['my_field'])) {
      $targets['my_field']['callback'] = 'MYMODULE_set_custom_field_value';
    }
  }
}

function MYMODULE_set_custom_field_value(FeedsSource $source, $entity, $target, array $values, array $mapping) {
  $xml = simplexml_load_file($url . $VALUETOPASS . '/api/xml');
  $multijob_array = json_decode(json_encode((array)$xml), TRUE);

  if (isset($multijob_array['action'][2]['cause']['upstreamBuild'])) {
    $multijob_build = $multijob_array['action'][2]['cause']['upstreamBuild'];
  } else {
    $multijob_build = '';
  }

  $entity->{$target}[$entity->language][0]['value'] = $value;
}
  • So you have configured the feed via the UI but are just triggering it via custom code? And you have a field mapping that is normally set to something non-blank but in this specific case it needs to be blank? Is that accurate? – rooby Jan 29 '18 at 11:29
  • I have a blank source mapping. I need to set it to some variable in my code. – zephirus Jan 29 '18 at 11:44
  • Better answer: I have configured the feed via UI, yes. In that configuration I have a blank source mapping to an existing field of the content type. I trigger the feed import with my custom module. And in that code, I need to set the field mapping to a value in my code (1 or 0). – zephirus Jan 29 '18 at 12:44
1

In the code where you run the importer you can only alter the field mapping.

To modify the field mapping configuration at that point to add custom data (you can also do things like remove fields from the mapping here):

// Load the importer.
$importer_id = 'my_importer';
$feeds_source = feeds_source($importer_id);
// Get the current field mappings.
$field_mappings = $feeds_source->importer->processor->getMappings();

foreach ($field_mappings as &$mapping) {
  // Add an arbitrary value to the mapping of my_field for
  // use later in the processor target callback.
  if ($mapping['target'] == 'my_field') {
    // Your logic goes here to populate this.
    $mapping['my_custom_value'] = 'My custom value';
  }
}

// Set the new field mappings.
$feeds_source->importer->processor->addConfig(array('mappings' => $field_mappings));
// Save the new field mappings.
$feeds_source->save();
// The previous call to FeedsProcessor::getMappings() cached
// the mapping, so we need to clear that before we run the import.
drupal_static_reset('FeedsProcessor::getMappings');

// Run the import.
$feeds_source->startImport();
while (FEEDS_BATCH_COMPLETE != $feeds_source->import());

Then to change the actual value that goes into the field, you have to do that at import time, when feeds is getting the value from the source and saving it to the target.

To do that you can implement hook_feeds_processor_targets_alter(), like this:

/**
 * Implements hook_feeds_processor_targets_alter().
 */
function my_module_feeds_processor_targets_alter(array &$targets, $entity_type, $bundle) {
  // Set a custom value setter callback for the my field on my node type.
  if ($entity_type == 'node' && $bundle == 'my_node_type') {
    if (isset($targets['my_field'])) {
      $targets['my_field']['callback'] = 'my_module_set_custom_field_value';
    }
  }
}

/**
 * Custom feeds target setter callback.
 */
function my_module_set_custom_field_value(FeedsSource $source, $entity, $target, array $values, array $mapping) {
  // Set the field value to our custom value if it's there.
  if (!empty($mapping['my_custom_value'])) {
    $entity->{$target}[$entity->language][0]['value'] = $mapping['my_custom_value'];
  }
}
  • Thanks rooby. I used your first code and it works (tested it directly). My only question now is: before my initial code, I will have a piece of code where I decide if I want to set that custom value or not. So, how can I pass that information to the code you gave me? Set a global variable? – zephirus Jan 29 '18 at 15:10
  • @zephirus How do you decide if you want to set it or not? If it is based on some setting on the feed or the entity that is being saved then you should have all the information required to check the condition in the target callback. – rooby Jan 29 '18 at 16:03
  • I decide it by reading a xml using 'simplexml_load_file' and 'json_decode'. I get an array and if a specific value of that array is set, I define a variable with the value that I want to set in the feeds importer. – zephirus Jan 29 '18 at 16:13
  • There are a few ways you could do it. You could add pass through the value in the mapping, which isn't really abusing the system since it is data relating to the mapping (I edited my answer to include this). You could also pass it through in the session or something if you wanted or you could recompute the value by rerunning the xml load and json decode in the target callback. Note that you can't really go adding random config to the importer, processor, etc. as it will strip config not specified by the class, so to go that way you'd have to add a custom feeds plugin. – rooby Jan 29 '18 at 17:00
  • I updated my question. Now it has the whole code including your suggestions. I'm just missing the $VALUETOPASS variable. I think pass it through the session is not a good idea because I have many imports at the same time. I didn't understand what you edited in your last answer also. – zephirus Jan 29 '18 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.