예제 #1
0
 /**
  * Bulk import of model records
  *
  * The actual meat of the import process happens here, this is called recursively via
  * AJAX to import sets of records. This is a refactored and generalized version of the
  * old Contacts importRecords.
  */
 public function actionImportModelRecords()
 {
     if (isset($_POST['count']) && file_exists($path = $this->safePath('data.csv')) && isset($_POST['model'])) {
         ini_set('auto_detect_line_endings', 1);
         // Account for Mac based CSVs if possible
         $importedIds = array();
         $modelName = ucfirst($_POST['model']);
         $count = $_POST['count'];
         // Number of records to import
         $metaData = $_SESSION['metaData'];
         $importMap = $_SESSION['importMap'];
         $fp = fopen($path, 'r+');
         fseek($fp, $_SESSION['offset']);
         // Seek to the right file offset
         // Whether the user has mapped the ID field
         $mappedId = false;
         // validate meta data
         if (!ArrayUtil::setEquals(array_keys($importMap), $metaData)) {
             throw new CHttpException(400, Yii::t('app', 'Bad import map'));
         }
         for ($i = 0; $i < $count; $i++) {
             // Loop through and start importing
             $csvLine = fgetcsv($fp, 0, $_SESSION['delimeter'], $_SESSION['enclosure']);
             if ($csvLine !== false && !is_null($csvLine)) {
                 if ($csvLine === array(null)) {
                     // Skip empty lines
                     continue;
                 }
                 if (count($csvLine) > count($metaData)) {
                     $csvLine = array_slice($csvLine, 0, count($metaData));
                 } else {
                     if (count($csvLine) < count($metaData)) {
                         $csvLine = array_pad($csvLine, count($metaData), null);
                     }
                 }
                 unset($_POST);
                 // Nix all invalid multibyte sequences to avoid errors
                 $csvLine = array_map('Formatter::mbSanitize', $csvLine);
                 if (!empty($metaData) && !empty($csvLine)) {
                     $importAttributes = array_combine($metaData, $csvLine);
                 } else {
                     continue;
                 }
                 // Locate an existing model to update, if requested, otherwise create
                 // a new model to populate
                 $model = new $modelName();
                 foreach ($metaData as $attribute) {
                     if ($importMap[$attribute] === 'id') {
                         $mappedId = true;
                     }
                     $isActionText = $modelName === 'Actions' && $importMap[$attribute] === 'actionDescription';
                     if ($importMap[$attribute] === 'applyTags') {
                         $this->importTags($modelName, $importAttributes[$attribute]);
                         continue;
                     }
                     if (isset($importMap[$attribute]) && ($model->hasAttribute($importMap[$attribute]) || $isActionText)) {
                         $model = $this->importRecordAttribute($modelName, $model, $importMap[$attribute], $importAttributes[$attribute]);
                         $_POST[$importMap[$attribute]] = $model->{$importMap}[$attribute];
                     }
                 }
                 $this->fixupImportedAttributes($modelName, $model);
                 if (!$model->hasErrors() && $model->validate()) {
                     $importedIds = $this->saveImportedModel($model, $modelName, $importedIds);
                 } else {
                     $this->markFailedRecord($model, $csvLine, $metaData);
                 }
             } else {
                 $this->finishImportBatch($modelName, $mappedId, true);
                 return;
             }
         }
         // Change the offset to wherever we got to and continue.
         $_SESSION['offset'] = ftell($fp);
         $this->finishImportBatch($modelName, $mappedId);
     }
 }