コード例 #1
0
 /**
  * Akce pro vytvoření nového atributu
  * @SWG\Post(
  *   tags={"Attributes"},
  *   path="/attributes",
  *   summary="Create new attribute using defined preprocessing",
  *   consumes={"application/json","application/xml"},
  *   produces={"application/json","application/xml"},
  *   security={{"apiKey":{}},{"apiKeyHeader":{}}},
  *   @SWG\Parameter(
  *     description="New attribute",
  *     name="body",
  *     required=true,
  *     @SWG\Schema(ref="#/definitions/NewAttributeInput"),
  *     in="body"
  *   ),
  *   @SWG\Response(
  *     response=201,
  *     description="Attribute created",
  *     @SWG\Schema(
  *       ref="#/definitions/AttributeResponse"
  *     )
  *   ),
  *   @SWG\Response(
  *     response=400,
  *     description="Invalid API key supplied",
  *     @SWG\Schema(ref="#/definitions/StatusResponse")
  *   )
  * )
  * @throws \InvalidArgumentException
  */
 public function actionCreate()
 {
     /** @var array $inputData */
     $inputData = $this->input->getData();
     $miner = $this->findMinerWithCheckAccess(@$inputData['miner']);
     $this->minersFacade->checkMinerMetasource($miner);
     $currentUser = $this->getCurrentUser();
     //aktualizace informace o datových sloupcích
     $this->datasourcesFacade->updateDatasourceColumns($miner->datasource, $currentUser);
     try {
         if (!empty($inputData['column'])) {
             $datasourceColumn = $this->datasourcesFacade->findDatasourceColumn($miner->datasource, @$inputData['column']);
         } else {
             $datasourceColumn = $this->datasourcesFacade->findDatasourceColumnByName($miner->datasource, @$inputData['columnName']);
         }
     } catch (\Exception $e) {
         throw new InvalidArgumentException("Datasource columns was not found: " . @$inputData['columnName']);
     }
     //inicializace formátu
     $format = $datasourceColumn->format;
     if (!$format) {
         //TODO implementovat podporu automatického mapování
         $format = $this->metaAttributesFacade->simpleCreateMetaAttributeWithFormatFromDatasourceColumn($datasourceColumn, $currentUser);
         $datasourceColumn->format = $format;
         $this->datasourcesFacade->saveDatasourceColumn($datasourceColumn);
     }
     //vytvoření nového atributu
     $attribute = new Attribute();
     $attribute->metasource = $miner->metasource;
     $attribute->datasourceColumn = $datasourceColumn;
     $attribute->name = $this->minersFacade->prepareNewAttributeName($miner, $inputData['name']);
     $attribute->type = $attribute->datasourceColumn->type;
     if (@$inputData['specialPreprocessing'] == Preprocessing::SPECIALTYPE_EACHONE) {
         $preprocessing = $this->metaAttributesFacade->findPreprocessingEachOne($datasourceColumn->format);
         $attribute->preprocessing = $preprocessing;
     } else {
         throw new \BadMethodCallException('Selected preprocessing type is not supported.');
         //FIXME je nutné nalézt příslušný preprocessing...
     }
     $attribute->active = false;
     $this->metasourcesFacade->saveAttribute($attribute);
     //inicializace preprocessingu
     $metasourceTask = $this->metasourcesFacade->startAttributesPreprocessing($miner->metasource, [$attribute]);
     while ($metasourceTask && $metasourceTask->state != MetasourceTask::STATE_DONE) {
         $metasourceTask = $this->metasourcesFacade->preprocessAttributes($metasourceTask);
     }
     //smazání předzpracovávací úlohy
     $this->metasourcesFacade->deleteMetasourceTask($metasourceTask);
     $this->setXmlMapperElements('attribute');
     $this->resource = $attribute->getDataArr();
     $this->sendResource();
 }
