|  | @@ -8,18 +8,128 @@
 | 
	
		
			
				|  |  |   * @license Licensed under the General Public License version 2 and later, and the CeCILL 2.0 license.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Information/utility class about CaseTracker in a Migrate context.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +class CaseTrackerMeta {
 | 
	
		
			
				|  |  | +  public static function getFields() {
 | 
	
		
			
				|  |  | +    $fields = array(
 | 
	
		
			
				|  |  | +      'pid'              => t('Case project'),
 | 
	
		
			
				|  |  | +      'case_number'      => t('Case number'),
 | 
	
		
			
				|  |  | +      'assign_to'        => t('Case assigned to'),
 | 
	
		
			
				|  |  | +      'case_priority_id' => t('Case priority'),
 | 
	
		
			
				|  |  | +      'case_type_id'     => t('Case type'),
 | 
	
		
			
				|  |  | +      'case_status_id'   => t('Case status'),
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +    return $fields;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class MigrateDestinationCommentFollowup extends MigrateDestinationComment {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function __construct() {
 | 
	
		
			
				|  |  | +    parent::__construct(MigrateDestinationNodeCase::ct_bundle);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Could also be implemented as a migrate hook_migrate_fields() in module.
 | 
	
		
			
				|  |  | +   * Which is best ?
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * (non-PHPdoc)
 | 
	
		
			
				|  |  | +   * @see MigrateDestinationComment::fields()
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  public function fields() {
 | 
	
		
			
				|  |  | +    $fields = parent::fields();
 | 
	
		
			
				|  |  | +    $fields['revision_id'] = t('Ticket revision ID');
 | 
	
		
			
				|  |  | +    $fields += CaseTrackerMeta::getFields();
 | 
	
		
			
				|  |  | +    return $fields;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function prepare($entity, stdClass $source_row) {
 | 
	
		
			
				|  |  | +    $ticket = node_load($entity->nid);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // ticket->casetracker is assigned by CT to both new and old, so clone is
 | 
	
		
			
				|  |  | +    // required, to avoid overwriting one state with the other
 | 
	
		
			
				|  |  | +    $entity->casetracker = clone $ticket->casetracker;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // CT needs a name in assign_to, not an uid
 | 
	
		
			
				|  |  | +    $entity->casetracker->assign_to = casetracker_get_name($entity->casetracker->assign_to);
 | 
	
		
			
				|  |  | +    //print_r($entity);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $entity->revision_id = $ticket->vid;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Casetracker-specific destination node handling
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +class MigrateDestinationNodeCase extends MigrateDestinationNode {
 | 
	
		
			
				|  |  | +  const ct_bundle = 'casetracker_basic_case';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function __construct() {
 | 
	
		
			
				|  |  | +    parent::__construct(self::ct_bundle);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Could also be implemented as a migrate hook_migrate_fields() in module.
 | 
	
		
			
				|  |  | +   * Which is best ?
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * (non-PHPdoc)
 | 
	
		
			
				|  |  | +   * @see MigrateDestinationNode::fields()
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  public function fields() {
 | 
	
		
			
				|  |  | +    $fields = parent::fields();
 | 
	
		
			
				|  |  | +    $fields += CaseTrackerMeta::getFields();
 | 
	
		
			
				|  |  | +    return $fields;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Casetracker saves its fields in a separate stdClass extra field.
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * (non-PHPdoc)
 | 
	
		
			
				|  |  | +   * @see MigrateDestinationEntity::prepare()
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  public function prepare($entity, stdClass $source_row) {
 | 
	
		
			
				|  |  | +    $extraFields = array(
 | 
	
		
			
				|  |  | +      'pid',
 | 
	
		
			
				|  |  | +      'case_priority_id',
 | 
	
		
			
				|  |  | +      'case_type_id',
 | 
	
		
			
				|  |  | +      'assign_to',
 | 
	
		
			
				|  |  | +      'case_status_id',
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $entity->casetracker = new stdClass();
 | 
	
		
			
				|  |  | +    foreach ($extraFields as $extra) {
 | 
	
		
			
				|  |  | +      if (isset($entity->$extra)) {
 | 
	
		
			
				|  |  | +        $entity->casetracker->$extra = $entity->$extra;
 | 
	
		
			
				|  |  | +        unset($entity->extra);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $entity->casetracker->case_type_id = 9; // Bug. Case type is not a default Unfuddle field
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  abstract class UnfuddleMigration extends XMLMigration {
 | 
	
		
			
				|  |  | -  public $items_url;
 | 
	
		
			
				|  |  | +  protected static $fields = array();
 | 
	
		
			
				|  |  |    public $item_ID_xpath = 'id';
 | 
	
		
			
				|  |  | +  public $items_url;
 | 
	
		
			
				|  |  |    public $unmigratedDestinations = array();
 | 
	
		
			
				|  |  |    public $unmigratedSources = array();
 | 
	
		
			
				|  |  | -  protected static $fields = array();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    public function __construct($group) {
 | 
	
		
			
				|  |  |      parent::__construct($group);
 | 
	
		
			
				|  |  |      $this->items_url = file_directory_path() . '/unfuddle/backup.xml';
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  public function addXPathFieldMapping($destination_field, $source_field, $xpath = NULL) {
 | 
	
		
			
				|  |  | +    if (!isset($xpath)) {
 | 
	
		
			
				|  |  | +      $xpath = $source_field;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return $this->addFieldMapping($destination_field, $source_field)
 | 
	
		
			
				|  |  | +      ->xpath($xpath);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    public function afterConstruct() {
 | 
	
		
			
				|  |  |      $this->addUnmigratedDestinations($this->unmigratedDestinations, t('White hole'));
 | 
	
		
			
				|  |  |      $this->addUnmigratedSources($this->unmigratedSources, t('Black hole'));
 | 
	
	
		
			
				|  | @@ -34,13 +144,6 @@ abstract class UnfuddleMigration extends XMLMigration {
 | 
	
		
			
				|  |  |      return self::$fields;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  public function addXPathFieldMapping($destination_field, $source_field, $xpath = NULL) {
 | 
	
		
			
				|  |  | -    if (!isset($xpath)) {
 | 
	
		
			
				|  |  | -      $xpath = $source_field;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    return $this->addFieldMapping($destination_field, $source_field)
 | 
	
		
			
				|  |  | -      ->xpath($xpath);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
	
		
			
				|  | @@ -75,35 +178,6 @@ class UnfuddlePeopleMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  |      'updated-at',
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  protected static function getFieldInfo() {
 | 
	
		
			
				|  |  | -    self::$fields = array(
 | 
	
		
			
				|  |  | -      'account-id'                    => t('Unfuddle account Id'),
 | 
	
		
			
				|  |  | -      'id'                            => t('User account ID'),
 | 
	
		
			
				|  |  | -      'created-at'                    => t('User account creation timestamp'),
 | 
	
		
			
				|  |  | -      'email'                         => t('Current email address for the account'),
 | 
	
		
			
				|  |  | -      'first-name'                    => t('User given name'),
 | 
	
		
			
				|  |  | -      'identity-url'                  => t('OpenID URL for the user account'),
 | 
	
		
			
				|  |  | -      'is-administrator'              => t('User is an Unfuddle project administrator'),
 | 
	
		
			
				|  |  | -      'is-removed'                    => t('User account has been removed'),
 | 
	
		
			
				|  |  | -      'last-name'                     => t('User last name'),
 | 
	
		
			
				|  |  | -      'last-signed-in'                => t('Latest login timestamp'),
 | 
	
		
			
				|  |  | -      'notification-frequency'        => t('Unfuddle notification frequency'),
 | 
	
		
			
				|  |  | -      'notification-ignore-self'      => t('Ignore self when sending notifications'),
 | 
	
		
			
				|  |  | -      'notification-last-sent'        => t('Timestamp of latest notification sent'),
 | 
	
		
			
				|  |  | -      'notification-scope-messages'   => t('Send message notifications'),
 | 
	
		
			
				|  |  | -      'notification-scope-milestones' => t('Send milestones notifications'),
 | 
	
		
			
				|  |  | -      'notification-scope-notebooks'  => t('Send notebooks notifications'),
 | 
	
		
			
				|  |  | -      'notification-scope-source'     => t('Send source notifications'),
 | 
	
		
			
				|  |  | -      'notification-scope-tickets'    => t('Send tickets notifications'),
 | 
	
		
			
				|  |  | -      'text-markup'                   => t('Preferred markup format for issues'),
 | 
	
		
			
				|  |  | -      'time-zone'                     => t('Timezone'),
 | 
	
		
			
				|  |  | -      'updated-at'                    => t('Timestamp of latest user account change'),
 | 
	
		
			
				|  |  | -      'username'                      => t('The user account login name'),
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return parent::getFieldInfo();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    public function __construct() {
 | 
	
		
			
				|  |  |      parent::__construct(MigrateGroup::getInstance('Unfuddle'));
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -145,6 +219,35 @@ class UnfuddlePeopleMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  |      $this->afterConstruct();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  protected static function getFieldInfo() {
 | 
	
		
			
				|  |  | +    self::$fields = array(
 | 
	
		
			
				|  |  | +      'account-id'                    => t('Unfuddle account Id'),
 | 
	
		
			
				|  |  | +      'id'                            => t('User account ID'),
 | 
	
		
			
				|  |  | +      'created-at'                    => t('User account creation timestamp'),
 | 
	
		
			
				|  |  | +      'email'                         => t('Current email address for the account'),
 | 
	
		
			
				|  |  | +      'first-name'                    => t('User given name'),
 | 
	
		
			
				|  |  | +      'identity-url'                  => t('OpenID URL for the user account'),
 | 
	
		
			
				|  |  | +      'is-administrator'              => t('User is an Unfuddle project administrator'),
 | 
	
		
			
				|  |  | +      'is-removed'                    => t('User account has been removed'),
 | 
	
		
			
				|  |  | +      'last-name'                     => t('User last name'),
 | 
	
		
			
				|  |  | +      'last-signed-in'                => t('Latest login timestamp'),
 | 
	
		
			
				|  |  | +      'notification-frequency'        => t('Unfuddle notification frequency'),
 | 
	
		
			
				|  |  | +      'notification-ignore-self'      => t('Ignore self when sending notifications'),
 | 
	
		
			
				|  |  | +      'notification-last-sent'        => t('Timestamp of latest notification sent'),
 | 
	
		
			
				|  |  | +      'notification-scope-messages'   => t('Send message notifications'),
 | 
	
		
			
				|  |  | +      'notification-scope-milestones' => t('Send milestones notifications'),
 | 
	
		
			
				|  |  | +      'notification-scope-notebooks'  => t('Send notebooks notifications'),
 | 
	
		
			
				|  |  | +      'notification-scope-source'     => t('Send source notifications'),
 | 
	
		
			
				|  |  | +      'notification-scope-tickets'    => t('Send tickets notifications'),
 | 
	
		
			
				|  |  | +      'text-markup'                   => t('Preferred markup format for issues'),
 | 
	
		
			
				|  |  | +      'time-zone'                     => t('Timezone'),
 | 
	
		
			
				|  |  | +      'updated-at'                    => t('Timestamp of latest user account change'),
 | 
	
		
			
				|  |  | +      'username'                      => t('The user account login name'),
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return parent::getFieldInfo();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    /**
 | 
	
		
			
				|  |  |     * - Timestamp format conversion not needed, as per MigrationBase::timestamp()
 | 
	
		
			
				|  |  |     * - Invert is-removed to convert to status
 | 
	
	
		
			
				|  | @@ -198,6 +301,46 @@ class UnfuddleProjectMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  |      'categories', // @todo TODO Taxonomy ?
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  public function __construct() {
 | 
	
		
			
				|  |  | +    parent::__construct(MigrateGroup::getInstance('Unfuddle'));
 | 
	
		
			
				|  |  | +    $item_xpath = '/account/projects/project';
 | 
	
		
			
				|  |  | +    $items_class = new MigrateItemsXML($this->items_url, $item_xpath, $this->item_ID_xpath);
 | 
	
		
			
				|  |  | +    $this->source = new MigrateSourceMultiItems($items_class, self::getFieldInfo());
 | 
	
		
			
				|  |  | +    $source_key = array(
 | 
	
		
			
				|  |  | +      'id' => array(
 | 
	
		
			
				|  |  | +        'type' => 'int',
 | 
	
		
			
				|  |  | +        'unsigned' => TRUE,
 | 
	
		
			
				|  |  | +        'not null' => TRUE,
 | 
	
		
			
				|  |  | +      )
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $this->dependencies = array('UnfuddlePeople');
 | 
	
		
			
				|  |  | +    $this->destination = new MigrateDestinationNode('casetracker_basic_project');
 | 
	
		
			
				|  |  | +    $this->map = new MigrateSQLMap('unfuddle_project',
 | 
	
		
			
				|  |  | +      $source_key,
 | 
	
		
			
				|  |  | +      MigrateDestinationNode::getKeySchema());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('created',  'created-at');
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('status',   'archived')
 | 
	
		
			
				|  |  | +      ->description(t('Inverted when converting to node.status'));
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('body',     'description')
 | 
	
		
			
				|  |  | +      ->description(t('Applying site default input format: will often be wrong'));
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('teaser',   node_teaser('description', FILTER_FORMAT_DEFAULT))
 | 
	
		
			
				|  |  | +      ->description(t('Applying site default input format: will often be wrong'));
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('changed',  'updated-at');
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('title',    'title');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('uid',           NULL)
 | 
	
		
			
				|  |  | +      ->sourceMigration('UnfuddlePeople')
 | 
	
		
			
				|  |  | +      ->defaultValue(1);
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('revision_uid',  NULL)
 | 
	
		
			
				|  |  | +      ->sourceMigration('UnfuddlePeople')
 | 
	
		
			
				|  |  | +      ->defaultValue(1);
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('path',      'short-name')
 | 
	
		
			
				|  |  | +      ->description(t('Auto-aliased to project/(short-name)'));
 | 
	
		
			
				|  |  | +    $this->afterConstruct();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    protected static function getFieldInfo() {
 | 
	
		
			
				|  |  |      self::$fields = array(
 | 
	
		
			
				|  |  |        'account-id'                          => t('Unfuddle account Id'),
 | 
	
	
		
			
				|  | @@ -244,9 +387,51 @@ class UnfuddleProjectMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  |      return self::$fields;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  public function preparerow(stdClass $row) {
 | 
	
		
			
				|  |  | +    $row->xml->{'archived'} = ((int) $row->xml->{'archived'}) ? 0 : 1;
 | 
	
		
			
				|  |  | +    $row->xml->{'short-name'} = 'project/'. drupal_clean_css_identifier($row->xml->{'short-name'});
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Import ticket follow-up (comments) data from Unfuddle into CaseTracker project comments
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +class UnfuddleTicketFollowupMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  | +  public $unmigratedDestinations = array(
 | 
	
		
			
				|  |  | +    'hostname',
 | 
	
		
			
				|  |  | +    'status',
 | 
	
		
			
				|  |  | +    'thread',
 | 
	
		
			
				|  |  | +    'name',
 | 
	
		
			
				|  |  | +    'mail',
 | 
	
		
			
				|  |  | +    'homepage',
 | 
	
		
			
				|  |  | +    'language',
 | 
	
		
			
				|  |  | +    'revision_id',
 | 
	
		
			
				|  |  | +  );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public $unmigratedSources = array(
 | 
	
		
			
				|  |  | +    'created-at',
 | 
	
		
			
				|  |  | +    'body-format',
 | 
	
		
			
				|  |  | +    'parent-type',
 | 
	
		
			
				|  |  | +  );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  protected static function getFieldInfo() {
 | 
	
		
			
				|  |  | +    self::$fields = array(
 | 
	
		
			
				|  |  | +      'author-id'                            => t('Comment author'),
 | 
	
		
			
				|  |  | +      'body'                                 => t('Comment text. Applying site default input format: will often be wrong'),
 | 
	
		
			
				|  |  | +      'body-format'                          => t('Comment text input format. No direct mapping to Drupal format defaults'),
 | 
	
		
			
				|  |  | +      'created-at'                           => t('The follow-up creation timestamp'),
 | 
	
		
			
				|  |  | +      'updated-at'                           => t('The follow-up latest update timestamp'),
 | 
	
		
			
				|  |  | +      'parent-id'                            => t('The ticket to which the follow-up applies'),
 | 
	
		
			
				|  |  | +      'parent-type'                          => t('The follow-up parent type: always Ticket'),
 | 
	
		
			
				|  |  | +      'x-subject'                            => t('Virtual: from body'),
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return self::$fields;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    public function __construct() {
 | 
	
		
			
				|  |  |      parent::__construct(MigrateGroup::getInstance('Unfuddle'));
 | 
	
		
			
				|  |  | -    $item_xpath = '/account/projects/project';
 | 
	
		
			
				|  |  | +    $item_xpath = '/account/projects/project/tickets/ticket/comments/comment';
 | 
	
		
			
				|  |  |      $items_class = new MigrateItemsXML($this->items_url, $item_xpath, $this->item_ID_xpath);
 | 
	
		
			
				|  |  |      $this->source = new MigrateSourceMultiItems($items_class, self::getFieldInfo());
 | 
	
		
			
				|  |  |      $source_key = array(
 | 
	
	
		
			
				|  | @@ -257,93 +442,38 @@ class UnfuddleProjectMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  |        )
 | 
	
		
			
				|  |  |      );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    $this->dependencies = array('UnfuddlePeople');
 | 
	
		
			
				|  |  | -    $this->destination = new MigrateDestinationNode('casetracker_basic_project');
 | 
	
		
			
				|  |  | -    $this->map = new MigrateSQLMap('unfuddle_project',
 | 
	
		
			
				|  |  | +    $this->dependencies = array('UnfuddlePeople', 'UnfuddleProject', 'UnfuddleTicket');
 | 
	
		
			
				|  |  | +    $this->destination = new MigrateDestinationCommentFollowup();
 | 
	
		
			
				|  |  | +    $this->map = new MigrateSQLMap('unfuddle_ticket_followup',
 | 
	
		
			
				|  |  |        $source_key,
 | 
	
		
			
				|  |  |        MigrateDestinationNode::getKeySchema());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    $this->addXPathFieldMapping('created',  'created-at');
 | 
	
		
			
				|  |  | -    $this->addXPathFieldMapping('status',   'archived')
 | 
	
		
			
				|  |  | -      ->description(t('Inverted when converting to node.status'));
 | 
	
		
			
				|  |  | -    $this->addXPathFieldMapping('body',     'description')
 | 
	
		
			
				|  |  | -      ->description(t('Applying site default input format: will often be wrong'));
 | 
	
		
			
				|  |  | -    $this->addXPathFieldMapping('teaser',   node_teaser('description', FILTER_FORMAT_DEFAULT))
 | 
	
		
			
				|  |  | +    $ar1 = drupal_map_assoc($this->unmigratedDestinations);
 | 
	
		
			
				|  |  | +    $ar2 = CaseTrackerMeta::getFields();
 | 
	
		
			
				|  |  | +    $this->unmigratedDestinations = array_keys($ar1 + $ar2); // Note: PID ignored
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('uid',              'author-id')
 | 
	
		
			
				|  |  | +      ->sourceMigration('UnfuddlePeople');
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('comment',          'body')
 | 
	
		
			
				|  |  |        ->description(t('Applying site default input format: will often be wrong'));
 | 
	
		
			
				|  |  | -    $this->addXPathFieldMapping('changed',  'updated-at');
 | 
	
		
			
				|  |  | -    $this->addXPathFieldMapping('title',    'title');
 | 
	
		
			
				|  |  | +      $this->addXPathFieldMapping('nid',            'parent-id')
 | 
	
		
			
				|  |  | +      ->sourceMigration('UnfuddleTicket');
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('timestamp',        'updated-at');
 | 
	
		
			
				|  |  | +    $this->addXPathFieldMapping('subject',          'x-subject')
 | 
	
		
			
				|  |  | +      ->description(t('Generated'));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    $this->addXPathFieldMapping('uid',           NULL)
 | 
	
		
			
				|  |  | -      ->sourceMigration('UnfuddlePeople')
 | 
	
		
			
				|  |  | -      ->defaultValue(1);
 | 
	
		
			
				|  |  | -    $this->addXPathFieldMapping('revision_uid',  NULL)
 | 
	
		
			
				|  |  | -      ->sourceMigration('UnfuddlePeople')
 | 
	
		
			
				|  |  | -      ->defaultValue(1);
 | 
	
		
			
				|  |  | -    $this->addXPathFieldMapping('path',      'short-name')
 | 
	
		
			
				|  |  | -      ->description(t('Auto-aliased to project/(short-name)'));
 | 
	
		
			
				|  |  |      $this->afterConstruct();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    public function preparerow(stdClass $row) {
 | 
	
		
			
				|  |  | -    $row->xml->{'archived'} = ((int) $row->xml->{'archived'}) ? 0 : 1;
 | 
	
		
			
				|  |  | -    $row->xml->{'short-name'} = 'project/'. drupal_clean_css_identifier($row->xml->{'short-name'});
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -class MigrateDestinationNodeCase extends MigrateDestinationNode {
 | 
	
		
			
				|  |  | -  public function __construct() {
 | 
	
		
			
				|  |  | -    parent::__construct('casetracker_basic_case');
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /**
 | 
	
		
			
				|  |  | -   * Could also be implemented as a migrate hook_migrate_fields() in module.
 | 
	
		
			
				|  |  | -   * Which is best ?
 | 
	
		
			
				|  |  | -   *
 | 
	
		
			
				|  |  | -   * (non-PHPdoc)
 | 
	
		
			
				|  |  | -   * @see MigrateDestinationNode::fields()
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  | -  public function fields() {
 | 
	
		
			
				|  |  | -    $fields = parent::fields();
 | 
	
		
			
				|  |  | -    $fields += array(
 | 
	
		
			
				|  |  | -      'pid'              => t('Case project'),
 | 
	
		
			
				|  |  | -      'case_number'      => t('Case number'),
 | 
	
		
			
				|  |  | -      'assign_to'        => t('Case assigned to'),
 | 
	
		
			
				|  |  | -      'case_priority_id' => t('Case priority'),
 | 
	
		
			
				|  |  | -      'case_type_id'     => t('Case type'),
 | 
	
		
			
				|  |  | -      'case_status_id'   => t('Case status'),
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -    return $fields;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /**
 | 
	
		
			
				|  |  | -   * Casetracker saves its fields in a separate stdClass extra field.
 | 
	
		
			
				|  |  | -   *
 | 
	
		
			
				|  |  | -   * (non-PHPdoc)
 | 
	
		
			
				|  |  | -   * @see MigrateDestinationEntity::prepare()
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  | -  public function prepare($entity, stdClass $source_row) {
 | 
	
		
			
				|  |  | -    $extraFields = array(
 | 
	
		
			
				|  |  | -      'pid',
 | 
	
		
			
				|  |  | -      'case_priority_id',
 | 
	
		
			
				|  |  | -      'case_type_id',
 | 
	
		
			
				|  |  | -      'assign_to',
 | 
	
		
			
				|  |  | -      'case_status_id',
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    $entity->casetracker = new stdClass();
 | 
	
		
			
				|  |  | -    foreach ($extraFields as $extra) {
 | 
	
		
			
				|  |  | -      if (isset($entity->$extra)) {
 | 
	
		
			
				|  |  | -        $entity->casetracker->$extra = $entity->$extra;
 | 
	
		
			
				|  |  | -        unset($entity->extra);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    $entity->casetracker->case_type_id = 9; // Bug. Case type is not a default Unfuddle field
 | 
	
		
			
				|  |  | +    $row->xml->{'x-subject'} = strip_tags(node_teaser($row->xml->{'body'}, FILTER_FORMAT_DEFAULT, 40));
 | 
	
		
			
				|  |  | +//    echo "SOURCE " . __FUNCTION__ . PHP_EOL;
 | 
	
		
			
				|  |  | +//    print_r($row->xml);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  | - * Import "project" ticket data from Unfuddle into CaseTracker project nodes
 | 
	
		
			
				|  |  | + * Import ticket data from Unfuddle into CaseTracker project nodes
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  class UnfuddleTicketMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  |    public $unmigratedDestinations = array(
 | 
	
	
		
			
				|  | @@ -366,37 +496,6 @@ class UnfuddleTicketMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  |      'version-id',
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  protected static function getFieldInfo() {
 | 
	
		
			
				|  |  | -    self::$fields = array(
 | 
	
		
			
				|  |  | -      'assignee-id'                         => t('User Id'),
 | 
	
		
			
				|  |  | -      'component-id'                        => t('The project component (unused)'),
 | 
	
		
			
				|  |  | -      'created-at'                          => t('Ticket creation timestamp'),
 | 
	
		
			
				|  |  | -      'description'                         => t('Description'),
 | 
	
		
			
				|  |  | -      'description-format'                  => t('The ticket body format - does not match Drupal formats'),
 | 
	
		
			
				|  |  | -      'due-on'                              => t('Timestamp the ticket should be resolved by'),
 | 
	
		
			
				|  |  | -    /*
 | 
	
		
			
				|  |  | -      'fieldn-value-id' => t('The value for custom field n'),
 | 
	
		
			
				|  |  | -     */
 | 
	
		
			
				|  |  | -      'hours-estimate-current'              => t('The current estimate for ticket resolution'),
 | 
	
		
			
				|  |  | -      'hours-estimate-initial'              => t('The initial estimate for ticket resolution'),
 | 
	
		
			
				|  |  | -      'milestone-id'                        => t('The milestone for which resolution of this ticket is due'),
 | 
	
		
			
				|  |  | -      'number'                              => t('An apparent duplicate of the ticket id'),
 | 
	
		
			
				|  |  | -      'priority'                            => t('The priority level for the ticket'),
 | 
	
		
			
				|  |  | -      'project-id'                          => t('The project this ticket belongs to'),
 | 
	
		
			
				|  |  | -      'reporter-id'                         => t('The user reporting the ticket'),
 | 
	
		
			
				|  |  | -      'resolution'                          => t('The way the ticket was resolved'),
 | 
	
		
			
				|  |  | -      'resolution-description'              => t('Details about the way the ticket was resolved'),
 | 
	
		
			
				|  |  | -      'severity-id'                         => t('The ticket severity level'),
 | 
	
		
			
				|  |  | -      'status'                              => t('The ticket status'),
 | 
	
		
			
				|  |  | -      'summary'                             => t('The ticket summary'),
 | 
	
		
			
				|  |  | -      'updated-at'                          => t('Timestamp of latest ticket change'),
 | 
	
		
			
				|  |  | -      'version-id'                          => t('The ticket version'),
 | 
	
		
			
				|  |  | -      'slug'                                => t('Virtual: ticket summary, converted to slug'),
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return self::$fields;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    public function __construct() {
 | 
	
		
			
				|  |  |      parent::__construct(MigrateGroup::getInstance('Unfuddle'));
 | 
	
		
			
				|  |  |      $item_xpath = '/account/projects/project/tickets/ticket';
 | 
	
	
		
			
				|  | @@ -442,6 +541,37 @@ class UnfuddleTicketMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  |      $this->afterConstruct();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  protected static function getFieldInfo() {
 | 
	
		
			
				|  |  | +    self::$fields = array(
 | 
	
		
			
				|  |  | +      'assignee-id'                         => t('User Id'),
 | 
	
		
			
				|  |  | +      'component-id'                        => t('The project component (unused)'),
 | 
	
		
			
				|  |  | +      'created-at'                          => t('Ticket creation timestamp'),
 | 
	
		
			
				|  |  | +      'description'                         => t('Description'),
 | 
	
		
			
				|  |  | +      'description-format'                  => t('The ticket body format - does not match Drupal formats'),
 | 
	
		
			
				|  |  | +      'due-on'                              => t('Timestamp the ticket should be resolved by'),
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  | +      'fieldn-value-id' => t('The value for custom field n'),
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +      'hours-estimate-current'              => t('The current estimate for ticket resolution'),
 | 
	
		
			
				|  |  | +      'hours-estimate-initial'              => t('The initial estimate for ticket resolution'),
 | 
	
		
			
				|  |  | +      'milestone-id'                        => t('The milestone for which resolution of this ticket is due'),
 | 
	
		
			
				|  |  | +      'number'                              => t('An apparent duplicate of the ticket id'),
 | 
	
		
			
				|  |  | +      'priority'                            => t('The priority level for the ticket'),
 | 
	
		
			
				|  |  | +      'project-id'                          => t('The project this ticket belongs to'),
 | 
	
		
			
				|  |  | +      'reporter-id'                         => t('The user reporting the ticket'),
 | 
	
		
			
				|  |  | +      'resolution'                          => t('The way the ticket was resolved'),
 | 
	
		
			
				|  |  | +      'resolution-description'              => t('Details about the way the ticket was resolved'),
 | 
	
		
			
				|  |  | +      'severity-id'                         => t('The ticket severity level'),
 | 
	
		
			
				|  |  | +      'status'                              => t('The ticket status'),
 | 
	
		
			
				|  |  | +      'summary'                             => t('The ticket summary'),
 | 
	
		
			
				|  |  | +      'updated-at'                          => t('Timestamp of latest ticket change'),
 | 
	
		
			
				|  |  | +      'version-id'                          => t('The ticket version'),
 | 
	
		
			
				|  |  | +      'slug'                                => t('Virtual: ticket summary, converted to slug'),
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return self::$fields;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    public function preparerow(stdClass $row) {
 | 
	
		
			
				|  |  |      /*
 | 
	
		
			
				|  |  |      $row->xml->{'archived'} = ((int) $row->xml->{'archived'}) ? 0 : 1;
 | 
	
	
		
			
				|  | @@ -473,3 +603,4 @@ class UnfuddleTicketMigration extends UnfuddleMigration {
 | 
	
		
			
				|  |  |    $row->xml->{'slug'} = 'case/'. drupal_strtolower(drupal_clean_css_identifier((string) $row->xml->{'summary'}));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 |