Changeset 57102

Show
Ignore:
Timestamp:
30/06/08 16:12:47 (2 months ago)
Author:
ischommer
Message:

FEATURE Using $columnMap and $hasHeaderRow in combination for CsvBulkLoader? class
BUGFIX More robust iteration over $columnMap in CsvBulkLoader?

Location:
modules/sapphire/branches/roa/tools
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • modules/sapphire/branches/roa/tools/BulkLoader.php

    r56537 r57102  
    66 * You can configure column-handling,  
    77 *  
    8  * @todo Allow updating of existing records based on user-specified unique criteria/callbacks (e.g. database ID) 
    98 * @todo Add support for adding/editing has_many relations. 
    109 * @todo Add support for deep chaining of relation properties (e.g. Player.Team.Stats.GoalCount) 
     10 * @todo Character conversion 
    1111 *  
    1212 * @see http://rfc.net/rfc4180.html 
     
    4141         * The column count should match the count of array elements, 
    4242         * fill with NULL values if you want to skip certain columns. 
     43         * 
     44         * You can also combine {@link $hasHeaderRow} = true and {@link $columnMap} 
     45         * and omit the NULL values in your map. 
    4346         *  
    4447         * Supports one-level chaining of has_one relations and properties with dot notation 
  • modules/sapphire/branches/roa/tools/CsvBulkLoader.php

    r54730 r57102  
    3939                 
    4040                $return = new DataObjectSet(); 
    41                  
    42                 // assuming that first row is column naming if no columnmap is passed 
     41 
    4342                if($this->hasHeaderRow && $this->columnMap) { 
    4443                        $columnRow = fgetcsv($file, 0, $this->delimiter, $this->enclosure); 
    45                         $columnMap = $this->columnMap; 
     44                        $columnMap = array(); 
     45                        foreach($columnRow as $k => $origColumnName) { 
     46                                if(isset($this->columnMap[$origColumnName])) { 
     47                                        $columnMap[$origColumnName] = $this->columnMap[$origColumnName]; 
     48                                } else { 
     49                                        $columnMap[$origColumnName] = null; 
     50                                } 
     51                                 
     52                        } 
    4653                } elseif($this->columnMap) { 
    4754                        $columnMap = $this->columnMap; 
    4855                } else { 
     56                        // assuming that first row is column naming if no columnmap is passed 
    4957                        $columnRow = fgetcsv($file, 0, $this->delimiter, $this->enclosure); 
    5058                        $columnMap = array_combine($columnRow, $columnRow); 
    5159                } 
    5260                 
     61                $rowIndex = 0; 
    5362                while (($row = fgetcsv($file, 0, $this->delimiter, $this->enclosure)) !== FALSE) { 
    54                         $indexedRow = array_combine(array_values($columnMap), array_values($row)); 
     63                        $rowIndex++; 
     64                         
     65                        /* 
     66                        // the columnMap should have the same amount of columns as each record row 
     67                        if(count(array_keys($columnMap)) == count(array_values($row))) { 
     68                                user_error("CsvBulkLoader::processAll(): Columns in row {$rowIndex} don't match the \$columnMap", E_USER_WARNING); 
     69                        } 
     70                        */ 
     71                         
     72                        $indexedRow = array(); 
     73                        foreach($columnMap as $origColumnName => $fieldName) { 
     74                                // in case the row has less fields than the columnmap, 
     75                                // ignore the "leftover" mappings 
     76                                if(!isset($row[count($indexedRow)])) { 
     77                                                user_error("CsvBulkLoader::processAll(): Columns in row {$rowIndex} don't match the \$columnMap", E_USER_NOTICE); 
     78                                        continue; 
     79                                } 
     80         
     81                                $indexedRow[$origColumnName] = $row[count($indexedRow)]; 
     82                        } 
     83 
    5584                        $return->push($this->processRecord($indexedRow, $columnMap)); 
    5685                } 
     
    71100                // we can't combine runs, as other columns might rely on the relation being present 
    72101                $relations = array(); 
    73                 foreach($record as $key => $val) { 
     102                foreach($record as $origColumnName => $val) { 
     103                        $fieldName = $columnMap[$origColumnName]; 
     104                         
    74105                        // don't bother querying of value is not set 
    75106                        if($this->isNullValue($val)) continue; 
    76107                         
    77108                        // checking for existing relations 
    78                         if(isset($this->relationCallbacks[$key])) { 
     109                        if(isset($this->relationCallbacks[$fieldName])) { 
    79110                                // trigger custom search method for finding a relation based on the given value 
    80111                                // and write it back to the relation (or create a new object) 
    81                                 $relationName = $this->relationCallbacks[$key]['relationname']; 
    82                                 $relationObj = $obj->{$this->relationCallbacks[$key]['callback']}($val, $record); 
     112                                $relationName = $this->relationCallbacks[$fieldName]['relationname']; 
     113                                $relationObj = $obj->{$this->relationCallbacks[$fieldName]['callback']}($val, $record); 
    83114                                if(!$relationObj || !$relationObj->exists()) { 
    84115                                        $relationClass = $obj->has_one($relationName); 
     
    89120                                $obj->{"{$relationName}ID"} = $relationObj->ID; 
    90121                                $obj->write(); 
    91                         } elseif(strpos($key, '.') !== false) { 
     122                        } elseif(strpos($fieldName, '.') !== false) { 
    92123                                // we have a relation column with dot notation 
    93                                 list($relationName,$columnName) = split('\.', $key); 
     124                                list($relationName,$columnName) = split('\.', $fieldName); 
    94125                                $relationObj = $obj->getComponent($relationName); // always gives us an component (either empty or existing) 
    95126                                $obj->setComponent($relationName, $relationObj); 
     
    103134                $id = ($preview) ? 0 : $obj->write(); 
    104135 
    105                  
    106136                // second run: save data 
    107                 foreach($record as $key => $val) { 
    108                         if($this->isNullValue($val, $key)) continue; 
    109                          
    110                         if($obj->hasMethod("import{$key}")) { 
    111                                 $obj->{"import{$key}"}($val, $record); 
    112                         } elseif(strpos($key, '.') !== false) { 
     137                foreach($record as $origColumnName => $val) { 
     138                        $fieldName = $columnMap[$origColumnName]; 
     139 
     140                        if($this->isNullValue($val, $fieldName)) continue; 
     141 
     142                        if($obj->hasMethod("import{$fieldName}")) { 
     143                                $obj->{"import{$fieldName}"}($val, $record); 
     144                        } elseif(strpos($fieldName, '.') !== false) { 
    113145                                // we have a relation column 
    114                                 list($relationName,$columnName) = split('\.', $key); 
     146                                list($relationName,$columnName) = split('\.', $fieldName); 
    115147                                $relationObj = $obj->getComponent($relationName); 
    116148                                $relationObj->{$columnName} = $val; 
    117149                                $relationObj->write(); 
    118150                                $obj->flushCache(); // avoid relation caching confusion 
    119                         } elseif($obj->hasField($key) || $obj->hasMethod($key)) { 
     151                        //} elseif($obj->hasField($fieldName) || $obj->hasMethod($fieldName)) { 
     152                        } else { 
    120153                                // plain old value setter 
    121                                 $obj->{$key} = $val; 
     154                                $obj->{$fieldName} = $val; 
    122155                        } 
    123156                } 
     
    150183                        if(is_string($duplicateCheck)) { 
    151184                                $SQL_fieldName = Convert::raw2sql($duplicateCheck);  
    152                                 $SQL_fieldValue = $record[$columnMap[$fieldName]]; 
     185 
     186                                if(!isset($record[$fieldName])) { 
     187                                        user_error("CsvBulkLoader:processRecord: Couldn't find duplicate identifier '{$fieldName}' in columns", E_USER_ERROR); 
     188                                } 
     189                                $SQL_fieldValue = $record[$fieldName]; 
    153190                                $existingRecord = DataObject::get_one($this->objectClass, "`$SQL_fieldName` = '{$SQL_fieldValue}'"); 
    154191                                if($existingRecord) return $existingRecord; 
    155192                        } elseif(is_array($duplicateCheck) && isset($duplicateCheck['callback'])) { 
    156                                 $existingRecord = singleton($this->objectClass)->{$duplicateCheck['callback']}($val, $record); 
     193                                $existingRecord = singleton($this->objectClass)->{$duplicateCheck['callback']}($record[$fieldName], $record); 
    157194                                if($existingRecord) return $existingRecord; 
    158195                        } else {