/**
  *
  * @param string $zipFilePath
  * @param LexiconProjectModel $projectModel
  * @param LiftMergeRule $mergeRule
  * @param boolean $skipSameModTime
  * @param boolean $deleteMatchingEntry
  * @throws \Exception
  * @return \Api\Model\Languageforge\Lexicon\LiftImport
  */
 public function importZip($zipFilePath, $projectModel, $mergeRule = LiftMergeRule::IMPORT_WINS, $skipSameModTime = false, $deleteMatchingEntry = false)
 {
     $assetsFolderPath = $projectModel->getAssetsFolderPath();
     $extractFolderPath = $assetsFolderPath . '/initialUpload_' . mt_rand();
     $this->report = new ImportErrorReport();
     $zipNodeError = new ZipImportNodeError(ZipImportNodeError::FILE, basename($zipFilePath));
     try {
         self::extractZip($zipFilePath, $extractFolderPath);
         // Now find the .lift file in the uploaded zip
         $dirIter = new \RecursiveDirectoryIterator($extractFolderPath);
         $iterIter = new \RecursiveIteratorIterator($dirIter);
         $liftIter = new \RegexIterator($iterIter, '/\\.lift$/', \RegexIterator::MATCH);
         $liftFilePaths = array();
         foreach ($liftIter as $file) {
             $liftFilePaths[] = $file->getPathname();
         }
         if (empty($liftFilePaths)) {
             throw new \Exception("Uploaded file does not contain any LIFT data");
         }
         if (count($liftFilePaths) > 1) {
             foreach (array_slice($liftFilePaths, 1) as $filename) {
                 $zipNodeError->addUnhandledLiftFile(basename($filename));
             }
         }
         // Import subfolders
         foreach (glob($extractFolderPath . '/*', GLOB_ONLYDIR) as $folderPath) {
             $folderName = basename($folderPath);
             switch ($folderName) {
                 case 'pictures':
                 case 'audio':
                 case 'others':
                 case 'WritingSystems':
                     $assetsPath = $assetsFolderPath . "/" . $folderName;
                     if (file_exists($folderPath) && is_dir($folderPath)) {
                         FileUtilities::copyDirTree($folderPath, $assetsPath);
                     }
                     break;
                 default:
                     $zipNodeError->addUnhandledSubfolder($folderName);
             }
         }
         // Import first .lift file (only).
         $this->liftFilePath = $liftFilePaths[0];
         $this->merge($this->liftFilePath, $projectModel, $mergeRule, $skipSameModTime, $deleteMatchingEntry);
         if ($zipNodeError->hasError()) {
             error_log($zipNodeError->toString() . "\n");
         }
         foreach ($this->report->nodeErrors as $subnodeError) {
             $zipNodeError->addSubnodeError($subnodeError);
         }
         $this->report = new ImportErrorReport();
         $this->report->nodeErrors[] = $zipNodeError;
     } catch (Exception $e) {
         if ($zipNodeError->hasError()) {
             error_log($zipNodeError->toString() . "\n");
         }
         foreach ($this->report->nodeErrors as $subnodeError) {
             $zipNodeError->addSubnodeError($subnodeError);
         }
         $this->report = new ImportErrorReport();
         $this->report->nodeErrors[] = $zipNodeError;
         throw new \Exception($e);
     }
     return $this;
 }
 public function testZipImport_ImportReport_FormatOk()
 {
     $rangeImportNodeError = new LiftRangeImportNodeError(LiftRangeImportNodeError::FILE, 'Test.lift-ranges');
     $rangeImportNodeError->addRangeNotFound('rangeId_01');
     $rangeImportNodeError->addRangeNotFound('rangeId_02');
     $exampleImportNodeError = new LiftImportNodeError(LiftImportNodeError::EXAMPLE, '');
     $exampleImportNodeError->addUnhandledElement('elementName01');
     $senseImportNodeError = new LiftImportNodeError(LiftImportNodeError::SENSE, '00001-00001');
     $senseImportNodeError->addUnhandledField('typeName01');
     $senseImportNodeError->addUnhandledMedia('url01', 'context01');
     $senseImportNodeError->addSubnodeError($exampleImportNodeError);
     $entryImportNodeError = new LiftImportNodeError(LiftImportNodeError::ENTRY, '00000-00001');
     $entryImportNodeError->addUnhandledNote('noteType01');
     $entryImportNodeError->addUnhandledTrait('traitName01');
     $entryImportNodeError->addSubnodeError($senseImportNodeError);
     $liftImportNodeError = new LiftImportNodeError(LiftImportNodeError::FILE, 'Test.lift');
     $liftImportNodeError->addSubnodeError($rangeImportNodeError);
     $liftImportNodeError->addSubnodeError($entryImportNodeError);
     $zipNodeError = new ZipImportNodeError(ZipImportNodeError::FILE, 'Test.zip');
     $zipNodeError->addSubnodeError($liftImportNodeError);
     $report = new ImportErrorReport();
     $report->nodeErrors[] = $zipNodeError;
     //         echo "<pre>";
     //         echo $report->toFormattedString();
     //         echo "</pre>";
     $this->assertRegExp("/" . self::zipImportReport . "/", $report->toFormattedString());
 }