4

I am trying to migrate files to a content type called educational activity. My issue is that some instances of this content type have more than one file attachment. So what I am trying to do is use concatenation to get all the file names in one field and then append them to the node like it's done with multi-value fields. However the migration outputs: "ltrim() expects parameter 1 to be string, array given". It seems that after the concatenation I end up with an array of arrays instead of an array with file names, but I can't figure out why.

This is the code:

class EducationalActivityMigration extends EduMigration {



public function __construct() {

parent::__construct();

#Define variable for the default user id (user="grammateia") wherever it is used (uid, revision_uid, etc.). 
$user=36;

# Human-friendly description of your migration process. Be as detailed as you like.

$this->description = t('Migrate the Educational Activity content type along with its fields');

/** 
 * We create the mapping in the database to be migrated instead of our default db.
 * Map Tables issue: http://drupal.org/node/1014558.
 */

$this->map = new MigrateSQLMap($this->machineName,
    array(
      'nid' => array('type' => 'int',
                       'not null' => TRUE,
                       'description' => 'Node ID',
                       'alias' => 'n'
                      )
    ),
    MigrateDestinationNode::getKeySchema(), 'migrationDB');




$query = Database::getConnection('default', 'migrationDB')
           ->select('node', 'n');      
$query->leftJoin('content_field_description', 'fd', 'n.nid = fd.nid');
$query->join('node_revisions', 'nrevi', 'nrevi.vid = n.vid');
//$query->leftJoin('node_revisions', 'nrev', 'n.nid = nrev.nid');
$query->leftJoin('content_field_age', 'fa', 'n.nid = fa.nid');
$query->leftJoin('content_field_target_group', 'tg', 'n.nid = tg.nid');
$query->leftJoin('content_field_rights_type', 'rt', 'n.nid = rt.nid');
$query->leftJoin('content_field_rights_holder', 'rh', 'n.nid = rh.nid');
$query->leftJoin('content_field_use_license', 'ul', 'n.nid = ul.nid');
$query->leftJoin('content_field_educational_stage', 'es', 'n.nid = es.nid');
$query->leftJoin('content_field_course', 'co', 'n.nid = co.nid');
$query->leftJoin('content_field_class', 'cl', 'n.nid = cl.nid');
$query->leftJoin('content_field_related_key_competence', 'rkc', 'n.nid = rkc.nid');
$query->leftJoin('content_field_filename', 'fi', 'n.nid = fi.nid');
$query->leftJoin('files', 'fil', 'fil.fid = fi.field_filename_fid');
$query->leftJoin('content_field_images', 'fim', 'n.nid = fim.nid');
$query->leftJoin('files', 'file', 'file.fid = fim.field_images_fid');
$query->addExpression('GROUP_CONCAT(DISTINCT fa.field_age_value)', 'age_list');
$query->addExpression('GROUP_CONCAT(DISTINCT tg.field_target_group_value)', 'target_list');
$query->addExpression('GROUP_CONCAT(rt.field_rights_type_value)', 'rights_list');
$query->addExpression('GROUP_CONCAT(DISTINCT rh.field_rights_holder_value)', 'holder_list');
$query->addExpression('GROUP_CONCAT(ul.field_use_license_value)', 'license_list');
$query->addExpression('GROUP_CONCAT(es.field_educational_stage_value)', 'edustage_list');
$query->addExpression('GROUP_CONCAT(DISTINCT co.field_course_value)', 'course_list');
$query->addExpression('GROUP_CONCAT(DISTINCT cl.field_class_value)', 'class_list');
$query->addExpression('GROUP_CONCAT(DISTINCT rkc.field_related_key_competence_value)', 'competence_list');
$query->addExpression('GROUP_CONCAT(fil.filename)', 'file_list');
//$query->addExpression('GROUP_CONCAT(file.filename)', 'image_list');
$query->fields('n')
        ->fields('fd', array('field_description_value'))
        ->fields('nrevi', array('body'))
        ->fields('fa', array('field_age_value'))
        ->fields('tg', array('field_target_group_value'))
        ->fields('rt', array('field_rights_type_value'))
        ->fields('rh', array('field_rights_holder_value'))
        ->fields('ul', array('field_use_license_value'))
        ->fields('es', array('field_educational_stage_value'))
        ->fields('co', array('field_course_value'))
        ->fields('cl', array('field_class_value'))
        ->fields('rkc', array('field_related_key_competence_value'))
        ->fields('fil', array('fid', 'filename', 'filepath', 'filemime', 'filesize', 'timestamp'))
        ->fields('file', array('fid', 'filename', 'filepath', 'filemime', 'filesize', 'timestamp'))
        ->condition('type', "educational_activity",'=')
        ->groupBy('n.nid');


# Create a MigrateSource object, which manages retrieving the input data.
$this->source = new MigrateSourceSQL($query);

# Set up our destination node as the Educational Activity node
$this->destination = new MigrateDestinationNode('educational_activity');



/**
 *  FIELDS WITH THE SAME NAME IN BOTH DBs
 *
 *  @nid: The primary identifier for a node.
 *  @title: General title of the node in plain text.
 *  @status: Boolean expression stating if the node is published.
 *  @created: Integer type timestamp of the node's creation.
 *  @changed: Integer type timestamp of the node's latest change.
 *  @promote: Boolean expression indicating if the node is present in the front page.
 *  @sticky: Boolean expression stating if the node should be at the top of the list wherever it appears.
 *  @comment:Shows whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write).
 *
 */

$this->addSimpleMappings(array ('title', 'status', 'created', 'changed', 'promote', 'sticky', 
'comment'));

/**
 *  FIELDS WITH DEFAULT VALUES
 *  
 *  @uid: value "36" corresponds to "grammateia" user.
 *  @language: default value set to "Ellinika".
 *  @translate: default value set to False.
 *  @tnid:The translation set id for this node, which equals the node id of the source post in each set.
 *  @revision_uid: The user id that shows which user did the revision.
 */

$this->addFieldMapping('uid')
  ->defaultValue($user);
  $this->addFieldMapping('language', 'language')
    ->defaultValue('el');
    $this->addFieldMapping('translate', 'translate')
    ->defaultValue('FALSE');
    $this->addFieldMapping('tnid', 'tnid')
    ->defaultValue('0');
    $this->addFieldMapping('revision_uid')
  ->defaultValue($user);

/** 
 * FIELDS PENDING MIGRATION
 *
 * @vid: It means 'version id'. For every node in the node table, Drupal can save multiple versions in the node_revisions table. 
 * The version id is the unique identifier in the node_revisions table. 
 */

$this->addFieldMapping('vid', 'vid')
     ->description(t('Pending Migration Status'))
     ->issueGroup(t('What are gonna do with these?'));

/**
 * SOURCE FIELDS NOT TO BE MIGRATED
 *
 * @type: Shows the content type, not needed since we input the type in the MigrateDestinationNode constructor.
 * @moderate: Boolean expression showing if the node is under moderation. Moderation support has moved out of core. 
 */

$this->addUnmigratedSources(array ('type', 'moderate', 'field_programma_ekpaid', 'field_syggrafiki_omada_ekp', 'field_schoolunit_ekp', 'fid','filepath', 'filemime', 'filesize', 'timestamp', 'file_fid', 'file_filepath', 'file_filemime', 'file_filesize', 'file_timestamp'), t('Source fields that we will not be migrating'));

/**
 * DESTINATION FIELDS NOT TO BE MIGRATED
 */

$this->addUnmigratedDestinations (array('revision', 'log', 'is_new', 'field_rights_holder:language', 'field_keywords', 
'field_keywords:source_type', 'field_keywords:create_term', 'field_keywords:ignore_case', 'field_knowledge_tree_category', 
'field_knowledge_tree_category:source_type', 'field_knowledge_tree_category:create_term', 'field_knowledge_tree_category:ignore_case', 
'field_tag', 'field_tag:source_type', 'field_tag:create_term', 'field_tag:ignore_case', 'field_related_item:language', 'field_body:summary', 
'field_body:format', 'field_body:language', 'field_description:language', 'field_description:format', 'field_attachment:destination_file', 'field_attachment:description', 'field_attachment:display'),t('Destination fields that we will not be migrating'));

/**
 * FIELDS TO BE MIGRATED
 */


 $this->addFieldMapping('field_body', 'body')
      ->arguments(array('format' => 'full_html'));
 $this->addFieldMapping('field_description', 'field_description_value')
      ->arguments(array('format' => 'full_html'));
 $this->addFieldMapping('field_age', 'age_list')
      ->separator(',')
      ->arguments(array('source_type' => 'field_age_value'));
 $this->addFieldMapping('field_target_group', 'target_list')
      ->separator(',')
      ->arguments(array('source_type' => 'field_target_group_value'));
 $this->addFieldMapping('field_rights_type', 'rights_list')
      ->separator(',')
      ->arguments(array('source_type' => 'field_rights_type_value'));
 $this->addFieldMapping('field_rights_holder', 'holder_list')
      ->separator('--')
      ->arguments(array('source_type' => 'field_rights_holder_value'));
 $this->addFieldMapping('field_use_license', 'license_list')
      ->separator(',')
      ->arguments(array('source_type' => 'field_use_license_value'));
 $this->addFieldMapping('field_educational_stage', 'edustage_list')
      ->separator(',')
      ->arguments(array('source_type' => 'field_educational_stage_value'));
 $this->addFieldMapping('field_course', 'course_list')
      ->separator(',')
      ->arguments(array('source_type' => 'field_course_value'));
 $this->addFieldMapping('field_class', 'class_list')
      ->separator(',')
      ->arguments(array('source_type' => 'field_class_value'));
 $this->addFieldMapping('field_related_key_competence', 'competence_list')
      ->separator(',')
      ->arguments(array('source_type' => 'field_related_key_competence_value'));

 $this->addFieldMapping('field_attachment:file_class')
      ->defaultValue('MigrateFileUri');
 $this->addFieldMapping('field_attachment:language')
      ->defaultValue('el');
 $this->addFieldMapping('field_attachment:destination_dir')
      ->defaultValue('sites/default/files/educational_activity');
 $this->addFieldMapping('field_attachment:file_replace')
      ->defaultValue('FILE_EXISTS_REUSE');
 $this->addFieldMapping('field_attachment:preserve_files')
      ->defaultValue(TRUE);
 $this->addFieldMapping('field_attachment:source_dir')
      ->defaultValue('C:/xampp/htdocs/protovoulia.org/sites/default/files');




 #Copy files (word etc)
 $this->addFieldMapping('field_attachment', 'file_list')
      ->separator(',')
      ->arguments(array('source_type' => 'filename'));

 #Copy Images
 //$this->addFieldMapping('field_attachment', 'image_list')
      //->separator(',')
      //->arguments(array('source_type' => 'filename'));



/**
 * We conditionally DNM these fields, so your field mappings will be clean,
 * whether or not you have path and or pathauto enabled.
 */

if(module_exists('path')) {

  $this->addFieldMapping('path')
       ->issueGroup(t('DNM'));
  if (module_exists('pathauto')) {
    $this->addFieldMapping('pathauto')
         ->issueGroup(t('DNM'));
  }

}//if ends

}//construct ends


}//class ends

