/**
  * @param string $targetPath
  * @param string $linkPath
  */
 private function moveExistingFilesAndCreateSymlink($targetPath, $linkPath)
 {
     // target must be a folder (or link to folder)
     if (file_exists($targetPath)) {
         if (!is_dir($targetPath)) {
             unlink($targetPath);
         }
     } else {
         FileUtilities::createAllFolders($targetPath);
     }
     if (file_exists($linkPath)) {
         if (is_dir($linkPath) && !is_link($linkPath)) {
             FileUtilities::copyFolderTree($linkPath, $targetPath);
             FileUtilities::removeFolderAndAllContents($linkPath);
         } else {
             unlink($linkPath);
         }
     }
     FileUtilities::createAllFolders($targetPath);
     symlink($targetPath, $linkPath);
 }
 /**
  *
  * @param string $zipFilePath
  * @param LexProjectModel $projectModel
  * @param string $mergeRule (use LiftMergeRule const)
  * @param boolean $skipSameModTime
  * @param boolean $deleteMatchingEntry
  * @throws \Exception
  * @return 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::copyFolderTree($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->getMessage(), $e->getCode());
     }
     return $this;
 }