Non puoi selezionare più di 25 argomenti
Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
1781 righe
50 KiB
1781 righe
50 KiB
<?php |
|
|
|
use Mtownsend\XmlToArray\XmlToArray; |
|
|
|
include_once 'BS4FormGenerator.trait.php'; |
|
include_once 'TedEsenderFieldsManager.trait.php'; |
|
include_once 'TedEsenderHelpersFuncions.trait.php'; |
|
include_once 'TedEsenderApiManager.trait.php'; |
|
include_once 'TedEsenderSuggestions.class.php'; |
|
|
|
class eSenderManager { |
|
|
|
use BS4FormGenerator, TedEsenderFieldsManager, TedEsenderHelpersFuncions, TedEsenderApiManager, TedEsenderSuggestions; |
|
|
|
const MUL = "£"; |
|
const DEFAULT = 0; |
|
const REMOVED_SUBSECTIONS = 1; |
|
const EDITED_SUBSECTION = 2; |
|
|
|
/** |
|
* XSD schema file name |
|
* |
|
* @var String |
|
*/ |
|
private $xsd; |
|
|
|
/** |
|
* |
|
* @var DOMXPath |
|
*/ |
|
private $xpath; |
|
|
|
/** |
|
* Form Attributes |
|
* |
|
* @var Array |
|
*/ |
|
public $formAttributes; |
|
|
|
/** |
|
* Form Sections |
|
* |
|
* @var Array |
|
*/ |
|
public $sections; |
|
|
|
/** |
|
* Current Section |
|
* |
|
* @var Array |
|
*/ |
|
private $current_section; |
|
|
|
/** |
|
* Record salvato nel database |
|
* |
|
* @var Array |
|
*/ |
|
public $info; |
|
|
|
/** |
|
* Elements list |
|
* |
|
* @var Array |
|
*/ |
|
private $elements; |
|
|
|
/** |
|
* Debug switch |
|
* |
|
* @var Bool |
|
*/ |
|
public $debug; |
|
|
|
/** |
|
* Ignored Keys |
|
* |
|
* @var Array |
|
*/ |
|
public $ignored_keys; |
|
|
|
/** |
|
* Settings |
|
* |
|
* @var Array |
|
*/ |
|
public $setting; |
|
|
|
/** |
|
* title |
|
* |
|
* @var String |
|
*/ |
|
public $title; |
|
|
|
/** |
|
* Check for form Rows |
|
* |
|
* @var boolean |
|
*/ |
|
private $hasAnotherRow = false; |
|
|
|
|
|
/** |
|
* Total completed sections number; |
|
*/ |
|
public $total_completed; |
|
|
|
/** |
|
* Suggestions from connected modules; |
|
* |
|
* @var Array |
|
*/ |
|
private $suggestions; |
|
|
|
/** |
|
* Event to trigger after suggestions; |
|
* |
|
* @var Array |
|
*/ |
|
private $suggestionTriggers; |
|
|
|
/** |
|
* Define if instance is deferred or not; |
|
*/ |
|
public $deferred; |
|
|
|
/** |
|
* Connsessione al database |
|
* |
|
* @var mixed |
|
*/ |
|
private $pdo; |
|
|
|
/** |
|
* Form ID |
|
* |
|
* @var mixed |
|
*/ |
|
public $form_section; |
|
|
|
/** |
|
* Load XSD Form |
|
* |
|
* @param String $form |
|
* @param String $directory |
|
* @return void |
|
*/ |
|
function __construct(String $form, Int $codice = 0, Array $settings, String $directory = "config/xml") |
|
{ |
|
global $pdo, $root; |
|
|
|
$this->pdo = $pdo; |
|
if(!str_ends_with($form, ".xsd")) { |
|
$form .= ".xsd"; |
|
} |
|
|
|
$this->form_section = $this->notice = $form; |
|
|
|
|
|
$this->init($codice); |
|
if($directory == "config/xml") { |
|
$directory = "{$root}/backend/guue/{$directory}"; |
|
} |
|
|
|
$this->settings = $settings; |
|
|
|
$this->fields = []; |
|
|
|
$this->settings = file_get_contents("{$root}/backend/guue/config/settings.json"); |
|
$this->settings = json_decode($this->settings, true); |
|
|
|
$this->title = $this->settings["forms"][$this->form_section]["name"]; |
|
|
|
ini_set('max_execution_time', 300); |
|
ini_set('memory_limit', "512M"); |
|
|
|
$this->debug = false; |
|
|
|
$this->group = 0; |
|
|
|
$this->mapper = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . ".." . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "localization.json"); |
|
$this->mapper = json_decode($this->mapper, TRUE); |
|
|
|
$this->mapper["ERRORS_DICT"] = json_decode(file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . ".." . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "errors.json"), true); |
|
|
|
$this->translator = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . ".." . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "translator.json"); |
|
$this->translator = json_decode($this->translator, TRUE); |
|
|
|
$this->elements = [ |
|
"empty", |
|
"email", |
|
"url", |
|
"text_ft_multi_lines", |
|
"url", |
|
"string_400", |
|
"string_200", |
|
"string_not_empty", |
|
"string_with_letter", |
|
"string", |
|
"string_20", |
|
"string_30", |
|
"string_50", |
|
"string_100", |
|
"string_150", |
|
"string_200", |
|
"string_250", |
|
"string_300", |
|
"string_400", |
|
"string_500", |
|
"string_1000", |
|
"text_ft_single_line", |
|
"text_ft_multi_lines", |
|
"text_ft_multi_lines_or_string", |
|
"nonNegativeInteger", |
|
"_2car", |
|
"_3car", |
|
"_4car", |
|
"_5car", |
|
"alphanum", |
|
"nb", |
|
"prct", |
|
"decimal", |
|
"time", |
|
"date_full", |
|
"date", |
|
"duration_unit_m_d", |
|
"duration_unit_m_y", |
|
]; |
|
|
|
$this->ignored_keys = [ |
|
self::MUL, |
|
"COUNTRY_ORIGIN", |
|
"ADDRESS_CONTRACTING_BODY_ADDITIONAL", |
|
"ADDRESS_FURTHER_INFO", |
|
"_attributes", |
|
"ADDRESS_PARTICIPATION", |
|
"LOT_DIVISION", |
|
"ADDRESS_PARTICIPATION", |
|
"LOT_DIVISION_SETTINGS", |
|
"LOT_DIVISION", |
|
"LOT_MAX_NUMBER", |
|
"CPV_MAIN", |
|
"AC", |
|
"AC_QUALITY", |
|
"AC_COST", |
|
"time_frame", |
|
"RADIO_FOR_ECONOMIC_CRITERIA_DOC", |
|
"RADIO_FOR_TECHNICAL_CRITERIA_DOC", |
|
"RADIO_FOR_PT_RESTRICTED", |
|
"LANGUAGES", |
|
"LANGUAGE", |
|
"TYPE_CONTRACT", |
|
"RADIO_FOR_GPA", |
|
"AC_QUALITY_SECTION", |
|
"CPV_ADDITIONAL", |
|
"DATE_RECEIPT_TENDERS", |
|
"TIME_RECEIPT_TENDERS", |
|
"OBJECT_DESCR", |
|
"AWARDED_CONTRACT", |
|
"NO_AWARDED_CONTRACT", |
|
"PROCUREMENT_DISCONTINUED", |
|
"ORIGINAL_OTHER_MEANS", |
|
"RADIO_FOR_ORIGINAL_OTHER_MEANS_SECTION", |
|
"CONTRACTORS", |
|
"CONTRACTOR", |
|
"VALUES", |
|
"CONTRACTOR_SME_MAN", |
|
"ITEM", |
|
"TOWN", |
|
"RADIO_FOR_DEPOSIT_GUARANTEE_REQUIRED", |
|
"RADIO_FOR_MAIN_FINANCING_CONDITION", |
|
"RADIO_FOR_LEGAL_FORM", |
|
"RADIO_FOR_PARTICULAR_PROFESSION", |
|
"PARTICULAR_PROFESSION", |
|
"D_ACCORDANCE_ARTICLE", |
|
"AGREE_TO_PUBLICATION_MAN", |
|
"NON_COMMUNITY_ORIGIN", |
|
"TED_ESENDERS.FORM_SECTION.F07_2014.LEFTI.SECTION_FOR_QUALIFICATION", |
|
"NO_AWARDED_PRIZE", |
|
"AWARDED_PRIZE", |
|
"WINNER", |
|
"ADDRESS_WINNER", |
|
"RADIO_FOR_ENOTICES", |
|
"ORIGINAL_ENOTICES", |
|
"ORIGINAL_TED_ESENDER", |
|
"CHANGE", |
|
"SECTION_FOR_CHANGE", |
|
"OLD_VALUE", |
|
"NEW_VALUE", |
|
"RADIO_FOR_ANNEX_D4_PART_1", |
|
"PT_AWARD_CONTRACT_WITHOUT_PUBLICATION", |
|
"RADIO_FOR_DOCUMENT_URL_OPT_SECTION", |
|
"RADIO_FOR_ADDESS_PARTICIPATION", |
|
"RADIO_FOR_OPENING_CONDITION", |
|
"OBJECT_CONTRACT", |
|
"LEGAL_FORM", |
|
"OPENING_CONDITION", |
|
"DATE_RECEIPT_TENDERS", |
|
"RADIO_FOR_OPENING_CONDITION", |
|
"DURATION_TENDER_VALID", |
|
"DATE_OPENING_TENDERS", |
|
"SEVERAL_OPERATORS", |
|
"D_FROM_WINDING_PROVIDER", |
|
"D_FROM_LIQUIDATOR_CREDITOR", |
|
"AWARD_CONTRACT", |
|
"RADIO_FOR_LIKELY_SUBCONTRACTED", |
|
"NO_LOT_DIVISION", |
|
"REDUCTION_RECOURSE_SECTION", |
|
"NOTICE_NUMBER_OJ", |
|
"FRAMEWORK", |
|
"NB_PARTICIPANTS", |
|
"DPS_ADDITIONAL_PURCHASERS", |
|
"INFO_ADD", |
|
"PLACE", |
|
"TIME_OPENING_TENDERS", |
|
"TITLE", |
|
"LOT_NO", |
|
"NUTS", |
|
"MAIN_SITE", |
|
"SHORT_DESCR", |
|
"DURATION", |
|
"DATE_START", |
|
"DATE_END", |
|
"AC_WEIGHTING", |
|
"RENEWAL_DESCR", |
|
"NO_EU_PROGR_RELATED", |
|
"NB_MAX_LIMIT_CANDIDATE", |
|
"NB_MIN_LIMIT_CANDIDATE", |
|
"NB_ENVISAGED_CANDIDATE", |
|
"CRITERIA_CANDIDATE", |
|
"OPTIONS_DESCR", |
|
"EU_PROGR_RELATED", |
|
"ESTIMATED_TIMING", |
|
"EORDERING", |
|
"EPAYMENT", |
|
"EINVOICING", |
|
"OFFICIALNAME", |
|
"ADDRESS", |
|
"POSTAL_CODE", |
|
"COUNTRY", |
|
"TOWN", |
|
"E_MAIL", |
|
"PHONE", |
|
"FAX", |
|
"URL", |
|
"DATE_DISPATCH_NOTICE", |
|
"REVIEW_PROCEDURE", |
|
"NATIONALID", |
|
"CONTACT_POINT", |
|
"URL_GENERAL", |
|
"URL_BUYER", |
|
"JOINT_PROCUREMENT_INVOLVED", |
|
"PROCUREMENT_LAW", |
|
"REFERENCE_NUMBER", |
|
"PT_AWARD_CONTRACT_WITHOUT_CALL", |
|
"D_NO_TENDERS_REQUESTS", |
|
"D_PURE_RESEARCH", |
|
"D_EXTREME_URGENCY", |
|
"D_ADD_DELIVERIES_ORDERED", |
|
"CTYPE", |
|
"D_BARGAIN_PURCHASE", |
|
"D_OUTSIDE_SCOPE", |
|
"D_JUSTIFICATION", |
|
"DPS", |
|
"EAUCTION_USED", |
|
"TERMINATION_DPS_SECTION", |
|
"TERMINATION_PIN", |
|
"CONTRACT_NO", |
|
"NB_TENDERS_RECEIVED", |
|
"NB_TENDERS_RECEIVED_SME", |
|
"RADIO_FOR_ANNEX_D2_PART1", |
|
"QUALIFICATION", |
|
"RADIO_FOR_INFORMATION", |
|
"PARTICIPANT_NAME", |
|
"PARTICIPANT_NAME_ADDITIONAL", |
|
"RADIO_FOR_VAL_PRIZE", |
|
"VAL_PRIZE", |
|
"DIRECTIVE_2014_23_EU", |
|
"DIRECTIVE_2014_24_EU", |
|
"DIRECTIVE_2014_25_EU", |
|
"DIRECTIVE_2009_81_EC", |
|
"AC_CRITERIA", |
|
"RADIO_FOR_PT_NEGOTIATED_WITHOUT_PUBLICATION", |
|
"PT_NEGOTIATED_WITHOUT_PUBLICATION", |
|
"DESCRIPTION_PROCUREMENT", |
|
"AC_CRITERION", |
|
"ESENDER_LOGIN", |
|
"CUSTOMER_LOGIN", |
|
"JUSTIFICATION", |
|
"D_CONTRACT_AWARDED_DESIGN_CONTEST", |
|
"D_COMMODITY_MARKET", |
|
"RADIO_FOR_D_MANUF_FOR_RESEARCH", |
|
"QS", |
|
"VAL_REVENUE", |
|
"VAL_PRICE_PAYMENT", |
|
"T" |
|
]; |
|
|
|
$this->xsd = $form; |
|
$this->directory = $directory; |
|
$this->suggestionTriggers = []; |
|
$this->dom = new DOMDocument(); |
|
$this->dom->load("{$this->directory}/{$this->xsd}", LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NOENT|LIBXML_XINCLUDE); |
|
|
|
$this->dom = $this->loadIncludes($this->dom, $this->directory); |
|
$this->dom = $this->loadImports($this->dom, $this->directory); |
|
|
|
$this->xml = $this->dom->saveXML(); |
|
$this->xml = str_replace(["xs:", "lb:", "n2016:"], "", $this->xml); |
|
|
|
$this->dom = new SimpleXMLIterator($this->xml); |
|
|
|
$this->form = $this->dom->xpath("element[@name='".str_replace(".xsd","",$form)."']"); |
|
if(is_array($this->form) && count($this->form) == 1) $this->form = reset($this->form); |
|
|
|
$this->getSections(); |
|
|
|
} |
|
|
|
/** |
|
* List alla available notices' form |
|
* |
|
* @return Array |
|
*/ |
|
static public function listAvailableNoticeForms() : ?Array { |
|
|
|
global $config; |
|
|
|
$path = dirname(__DIR__); |
|
$forms = glob("{$path}/config/xml/F*_2014.xsd"); |
|
$settings = jsonToArray("{$path}/config/settings.json"); |
|
|
|
$select = [ |
|
'name' => 'form', |
|
'title' => "Tipologia di avviso", |
|
'attrs' => [ |
|
'rel' => 'S;12;12;A' |
|
], |
|
'options' => [] |
|
]; |
|
|
|
foreach ($forms as $value) { |
|
|
|
if ($settings["forms"][basename($value)]["active"] || $config["developEnv"]) { |
|
|
|
$select['options'][str_replace('.xsd', "", basename($value))] = $settings["forms"][basename($value)]["name"]; |
|
|
|
} |
|
|
|
} |
|
|
|
return $select; |
|
|
|
} |
|
|
|
/** |
|
* Get eNotice version: eSender|eForms |
|
* |
|
* @return void |
|
*/ |
|
static public function getVersion(Int $codice = 0) { |
|
|
|
if(! empty($codice)) { |
|
|
|
global $pdo; |
|
return $pdo->go("SELECT `version` FROM b_guue WHERE codice = :codice", [":codice" => $codice])->fetch(PDO::FETCH_COLUMN, 0); |
|
|
|
} |
|
|
|
if(DEVELOP_ENV || strtotime('now') >= strtotime('2023-10-15 00:00:00')) { |
|
|
|
return "eForms"; |
|
|
|
} |
|
|
|
return "eSender"; |
|
|
|
} |
|
|
|
|
|
/** |
|
* Returns the modules that can provide data |
|
* |
|
* @param string $modulo |
|
* @param integer $elemento |
|
* @return array |
|
*/ |
|
public static function moduliCollegati() { |
|
return [ |
|
"gare" => "/gare/guue/init.php", |
|
"pcp" => "/pcp/guue/init.php", |
|
"concorsi" => "/concorsi/guue/init.php", |
|
]; |
|
} |
|
|
|
/** |
|
* Returns all the pubblications of a specific platform's module |
|
* |
|
* @param string $modulo |
|
* @param integer $elemento |
|
* @return array |
|
*/ |
|
public static function getPubblicazioniFromModulo(string $modulo, int $elemento) { |
|
global $pdo; |
|
if (!empty(self::moduliCollegati()[$modulo])) { |
|
|
|
return $pdo->go("SELECT codice, titolo, numero, anno, numero_ojs, version, numero_tecnico, form, stato, data_trasmissione, data_pubblicazione |
|
FROM b_guue |
|
WHERE modulo = :modulo AND codice_elemento = :elemento AND soft_delete = 'N'", |
|
[":modulo"=>$modulo,":elemento"=>$elemento])->fetchAll(PDO::FETCH_ASSOC); |
|
} |
|
} |
|
|
|
/** |
|
* Init the model retrieving stored data or it returning a new instance |
|
* |
|
* @param integer $codice |
|
* @return void |
|
*/ |
|
private function init($codice = 0) |
|
{ |
|
|
|
$this->info = get_campi("b_guue"); |
|
$this->info["codice"] = 0; |
|
$this->info["codice_ente"] = $_SESSION["ente"]->codice; |
|
$this->info["form"] = $this->form_section; |
|
$this->info["anno"] = date('Y'); |
|
$this->info["data_creazione"] = date('d/m/Y H:i:s'); |
|
$this->info["utente_modifica"] = $_SESSION["utente"]->codice ?? 0; |
|
$this->info["valori"] = []; |
|
|
|
if(! empty($codice)) { |
|
|
|
$bind = [ |
|
':codice' => $codice, |
|
]; |
|
|
|
$sql = "SELECT * FROM b_guue WHERE codice = :codice"; |
|
|
|
if (! empty($_SESSION["utente"]) && !isset($_SESSION["utente"]->elaborazioneCoda) && ! $_SESSION["utente"]->fromHere()) { |
|
$sql = "{$sql} AND codice_ente = :codice_ente"; |
|
$bind[":codice_ente"] = $_SESSION["utente"]->codice_ente; |
|
} |
|
|
|
if (! empty($_SESSION["utente"]) && !isset($_SESSION["utente"]->elaborazioneCoda) && $_SESSION["utente"]->gerarchia > 10) { |
|
$ids = Utente::getPermissionsInModulo($_SESSION["ente"]->codice,$_SESSION["utente"]->codice,"guue"); |
|
$ids = implode(",",$ids); |
|
$sql .= " AND codice IN ({$ids}) "; |
|
} |
|
|
|
$ris = $this->pdo->go($sql, $bind); |
|
if($ris->rowCount() == 1) { |
|
$rec = $ris->fetch(PDO::FETCH_ASSOC); |
|
$this->info = $rec; |
|
if($this->isJson($this->info["valori"])) { |
|
$this->info["valori"] = json_decode($this->info["valori"], 1); |
|
} |
|
} |
|
|
|
} |
|
} |
|
|
|
/** |
|
* Load includes in XML Schema |
|
* |
|
* @param DOMDocument $dom Instance of DOMDocument |
|
* @param String $filepath |
|
* @param String $namesp |
|
* @return void |
|
*/ |
|
private function loadIncludes(DOMDocument $dom, String $filepath = '', String $namespace = '') { |
|
$query = "//*[local-name()='include']"; |
|
$xpath = new \DOMXPath($this->dom); |
|
if($xpath->query($query)->length > 0) { |
|
$this->dom = $this->loadExt($xpath->query($query), $dom, $filepath); |
|
$this->dom = $this->loadIncludes($this->dom, $this->directory); |
|
} |
|
return $this->dom; |
|
} |
|
|
|
/** |
|
* Load imports |
|
* |
|
* @param DOMDocument $dom Instance of DOMDocument |
|
* @param String $filepath |
|
* |
|
* @return void |
|
*/ |
|
private function loadImports($dom, String $filepath = '') { |
|
$query = "//*[local-name()='import']"; |
|
$xpath = new \DOMXPath($this->dom); |
|
if($xpath->query($query)->length > 0) { |
|
$this->dom = $this->loadExt($xpath->query($query), $dom, $filepath); |
|
$this->dom = $this->loadIncludes($this->dom, $this->directory); |
|
} |
|
return $this->dom; |
|
} |
|
|
|
/** |
|
* Load imports o includes |
|
* |
|
* @param DOMDocument $dom Instance of DOMDocument |
|
* @param String $filepath |
|
* |
|
* @return void |
|
*/ |
|
private function loadExt($includes, $dom, $filepath) |
|
{ |
|
if(! empty($includes->length)) { |
|
|
|
foreach ($includes as $file) { |
|
|
|
$parent = $file->parentNode; |
|
|
|
$xsdFileName = realpath($filepath.DIRECTORY_SEPARATOR.$file->getAttribute("schemaLocation")); |
|
|
|
if (! file_exists($xsdFileName)) continue; |
|
if(in_array($xsdFileName, $this->loadedFiles ?? [])) continue; |
|
|
|
$xsd = new \DOMDocument(); |
|
$result = $xsd->load($xsdFileName, LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NOENT|LIBXML_XINCLUDE); |
|
if($result) { |
|
|
|
$this->loadedFiles[] = $xsdFileName; |
|
|
|
foreach ($xsd->documentElement->childNodes as $node) { |
|
$node = $dom->importNode($node, true); |
|
$parent->insertBefore($node, $file); |
|
} |
|
|
|
} |
|
|
|
$parent->removeChild($file); |
|
|
|
} |
|
|
|
} |
|
|
|
return $dom; |
|
} |
|
|
|
/** |
|
* Get Form Sections |
|
* |
|
* @return void |
|
*/ |
|
private function getSections() |
|
{ |
|
|
|
$this->sections = []; |
|
|
|
$this->total_completed = 0; |
|
|
|
foreach ($this->form->complexType->sequence->element as $element) { |
|
|
|
if(empty($element["name"]) && empty($element["ref"])) continue; |
|
|
|
$section = [ |
|
'name' => ! empty((string) $element["name"]) ? (string) $element["name"] : (string) $element["ref"], |
|
'type' => (string) $element["type"] ?? null, |
|
'object' => $element->getName() |
|
]; |
|
|
|
$section["completed"] = false; |
|
if ($this->sectionCompleted($section["name"])) { |
|
$section["completed"] = true; |
|
$this->total_completed++; |
|
} |
|
|
|
if(empty($section["type"]) && ! empty((string) $element["ref"])) $section["type"] = (string) $element["ref"]; |
|
|
|
$this->sections[] = $section; |
|
|
|
$subsections = array_filter($this->settings["subsections"], function($subsection) use ($section){ |
|
return $subsection["parent"] == $section["name"]; |
|
}); |
|
|
|
if (count($subsections) > 0) { |
|
|
|
foreach ($subsections as $sub) { |
|
|
|
$sub["check"] = str_replace("[[FORM]]", $this->form_section, $sub["check"]); |
|
$search = "//*[@name='{$sub["name"]}']"; |
|
|
|
if (count($this->dom->xpath($search)) > 0) { |
|
|
|
$sub["type"] = $this->dom->xpath($search)[0]->attributes()["type"]->__toString(); |
|
$check = self::get($this->info["valori"], $sub["check"]); |
|
$key = str_replace("[[FORM]]",$this->form_section,$sub["key"]); |
|
if ($sub["name"] == $sub["parent"]) { |
|
$key = "{$key}.{$sub["name"]}"; |
|
} |
|
$subsection_contents = self::get($this->info["valori"], $key); |
|
|
|
|
|
if(is_numeric($check) && $check > 0) { |
|
|
|
for ($i=0; $i < (int) $check; $i++) { |
|
|
|
$j = $i + 1; |
|
|
|
if(empty($subsection_contents) || empty($subsection_contents["£"][$j])) { |
|
|
|
//aggiungi le sottosezioni al draft se sono vuote o non valorizzate |
|
//prima di verificare se le sezioni sono completate |
|
$drafted_sections = self::get($this->info["valori"],"TED_ESENDERS.DRAFT_SECTIONS") ?? []; |
|
$draft = str_replace("TED_ESENDERS.FORM_SECTION.[[FORM]].","",$sub["key"]). ".£." . $j; |
|
if ($sub["parent"] == $sub["name"]) { |
|
$draft = "{$sub['name']}.{$draft}"; |
|
} |
|
if (!in_array($draft, $drafted_sections)) { |
|
$drafted_sections[] = $draft; |
|
} |
|
self::set($this->info["valori"],"TED_ESENDERS.DRAFT_SECTIONS",$drafted_sections); |
|
} |
|
|
|
$completed = $this->sectionCompleted("{$section["name"]}.{$sub["name"]}.£.{$j}"); |
|
if ($completed) { |
|
$this->total_completed++; |
|
} |
|
$section = [ |
|
"name" => $section["name"], |
|
"subsection" => $sub["name"], |
|
"type" => $sub["type"], |
|
"object" => "element", |
|
"completed" => $completed, |
|
"index" => $i + 1 |
|
]; |
|
|
|
$this->sections[] = $section; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
} |
|
|
|
} |
|
|
|
|
|
} |
|
} |
|
|
|
/** |
|
* Check all form sections was completed |
|
* @return bool |
|
*/ |
|
public function ready() : bool { |
|
return $this->total_completed == count($this->sections); |
|
} |
|
|
|
/** |
|
* Check if given section is last needed to complete form |
|
* @param String $section |
|
* @return bool |
|
*/ |
|
public function willFormBeReadyAfterSectionCompletion(String $section, String $index) : bool { |
|
if ($this->total_completed == count($this->sections) - 1) { |
|
$draft_sections = $this->get($this->info["valori"],"TED_ESENDERS.DRAFT_SECTIONS"); |
|
$section_check = $section; |
|
if (!is_array($draft_sections)) { |
|
return false; |
|
} |
|
#se non è presente un alcun index non siamo in una sottosezione, quindi possiamo essere più stringenti nella verifica |
|
if (empty($index)) { |
|
return count($draft_sections) == 0 || (count($draft_sections) == 1 && $draft_sections[array_keys($draft_sections)[0]] == $section); |
|
} |
|
#altrimenti controlla se è presente una corrispondenza per la sezione attuale |
|
return count($draft_sections) == 0 || (count($draft_sections) == 1 && strpos($draft_sections[array_keys($draft_sections)[0]],$section_check . ".£.{$index}") !== false); |
|
} |
|
return false; |
|
} |
|
|
|
/** |
|
* Check if given section is completed |
|
* @param SimpleXMLIterator $element |
|
* @return bool |
|
*/ |
|
public function sectionCompleted(String $section) { |
|
return $this->get($this->info["valori"], "TED_ESENDERS.FORM_SECTION.{$this->form_section}.{$section}") !== null && !in_array( |
|
$section, $this->get($this->info["valori"],"TED_ESENDERS.DRAFT_SECTIONS") ?? [] |
|
); |
|
|
|
} |
|
|
|
/** |
|
* Check if form is completed |
|
* |
|
* @return Bool|null |
|
*/ |
|
public function completed() : ?Bool |
|
{ |
|
$this->getSections(); |
|
$check = array_unique(array_column($this->sections, "completed")); |
|
if(count($check) == 1 && $check[0]) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
return false; |
|
} |
|
|
|
/** |
|
* Get fields For Section |
|
* |
|
* @param Array $section |
|
* @param Bool $multiple |
|
* |
|
* @return void |
|
*/ |
|
public function getFieldsForSection(Array $section, Array $name = [], $multiple = false) |
|
{ |
|
$this->fields[$section["name"]] = []; |
|
$this->optionals[$section["name"]] = []; |
|
|
|
if(empty($name)) { |
|
$name = [ |
|
"TED_ESENDERS", |
|
"FORM_SECTION", |
|
$this->form_section |
|
]; |
|
} |
|
|
|
if($section["object"] == "element") $name[] = $section["name"]; |
|
if($multiple) { |
|
$name[] = TedEsender::MUL; |
|
if(isset($section["index"])) { |
|
$name[] = $section["index"]; |
|
} |
|
} |
|
|
|
$type = $this->getTypeElement($section["type"]); |
|
|
|
if(! empty($type)) { |
|
if(is_array($type)) $type = reset($type); |
|
$this->getField($section["name"], $type, ["name" => $name]); |
|
|
|
} |
|
//if ($this->debug) dd($this->fields); |
|
} |
|
|
|
private function getFormContent() { |
|
return $this->info["valori"]["TED_ESENDERS"]["FORM_SECTION"][((string) $this->form->attributes()["name"])]; |
|
} |
|
|
|
/** |
|
* unpack choices from XMLIterator |
|
* @param Array $node |
|
* @return Array |
|
*/ |
|
private function unpackChoice(Array $node) { |
|
$result = []; |
|
foreach ($node as $key => $value) { |
|
|
|
if ($key == "sequence") { |
|
array_push($result, ...$this->unpackChoice($value)); |
|
} |
|
|
|
if ($key == "element") { |
|
if (is_array($value)) { |
|
|
|
foreach ($value as $v) { |
|
|
|
if (is_a( $v, SimpleXMLIterator::class ) ) { |
|
array_push($result, ((string) $v->attributes()["name"])); |
|
} else if (is_array($v)) { |
|
if ($v["ref"]) { |
|
array_push($result, $v["ref"]); |
|
} |
|
|
|
} |
|
} |
|
} |
|
} |
|
} |
|
return array_filter($result, function($value) { return !is_null($value) && $value !== ''; }); |
|
} |
|
|
|
/** |
|
* Get the element description parameters |
|
* |
|
* @param String $t |
|
* @return SimpleXMLElement |
|
*/ |
|
private function getTypeElement(String $t) |
|
{ |
|
$type = $this->dom->xpath("simpleType[@name='{$t}']"); |
|
if(empty($type)) $type = $this->dom->xpath("complexType[@name='{$t}']"); |
|
if(empty($type)) $type = $this->dom->xpath("group[@name='{$t}']"); |
|
if(empty($type)) $type = $this->dom->xpath("element[@name='{$t}']"); |
|
|
|
if(! empty($type) && is_array($type)) $type = reset($type); |
|
return $type; |
|
} |
|
|
|
/** |
|
* Questa funzione è da riscrivere, mo funziona a pezza |
|
* Lo scopo di questa funzione è cercare all'interno di un array di array il primo ["name"] che trova |
|
*/ |
|
private static function unpackUntil($arr, String $key, $or) { |
|
#controlla se nell'array c'è la chiave ricercata |
|
if (is_array($arr)) { |
|
if (!empty($arr[$key])) { |
|
return $arr[$key]; |
|
#se non è presente e l'array è numerico cercala negli indici |
|
} else if (!empty($arr[$or]) && is_array($arr[$or])) { |
|
if (!empty($arr[$or]["info"]) && !empty($arr[1])) { |
|
$or = 1; |
|
} |
|
return self::unpackUntil($arr[$or], $key, $or); |
|
#se non è numerico cercala all'interno delle chiavi |
|
} else if (!empty($arr) && isAssociative($arr)) { |
|
$last = array_keys($arr)[0]; |
|
return self::unpackUntil($arr[$last],$key, $or); |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
/** |
|
* Print form fields |
|
* |
|
* @param Array $field |
|
* @return void |
|
*/ |
|
private function printField(Array $field, Bool $row = true) |
|
{ |
|
if(! empty($field["info"]["title"])) { |
|
|
|
if($row) { ?><div class="row"><? } |
|
|
|
?> |
|
<div class="col-12 my-3 <?=!empty($field["info"]["hidden"]) && $field["info"]["hidden"] == true ? "d-none" : null?>"> |
|
|
|
<? |
|
switch($field["info"]["style"] ?? null) { |
|
case "subtitle": |
|
$style = "border-bottom mb-0 border-black text-muted h6"; |
|
break; |
|
case "annotation": |
|
$style = "border-dark mb-0 h6 text-muted small"; |
|
break; |
|
default: |
|
$style = "border-bottom border-dark mb-0 h5"; |
|
break; |
|
} |
|
$class = ""; |
|
if (!empty($field["info"]["attrs"]["class"])) { |
|
$class = $field["info"]["attrs"]["class"]; |
|
} |
|
?> |
|
<p class="<?=$style?> <?=$class?>"> |
|
<?= $this->translate($field["info"]["title"], self::unpackUntil($field,"name",0)) ?> |
|
</p> |
|
</div> |
|
<? |
|
unset($field["info"]); |
|
$this->printField($field, false); |
|
|
|
if($row) { ?></div><? } |
|
|
|
} else { |
|
if(! empty($field["name"]) && ! empty($field["type"]) && method_exists($this, "__{$field["type"]}")) { |
|
|
|
$key = trim(str_replace(['][', '[', ']'], '.', str_replace("guue", "", $field["name"])), '.'); |
|
$value = $this->get($this->info["valori"], $key); |
|
if (!isset($value)) { |
|
$value = (string) $this->getSuggetion($key); |
|
if (isset($value) && !empty($field["attrs"]) && is_array($field["attrs"]) && (in_array("onChange",array_keys($field["attrs"])) !== false || in_array("onclick",array_keys($field["attrs"])) !== false)) { |
|
$field["triggerOnChange"] = true; |
|
} |
|
} |
|
if(isset($value) && is_string($value)) { |
|
$field["val"] = $value; |
|
} |
|
echo $this->{$field["type"]}($field); |
|
|
|
} else { |
|
|
|
$fields = $field; |
|
|
|
foreach ($fields as $key => $field) { |
|
|
|
if( (strpos($key, "RADIO_FOR") !== false || empty($field["name"])) && ! in_array($key, $this->ignored_keys) && ! is_numeric($key)) { |
|
$attrs = ""; |
|
$class = ""; |
|
$required_check = ""; |
|
if(is_array($field) && in_array("radio", array_column($field, "type"))) { |
|
if ($field[0]["required"] ?? false) { |
|
$required_check = " <?= TedEsender::MANDATORY_ASTERISK ?>"; |
|
} |
|
$validation = array_unique(array_column($field, "group_validate")); |
|
|
|
if(empty($validation) || (count($validation) == 1 && $validation[0])) { |
|
$attrs = 'rel="S;0;0;checked;group_one" title="' . $this->translate($key, self::unpackUntil($field,"name",0)) . '"'; |
|
$class = "valida"; |
|
} |
|
} |
|
$title = $this->translate($key, self::unpackUntil($field,"name",0)) . $required_check; |
|
if (!empty($this->settings["titles"][$key])) { |
|
$title = $this->translate($this->settings["titles"][$key], self::unpackUntil($field,"name",0)) . $required_check; |
|
} |
|
?><div class="col-12 my-3 <?=strpos($key, "TITLE_FOR") !== false ? "d-none" : null ?>"><p class="border-bottom mb-0 <?= strpos($title ?? "", "):") === false ? "border-black text-muted h6" : "h5"?>"><?= $title ?></p></div><div class="col-12 form-group"><div class="<?= $class ?> row" <?= $attrs ?>><? |
|
} |
|
|
|
if(! empty($field["name"]) && empty($field["title"])) $field["title"] = $this->translate($key, self::unpackUntil($field,"name",$key)); |
|
$this->printField($field, false); |
|
|
|
if( (strpos($key, "RADIO_FOR") !== false || empty($field["name"])) && ! in_array($key, $this->ignored_keys) && ! is_numeric($key)) { |
|
|
|
?></div></div><? |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
} |
|
|
|
/** |
|
* Store data |
|
* |
|
* @param Array $data |
|
* @return void |
|
*/ |
|
public function save(Array $data) : array |
|
{ |
|
$result = [ |
|
"action" => self::DEFAULT, |
|
"codice" => null |
|
]; |
|
$subsection = null; |
|
$record = $this->info; |
|
|
|
$draft = $record["valori"]["TED_ESENDERS"]["DRAFT_SECTIONS"] ?? []; |
|
if (empty($record["codice"]) && empty($draft)) { |
|
foreach ($this->sections as $section) { |
|
$draft[] = $section["name"]; |
|
} |
|
} |
|
$to_draft = $data["current_section"]; |
|
if ($data["draft"] == "S" && empty($data["current_sub_section"])) { |
|
array_push($draft, $to_draft); |
|
} else if (in_array($to_draft, $draft) && empty($data["current_sub_section"])) { |
|
unset($draft[(array_search($to_draft,$draft))]); |
|
} |
|
|
|
if(! empty($data["titolo"])) { $record["titolo"] = $data["titolo"]; } |
|
if(! empty($this->settings["sections"][$data["current_section"]])) { |
|
|
|
if(! empty($data["current_sub_section"])) { |
|
|
|
$key = "{$this->settings["sections"][$data["current_section"]]}.{$data["current_sub_section"]}"; |
|
$key = str_replace("[[FORM]]", $this->form_section, $key); |
|
|
|
if(! empty($data["current_sub_section_index"])) { |
|
$key = "{$key}.£.{$data["current_sub_section_index"]}"; |
|
|
|
$draft_key = str_replace("TED_ESENDERS.FORM_SECTION.{$this->form_section}.","",$key); |
|
if ($data["draft"] == "S") { |
|
array_push($draft,$draft_key); |
|
} else if (in_array($draft_key, $draft)) { |
|
unset($draft[(array_search($draft_key,$draft))]); |
|
} |
|
} |
|
|
|
self::set($record["valori"], $key, []); |
|
|
|
$result["action"] = self::EDITED_SUBSECTION; |
|
|
|
} else { |
|
|
|
$key = "{$this->settings["sections"][$data["current_section"]]}"; |
|
$key = str_replace("[[FORM]]", $this->form_section, $key); |
|
|
|
$subsections = array_filter($this->settings["subsections"], function($subsection) use ($data) { |
|
return $subsection["parent"] == $data["current_section"] && !empty( |
|
self::get($this->info["valori"], str_replace("[[FORM]]", $this->form_section, $subsection["check"])) |
|
); |
|
}); |
|
|
|
if (count($subsections) > 0) { |
|
|
|
foreach ($subsections as $subsection) { |
|
|
|
$subsection_check = str_replace("[[FORM]]", $this->form_section, $subsection["check"]); |
|
$subsection_key = str_replace("[[FORM]]", $this->form_section, $subsection["key"]); |
|
|
|
#se il valore risulta vuoto all'interno del form, viene inserito come zero |
|
if (empty(self::get($data["guue"],$subsection_check)) && $subsection["name"] == $subsection["parent"]) { |
|
self::set($data["guue"],$subsection_check,0); |
|
} |
|
$check = (int) (self::get($data["guue"], $subsection_check)); |
|
$valori = self::get($record["valori"], $subsection_key) ?? []; |
|
|
|
if(is_numeric($check) && $check > 0) { |
|
|
|
if (isset($valori["£"]) && count($valori["£"]) > $check ) { |
|
$difference = count($valori["£"]) - $check; |
|
$keys = array_slice(array_keys($valori["£"]),count($valori["£"]) - $difference, count($valori["£"])); |
|
foreach ($keys as $key) { |
|
unset($valori["£"][$key]); |
|
} |
|
} else if (isset($valori[$data["current_section"]]["£"]) && $valori[$data["current_section"]]["£"] > $check) { |
|
$difference = count($valori[$data["current_section"]]["£"]) - $check; |
|
$keys = array_slice(array_keys($valori[$data["current_section"]]["£"]),count($valori[$data["current_section"]]["£"]) - $difference, count($valori[$data["current_section"]]["£"])); |
|
foreach ($keys as $key) { |
|
unset($valori[$data["current_section"]]["£"][$key]); |
|
} |
|
|
|
} |
|
|
|
|
|
self::set($subsection["valori"], $subsection_key, $valori); |
|
|
|
} else { #nel caso in cui il check sia vuoto ma sono presenti dei contenuti rimuovili |
|
|
|
foreach ($draft as $index => $draft_section) { |
|
if (strpos($draft_section,"{$subsection['parent']}.{$subsection['name']}.£") !== false) { |
|
unset($draft[$index]); |
|
} |
|
} |
|
if (!empty($valori["£"])) { |
|
unset($valori["£"]); |
|
#controlla se la sezione è presente nelle draft |
|
} |
|
|
|
$result["action"] = self::REMOVED_SUBSECTIONS; |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
self::set($record["valori"], $key, []); |
|
} |
|
|
|
} else { |
|
|
|
self::set($record["valori"],"TED_ESENDERS.FORM_SECTION.{$this->form_section}.{$data['current_section']}",[]); |
|
} |
|
$this->removeOverridedKeys($data["guue"]); |
|
$record["valori"] = $this->md_array_merge($record["valori"], $data["guue"]); |
|
|
|
$draft = array_unique($draft); |
|
self::set($record["valori"],"TED_ESENDERS.DRAFT_SECTIONS",$draft); |
|
|
|
if(! empty($subsection["valori"])) { |
|
$record["valori"] = $this->md_array_merge($record["valori"], $subsection["valori"]); |
|
} |
|
$this->sortSections(); |
|
$record["valori"] = $this->fixHtmlVaues($record["valori"]); |
|
array_walk_recursive($record["valori"], 'htmlentitiesdecode'); |
|
$record["valori"] = json_encode($record["valori"],JSON_INVALID_UTF8_IGNORE); |
|
$record["data_aggiornamento"] = date('d/m/Y H:i:s'); |
|
$record["data_trasmissione"] = null; |
|
$record["modulo"] = $_POST["modulo"] ?? null; |
|
$record["codice_elemento"] = $_POST["codice_elemento"] ?? 0; |
|
$record["stato"] = self::stati()[0]["title"]; |
|
if (! $_SESSION["utente"]->fromHere()) { |
|
$record["codice_ente"] = $_SESSION["utente"]->codice_ente; |
|
} |
|
|
|
$salva = new Salva(); |
|
$salva->debug = false; |
|
$salva->nome_tabella = "b_guue"; |
|
$salva->operazione = "INSERT"; |
|
$salva->ignore = ["soft_delete"]; |
|
if(! empty($record["codice"])) { |
|
$salva->operazione = "UPDATE"; |
|
$salva->ignore[] = "data_creazione"; |
|
$salva->ignore[] = "utente_modifica"; |
|
$salva->ignore[] = "data_pubblicazione"; |
|
} |
|
$salva->oggetto = $record; |
|
$codice = $salva->save(); |
|
|
|
if(! empty($codice)) { |
|
|
|
$this->info = $salva->oggetto; |
|
$this->info["codice"] = $codice; |
|
|
|
if($_SESSION["utente"]->gerarchia > 15 && $salva->operazione == "INSERT") { |
|
|
|
$permesso = []; |
|
$permesso["sezione"] = "guue"; |
|
$permesso["codice_elemento"] = $this->info["codice"]; |
|
$permesso["codice_gestore"] = $_SESSION["ente"]->codice; |
|
$permesso["funzione"] = "0"; |
|
$permesso["codice_utente"] = $_SESSION["utente"]->codice; |
|
|
|
$salva = new salva(); |
|
$salva->debug = false; |
|
$salva->raw = true; |
|
|
|
$salva->nome_tabella = "r_permessi"; |
|
$salva->operazione = "INSERT"; |
|
$salva->oggetto = $permesso; |
|
$salva->save(); |
|
|
|
} |
|
|
|
$this->info["valori"] = json_decode($this->info["valori"], 1); |
|
$result["codice"] = $codice; |
|
return $result; |
|
|
|
} |
|
$result["codice"] = $codice; |
|
return $result; |
|
|
|
} |
|
|
|
public function getLastNumber() : int { |
|
$number = 0; |
|
$latest = $this->pdo->go("SELECT MAX(numero) FROM b_guue WHERE anno = :anno", [":anno" => date('Y')])->fetch(PDO::FETCH_COLUMN, 0); |
|
if($latest > 0) { $number = $latest; } |
|
return $number; |
|
} |
|
|
|
/** |
|
* Create xml notice |
|
* |
|
* @param Array $valori |
|
* @return void |
|
*/ |
|
public function xml(Array $data = [], Array $ente = [], bool $update_state = true) : void |
|
{ |
|
if(empty($ente) || empty($ente["id_guue"])) { $ente = $_SESSION["ente"]->getInfo(); } |
|
if(empty($data)) { $data = $this->info; } |
|
if(empty($data["numero"])) { |
|
$data["numero"] = $this->getLastNumber() + 1; |
|
$this->info["numero"] = $data["numero"]; |
|
$this->pdo->go( |
|
"UPDATE b_guue SET numero = :numero WHERE codice = :codice", |
|
[":numero" => $data["numero"], ":codice" => $this->info['codice']] |
|
); |
|
} |
|
if(strlen($data["numero"]) < 6) { |
|
$data["numero"] = str_repeat("0", 6 - strlen($data["numero"])) . $data["numero"]; |
|
} |
|
|
|
$this->auth(); |
|
|
|
$TED_ESENDERS = $data["valori"]["TED_ESENDERS"]; |
|
|
|
$data["valori"]["TED_ESENDERS"] = [ |
|
"_attributes" => [ |
|
"xmlns" =>"http://publications.europa.eu/resource/schema/ted/R2.0.9/reception", |
|
"xmlns:tg"=>"http://publications.europa.eu/resource/schema/ted/R2.0.9/reception", |
|
"xmlns:tg-nuts"=>"http://publications.europa.eu/resource/schema/ted/2021/nuts", |
|
"xmlns:tg-curr" => "http://publications.europa.eu/resource/authority/currency", |
|
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance", |
|
"xsi:schemaLocation"=>"http://publications.europa.eu/resource/schema/ted/R2.0.9.S05/publication TED_EXPORT.xsd", |
|
"VERSION"=>"R2.0.9.S05", |
|
], |
|
"SENDER" => [ |
|
"IDENTIFICATION" => [ |
|
"ESENDER_LOGIN" => $this->username, |
|
"CUSTOMER_LOGIN" => $ente["id_guue"] ?? "__£__", |
|
"NO_DOC_EXT" => "{$data["anno"]}-{$data["numero"]}", |
|
"SOFTWARE_VERSION" => "3.0", |
|
], |
|
"CONTACT" => [ |
|
"ORGANISATION" => "STUDIO AMICA SRL", |
|
"COUNTRY" => [ |
|
"_attributes" => [ |
|
"VALUE" => "IT" |
|
] |
|
], |
|
"PHONE" => "", |
|
"E_MAIL" => "gaetano.lolli@studioamica.it", |
|
] |
|
] |
|
]; |
|
|
|
$data["valori"]["TED_ESENDERS"] = array_merge($data["valori"]["TED_ESENDERS"], $TED_ESENDERS); |
|
foreach ($data["valori"]["TED_ESENDERS"]["FORM_SECTION"] as $key => $form) { |
|
$data["valori"]["TED_ESENDERS"]["FORM_SECTION"][$key] = array_merge([ |
|
"_attributes" => [ |
|
"LG" => "IT", |
|
"CATEGORY" => "ORIGINAL", |
|
"FORM" => substr($key, 0, strpos($key, "_")), |
|
] |
|
], $data["valori"]["TED_ESENDERS"]["FORM_SECTION"][$key]); |
|
} |
|
|
|
try { |
|
|
|
$stati = $this->stati(); |
|
$stato = $stati[0]["title"]; |
|
|
|
$this->xml = $this->errors = ""; |
|
$this->fixArrayForXml($data["valori"]); |
|
$this->xml = \Spatie\ArrayToXml\ArrayToXml::convert($data["valori"]["tg:TED_ESENDERS"], "tg:TED_ESENDERS"); |
|
|
|
$originalErrorHandling = libxml_use_internal_errors(true); |
|
|
|
$document = new DOMDocument(); |
|
$document->loadXML($this->xml); |
|
$document->schemaValidate(__DIR__ . "/../config/xml/TED_ESENDERS.xsd"); |
|
|
|
$errors = libxml_get_errors(); |
|
$this->errors = []; |
|
if(! empty($errors)) { |
|
foreach ($errors as $error) { |
|
$e = str_replace(["{http://publications.europa.eu/resource/schema/ted/R2.0.9/reception}", "{http://publications.europa.eu/resource/schema/ted/2021/nuts}"], "", $error->message); |
|
$e = preg_replace('/[[:cntrl:]]/', '', $e); |
|
if(! in_array($e, $this->errors)) $this->errors[] = $e; |
|
} |
|
} |
|
$this->errors = array_filter($this->errors); |
|
|
|
libxml_clear_errors(); |
|
libxml_use_internal_errors($originalErrorHandling); |
|
|
|
} catch (\Throwable $th) { |
|
|
|
$message = "GUUE CODICE: {$this->info["codice"]} IMPOSSIBILE GENERARE XML. ERRORE: " . $th->getMessage(); |
|
if ($this->debug) { |
|
echo $message; |
|
} |
|
error_log($message); |
|
|
|
} finally { |
|
|
|
if(! empty($this->xml) && empty($this->errors)) { |
|
|
|
$stato = $stati[1]["title"]; |
|
|
|
} |
|
|
|
$this->errors = base64_encode(json_encode($this->errors)); |
|
|
|
$s = array_flip(array_column($stati, 'title')); |
|
if($stati[$s[$stato]]["status"] < 20) { |
|
|
|
if ($update_state) { |
|
$this->pdo->go("UPDATE b_guue |
|
SET xml = :xml, errori = :errori, stato = :stato, data_aggiornamento = NOW() |
|
WHERE codice = :codice", |
|
[ |
|
":xml" => base64_encode($this->xml), |
|
":errori" => $this->errors, |
|
":stato" => $stato, |
|
":codice" => $this->info["codice"] |
|
]); |
|
} |
|
|
|
} |
|
|
|
|
|
} |
|
|
|
} |
|
|
|
public function getBreadcrumb($breadcrumb = []) { |
|
if (!empty($this->info["modulo"]) && !empty(!empty($this->info["codice_elemento"]))) { |
|
if ($_SESSION["utente"]->permission($this->info["modulo"],$this->info["codice_elemento"])) { |
|
global $beRoot; |
|
if (file_exists("{$beRoot}/{$this->info["modulo"]}/panel.php")) { |
|
$infoModulo = Modulo::getInfo($this->info["modulo"]); |
|
$breadcrumb["/{$this->info["modulo"]}/panel.php?codice={$this->info["codice_elemento"]}"] = __guue($infoModulo["titolo"]) . " - " . __guue("Pannello"); |
|
} |
|
} |
|
} |
|
return $breadcrumb; |
|
} |
|
|
|
/** |
|
* It iterate form field group |
|
* |
|
* @param String $section |
|
* @param array $fields |
|
* @return void |
|
*/ |
|
public function printFields(String $section, Array $fields = []) |
|
{ |
|
if(empty($fields)) { $fields = $this->fields; } |
|
foreach ($fields as $field) { |
|
if(! isset($field[$section]) && is_array($field)) { |
|
$this->printFields($section, $field); |
|
} else { |
|
$this->printField($field[$section]); |
|
} |
|
} |
|
|
|
} |
|
|
|
/** |
|
* Main function to print a form section |
|
* |
|
* @param Array $section |
|
* @return void |
|
*/ |
|
public function printForm(Array $section) |
|
{ |
|
if(! empty($section["name"])) { |
|
|
|
$n = []; |
|
$this->current_section = $s = $section; |
|
|
|
if(! empty($section["subsection"])) { |
|
|
|
$n = [ |
|
"TED_ESENDERS", |
|
"FORM_SECTION", |
|
$this->form_section, |
|
$section["name"], |
|
]; |
|
|
|
$s["name"] = $s["subsection"]; |
|
|
|
$m = true; |
|
$this->getFieldsForSection($s, $n, $m); |
|
$fields = $this->fields["TED_ESENDERS"]["FORM_SECTION"][$this->form_section][$section["name"]][$section["subsection"]]; |
|
if($m && isset($section["index"])) { $fields = $fields[TedEsender::MUL][$section["index"]]; } |
|
$this->setMissingTitles($fields, $section["subsection"]); |
|
|
|
} else { |
|
|
|
$this->getFieldsForSection($s); |
|
$fields = $this->fields["TED_ESENDERS"]["FORM_SECTION"][$this->form_section][$section["name"]]; |
|
$this->setMissingTitles($fields, $section["name"]); |
|
|
|
} |
|
|
|
if(! empty($this->fields["TED_ESENDERS"]["FORM_SECTION"][$this->form_section][$section["name"]])) { |
|
?> |
|
<p class="h3 mb-4"><?= $this->translate($section["name"], self::unpackUntil($section,"name",0)) ?></p> |
|
<div class="row"> |
|
<? |
|
$this->printField($fields, false); |
|
?> |
|
</div> |
|
<? |
|
} |
|
} |
|
?> |
|
<script type="text/javascript"> |
|
|
|
var add2GUUE = function (target, data) { |
|
$.ajax({ |
|
type: "POST", |
|
url: "/backend/guue/add2GUUE.php?codice=<?= $this->info["codice"] ?>", |
|
data: {data: data}, |
|
dataType: "html", |
|
beforeSend: function() { |
|
$("#wait_div").show(); |
|
} |
|
}) |
|
.fail(function(response) { |
|
swal(js_dict["error-retry"]); |
|
}) |
|
.done(function(response) { |
|
$(target).append(response); |
|
f_ready(); |
|
}) |
|
.always(function() { |
|
$("#wait_div").slideUp('fast'); |
|
}); |
|
} |
|
|
|
var disableSibling = function (disabler, disabled) { |
|
// console.log(disabled); |
|
if ( $(disabler).val() != "" && $(disabler).val() != undefined && $(disabler).val() != null ) { |
|
$(disabled).prop('disabled', true); |
|
$(disabled).prop('disabled', true).trigger("chosen:updated"); |
|
} else { |
|
$(disabled).prop('disabled', false); |
|
$(disabled).prop('disabled', false).trigger("chosen:updated"); |
|
} |
|
} |
|
<? |
|
if (!empty($this->suggestionTriggers)) { |
|
foreach($this->suggestionTriggers AS $triggerID) { |
|
?> |
|
$("#<?= $triggerID ?>").trigger("change"); |
|
<? |
|
} |
|
} |
|
?> |
|
</script> |
|
<? |
|
} |
|
|
|
/** |
|
* Label translator |
|
* |
|
* @param String $string |
|
* @return void |
|
*/ |
|
public function translate(String $string, ?String $name = null) |
|
{ |
|
if (!empty($this->settings["dynamic_translations"][$this->form_section])) { |
|
$string = $this->settings["dynamic_translations"][$this->form_section][$string] ?? $string; |
|
} |
|
|
|
$name = explode("][",substr($name,5,-1)); |
|
$section = null; |
|
|
|
if (count($name) > 3) { $section = $name[3]; } |
|
//Parse settings name array searching for last subsection |
|
foreach ([4,7] as $pos) { |
|
if (count($name) > $pos && in_array($name[$pos], array_map(function($section){ return ($section["name"]); },$this->settings["subsections"]))) { |
|
$section = $name[$pos]; |
|
} |
|
} |
|
|
|
$numeration = ""; |
|
|
|
if ( |
|
! empty($section) && |
|
! empty($this->settings["numeration_map"]) && |
|
! empty($this->settings["numeration_map"]["{$this->form_section}"]) && |
|
! empty($this->settings["numeration_map"]["{$this->form_section}"]["{$section}"]) && |
|
! empty($this->settings["numeration_map"]["{$this->form_section}"]["{$section}"]["{$string}"]) |
|
) { |
|
$numeration = $this->settings["numeration_map"]["{$this->form_section}"]["{$section}"]["{$string}"]; |
|
} |
|
|
|
$translate_functions = [ |
|
"PT_NEGOTIATED_WITHOUT_PUBLICATION" => function() use ($string, $name) : String { |
|
if (in_array($name[count($name)-2], ["DIRECTIVE_2014_24_EU","DIRECTIVE_2014_25_EU","DIRECTIVE_2009_81_EC"]) && $string == "PT_NEGOTIATED_WITHOUT_PUBLICATION") { |
|
return $name[count($name)-2] . "_SELECTION_WITHOUT_PUBLICATION"; |
|
} |
|
return $string; |
|
}, |
|
"PT_AWARD_CONTRACT_WITHOUT_CALL" => function() use ($string, $name) : String { |
|
if (in_array($name[count($name)-2], ["DIRECTIVE_2014_24_EU","DIRECTIVE_2014_25_EU","DIRECTIVE_2009_81_EC"]) && $string == "PT_AWARD_CONTRACT_WITHOUT_CALL") { |
|
return $name[count($name)-2] . "_SELECTION_WITHOUT_CALL"; |
|
} |
|
return $string; |
|
}, |
|
"ADDRESS_REVIEW_BODY_WARNING" => function() use ($string, $name) : String { |
|
return __guue('(Indirizzo del corpo di revisione)'); |
|
}, |
|
"ADDRESS_MEDIATION_BODY_WARNING" => function() use ($string, $name) : String { |
|
return __guue('(Responsabile delle procedure di mediazione)'); |
|
}, |
|
"ADDRESS_REVIEW_INFO_WARNING" => function() use ($string, $name) : String { |
|
return __guue('(Informazioni sulla revisione)'); |
|
}, |
|
"ADDRESS_CONTRACTING_BODY_WARNING" => function() use ($string, $name) : String { |
|
return __guue('(Denominazione e indirizzi)'); |
|
}, |
|
"ADDRESS_CONTRACTING_BODY_ADDITIONAL_WARNING" => function() use ($string, $name) : String { |
|
return __guue('(Altre stazioni appaltanti)'); |
|
}, |
|
"ADDRESS_PARTICIPATION_WARNING" => function() use ($string, $name) : String { |
|
return __guue("(Offerte e domande di partecipazione)"); |
|
}, |
|
"ADDRESS_FURTHER_INFO_WARNING" => function() use ($string, $name) : String { |
|
return __guue("(Ulteriori informazioni sono disponibili presso)"); |
|
} |
|
|
|
]; |
|
if (!empty($name) && in_array($string, array_keys($translate_functions))) { |
|
$translate_func = $translate_functions[$string]; |
|
$string = $translate_func(); |
|
} |
|
if(! empty($this->mapper[$string])) { |
|
if(! empty($this->translator[$this->mapper[$string]]["it"])) $string = $this->translator[$this->mapper[$string]]["it"]; |
|
} |
|
|
|
if (!empty($numeration)) { |
|
return $numeration . " " . $string; |
|
} |
|
return $string; |
|
} |
|
|
|
|
|
#region [Validation Rules Traductions] |
|
private function dateFormatValidationRule(Array $matches, String $raw_err) : String { |
|
$key = str_replace($matches[1], "", $matches[0]); |
|
if (!empty($this->mapper["ERRORS_DICT"][$key]["it"])) { |
|
$err = $this->mapper["ERRORS_DICT"][$key]["it"]; |
|
$chunk = str_split($matches[1], 2); |
|
$chunk[2] = $chunk[2] . $chunk[3]; |
|
unset($chunk[3]); |
|
$err = str_replace("[[DATE]]",implode("/",$chunk),$err); |
|
} |
|
return $err ?? $matches[0]; |
|
} |
|
|
|
private function phoneNumberValidationRule(Array $matches, String $raw_err) : String { |
|
$err = null; |
|
if (count($matches) > 2) { |
|
if ($matches[1] == "phone") { |
|
$matches[1] = "Tel"; |
|
} |
|
$matches[1] = ucfirst($matches[1]); |
|
$err = __guue($matches[1]) . " {$matches[2]} " . __guue("non è un numero telefonico valido."); |
|
} |
|
return $err ?? $matches[0]; |
|
} |
|
|
|
private function numberNoticeValidationRule(Array $matches, String $raw_err) : String { |
|
$err = null; |
|
if (count($matches) > 1) { |
|
$err = $matches[1] . " " . __guue("non è un numero di avviso valido."); |
|
} |
|
return $err; |
|
} |
|
|
|
private function annexD1ValidationRule(Array $matches, String $raw_err) : String { |
|
$m = []; |
|
preg_match_all('/[[][@]CTYPE[=](\w+)[]]/m', $raw_err, $m); |
|
if (count($m) > 1 && count($m[1]) > 1) { |
|
return __guue("Attenzione, la tipologia del contratto risulta incoerente con la giustificazione dell'allegato Annex D1, Tipologia del contratto ({$this->translate($m[1][0])}) è differente dalla tipologia accettata ({$this->translate($m[1][1])})"); |
|
} |
|
return $raw_err; |
|
} |
|
|
|
private function publicationValidationRule(Array $matches, String $raw_err) : String { |
|
$matches = []; |
|
preg_match_all('/([A-Z0-9_]+)[\/][@][A-Z0-9_]+=\w+ and ([A-Z0-9_]+)[\/]([A-Z0-9_]+)[[].*[@]PUBLICATION[]]/',$raw_err,$matches); |
|
if (count($matches) > 3) { |
|
if ($matches[2] == [] || $matches[3] == []) { |
|
return $raw_err; |
|
} |
|
$section2 = $matches[2][0]; |
|
$section3 = $matches[3][0]; |
|
$replacements = [ |
|
"AWARDED_CONTRACT" => "RADIO_FOR_SME_SECTION", |
|
"CONTRACTORS" => "ADDRESS_CONTRACTOR", |
|
"VALUES" => "VALUE", |
|
"AC" => "AC_DEF" |
|
]; |
|
if (!empty( $replacements[$section2]) ) { |
|
$section2 = $replacements[$section2]; |
|
} |
|
if (!empty( $replacements[$section3]) ) { |
|
$section3 = $replacements[$section3]; |
|
} |
|
$section = __guue("Sezione") . ": " . $this->translate($section2) . ", " . $this->translate($section3); |
|
return __guue("La pubblicazione è richiesta per contratti sotto direttiva 2014/25/EU") . ". " . $section; |
|
} |
|
return $raw_err; |
|
} |
|
|
|
private function repeatValidationRule(Array $matches, String $raw_err) : String { |
|
if ($matches > 2) { |
|
$element = $this->translate(strtoupper($matches[2])); |
|
$type = $this->translate(strtoupper($matches[1])); |
|
return __guue("Non è possibile inserire molteplici elementi") . "(" . $element . " ), " . __guue("se la tipologia di avviso è") . " (" . $type . " )"; |
|
} |
|
return $raw_err; |
|
} |
|
|
|
private function qualificationValidationRule(Array $matches, String $raw_err) : String { |
|
$matches = []; |
|
preg_match_all('/\w+[\/][@]TYPE[=](\w+) and (\w+)[[](\d)[]][\/](\w+)[[][\d][]][\/]QS[\/](\w+)/s',$raw_err, $matches); |
|
if (count($matches) > 5) { |
|
$type = $this->translate($matches[1][0]); |
|
$section = $this->translate($matches[2][0]); |
|
$index = $this->translate($matches[3][0]); |
|
$subsection = $this->translate($matches[4][0]); |
|
$field = $this->translate($matches[5][0]); |
|
|
|
return " n.{$index} " . "(". $field . " ) " . __guue("è prevista solo se la tipologia del contratto è un Sistema di qualificazione ") . "(" . $type . " )"; |
|
} |
|
return $raw_err; |
|
} |
|
#endregion |
|
|
|
/** |
|
* Convert validation rules errors into human readable errors |
|
* |
|
* @param array $errors |
|
* @return array |
|
*/ |
|
public function validationRuleToHuman(Array $errors) { |
|
$latin = [ |
|
1 => "I", |
|
2 => "II", |
|
3 => "III", |
|
4 => "IV", |
|
5 => "V", |
|
6 => "VI", |
|
7 => "VII", |
|
8 => "VIII", |
|
9 => "IX", |
|
10 => "X", |
|
]; |
|
|
|
foreach ($errors as $index => $err) { |
|
$raw_err = $err; |
|
$matches = []; |
|
preg_match('/[:](.*)[.][<]br[>]/s', $err, $matches); |
|
if (count($matches) == 2) { |
|
$err = trim($matches[1]); |
|
} else { |
|
$matches = []; |
|
preg_match('/:([ ]\w+[-]\w+[-]\w+[:].*)[.][ ][<]br[>]/s', $err, $matches); |
|
if (count($matches) != 0) { |
|
$err = trim($matches[count($matches)-1]); |
|
} |
|
} |
|
$err = str_replace(['"',';',',',"'","/","(",")","<br>"], "", $err); |
|
$err = str_replace([":"," ","__"], "_", $err); |
|
$err = str_replace("...","", $err); |
|
$err = strtolower($err); |
|
|
|
#TODO: Rimuove gli errori relativi al campo lingua, da adattare una volta implementate le altre lingue |
|
$languages_errors = [ |
|
"s4-02-04_languages_not_foreseen_if_the_notice_aims_at_reducing_time_limits", |
|
"s4-02-04_languages_not_foreseen_if_contract_award_notice", |
|
"s4-02-04_languages_not_foreseen_if_it_is_about_a_qualification_system", |
|
"s4-02-04_languages_not_foreseen_if_concession_award_notice", |
|
"s4-02-04_languages_mandatory_if_this_notice_is_a_call_for_competition", |
|
"s4-02-04_languages_mandatory_if_prior_information_notice" |
|
]; |
|
if (in_array($err,$languages_errors)) { |
|
unset($errors[$index]); |
|
continue; |
|
} |
|
################# |
|
|
|
if (!empty($this->mapper["ERRORS_DICT"][$err]["it"])) { |
|
$err = $this->mapper["ERRORS_DICT"][$err]["it"]; |
|
} else { |
|
foreach ([ |
|
'/and_lefti_s3_legal_economic_financial_and_technical_information_not_foreseen_if/s' => $this->mapper["ERRORS_DICT"]["and_lefti_s3_legal_economic_financial_and_technical_information_not_foreseen_if"]["it"], |
|
'/notice_dispatch_date_element_must_contain_the_real_sending_date_of_xml_notice[.]dispatch_date_in_the_notice_is_(\d+)/s' => 'dateFormatValidationRule', |
|
'/lot_no_must_be_unique_within/s' => __guue('Il numero dei lotti deve essere univoco.'), |
|
'/element_(\w+)_(.*)_is_not_a_valid_value_of_the_atomic_type_phone/s' => 'phoneNumberValidationRule', |
|
'/element_notice_number_oj_[[]facet_pattern[]]_the_value_(.*)_is_not/s' => 'numberNoticeValidationRule', |
|
'/annex_d-1_justification_inconsistency_with_the_contract_type/s' => 'annexD1ValidationRule', |
|
'/is_not_a_valid_value_of_the_atomic_type_noticeno/s' => __guue('Il numero dell\'avviso non è valido'), |
|
'/duplicate_no_doc_ext_a_notice_with_the_same_identifier_has_already_been_received/s' => __guue('Attenzione, un form con lo stesso identificativo è già stato ricevuto'), |
|
'/the_agreement_to_the_publication_of_information_is_required_only_in_case_of_a_notice_covered_by_directive_201425eu/s' => 'publicationValidationRule', |
|
'/notice[@]type[=](\w+)_and_number(\w+)[=].*the_section_could_not_be_repeated/s' => 'repeatValidationRule', |
|
'/s2-02-08_duration_of_the_qualification_system_foreseen_for_a_qualification_system/s' => 'qualificationValidationRule' |
|
] as $regex => $callback) { |
|
$matches = []; |
|
preg_match($regex, $err, $matches); |
|
if (count($matches) != 0) { |
|
if (method_exists($this, $callback)) { |
|
$err = $this->{$callback}($matches, $raw_err); |
|
} else if (is_string($callback)) { |
|
$err = $callback; |
|
} |
|
} |
|
} |
|
|
|
} |
|
|
|
$section_matches = []; |
|
preg_match('/S(\d+[-]\d+[-]\d+)[:]|S(\d+)/',$raw_err,$section_matches); |
|
$err_sect = ""; |
|
if (!empty($section_matches) && count($section_matches) > 1) { |
|
$section_matches = (explode("-",$section_matches[count($section_matches) - 1])); |
|
foreach ($section_matches as $i => $identifier) { |
|
$section_matches[$i] = (int) $identifier; |
|
if ($i == 0) { |
|
$section_matches[$i] = "{$latin[$identifier]})"; |
|
} |
|
} |
|
$err_sect = __guue("Sezione") . " {$section_matches[0]} " . (implode(".",array_slice($section_matches,1))) . " "; |
|
} |
|
|
|
$err = $err_sect . $err; |
|
$errors[$index] = $err; |
|
} |
|
return array_unique($errors); |
|
} |
|
|
|
|
|
public function setMode(string $string) : void {} |
|
|
|
public function manageChangeSection() : void {} |
|
|
|
public function getReorderedSections() : void {} |
|
} |
|
|
|
include_once 'eFormsManager.class.php';
|