Unfortunately, I didn't come to a working solution reading all the other questions.

3
  • *Update: Creating a separate table with all the information needed in order to avoid using one of the left joins, results in the same error. It seems that copying multiple files is not properly supported. Still investigating... – Jim Bidis Jan 10 '13 at 10:16
  • Did you try implementing prepareRow() function to transform your source field in an array? – ermannob Jan 17 '13 at 13:58
  • No not yet, had it in mind though, but haven't had the time. I will certainly give it a try, thanks for the input. – Jim Bidis Jan 17 '13 at 17:22
5

So after managing to spend some time resolving this issue, I managed to migrate multiple files in a node like so:

To begin with this line:

$query->addExpression('GROUP_CONCAT(fil.filename)', 'file_list');

becomes:

$query->addExpression('GROUP_CONCAT(DISTINCT fil.filename)', 'file_list');

Cause we need to avoid migrating duplicates.

Secondly, this line:

->fields('fil', array('fid', 'filename', 'filepath', 'filemime', 'filesize', 'timestamp'))

became:

->fields('fil', array('filename'))

We don't really need to migrate this info cause the migration process can discover these values by itself. If however anyone believes that these should be migrated please advise.

And last and more importantly these lines:

 $this->addFieldMapping('field_attachment:file_class')
  ->defaultValue('MigrateFileUri');
