/** * Formulář pro zadání preprocessingu pomocí nominal enumeration * @return Form */ protected function createComponentNewNominalEnumerationForm() { $form = new Form(); $form->setTranslator($this->translator); $form->addText('preprocessingName', 'Preprocessing name:')->setRequired(false)->setAttribute('placeholder', $this->translate('Nominal bins'))->setAttribute('title', $this->translate('You can left this field blank, it will be filled in automatically.'))->addRule(function (TextInput $textInput) { $form = $textInput->getForm(true); $formValues = $form->getValues(true); $textInputValue = $textInput->value; //nalezení aktuálního formátu $miner = $this->findMinerWithCheckAccess($formValues['miner']); $datasourceColumn = $this->findDatasourceColumn($miner->datasource, $formValues['column']); $format = $datasourceColumn->format; $textInput->setAttribute('placeholder', $this->prepareNominalEnumerationPreprocessingName($format, $formValues)); if ($textInputValue != '') { //check preprocessings $existingPreprocessings = $format->preprocessings; if (!empty($existingPreprocessings)) { foreach ($existingPreprocessings as $existingPreprocessing) { if ($existingPreprocessing->name == $textInput) { return false; } } } } return true; }, 'This preprocessing name already exists. Please select a new one...')->addRule(function (TextInput $input) { $values = $input->getForm(true)->getValues(true); return count($values['valuesBins']) > 0; }, 'You have to input at least one bin!'); $form->addText('attributeName', 'Create attribute with 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->addHidden('column'); $form->addHidden('miner'); $form->addHidden('formatType'); $form->addHidden('formatId'); /** @var Container $valuesBins */ $valuesBins = $form->addDynamic('valuesBins', function (Container $valuesBin) { $valuesBin->addText('name', 'Bin name:')->setRequired(true)->setRequired('Input bin name!')->addRule(function (TextInput $input) { $values = $input->parent->getValues(true); return count($values['values']) > 0; }, 'Add at least one value!')->addRule(function (TextInput $input) { //kontrola, jestli má každý BIN jiný název $values = $input->getParent()->getParent()->getValues(true); $inputValue = $input->getValue(); $usesCount = 0; if (!empty($values)) { foreach ($values as $value) { if ($value['name'] == $inputValue) { $usesCount++; } } } return $usesCount <= 1; }, 'This name is used for other bin!'); /** @var Container $intervals */ $intervals = $valuesBin->addDynamic('values', function (Container $interval) { $interval->addText('value')->setAttribute('readonly'); $interval->addSubmit('remove', 'x')->setAttribute('class', 'removeValue')->setValidationScope([])->onClick[] = function (SubmitButton $submitButton) { $intervals = $submitButton->parent->parent; $intervals->remove($submitButton->parent, TRUE); }; }); $addValueSubmit = $valuesBin->addSubmit('addValue', 'Add value'); $value = $valuesBin->addText('value', null, ''); //TODO dodělat select... $value->addConditionOn($addValueSubmit, Form::SUBMITTED)->setRequired('Input value!')->addConditionOn($valuesBin->getForm(true)->getComponent('formatType'), Form::EQUAL, Format::DATATYPE_VALUES)->addRule(function (TextInput $input) { $inputValue = $input->getValue(); $values = $input->getForm(true)->getValues(true); $format = $this->metaAttributesFacade->findFormat($values['formatId']); $values = $format->values; if (!empty($values)) { foreach ($values as $value) { if ($value->value == $inputValue) { return true; } } } return false; }, 'You have to input existing value!')->elseCondition()->addRule(Form::FLOAT, 'You have to input number!')->endCondition(); $value->addRule(function (TextInput $input) { $values = $input->getForm(true)->getValues(true); $usedValuesArr = []; if (!empty($values['valuesBins'])) { foreach ($values['valuesBins'] as $valuesBin) { if (!empty($valuesBin['values'])) { foreach ($valuesBin['values'] as $value) { $usedValuesArr[] = $value['value']; } } } } return !in_array($input->value, $usedValuesArr); }, 'This value is already used!'); $addValueSubmit->setValidationScope([$value])->onClick[] = function (SubmitButton $submitButton) use($intervals) { $values = $submitButton->getParent()->getValues(true); $valueItem = $submitButton->getParent()['values']->createOne(); $valueItem->setValues(['value' => $values['value']]); $submitButton->getParent()->setValues(['value' => '']); }; $valuesBin->addSubmit('remove', 'Remove bin')->setAttribute('class', 'removeBin')->setValidationScope([])->onClick[] = function (SubmitButton $submitButton) { $submitButton->getParent()->getParent()->remove($submitButton->getParent(), true); }; }, 0); $valuesBins->addSubmit('addBin', 'Add bin')->setValidationScope([])->onClick[] = function (SubmitButton $submitButton) { $submitButton->getParent()->createOne(); }; $form->addSubmit('submitAll', 'Save preprocessing & create attribute')->onClick[] = function (SubmitButton $submitButton) { #region vytvoření preprocessingu $values = $submitButton->getForm(true)->getValues(true); $miner = $this->findMinerWithCheckAccess($values['miner']); $this->minersFacade->checkMinerMetasource($miner); //vytvoření preprocessingu $datasourceColumn = $this->findDatasourceColumn($miner->datasource, $values['column']); $format = $datasourceColumn->format; $preprocessing = new Preprocessing(); $preprocessing->name = $values['preprocessingName'] != '' ? $values['preprocessingName'] : $this->prepareNominalEnumerationPreprocessingName($format, $values); $preprocessing->format = $format; $preprocessing->user = $this->getCurrentUser(); $this->preprocessingsFacade->savePreprocessing($preprocessing); foreach ($values['valuesBins'] as $valuesBinValues) { $valuesBin = new ValuesBin(); $valuesBin->format = $format; $valuesBin->name = $valuesBinValues['name']; $this->metaAttributesFacade->saveValuesBin($valuesBin); foreach ($valuesBinValues['values'] as $valuesValues) { try { $value = $this->metaAttributesFacade->findValue($format, $valuesValues['value']); } catch (\Exception $e) { $value = new Value(); $value->value = $valuesValues['value']; $this->metaAttributesFacade->saveValue($value); } $valuesBin->addToValues($value); } $this->metaAttributesFacade->saveValuesBin($valuesBin); $preprocessing->addToValuesBins($valuesBin); } $this->preprocessingsFacade->savePreprocessing($preprocessing); //vytvoření atributu $attribute = new Attribute(); $attribute->metasource = $miner->metasource; $attribute->datasourceColumn = $datasourceColumn; $attribute->name = $values['attributeName']; $attribute->type = $attribute->datasourceColumn->type; $attribute->preprocessing = $preprocessing; $this->minersFacade->prepareAttribute($miner, $attribute); $this->metasourcesFacade->saveAttribute($attribute); $this->minersFacade->checkMinerState($miner, $this->getCurrentUser()); $this->redirect('reloadUI'); #endregion vytvoření preprocessingu }; $presenter = $this; $form->addSubmit('storno', 'storno')->setValidationScope([])->onClick[] = function (SubmitButton $submitButton) use($presenter) { $values = $submitButton->getForm()->getValues(); $presenter->redirect('addAttribute', array('column' => $values->column, 'miner' => $values->miner)); }; return $form; }
/** * Funkce pro načtení PMML * @param string|\SimpleXMLElement $pmml * @param int &$rulesCount = null - informace o počtu importovaných pravidel * @param bool $updateImportedRulesHeads=false * @return bool * @throws \Exception */ public function fullParseRulesPMML($pmml, &$rulesCount = null, $updateImportedRulesHeads = false) { Debugger::log('fullParseRulesPMML start ' . time(), ILogger::DEBUG); if ($pmml instanceof \SimpleXMLElement) { $xml = $pmml; } else { $xml = simplexml_load_string($pmml); } $xml->registerXPathNamespace('guha', 'http://keg.vse.cz/ns/GUHA0.1rev1'); $guhaAssociationModel = $xml->xpath('//guha:AssociationModel'); $guhaAssociationModel = $guhaAssociationModel[0]; $rulesCount = (string) $guhaAssociationModel['numberOfRules']; /** @var \SimpleXMLElement $associationRulesXml */ $associationRulesXml = $guhaAssociationModel->AssociationRules; if (count($associationRulesXml->AssociationRule) == 0) { return true; } //pokud nejsou vrácena žádná pravidla, nemá smysl zpracovávat cedenty... #region zpracování cedentů jen s jedním subcedentem $dbaItems = $associationRulesXml->xpath('./DBA[count(./BARef)=1]'); $alternativeCedentIdsArr = array(); if (!empty($dbaItems)) { foreach ($dbaItems as $dbaItem) { $idStr = (string) $dbaItem['id']; $BARefStr = (string) $dbaItem->BARef; $alternativeCedentIdsArr[$idStr] = isset($alternativeCedentIdsArr[$BARefStr]) ? $alternativeCedentIdsArr[$BARefStr] : $BARefStr; } } if (!empty($alternativeCedentIdsArr)) { do { $repeat = false; foreach ($alternativeCedentIdsArr as $id => $referencedId) { if (isset($alternativeCedentIdsArr[$referencedId])) { $alternativeCedentIdsArr[$id] = $alternativeCedentIdsArr[$referencedId]; $repeat = true; } } } while ($repeat); } #endregion /** @var Cedent[] $cedentsArr */ $cedentsArr = []; /** @var RuleAttribute[] $ruleAttributesArr */ $ruleAttributesArr = []; /** @var string[] $unprocessedIdsArr */ $unprocessedIdsArr = []; /** @var ValuesBin[]|Value[] $valuesBinsArr */ $valuesBinsArr = []; /** @var Attribute[] $attributesArr - pole indexované pomocí názvů atributů použitých v PMML */ $attributesArr = $this->miner->metasource->getAttributesByNamesArr(); #region zpracování rule attributes $bbaItems = $associationRulesXml->xpath('//BBA'); if (!empty($bbaItems)) { foreach ($bbaItems as $bbaItem) { $ruleAttribute = new RuleAttribute(); $idStr = (string) $bbaItem['id']; //uložení vazby na Attribute $attributeName = (string) $bbaItem->FieldRef; $valueName = (string) $bbaItem->CatRef; $attribute = $attributesArr[$attributeName]; $ruleAttribute->attribute = $attribute; $valueItem = $attribute->preprocessing->findValue($valueName); if ($valueItem instanceof Value) { $ruleAttribute->value = $valueItem; } elseif ($valueItem instanceof ValuesBin) { $ruleAttribute->valuesBin = $valueItem; } elseif ($attribute->preprocessing->specialType == Preprocessing::SPECIALTYPE_EACHONE) { //pokud jde o preprocessing each-one a nebyla nalezena příslušná hodnota v DB, tak ji uložíme $value = new Value(); $value->format = $attribute->preprocessing->format; $value->value = $valueName; $this->metaAttributesFacade->saveValue($value); $ruleAttribute->value = $value; } $this->rulesFacade->saveRuleAttribute($ruleAttribute); $ruleAttributesArr[$idStr] = $ruleAttribute; } } //pročištění pole s alternativními IDčky if (!empty($alternativeCedentIdsArr)) { foreach ($alternativeCedentIdsArr as $id => $alternativeId) { if (isset($ruleAttributesArr[$alternativeId])) { unset($alternativeCedentIdsArr[$id]); } } } #endregion #region zpracování cedentů s více subcedenty/hodnotami $dbaItems = $associationRulesXml->xpath('./DBA[count(./BARef)>0]'); if (!empty($dbaItems)) { do { foreach ($dbaItems as $dbaItem) { $idStr = (string) $dbaItem['id']; if (isset($cedentsArr[$idStr])) { continue; } if (isset($alternativeCedentIdsArr[$idStr])) { continue; } if (isset($ruleAttributesArr[$idStr])) { continue; } $process = true; foreach ($dbaItem->BARef as $BARef) { $BARefStr = (string) $BARef; if (isset($alternativeCedentIdsArr[$BARefStr])) { $BARefStr = $alternativeCedentIdsArr[$BARefStr]; } if (!isset($cedentsArr[$BARefStr]) && !isset($ruleAttributesArr[$BARefStr])) { $unprocessedIdsArr[$BARefStr] = $BARefStr; $process = false; } } if ($process) { unset($unprocessedIdsArr[$idStr]); //vytvoření konkrétního cedentu... $cedent = new Cedent(); if (isset($dbaItem['connective'])) { $cedent->connective = Strings::lower((string) $dbaItem['connective']); } else { $cedent->connective = 'conjunction'; } $this->rulesFacade->saveCedent($cedent); $cedentsArr[$idStr] = $cedent; foreach ($dbaItem->BARef as $BARef) { $BARefStr = (string) $BARef; if (isset($alternativeCedentIdsArr[$BARefStr])) { $BARefStr = $alternativeCedentIdsArr[$BARefStr]; } if (isset($cedentsArr[$BARefStr])) { $cedent->addToCedents($cedentsArr[$BARefStr]); } elseif (isset($ruleAttributesArr[$BARefStr])) { $cedent->addToRuleAttributes($ruleAttributesArr[$BARefStr]); } } $this->rulesFacade->saveCedent($cedent); } else { $unprocessedIdsArr[$idStr] = $idStr; } } } while (!empty($unprocessedIdsArr)); } #endregion #region association rules /** @var Cedent[] $topCedentsArr - pole s cedenty na vrcholné úrovni (pokud je ruleAttribute přímo na vrcholné úrovni, musí být zabalen v cedentu)*/ $topCedentsArr = array(); foreach ($associationRulesXml->AssociationRule as $associationRule) { $rule = false; if ($updateImportedRulesHeads) { try { $rule = $this->rulesFacade->findRuleByPmmlImportId($this->task->taskId, (string) $associationRule['id']); } catch (\Exception $e) { /*ignore*/ } } if (!$rule) { $rule = new Rule(); } $rule->task = $this->task; #region antecedent if (isset($associationRule['antecedent'])) { //jde o pravidlo s antecedentem $antecedentId = (string) $associationRule['antecedent']; if (isset($alternativeCedentIdsArr[$antecedentId])) { $antecedentId = $alternativeCedentIdsArr[$antecedentId]; } if (isset($cedentsArr[$antecedentId])) { $rule->antecedent = $cedentsArr[$antecedentId]; } else { if (isset($ruleAttributesArr[$antecedentId])) { if (!isset($topCedentsArr[$antecedentId])) { $cedent = new Cedent(); $cedent->connective = 'conjunction'; $this->rulesFacade->saveCedent($cedent); $topCedentsArr[$antecedentId] = $cedent; $cedent->addToRuleAttributes($ruleAttributesArr[$antecedentId]); $this->rulesFacade->saveCedent($cedent); } $rule->antecedent = $topCedentsArr[$antecedentId]; } else { throw new \Exception('Import failed!'); } } } else { //jde o pravidlo bez antecedentu $rule->antecedent = null; } #endregion antecedent #region consequent $consequentId = (string) $associationRule['consequent']; if (isset($alternativeCedentIdsArr[$consequentId])) { $consequentId = $alternativeCedentIdsArr[$consequentId]; } if (isset($cedentsArr[$consequentId])) { $rule->consequent = $cedentsArr[$consequentId]; } else { if (isset($ruleAttributesArr[$consequentId])) { if (!isset($topCedentsArr[$consequentId])) { $cedent = new Cedent(); $cedent->connective = 'conjunction'; $this->rulesFacade->saveCedent($cedent); $topCedentsArr[$consequentId] = $cedent; $cedent->addToRuleAttributes($ruleAttributesArr[$consequentId]); $this->rulesFacade->saveCedent($cedent); } $rule->consequent = $topCedentsArr[$consequentId]; } else { throw new \Exception('Import failed!'); } } #endregion consequent $rule->text = (string) $associationRule->Text; $fourFtTable = $associationRule->FourFtTable; $rule->a = (string) $fourFtTable['a']; $rule->b = (string) $fourFtTable['b']; $rule->c = (string) $fourFtTable['c']; $rule->d = (string) $fourFtTable['d']; $this->rulesFacade->saveRule($rule); } $this->rulesFacade->calculateMissingInterestMeasures($this->task); #endregion association rules Debugger::log('fullParseRulesPMML end ' . time(), ILogger::DEBUG); return true; }