public function match(Record $record)
 {
     $operator = $this->term['operator'];
     $property = Util::generateValidIdentifier($this->term['property']);
     $recordValue = strtolower($record->getProperty($property));
     $conditionValue = strtolower($this->term['value']);
     switch ($operator) {
         case '=':
             return $recordValue == $conditionValue;
             break;
         case '>':
             return $recordValue > $conditionValue;
             break;
         case '<':
             return $recordValue < $conditionValue;
             break;
         case '>=':
             return $recordValue >= $conditionValue;
             break;
         case '<=':
             return $recordValue <= $conditionValue;
             break;
         case '!=':
             return $recordValue != $conditionValue;
             break;
         case '*=':
             $p = strpos($recordValue, $conditionValue);
             if ($p !== false) {
                 return true;
             }
             break;
     }
     return false;
 }
Ejemplo n.º 2
0
 public function setProperty($property, $value)
 {
     $property = Util::generateValidIdentifier($property);
     if ($this->dataTypeDefinition->hasProperty($property, $this->view)) {
         $this->properties[$property] = (string) $value;
     } else {
         throw new CMDLParserException('Unknown property ' . $property, CMDLParserException::CMDL_UNKNOWN_PROPERTY);
     }
     return $this;
 }
Ejemplo n.º 3
0
 public function testListExtraction()
 {
     $result = Util::extractLists('(1:online,2:offline)');
     $this->assertCount(1, $result);
     $this->assertCount(2, $result[0]);
     $result = Util::extractLists('param1 "param 2" param3 (a,b,c)');
     $this->assertCount(1, $result);
     $this->assertArrayHasKey('a', $result[0]);
     $this->assertEquals('a', $result[0]['a']);
     $result = Util::extractLists('(a:dog,horse,c:cow) (green, blue, red ,purple)');
     $this->assertCount(2, $result);
     $this->assertArrayHasKey('a', $result[0]);
     $this->assertArrayHasKey('horse', $result[0]);
     $this->assertArrayHasKey('c', $result[0]);
     $this->assertContains('green', $result[1]);
     $this->assertContains('blue', $result[1]);
     $this->assertContains('red', $result[1]);
     $this->assertContains('purple', $result[1]);
     $result = Util::extractLists('(a:"Lassy",\'Black Beauty \',c: Milka Cow )');
     $this->assertCount(1, $result);
     $this->assertContains('Lassy', $result[0]);
     $this->assertContains('Black Beauty ', $result[0]);
     $this->assertContains('Milka Cow', $result[0]);
 }
 public static function normalizeFilterQuery(Application $app, $query, ContentTypeDefinition $contentTypeDefinition)
 {
     $query = str_replace('><', '*=', $query);
     try {
         $condition = self::parseCondition($query);
         if (is_array($condition) && count($condition) == 3) {
             $property = Util::generateValidIdentifier($condition[0]);
             if (!$contentTypeDefinition->hasProperty($property)) {
                 $app['context']->addAlertMessage('Cannot filter by property ' . $property . '.');
                 $query = '';
             }
         } else {
             $query = 'name *= ' . $query;
         }
         $filter = new PropertyFilter($query);
     } catch (\Exception $e) {
         $app['context']->addAlertMessage('Could not parse query.');
         $app['context']->setCurrentSearchTerm('');
         //$query  = '';
         $filter = '';
     }
     //$app['context']->setCurrentSearchTerm($query);
     return $filter;
 }
 protected function getConfigTypeTableName($ensureConfigTypeTableIsPresent = true)
 {
     $repository = $this->getRepository();
     $repositoryName = $repository->getName();
     $tableName = $repositoryName . '$$config';
     if ($tableName != Util::generateValidIdentifier($repositoryName) . '$$config') {
         throw new AnyContentClientException('Invalid repository name ' . $repositoryName);
     }
     if ($ensureConfigTypeTableIsPresent == true) {
         $this->ensureConfigTypeTableIsPresent();
     }
     return $tableName;
 }
 /**
  * remove protected properties and execute @name annotation
  *
  * @param Record $record
  */
 protected function finalizeRecord(Record $record, DataDimensions $dataDimensions)
 {
     // Apply @name annotation
     if ($record->getDataTypeDefinition()->hasNamingPattern()) {
         $record->setName(Util::applyNamingPattern($record->getProperties(), $record->getDataTypeDefinition()->getNamingPattern()));
     }
     // remove protected properties
     $properties = $record->getProperties();
     foreach ($record->getDataTypeDefinition()->getProtectedProperties($dataDimensions->getViewName()) as $property) {
         unset($properties[$property]);
     }
     $record->setProperties($properties);
     return $record;
 }
 public function createRepository($repositoryName)
 {
     if ($repositoryName != Util::generateValidIdentifier($repositoryName)) {
         throw new RepositoryException('Invalid repository name.');
     }
     $filename = $this->getCMDLDirectory();
     @mkdir($filename . '/' . $repositoryName);
     $this->repositories = null;
     return true;
 }
 public function saveConfig($configTypeDefinition, $properties, $workspace = 'default', $language = 'default')
 {
     $repositoryName = $this->repository->getName();
     $configTypeName = $configTypeDefinition->getName();
     $tableName = $repositoryName . '$$config';
     if ($tableName != Util::generateValidIdentifier($repositoryName) . '$$config') {
         throw new RepositoryException('Invalid repository and/or config type name(s).');
     }
     $possibleProperties = $configTypeDefinition->getProperties();
     $notallowed = array_diff(array_keys($properties), $possibleProperties);
     if (count($notallowed) != 0) {
         throw new RepositoryException('Trying to store undefined properties: ' . join(',', $notallowed) . '.', RepositoryException::REPOSITORY_INVALID_PROPERTIES);
     }
     $mandatoryProperties = $configTypeDefinition->getMandatoryProperties('default');
     $missing = array();
     foreach ($mandatoryProperties as $property) {
         if (array_key_exists($property, $properties)) {
             if ($properties[$property] == '') {
                 $missing[] = $property;
             }
         } else {
             $missing[] = $property;
         }
     }
     if (count($missing) != 0) {
         throw new RepositoryException('Trying to store config, but missing mandatory properties: ' . join(',', $missing) . '.', RepositoryException::REPOSITORY_MISSING_MANDATORY_PROPERTIES);
     }
     $dbh = $this->repository->getDatabaseConnection();
     $timestamp = time();
     $timeshiftTimestamp = $this->repository->getTimeshiftTimestamp();
     // get current revision
     $revision = 0;
     try {
         $record = $this->getConfig($configTypeName, $workspace, $language);
         $revision = $record['record']['info']['revision'];
     } catch (RepositoryException $e) {
         // never mind we don't need an existing record
     }
     // invalidate current revision
     $sql = 'UPDATE ' . $tableName . ' SET validuntil_timestamp = ? WHERE id = ? AND workspace = ? AND language = ? AND validfrom_timestamp <=? AND validuntil_timestamp >?';
     $params = array();
     $params[] = $timeshiftTimestamp;
     $params[] = $configTypeName;
     $params[] = $workspace;
     $params[] = $language;
     $params[] = $timeshiftTimestamp;
     $params[] = $timeshiftTimestamp;
     $stmt = $dbh->prepare($sql);
     $stmt->execute($params);
     $values = array();
     $values['id'] = $configTypeName;
     $values['hash'] = md5(serialize($properties));
     $values['workspace'] = $workspace;
     $values['language'] = $language;
     $values['revision'] = $revision + 1;
     $values['properties'] = json_encode($properties);
     $values['lastchange_timestamp'] = $timestamp;
     $values['lastchange_apiuser'] = $this->repository->getAPIUser();
     $values['lastchange_clientip'] = $this->repository->getClientIp();
     $values['lastchange_username'] = $this->repository->getCurrentUserName();
     $values['lastchange_firstname'] = $this->repository->getCurrentUserFirstname();
     $values['lastchange_lastname'] = $this->repository->getCurrentUserLastname();
     $values['validfrom_timestamp'] = $timeshiftTimestamp;
     $values['validuntil_timestamp'] = $this->repository->getMaxTimestamp();
     $sql = 'INSERT INTO ' . $tableName;
     $sql .= ' (' . join(',', array_keys($values)) . ')';
     $sql .= ' VALUES ( ?';
     $sql .= str_repeat(' , ?', count($values) - 1);
     $sql .= ')';
     $stmt = $dbh->prepare($sql);
     $stmt->execute(array_values($values));
     return true;
 }
 public static function adminAddConfigType(Application $app, Request $request, $repositoryAccessHash)
 {
     $url = $app['url_generator']->generate('admin');
     /** @var RepositoryManager $repositoryManager */
     $repositoryManager = $app['repos'];
     /** @var Repository $repository */
     $repository = $repositoryManager->getRepositoryByRepositoryAccessHash($repositoryAccessHash);
     if ($repository) {
         $configTypeName = substr(trim($request->request->get('create_config_type')), 0, 32);
         $configTypeName = Util::generateValidIdentifier($configTypeName);
         if ($configTypeName != '') {
             if (!$repository->hasConfigType($configTypeName)) {
                 $connection = $repository->getWriteConnection();
                 if ($connection->saveConfigTypeCMDL($configTypeName, '### definition of config type ' . $configTypeName . ' ###' . PHP_EOL)) {
                     $app['context']->addSuccessMessage('Config Type ' . $configTypeName . ' created.');
                     $app['menus']->clearCache();
                     return new RedirectResponse($url);
                 }
             } else {
                 $app['context']->addAlertMessage('Config Type ' . $configTypeName . ' already exists.');
             }
         }
     }
     $app['context']->addErrorMessage('Error generating new config type.');
     return new RedirectResponse($url);
 }
 public static function getMany(Application $app, Request $request, $repositoryName, $contentTypeName, $workspace = 'default', $clippingName = 'default', $language = 'default')
 {
     $timeshift = 0;
     $orderBy = 'id ASC';
     $limit = null;
     $page = 1;
     $subset = null;
     $filter = null;
     /** @var $repository Repository */
     $repository = $app['repos']->get($repositoryName);
     if ($repository) {
         $manager = $repository->getContentManager($contentTypeName);
         if ($manager) {
             if ($request->query->has('timeshift')) {
                 $timeshift = (int) $request->get('timeshift');
             }
             if ($request->query->has('language')) {
                 $language = $request->get('language');
             }
             if ($request->query->has('order')) {
                 if ($request->get('order') == 'property') {
                     $properties = explode(',', $request->get('properties'));
                     $orderBy = '';
                     foreach ($properties as $property) {
                         if ($manager->hasProperty(Util::generateValidIdentifier($property), $clippingName)) {
                             if (substr(trim($property), -1) == '-') {
                                 $orderBy .= 'property_' . Util::generateValidIdentifier($property) . ' DESC, ';
                             } else {
                                 $orderBy .= 'property_' . Util::generateValidIdentifier($property) . ' ASC, ';
                             }
                         } else {
                             return self::badRequest($app, self::UNKNOWN_PROPERTY, $repositoryName, $contentTypeName, $clippingName, $property);
                         }
                     }
                     $orderBy .= ' id ASC';
                 } else {
                     switch ($request->get('order')) {
                         case 'id':
                             $orderBy = 'id ASC';
                             break;
                         case 'id-':
                             $orderBy = 'id DESC';
                             break;
                         case 'name':
                             $orderBy = 'property_name ASC, id ASC';
                             break;
                         case 'name-':
                             $orderBy = 'property_name DESC, id ASC';
                             break;
                         case 'pos':
                             $orderBy = 'position ASC, id ASC';
                             break;
                         case 'pos-':
                             $orderBy = 'position DESC, id ASC';
                             break;
                         case 'change':
                             // reversed order for token "change", since usually you want to see the latest changes first
                             $orderBy = 'lastchange_timestamp DESC, id ASC';
                             break;
                         case 'change-':
                             $orderBy = 'lastchange_timestamp ASC, id DESC';
                             break;
                         case 'creation':
                             $orderBy = 'creation_timestamp ASC, id ASC';
                             break;
                         case 'creation-':
                             $orderBy = 'creation_timestamp DESC, id DESC';
                             break;
                         case 'status':
                             $orderBy = 'property_status ASC, id ASC';
                             break;
                         case 'status-':
                             $orderBy = 'property_status DESC, id ASC';
                             break;
                         case 'subtype':
                             $orderBy = 'property_subtype ASC, id ASC';
                             break;
                         case 'subtype-':
                             $orderBy = 'property_subtype DESC, id ASC';
                             break;
                     }
                 }
             }
             if ($request->query->has('limit')) {
                 $limit = (int) $request->get('limit');
                 if ($request->query->has('page')) {
                     $page = (int) $request->get('page');
                 }
             }
             if ($request->query->has('subset')) {
                 $subset = $request->get('subset');
             }
             if ($request->query->has('filter')) {
                 if (is_array($request->query->get('filter'))) {
                     $filter = FilterFactory::createFromArray($request->query->get('filter'));
                 } else {
                     $filter = FilterFactory::createFromQuery($request->query->get('filter'));
                 }
             }
             $records = $manager->getRecords($clippingName, $workspace, $orderBy, $limit, $page, $subset, $filter, $language, $timeshift);
             return $app->json($records);
         } else {
             return self::notFoundError($app, self::UNKNOWN_CONTENTTYPE, $repositoryName, $contentTypeName);
         }
     }
     return self::notFoundError($app, self::UNKNOWN_REPOSITORY, $repositoryName);
 }
 public function truncateConfigType($repositoryName, $configTypeName)
 {
     $tableName = $repositoryName . '$$config';
     if ($configTypeName != Util::generateValidIdentifier($configTypeName) || $repositoryName != Util::generateValidIdentifier($repositoryName)) {
         throw new \Exception('Invalid repository and/or config type name(s).', self::INVALID_NAMES);
     }
     $dbh = $this->getConnection();
     $sql = 'DELETE FROM ' . $tableName . ' WHERE id = ?';
     $stmt = $dbh->prepare($sql);
     $params = array();
     $params[] = $configTypeName;
     try {
         $stmt->execute($params);
     } catch (\PDOException $e) {
         return false;
     }
     return true;
 }
 public function sortRecords($list, $workspace = 'default', $language = 'default')
 {
     $repositoryName = $this->repository->getName();
     $contentTypeName = $this->contentTypeDefinition->getName();
     $tableName = $repositoryName . '$' . $contentTypeName;
     if ($tableName != Util::generateValidIdentifier($repositoryName) . '$' . Util::generateValidIdentifier($contentTypeName)) {
         throw new \Exception('Invalid repository and/or content type name(s).', self::INVALID_NAMES);
     }
     $dbh = $this->repository->getDatabaseConnection();
     $tempTableName = $tableName . '_' . substr(md5(uniqid(microtime(), true)), 0, 8);
     $timeshiftTimestamp = $this->repository->getTimeshiftTimestamp();
     $sql = 'CREATE TEMPORARY TABLE ' . $tempTableName . ' SELECT * FROM ' . $tableName . ' WHERE workspace = ? AND language = ? AND validfrom_timestamp <= ? AND validuntil_timestamp > ? AND deleted=0';
     $params = array();
     $params[] = $workspace;
     $params[] = $language;
     $params[] = $timeshiftTimestamp;
     $params[] = $timeshiftTimestamp;
     $stmt = $dbh->prepare($sql);
     $stmt->execute($params);
     $sql = 'UPDATE ' . $tempTableName . ' SET parent_id = null, position=null, position_left = null, position_right = null, position_level = null';
     $params = array();
     $stmt = $dbh->prepare($sql);
     $stmt->execute($params);
     $transform = new AdjacentList2NestedSet($list);
     $transform->traverse(0);
     $nestedSet = $transform->getNestedSet();
     $pos = 0;
     $ids = array();
     foreach ($nestedSet as $id => $item) {
         $ids[] = $id;
         $pos++;
         $sql = 'UPDATE ' . $tempTableName . ' SET parent_id = ?, position=?, position_left = ?, position_right = ?, position_level = ? WHERE id = ?';
         $params = array();
         $params[] = $item['parent_id'];
         $params[] = $pos;
         $params[] = $item['left'];
         $params[] = $item['right'];
         $params[] = $item['level'];
         $stmt = $dbh->prepare($sql);
         $params[] = $id;
         $stmt->execute($params);
     }
     // end validity of all current records
     $sql = 'UPDATE ' . $tableName . ' SET validuntil_timestamp = ? WHERE workspace = ? AND language = ? AND validfrom_timestamp <= ? AND validuntil_timestamp > ? AND deleted=0';
     $timeshiftTimestamp = $this->repository->getTimeshiftTimestamp();
     $params = array();
     $params[] = $timeshiftTimestamp;
     $params[] = $workspace;
     $params[] = $language;
     $params[] = $timeshiftTimestamp;
     $params[] = $timeshiftTimestamp;
     $stmt = $dbh->prepare($sql);
     $stmt->execute($params);
     // set validity of all new records
     $sql = 'UPDATE ' . $tempTableName . ' SET revision=revision+1, validfrom_timestamp = ?';
     $params = array();
     $params[] = $timeshiftTimestamp;
     $stmt = $dbh->prepare($sql);
     $stmt->execute($params);
     // Merge back
     $stmt = $dbh->prepare('INSERT INTO ' . $tableName . ' SELECT * FROM ' . $tempTableName);
     $stmt->execute();
     $stmt = $dbh->prepare('DROP TABLE ' . $tempTableName);
     $stmt->execute();
     //self::_updateContentInfo($content_type, $workspace);
     return true;
 }
 public function createRepository($repositoryName)
 {
     if ($repositoryName != Util::generateValidIdentifier($repositoryName)) {
         throw new RepositoryException('Invalid repository name.');
     }
     if (!$this->hasRepository($repositoryName)) {
         /** @var PDO $db */
         $dbh = $this->app['db']->getConnection();
         $sql = 'INSERT INTO _cmdl_ (repository) VALUES (?)';
         $stmt = $dbh->prepare($sql);
         try {
             $stmt->execute(array($repositoryName));
         } catch (\PDOException $e) {
         }
     }
     $this->repositories = null;
     return true;
 }