コード例 #2
0
 /**
  * Akce pro ověření přihlášeného uživatele
  * @param string $dbType
  * @SWG\Get(
  *   tags={"Databases"},
  *   path="/databases/{dbType}",
  *   summary="Get user access credentials for MySQL and other databases",
  *   produces={"application/json","application/xml"},
  *   security={{"apiKey":{}},{"apiKeyHeader":{}}},
  *   @SWG\Parameter(
  *     name="dbType",
  *     description="Type of database",
  *     required=true,
  *     type="string",
  *     in="path",
  *     enum={"limited","unlimited","mysql"}
  *   ),
  *   @SWG\Response(
  *     response=200,
  *     description="Connection params",
  *     @SWG\Schema(
  *       required={"server","username","password","database"},
  *       @SWG\Property(property="server",type="string",description="DB Server (IP or URL)"),
  *       @SWG\Property(property="port",type="integer",description="DB server port (empty if default)"),
  *       @SWG\Property(property="username",type="string",description="Database username"),
  *       @SWG\Property(property="password",type="string",description="Database password"),
  *       @SWG\Property(property="database",type="string",description="Database name"),
  *     )
  *   ),
  *   @SWG\Response(
  *     response=400,
  *     description="Invalid API key supplied",
  *     @SWG\Schema(ref="#/definitions/StatusResponse")
  *   )
  * )
  */
 public function actionRead($dbType)
 {
     $this->setXmlMapperElements('database');
     $dbType = strtolower($dbType);
     //kontrola toho, kdy byl naposled kontrolován přístup k DB
     if ($this->currentUser->getLastDbCheck($dbType) < time() - DatabaseFactory::DB_AVAILABILITY_CHECK_INTERVAL) {
         $this->currentUser->setLastDbCheck($dbType, time());
         $this->usersFacade->saveUser($this->currentUser);
         //TODO tahle kontrola by ještě měla být optimalizovaná
         $dbAvailabilityCheck = true;
     } else {
         $dbAvailabilityCheck = false;
     }
     //připravení informací o datovém zdroji pro konkrétního uživatele...
     $datasource = $this->datasourcesFacade->prepareNewDatasourceForUser($dbType, $this->currentUser, !$dbAvailabilityCheck);
     $dbConnection = $datasource->getDbConnection();
     #region sestavení data arr
     $result = [];
     if (!empty($dbConnection->dbServer)) {
         $result['server'] = $dbConnection->dbServer;
     }
     if (!empty($dbConnection->dbApi)) {
         $result['api'] = $dbConnection->dbApi;
     }
     if (!empty($dbConnection->dbPort)) {
         $result['port'] = $dbConnection->dbPort;
     }
     #endregion sestavení data arr
     $arr =& $result;
     if (!empty($datasource->dbUsername)) {
         $arr['username'] = $datasource->dbUsername;
     }
     $dbPassword = $datasource->getDbPassword();
     if (!empty($dbPassword)) {
         $arr['password'] = $dbPassword;
     }
     if (!empty($datasource->dbName)) {
         $arr['database'] = $datasource->dbName;
     }
     $this->resource = $arr;
     $this->sendResource();
 }
コード例 #3
0
 /**
  * Signál vracející přejmenovávací dialog
  * @param int $datasource
  * @param int $column
  */
 public function handleGetDatasourceColumnRenameDialog($datasource, $column)
 {
     $this->template->showDatasourceColumnRenameDialog = true;
     $datasourceColumn = $this->datasourcesFacade->findDatasourceColumn($datasource, $column);
     /** @var Form $form */
     $form = $this->getComponent('datasourceColumnRenameDialog');
     $form->setDefaults(array('name' => $datasourceColumn->name, 'datasource' => $datasource, 'column' => $column));
     if ($this->presenter->isAjax()) {
         $this->redrawControl('datasourceColumnRenameDialog');
     }
 }
