Ejemplo n.º 1
0
 /**
  * @param string $liftFilePath
  * @param LexiconProjectModel $projectModel
  * @param LiftMergeRule $mergeRule
  * @param boolean $skipSameModTime
  * @param boolean $deleteMatchingEntry
  * @return \Api\Model\Languageforge\Lexicon\LiftImport
  */
 public function merge($liftFilePath, $projectModel, $mergeRule = LiftMergeRule::CREATE_DUPLICATES, $skipSameModTime = true, $deleteMatchingEntry = false)
 {
     ini_set('max_execution_time', 180);
     // Sufficient time to import webster.  TODO Make this async CP 2014-10
     $entryList = new LexEntryListModel($projectModel);
     $entryList->read();
     $hasExistingData = $entryList->count != 0;
     if (!$hasExistingData) {
         $projectModel->config->clearAllInputSystems();
         // save and clear input systems
         $savedInputSystems = $projectModel->inputSystems->getArrayCopy();
         $projectModel->inputSystems->exchangeArray(array());
     }
     $reader = new \XMLReader();
     $reader->open($liftFilePath);
     $this->liftDecoder = new LiftDecoder($projectModel);
     $this->stats = new LiftImportStats($entryList->count);
     $this->report = new ImportErrorReport();
     $this->liftImportNodeError = new LiftImportNodeError(LiftImportNodeError::FILE, basename($liftFilePath));
     $liftRangeDecoder = new LiftRangeDecoder($projectModel);
     $liftRangeFiles = array();
     // Keys: filenames. Values: parsed files.
     $liftRanges = array();
     // Keys: @id attributes of <range> elements. Values: parsed <range> elements.
     $liftFolderPath = dirname($liftFilePath);
     while ($reader->read()) {
         // Read LIFT ranges in the header of the LIFT file
         if ($reader->nodeType == \XMLReader::ELEMENT && $reader->localName == 'range') {
             $node = $reader->expand();
             $rangeId = $node->attributes->getNamedItem('id')->textContent;
             $rangeHref = $node->attributes->getNamedItem('href')->textContent;
             $hrefPath = parse_url($rangeHref, PHP_URL_PATH);
             $rangeFilename = basename($hrefPath);
             $rangeImportNodeError = new LiftRangeImportNodeError(LiftRangeImportNodeError::FILE, $rangeFilename);
             if (!array_key_exists($rangeFilename, $liftRangeFiles)) {
                 // Haven't parsed the .lift-ranges file yet. We'll assume it is alongside the .lift file.
                 $rangeFilePath = $liftFolderPath . "/" . $rangeFilename;
                 if (file_exists($rangeFilePath)) {
                     $sxeNode = simplexml_load_file($rangeFilePath);
                     $parsedRanges = $liftRangeDecoder->decode($sxeNode);
                     $liftRanges = array_merge($liftRanges, $parsedRanges);
                     $liftRangeFiles[] = $rangeFilename;
                 } else {
                     // Range file was NOT found in alongside the .lift file
                     $rangeImportNodeError->addRangeFileNotFound(basename($liftFilePath));
                 }
             }
             // pull out the referenced range
             if (isset($liftRanges[$rangeId])) {
                 $range = $liftRanges[$rangeId];
             } else {
                 $range = null;
                 if (file_exists($rangeFilePath)) {
                     // Range was NOT found in referenced .lift-ranges file after parsing it
                     $rangeImportNodeError->addRangeNotFound($rangeId);
                 }
             }
             // Range elements defined in LIFT file override any values defined in .lift-ranges file.
             if ($node->hasChildNodes()) {
                 $rangeNode = self::domNode_to_sxeNode($node);
                 $range = $liftRangeDecoder->readRange($rangeNode, $range);
                 $liftRanges[$rangeId] = $range;
             }
             if ($rangeImportNodeError->hasErrors()) {
                 $this->liftImportNodeError->addSubnodeError($rangeImportNodeError);
             }
         }
         // Read the custom 'fields' spec in the header of the LIFT file
         if ($reader->nodeType == \XMLReader::ELEMENT && $reader->localName == 'fields') {
             $isInFieldsSectionOfLift = true;
             $this->liftDecoder->liftFields = array();
             while ($isInFieldsSectionOfLift && $reader->read()) {
                 if ($reader->nodeType == \XMLReader::ELEMENT && $reader->localName == 'field') {
                     $node = $reader->expand();
                     $sxeNode = self::domNode_to_sxeNode($node);
                     $LiftFieldTag = (string) $sxeNode['tag'];
                     $liftField = array();
                     foreach ($sxeNode as $element) {
                         if ($element->getName() === 'form') {
                             $inputSystemTag = (string) $element['lang'];
                             $liftField[$inputSystemTag] = (string) $element->text;
                         }
                     }
                     $this->liftDecoder->liftFields[$LiftFieldTag] = $liftField;
                 } elseif ($reader->nodeType == \XMLReader::END_ELEMENT && $reader->localName == 'fields') {
                     $isInFieldsSectionOfLift = false;
                 }
             }
         }
         // Read an entry node
         if ($reader->nodeType == \XMLReader::ELEMENT && $reader->localName == 'entry') {
             $this->stats->importEntries++;
             $node = $reader->expand();
             $sxeNode = self::domNode_to_sxeNode($node);
             $guid = $reader->getAttribute('guid');
             $existingEntry = $entryList->searchEntriesFor('guid', $guid);
             if ($existingEntry) {
                 $entry = new LexEntryModel($projectModel, $existingEntry['id']);
                 $dateModified = $reader->getAttribute('dateModified');
                 if (self::differentModTime($dateModified, $entry->authorInfo->modifiedDate) || !$skipSameModTime) {
                     if ($mergeRule == LiftMergeRule::CREATE_DUPLICATES) {
                         $entry = new LexEntryModel($projectModel);
                         $this->readEntryWithErrorReport($sxeNode, $entry, $mergeRule);
                         $entry->guid = '';
                         $entry->write();
                         $this->stats->entriesDuplicated++;
                     } else {
                         if (isset($sxeNode->{'lexical-unit'})) {
                             $this->readEntryWithErrorReport($sxeNode, $entry, $mergeRule);
                             $entry->write();
                             $this->stats->entriesMerged++;
                         } elseif (isset($sxeNode->attributes()->dateDeleted) && $deleteMatchingEntry) {
                             LexEntryModel::remove($projectModel, $existingEntry['id']);
                             $this->stats->entriesDeleted++;
                         }
                     }
                 } else {
                     // skip because same mod time and skip enabled
                     if (!isset($sxeNode->{'lexical-unit'}) && isset($sxeNode->attributes()->dateDeleted) && $deleteMatchingEntry) {
                         LexEntryModel::remove($projectModel, $existingEntry['id']);
                         $this->stats->entriesDeleted++;
                     }
                 }
             } else {
                 if (isset($sxeNode->{'lexical-unit'})) {
                     $entry = new LexEntryModel($projectModel);
                     $this->readEntryWithErrorReport($sxeNode, $entry, $mergeRule);
                     $entry->write();
                     $this->stats->newEntries++;
                 }
             }
         }
     }
     $reader->close();
     // put back saved input systems if none found in the imported data
     if (!$hasExistingData && $projectModel->inputSystems->count() <= 0) {
         $projectModel->inputSystems->exchangeArray($savedInputSystems);
     }
     // add lift ranges
     if ($mergeRule != LiftMergeRule::IMPORT_LOSES) {
         foreach ($liftRanges as $liftRangeCode => $liftRange) {
             // add everything except semantic domains
             if (strpos($liftRangeCode, 'semantic-domain') === false) {
                 self::rangeToOptionList($projectModel, $liftRangeCode, LexiconConfigObj::flexOptionlistName($liftRangeCode), $liftRange);
             }
         }
     }
     $this->report->nodeErrors[] = $this->liftImportNodeError;
     if ($this->report->hasError()) {
         error_log($this->report->toString());
     }
     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());
 }