Ejemplo n.º 14
0
 public static function parseAnnotation(DataTypeDefinition $dataTypeDefinition, FormElementDefinitionCollection $currentFormElementDefinitionCollection, $line)
 {
     $p = strpos($line, ' ');
     if ($p) {
         $annotationName = trim(substr($line, 1, $p));
         $onTheRight = substr($line, $p + 1);
         $lists = Util::extractLists($onTheRight);
         $params = Util::extractParams($onTheRight);
         $numericalLists = Util::extractLists($onTheRight, true);
     } else {
         $annotationName = substr($line, 1);
         $lists = array();
         $params = array();
         $numericalLists = array();
     }
     switch ($annotationName) {
         case 'title':
             $annotation = new DataTypeTitleAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'description':
             $annotation = new DataTypeDescriptionAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'name':
             $annotation = new ContentTypeNameAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'languages':
             $annotation = new DataTypeLanguagesAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'status':
             $annotation = new ContentTypeStatusAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'subtypes':
             $annotation = new ContentTypeSubtypesAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'workspaces':
             $annotation = new DataTypeWorkspacesAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'sortable':
             $annotation = new DataTypeSortableAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'time-shiftable':
             $annotation = new DataTypeTimeShiftableAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'default-value':
             $annotation = new FormElementDefaultValueAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'help':
             $annotation = new FormElementHelpAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'hint':
             $annotation = new FormElementHintAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'info':
             $annotation = new FormElementInfoAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'placeholder':
             $annotation = new FormElementPlaceholderAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'hidden-properties':
             $annotation = new FormElementCollectionHiddenPropertiesAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'insert':
             $annotation = new InsertAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists);
             break;
         case 'custom':
             $annotation = new CustomAnnotation($dataTypeDefinition, $currentFormElementDefinitionCollection, $params, $lists, $numericalLists);
             break;
         default:
             throw new CMDLParserException('Unknown annotation ' . $annotationName . '.', CMDLParserException::CMDL_UNKNOWN_ANNOTATION);
             break;
     }
     $dataTypeDefinition = $annotation->apply();
     return $dataTypeDefinition;
 }
 public function importXLSX(Repository $repository, $contentTypeName, $filename, $workspace = 'default', $language = 'default', $viewName = 'exchange')
 {
     $this->count = 0;
     $this->records = null;
     $this->stash = array();
     $this->error = false;
     $repository->selectContentType($contentTypeName);
     // Select view and fallback if necessary
     $contentTypeDefinition = $repository->getContentTypeDefinition();
     $viewDefinition = $contentTypeDefinition->getExchangeViewDefinition($viewName);
     $viewName = $viewDefinition->getName();
     $repository->selectWorkspace($workspace);
     $repository->selectLanguage($language);
     $repository->selectView($viewName);
     $objPHPExcel = \PHPExcel_IOFactory::load($filename);
     if ($objPHPExcel) {
         if ($this->isTruncateRecords()) {
             $this->deleteEffectiveRecords($repository, $workspace, $viewName, $language);
         }
         $objWorksheet = $objPHPExcel->getActiveSheet();
         $highestRow = $objWorksheet->getHighestRow();
         // e.g. 10
         $highestColumn = $objWorksheet->getHighestColumn();
         // e.g 'F'
         $highestColumnIndex = \PHPExcel_Cell::columnIndexFromString($highestColumn);
         // e.g. 5
         $idColumnIndex = null;
         $propertiesColumnIndices = array();
         for ($i = 0; $i <= $highestColumnIndex; $i++) {
             $value = trim($objWorksheet->getCellByColumnAndRow($i, 1)->getValue());
             if ($value != '') {
                 if (substr($value, 0, 1) == '.') {
                     if ($value == '.id') {
                         $idColumnIndex = $i;
                     }
                 } else {
                     $value = Util::generateValidIdentifier($value);
                     if ($contentTypeDefinition->hasProperty($value, $viewName)) {
                         $this->writeln('Detected valid property ' . $value);
                         $propertiesColumnIndices[$value] = $i;
                     }
                 }
             }
         }
         $this->writeln('');
         if (count($propertiesColumnIndices) != 0) {
             for ($row = 2; $row <= $highestRow; ++$row) {
                 $id = null;
                 if ($idColumnIndex !== null) {
                     if (!$this->isGenerateNewIDs()) {
                         $id = $objWorksheet->getCellByColumnAndRow($idColumnIndex, $row)->getValue();
                     }
                 }
                 $properties = array();
                 foreach ($propertiesColumnIndices as $property => $col) {
                     $value = $objWorksheet->getCellByColumnAndRow($col, $row)->getValue();
                     $properties[$property] = $value;
                 }
                 $record = new Record($contentTypeDefinition, 'Imported Record', $viewName, $workspace, $language);
                 $record->setProperties($properties);
                 $record->setID($id);
                 $msg = $this->stashRecord($repository, $record, $workspace, $viewName, $language);
                 $this->writeln($msg);
             }
             $this->writeln('');
             $this->writeln('Found ' . $this->count . ' records to import');
             $this->writeln('');
             if ($this->count != 0) {
                 $this->writeln('Starting bulk import');
                 $this->writeln('');
                 $this->saveRecords($repository);
                 $this->writeln('');
                 $this->writeln('');
             }
         } else {
             $this->writeln('Excel does not contain matching property columns.');
         }
     } else {
         $this->writeln('Error parsing Excel file.');
         $this->error = true;
     }
     return !$this->error;
 }