コード例 #4
0
 /**
  * Formulář pro vytvoření nového formátu
  * @return Form
  */
 protected function createComponentNewFormatForm()
 {
     $form = new Form();
     $form->addHidden('datasource');
     $form->addHidden('column');
     $metaAttribute = $form->addHidden('metaAttribute');
     $form->addText('metaAttributeName', 'Meta-attribute:')->setAttribute('readonly', 'readonly')->setAttribute('class', 'normalWidth');
     $formatName = $form->addText('formatName', 'Format name:')->setRequired()->setAttribute('class', 'normalWidth');
     $formatName->addRule(Form::MIN_LENGTH, 'Min length of format name is %s characters!', 3);
     $formatName->addRule(function (TextInput $control) use($metaAttribute) {
         try {
             $format = $this->metaAttributesFacade->findFormatByName($metaAttribute->value, $control->value);
             ///XXX
             if ($format instanceof Format) {
                 return false;
             }
         } catch (\Exception $e) {
             /*chybu ignorujeme (nenalezený metaatribut je OK)*/
         }
         return true;
     }, 'Format with this name already exists!');
     $form->addCheckbox('formatShared', 'Create shared (standard) format');
     $form->addSelect('formatType', 'Values range:', array('interval' => 'Continuous values (interval)', 'values' => 'Distinct values (enumeration)'))->setAttribute('class', 'normalWidth')->setDefaultValue('values');
     $submit = $form->addSubmit('create', 'Create format');
     $submit->setValidationScope(array($formatName));
     $submit->onClick[] = function (SubmitButton $button) {
         $values = $button->form->values;
         try {
             $datasourceColumn = $this->datasourcesFacade->findDatasourceColumn($values->datasource, $values->column);
             $metaAttribute = $this->metaAttributesFacade->findMetaAttribute($values->metaAttribute);
             $datasource = $this->datasourcesFacade->findDatasource($values->datasource);
             $this->databasesFacade->openDatabase($datasource->getDbConnection());
             $datasourceColumnValuesStatistic = $this->databasesFacade->getColumnValuesStatistic($datasource->dbTable, $datasourceColumn->name);
             $format = $this->metaAttributesFacade->createFormatFromDatasourceColumn($metaAttribute, $values->formatName, $datasourceColumn, $datasourceColumnValuesStatistic, @$values->formatType, @$values->formatShared);
             $datasourceColumn->format = $format;
             $this->datasourcesFacade->saveDatasourceColumn($datasourceColumn);
         } catch (\Exception $e) {
             $this->flashMessage($this->translator->translate('Format creation failed.'));
         }
         $this->redirect('Close');
     };
     $storno = $form->addSubmit('storno', 'Storno');
     $storno->setValidationScope(array());
     $storno->onClick[] = function (SubmitButton $button) {
         $values = $button->form->values;
         $this->redirect('SelectFormat', array('datasource' => $values->datasource, 'column' => $values->column, 'metaAttribute' => $values->metaAttribute));
     };
     $form->onError[] = function (Form $form) {
         $values = $form->values;
         $this->handleNewFormat($values->datasource, $values->column, $values->metaAttribute);
     };
     return $form;
 }
コード例 #5
0
 /**
  * Funkce pro nalezení datového zdroje s kontrolou oprávnění přístupu
  * @param int $datasourceId
  * @throws BadRequestException
  * @return Datasource
  */
 private function findDatasourceWithCheckAccess($datasourceId)
 {
     try {
         $datasource = $this->datasourcesFacade->findDatasource($datasourceId);
         if (!$this->datasourcesFacade->checkDatasourceAccess($datasource, $this->getCurrentUser())) {
             throw new BadRequestException("You are not authorized to use the selected datasource!");
         }
     } catch (\Exception $e) {
         throw new BadRequestException("Requested datasource was not found or is not accessible!");
     }
     return $datasource;
 }