$this->addFieldMapping('field_attachment:language')
  ->defaultValue('el');
$this->addFieldMapping('field_attachment:destination_dir')
  ->defaultValue('C:/xampp/htdocs/testpaideia/sites/default/files/educational_activity');
$this->addFieldMapping('field_attachment:file_replace')
  ->defaultValue('FILE_EXISTS_REUSE');
$this->addFieldMapping('field_attachment:preserve_files')
  ->defaultValue(TRUE);
$this->addFieldMapping('field_attachment:source_dir')
  ->defaultValue('C:/xampp/htdocs/protovoulia.org/sites/default/files');

#Copy files (word etc)
$this->addFieldMapping('field_attachment', 'file_list')
  ->separator(',')
  ->arguments(array('source_type' => 'filename'));

become:

#Copy files (word etc)
$this->addFieldMapping('field_attachment', 'file_list')
      ->separator(',');

 $this->addFieldMapping('field_attachment:file_class')
      ->defaultValue('MigrateFileUri');
 $this->addFieldMapping('field_attachment:language')
      ->defaultValue('el');
 $this->addFieldMapping('field_attachment:destination_dir')
      ->defaultValue('sites/default/files/educational_activity');
 $this->addFieldMapping('field_attachment:file_replace')
      ->defaultValue('FILE_EXISTS_REPLACE');
 $this->addFieldMapping('field_attachment:preserve_files')
      ->defaultValue(FALSE);
 $this->addFieldMapping('field_attachment:source_dir')
      ->defaultValue('C:/xampp/htdocs/protovoulia.org/sites/default/files');

We need to map the primary field (in my case field_attachment) before its subfields (e.g. field_attachment:preserve_files, field_attachment:file_replace etc.), otherwise the migration fails. That's it hope it was helpful.

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.