public function testBulkLoaderResultUpdated()
 {
     $results = BulkLoader_Result::create();
     $player = BulkLoaderTestPlayer::get()->find('Name', 'Vincent');
     $player->Status = 'Unavailable';
     $player->write();
     $results->addUpdated($player, 'Injured');
     $this->assertEquals($results->UpdatedCount(), 1);
     $this->assertSame('Vincent', $results->Updated()->find('Name', 'Vincent')->Name, 'The player Vincent should be recorded as updated');
     $this->assertSame('Unavailable', $results->Updated()->find('Name', 'Vincent')->Status, 'The player Vincent should have a Status of Unavailable');
     $this->assertSame('Injured', $results->Updated()->find('Name', 'Vincent')->_BulkLoaderMessage, 'Vincent is injured');
 }
 /**
  * @param array $record
  * @param array $columnMap
  * @param BulkLoader_Result $results
  * @param boolean $preview
  * @return number
  */
 protected function processRecord($record, $columnMap, &$results, $preview = false)
 {
     $posted = Controller::curr()->getRequest()->postVars();
     $default = WorkflowDefinitionExporter::$export_filename_prefix . '0.yml';
     $filename = isset($posted['_CsvFile']['name']) ? $posted['_CsvFile']['name'] : $default;
     // @todo is this the best way to extract records (nested array keys)??
     $struct = $record['Injector']['ExportedWorkflow'];
     $name = $struct['constructor'][0];
     $import = $this->createImport($name, $filename, $record);
     $template = Injector::inst()->createWithArgs('WorkflowTemplate', $struct['constructor']);
     $template->setStructure($struct['properties']['structure']);
     $def = WorkflowDefinition::create();
     $def->workflowService = singleton('WorkflowService');
     $def->Template = $template->getName();
     $obj = $def->workflowService->defineFromTemplate($def, $def->Template);
     $results->addCreated($obj, '');
     $objID = $obj->ID;
     // Update the import
     $import->DefinitionID = $objID;
     $import->write();
     $obj->destroy();
     unset($obj);
     return $objID;
 }
 /**
  * @todo Better messages for relation checks and duplicate detection
  * Note that columnMap isn't used.
  *
  * @param array $record
  * @param array $columnMap
  * @param BulkLoader_Result $results
  * @param boolean $preview
  *
  * @return int
  */
 protected function processRecord($record, $columnMap, &$results, $preview = false)
 {
     $class = $this->objectClass;
     // find existing object, or create new one
     $existingObj = $this->findExistingObject($record, $columnMap);
     $obj = $existingObj ? $existingObj : new $class();
     // first run: find/create any relations and store them on the object
     // we can't combine runs, as other columns might rely on the relation being present
     $relations = array();
     foreach ($record as $fieldName => $val) {
         // don't bother querying of value is not set
         if ($this->isNullValue($val)) {
             continue;
         }
         // checking for existing relations
         if (isset($this->relationCallbacks[$fieldName])) {
             // trigger custom search method for finding a relation based on the given value
             // and write it back to the relation (or create a new object)
             $relationName = $this->relationCallbacks[$fieldName]['relationname'];
             if ($this->hasMethod($this->relationCallbacks[$fieldName]['callback'])) {
                 $relationObj = $this->{$this->relationCallbacks[$fieldName]['callback']}($obj, $val, $record);
             } elseif ($obj->hasMethod($this->relationCallbacks[$fieldName]['callback'])) {
                 $relationObj = $obj->{$this->relationCallbacks[$fieldName]['callback']}($val, $record);
             }
             if (!$relationObj || !$relationObj->exists()) {
                 $relationClass = $obj->hasOneComponent($relationName);
                 $relationObj = new $relationClass();
                 //write if we aren't previewing
                 if (!$preview) {
                     $relationObj->write();
                 }
             }
             $obj->{"{$relationName}ID"} = $relationObj->ID;
             //write if we are not previewing
             if (!$preview) {
                 $obj->write();
                 $obj->flushCache();
                 // avoid relation caching confusion
             }
         } elseif (strpos($fieldName, '.') !== false) {
             // we have a relation column with dot notation
             list($relationName, $columnName) = explode('.', $fieldName);
             // always gives us an component (either empty or existing)
             $relationObj = $obj->getComponent($relationName);
             if (!$preview) {
                 $relationObj->write();
             }
             $obj->{"{$relationName}ID"} = $relationObj->ID;
             //write if we are not previewing
             if (!$preview) {
                 $obj->write();
                 $obj->flushCache();
                 // avoid relation caching confusion
             }
         }
     }
     // second run: save data
     foreach ($record as $fieldName => $val) {
         // break out of the loop if we are previewing
         if ($preview) {
             break;
         }
         // look up the mapping to see if this needs to map to callback
         $mapped = $this->columnMap && isset($this->columnMap[$fieldName]);
         if ($mapped && strpos($this->columnMap[$fieldName], '->') === 0) {
             $funcName = substr($this->columnMap[$fieldName], 2);
             $this->{$funcName}($obj, $val, $record);
         } else {
             if ($obj->hasMethod("import{$fieldName}")) {
                 $obj->{"import{$fieldName}"}($val, $record);
             } else {
                 $obj->update(array($fieldName => $val));
             }
         }
     }
     // write record
     $id = $preview ? 0 : $obj->write();
     // @todo better message support
     $message = '';
     // save to results
     if ($existingObj) {
         $results->addUpdated($obj, $message);
     } else {
         $results->addCreated($obj, $message);
     }
     $objID = $obj->ID;
     $obj->destroy();
     // memory usage
     unset($existingObj);
     unset($obj);
     return $objID;
 }
 /**
  * Import the given record
  *
  * @param array $record
  * @param array $columnMap
  * @param BulkLoader_Result $results
  * @param bool $preview
  * @return int
  */
 protected function processRecord($record, $columnMap, &$results, $preview = false)
 {
     if (!is_array($record) || empty($record) || !array_filter($record)) {
         $results->addSkipped("Empty/invalid record data.");
         return;
     }
     //map incoming record according to the standardisation mapping (columnMap)
     $record = $this->columnMapRecord($record);
     //skip if required data is not present
     if (!$this->hasRequiredData($record)) {
         $results->addSkipped("Required data is missing.");
         return;
     }
     $modelClass = $this->objectClass;
     $placeholder = new $modelClass();
     //populate placeholder object with transformed data
     foreach ($this->mappableFields_cache as $field => $label) {
         //skip empty fields
         if (!isset($record[$field]) || empty($record[$field])) {
             continue;
         }
         $this->transformField($placeholder, $field, $record[$field]);
     }
     //find existing duplicate of placeholder data
     $obj = null;
     $existing = null;
     if (!$placeholder->ID && !empty($this->duplicateChecks)) {
         $data = $placeholder->getQueriedDatabaseFields();
         //don't match on ID, ClassName or RecordClassName
         unset($data['ID'], $data['ClassName'], $data['RecordClassName']);
         $existing = $this->findExistingObject($data);
     }
     if ($existing) {
         $obj = $existing;
         $obj->update($data);
     } else {
         $obj = $placeholder;
     }
     //callback access to every object
     if (is_callable($this->recordCallback)) {
         $callback = $this->recordCallback;
         $callback($obj, $record);
     }
     $changed = $existing && $obj->isChanged();
     //try/catch for potential write() ValidationException
     try {
         // write obj record
         $obj->write();
         //publish pages
         if ($this->publishPages && $obj instanceof SiteTree) {
             $obj->publish('Stage', 'Live');
         }
         // save to results
         if ($existing) {
             if ($changed) {
                 $results->addUpdated($obj);
             } else {
                 $results->addSkipped("No data was changed.");
             }
         } else {
             $results->addCreated($obj);
         }
     } catch (ValidationException $e) {
         $results->addSkipped($e->getMessage());
     }
     $objID = $obj->ID;
     // reduce memory usage
     $obj->destroy();
     unset($existingObj);
     unset($obj);
     return $objID;
 }