コード例 #6
0
 /**
  * Akce vracející data description a konfiguraci pro EasyMiner UI
  * @param int $id_dm
  * @param int $miner
  * @throws ForbiddenRequestException
  */
 public function actionGetData($id_dm, $miner)
 {
     if (empty($miner)) {
         $miner = $id_dm;
     }
     //------------------------------------------------------------------------------------------------------------------
     $miner = $this->findMinerWithCheckAccess($miner);
     $minerType = $miner->type;
     $FLPathElement = 'FLPath_' . Strings::upper($minerType);
     //------------------------------------------------------------------------------------------------------------------
     #region připravení informací pro UI - s odděleným připravením DataDictionary
     $dataDescriptionPMML = null;
     $dataParser = new DataParser($dataDescriptionPMML, $this->config->{$FLPathElement}, $this->config->FGCPath, null, null, $this->translator->getLang());
     $dataParser->loadData();
     $responseContent = $dataParser->parseData();
     $user = $this->getCurrentUser();
     $responseContent['DD'] = ['dataDictionary' => $this->datasourcesFacade->exportDataDictionaryArr($miner->datasource, $user, $rowsCount), 'transformationDictionary' => $this->metasourcesFacade->exportTransformationDictionaryArr($miner->metasource, $user), 'recordCount' => $rowsCount];
     #endregion připravení informací pro UI - s odděleným připravením DataDictionary
     uksort($responseContent['DD']['transformationDictionary'], function ($a, $b) {
         return strnatcasecmp($a, $b);
     });
     uksort($responseContent['DD']['dataDictionary'], function ($a, $b) {
         return strnatcasecmp($a, $b);
         //return strnatcasecmp(mb_strtolower($a,'utf-8'),mb_strtolower($b,'utf-8'));
     });
     $responseContent['status'] = 'ok';
     $responseContent['miner_type'] = $miner->type;
     $responseContent['miner_name'] = $miner->name;
     if ($miner->ruleSet) {
         $ruleSet = $miner->ruleSet;
     } else {
         $ruleSet = $this->ruleSetsFacade->saveNewRuleSetForUser($miner->name, $this->getCurrentUser());
         $miner->ruleSet = $ruleSet;
         $this->minersFacade->saveMiner($miner);
     }
     $responseContent['miner_ruleset'] = ['id' => $ruleSet->ruleSetId, 'name' => $ruleSet->name];
     $responseContent['miner_config'] = $miner->getExternalConfig();
     $this->sendJsonResponse($responseContent);
 }
コード例 #7
0
 /**
  * Funkce vracející formulář pro vytvoření atributu na základě vybraného sloupce a preprocessingu
  * @return Form
  */
 protected function createComponentNewAttributeForm()
 {
     $form = new Form();
     $presenter = $this;
     $form->setTranslator($this->translator);
     $form->addHidden('miner');
     $form->addHidden('column');
     $form->addHidden('preprocessing');
     $form->addText('attributeName', 'Attribute name:')->setRequired('Input attribute name!')->addRule(Form::PATTERN, 'Attribute name can contain only letters, numbers and _ and has start with a letter.', '[a-zA-Z]{1}\\w*')->addRule(function (TextInput $input) {
         //kontrola, jestli již existuje atribtu se zadaným názvem
         $values = $input->getForm(true)->getValues();
         $miner = $this->findMinerWithCheckAccess($values->miner);
         $attributes = $miner->metasource->attributes;
         if (!empty($attributes)) {
             foreach ($attributes as $attribute) {
                 if ($attribute->name == $input->value) {
                     return false;
                 }
             }
         }
         return true;
     }, 'Attribute with this name already exists!');
     $form->addSubmit('submit', 'Create attribute')->onClick[] = function (SubmitButton $button) {
         $values = $button->form->values;
         $miner = $this->findMinerWithCheckAccess($values->miner);
         $this->minersFacade->checkMinerMetasource($miner);
         $attribute = new Attribute();
         $attribute->metasource = $miner->metasource;
         $attribute->datasourceColumn = $this->datasourcesFacade->findDatasourceColumn($miner->datasource, $values->column);
         $attribute->name = $values->attributeName;
         $attribute->type = $attribute->datasourceColumn->type;
         $attribute->preprocessing = $this->metaAttributesFacade->findPreprocessing($values->preprocessing);
         $attribute->active = false;
         $this->metasourcesFacade->saveAttribute($attribute);
         $metasourceTask = $this->metasourcesFacade->startAttributesPreprocessing($miner->metasource, [$attribute]);
         $this->redirect('preprocessingTask', ['id' => $metasourceTask->metasourceTaskId]);
     };
     $storno = $form->addSubmit('storno', 'storno');
     $storno->setValidationScope(array());
     $storno->onClick[] = function (SubmitButton $button) use($presenter) {
         //přesměrování na výběr preprocessingu
         $values = $button->form->getValues();
         $presenter->redirect('addAttribute', array('column' => $values->column, 'miner' => $values->miner));
     };
     return $form;
 }
コード例 #8
0
 /**
  * Akce pro vyhodnocení klasifikace
  * @SWG\Get(
  *   tags={"Evaluation"},
  *   path="/evaluation/classification",
  *   summary="Evaluate classification model",
  *   produces={"application/json","application/xml"},
  *   security={{"apiKey":{}},{"apiKeyHeader":{}}},
  *   @SWG\Parameter(
  *     name="scorer",
  *     description="Scorer type",
  *     required=true,
  *     type="string",
  *     in="query",
  *     enum={"easyMinerScorer","modelTester"}
  *   ),
  *   @SWG\Parameter(
  *     name="task",
  *     description="Task ID",
  *     required=false,
  *     type="integer",
  *     in="query"
  *   ),
  *   @SWG\Parameter(
  *     name="ruleSet",
  *     description="Rule set ID",
  *     required=false,
  *     type="integer",
  *     in="query"
  *   ),
  *   @SWG\Parameter(
  *     name="datasource",
  *     description="Datasource ID (if not specified, task datasource will be used)",
  *     required=false,
  *     type="integer",
  *     in="query"
  *   ),
  *   @SWG\Response(
  *     response=200,
  *     description="Evaluation result",
  *     @SWG\Schema(
  *       ref="#/definitions/ScoringResultResponse"
  *     )
  *   ),
  *   @SWG\Response(
  *     response=400,
  *     description="Invalid API key supplied",
  *     @SWG\Schema(ref="#/definitions/StatusResponse")
  *   )
  * )
  *
  * @throws BadRequestException
  * @throws NotImplementedException
  */
 public function actionClassification()
 {
     $this->setXmlMapperElements('classification');
     $inputData = $this->getInput()->getData();
     /** @var IScorerDriver $scorerDriver */
     if (empty($inputData['scorer'])) {
         $scorerDriver = $this->scorerDriverFactory->getDefaultScorerInstance();
     } else {
         $scorerDriver = $this->scorerDriverFactory->getScorerInstance($inputData['scorer']);
     }
     if (!empty($inputData['datasource'])) {
         try {
             $datasource = $this->datasourcesFacade->findDatasource(@$inputData['datasource']);
             if (!$this->datasourcesFacade->checkDatasourceAccess($datasource, $this->getCurrentUser())) {
                 throw new \Exception();
             }
         } catch (\Exception $e) {
             throw new BadRequestException("Requested data source was not found!");
         }
     } elseif (!empty($inputData['task'])) {
         $task = $this->findTaskWithCheckAccess($inputData['task']);
         $datasource = $task->miner->datasource;
     } else {
         throw new BadRequestException("Data source was not specified!");
     }
     if (!empty($inputData['task'])) {
         if (empty($task)) {
             $task = $this->findTaskWithCheckAccess($inputData['task']);
         }
         $result = $scorerDriver->evaluateTask($task, $datasource)->getCorrectIncorrectDataArr();
         $result['task'] = $task->getDataArr(false);
     } elseif (!empty($inputData['ruleSet'])) {
         $ruleSet = $this->ruleSetsFacade->findRuleSet($inputData['ruleSet']);
         //TODO kontrola oprávnění k rule setu
         $result = $scorerDriver->evaluateRuleSet($ruleSet, $datasource)->getDataArr();
         $result['ruleSet'] = $ruleSet->getDataArr();
     } else {
         throw new BadRequestException("No task or rule set found!");
     }
     $this->resource = $result;
     $this->sendResource();
 }
コード例 #9
0
 /**
  * @return Form
  */
 public function createComponentUploadForm()
 {
     $form = new Form();
     $form->setTranslator($this->translator);
     $form->addUpload('file', 'Upload file:')->setRequired('Je nutné vybrat soubor pro import!');
     $dbTypes = $this->datasourcesFacade->getDbTypes(true);
     if (count($dbTypes) == 1) {
         reset($dbTypes);
         $form->addHidden('dbType', key($dbTypes));
     } else {
         $form->addSelect('dbType', 'Database type:', $dbTypes)->setDefaultValue($this->datasourcesFacade->getPreferredDbType());
     }
     //přidání submit tlačítek
     $form->addSubmit('submit', 'Configure upload...')->onClick[] = function () {
         //nepodporujeme upload bez javascriptové konfigurace
         $this->flashMessage('For file upload using UI, you have to enable the javascript code!', 'error');
         $this->redirect('newMiner');
     };
     return $form;
 }
コード例 #10
0
 /**
  * Funkce pro kontrolu vstupů pro vytvoření nového mineru
  */
 public function validateCreate()
 {
     $currentUser = $this->getCurrentUser();
     /** @noinspection PhpMethodParametersCountMismatchInspection */
     $this->input->field('name')->addRule(IValidator::REQUIRED, 'Name is required!');
     /** @noinspection PhpMethodParametersCountMismatchInspection */
     $this->input->field('type')->addRule(IValidator::REQUIRED, 'Miner type is required!');
     /** @noinspection PhpMethodParametersCountMismatchInspection */
     $this->input->field('datasourceId')->addRule(IValidator::REQUIRED, 'Datasource ID is required!')->addRule(IValidator::CALLBACK, 'Requested datasource was not found, or is not accessible!', function ($value) use($currentUser) {
         try {
             $this->datasource = $this->datasourcesFacade->findDatasource($value);
             if ($this->datasourcesFacade->checkDatasourceAccess($this->datasource, $currentUser)) {
                 //kontrola dostupnosti kompatibilního mineru s vybraným datasource
                 $availableMinerTypes = $this->minersFacade->getAvailableMinerTypes($this->datasource->type);
                 return !empty($availableMinerTypes[$this->getInput()->getData()['type']]);
             } else {
                 return false;
             }
         } catch (\Exception $e) {
             return false;
         }
     });
     /** @noinspection PhpMethodParametersCountMismatchInspection */
     $this->input->field('ruleSetId')->addRule(IValidator::CALLBACK, 'Requested rule set was not found, or is not accessible!', function ($value) use($currentUser) {
         if (empty($value)) {
             return true;
         }
         try {
             $this->ruleSet = $this->ruleSetsFacade->findRuleSet($value);
             $this->ruleSetsFacade->checkRuleSetAccess($this->ruleSet, $currentUser);
             return true;
         } catch (\Exception $e) {
             return false;
         }
     });
 }
コード例 #11
0
 /**
  * Funkce pro aktualizaci info o atributech v DB
  * @param Metasource &$metasource
  * @param User $user
  */
 public function updateMetasourceAttributes(Metasource &$metasource, User $user)
 {
     /** @var IPreprocessing $preprocessing */
     $preprocessing = $this->preprocessingFactory->getPreprocessingInstance($metasource->getPpConnection(), $user);
     $ppDataset = $preprocessing->getPpDataset($metasource->ppDatasetId ? $metasource->ppDatasetId : $metasource->name);
     $datasource = $metasource->datasource;
     $metasource->size = $ppDataset->size;
     $ppAttributes = $preprocessing->getPpAttributes($ppDataset);
     #region připravení seznamu aktuálně existujících datasourceColumns
     /** @var Attribute[] $existingAttributesByPpDatasetAttributeId */
     $existingAttributesByPpDatasetAttributeId = [];
     /** @var Attribute[] $existingAttributesByName */
     $existingAttributesByName = [];
     /** @var Attribute[] $attributes */
     $attributes = $metasource->attributes;
     if (!empty($attributes)) {
         foreach ($attributes as &$attribute) {
             if (!empty($attribute->ppDatasetAttributeId)) {
                 $existingAttributesByPpDatasetAttributeId[$attribute->ppDatasetAttributeId] = $attribute;
             } else {
                 $existingAttributesByName[$attribute->name] = $attribute;
             }
         }
     }
     #endregion
     #region aktualizace seznamu sloupců získaných z DB
     if (!empty($ppAttributes)) {
         foreach ($ppAttributes as $ppAttribute) {
             if (!empty($ppAttribute->id) && is_int($ppAttribute->id) && isset($existingAttributesByPpDatasetAttributeId[$ppAttribute->id])) {
                 //sloupec s daným ID již je v databázi
                 $attribute = $existingAttributesByPpDatasetAttributeId[$ppAttribute->id];
                 $modified = false;
                 if ($attribute->name != $ppAttribute->name) {
                     $attribute->name = $ppAttribute->name;
                     $modified = true;
                 }
                 if (!$attribute->active) {
                     $modified = true;
                     $attribute->active = true;
                 }
                 if ($modified) {
                     $this->saveAttribute($attribute);
                 }
                 unset($existingAttributesByPpDatasetAttributeId[$ppAttribute->id]);
             } elseif (!empty($ppAttribute->name) && isset($existingAttributesByName[$ppAttribute->name])) {
                 //sloupec najdeme podle jména
                 $attribute = $existingAttributesByName[$ppAttribute->name];
                 if (!empty($ppAttribute->id) && $attribute->ppDatasetAttributeId != $ppAttribute->id) {
                     $attribute->ppDatasetAttributeId = $ppAttribute->id;
                     $attribute->active = true;
                     $this->saveAttribute($attribute);
                 } elseif (!$attribute->active) {
                     $attribute->active = true;
                     $this->saveAttribute($attribute);
                 }
                 unset($existingAttributesByName[$ppAttribute->name]);
             } elseif (!empty($ppAttribute->field)) {
                 //máme tu nový datový sloupec (který má svoji vazbu na datasource)
                 $attribute = new Attribute();
                 $attribute->metasource = $metasource;
                 try {
                     $datasourceColumn = $this->datasourcesFacade->findDatasourceColumnByDbDatasourceColumnId($datasource, $ppAttribute->field);
                 } catch (\Exception $e) {
                     $datasourceColumn = null;
                 }
                 $attribute->datasourceColumn = $datasourceColumn;
                 $attribute->name = $ppAttribute->name;
                 if (is_int($ppAttribute->id)) {
                     $attribute->ppDatasetAttributeId = $ppAttribute->id;
                 }
                 $attribute->active = true;
                 $attribute->type = $ppAttribute->type;
                 $this->saveAttribute($attribute);
             }
         }
     }
     #endregion
     #region deaktivace již neexistujících sloupců
     //TODO kontrola, jestli je není možné kompletně smazat (pokud ještě nebyly dovytvořeny v rámci preprocessingu)
     if (!empty($existingAttributesByPpDatasetAttributeId)) {
         foreach ($existingAttributesByPpDatasetAttributeId as &$attribute) {
             if ($attribute->active) {
                 $attribute->active = false;
                 $this->saveAttribute($attribute);
             }
         }
     }
     if (!empty($existingAttributesByName)) {
         foreach ($existingAttributesByName as &$attribute) {
             if ($attribute->active) {
                 $attribute->active = false;
                 $this->saveAttribute($attribute);
             }
         }
     }
     #endregion
     //aktualizace datového zdroje z DB
     $metasource = $this->findMetasource($metasource->metasourceId);
     #region vyčištění preprocessing úloh
     if (!empty($metasource->metasourceTasks)) {
         $attributesArr = $metasource->getAttributesArr();
         if (!empty($attributesArr)) {
             foreach ($metasource->metasourceTasks as $metasourceTask) {
                 if ($metasourceTask->type == MetasourceTask::TYPE_PREPROCESSING) {
                     if (!empty($metasourceTask->attributes)) {
                         $finished = true;
                         foreach ($metasourceTask->attributes as $taskAttribute) {
                             if (!$taskAttribute->active) {
                                 $finished = false;
                             }
                         }
                         if ($finished) {
                             $this->metasourceTasksRepository->delete($metasourceTask);
                         }
                     }
                 }
             }
         }
     }
     #endregion
 }