Przeglądaj źródła

Merge branch 'master' of ssh://biuro.biall-net.pl:2222/plabudda/se

* 'master' of ssh://biuro.biall-net.pl:2222/plabudda/se:
  updated bocian
  Włączenie BiAuditGenerate
  Implementacja UrlAction dla BI_audit_MSIG oraz zwracanie pustego xmla w przypadku braku wyników
  bug fix
  added ref list to row actions
a.binder 8 lat temu
rodzic
commit
2ba753abf0

+ 1 - 1
SE/bash_sync_perms.php

@@ -545,7 +545,7 @@ class SyncPerms {
 		echo "DBG: UrlAction_WmsGenerate->doGenerate() END\n";
 
 		echo "DBG: UrlAction_BiAuditGenerate->doGenerate() START...\n";
-		//Router::getRoute('UrlAction_BiAuditGenerate')->doGenerate(); //musze przetestowac raport!
+		Router::getRoute('UrlAction_BiAuditGenerate')->doGenerate(); //musze przetestowac raport!
 		echo "DBG: UrlAction_BiAuditGenerate->doGenerate() END\n";
 	}
 

+ 1 - 1
SE/projects/bocian

@@ -1 +1 @@
-Subproject commit fbda6b1279dceb97734fc9923c8cd26e8625709e
+Subproject commit 46765b95c9d49d36ff65afd37342f65968db0a99

+ 21 - 6
SE/se-lib/ACL.php

@@ -416,26 +416,41 @@ class ACL {
 	}
 	public static function getBackRefList($namespace) {
 		if (!$namespace) throw new Exception("Missing namespace");
-		$nsParts = explode('/', $namespace);
-		$typeName = array_pop($nsParts);
-		$typeName = implode("__x3A__", $nsParts) . ":{$typeName}";
 		return DB::getPDO()->fetchAll("
 			select c.ROOT_OBJECT_NS as namespace
 				, i.id as idInstance
 			from CRM_REF_CONFIG c
 				join CRM_INSTANCE_CONFIG i on ( i.namespace = c.ROOT_OBJECT_NS )
-			where ( c.CHILD_NAME = :type_name or c.CHILD_NAME = :namespace )
+			where ( c.CHILD_NS = :namespace )
+				and c.A_STATUS = 'NORMAL'
+		", [
+			':namespace' => $namespace,
+		]);
+	}
+	public static function getRefList($namespace) {
+		if (!$namespace) throw new Exception("Missing namespace");
+		return DB::getPDO()->fetchAll("
+			select c.CHILD_NS as namespace
+				, i.id as idInstance
+			from CRM_REF_CONFIG c
+				join CRM_INSTANCE_CONFIG i on ( i.namespace = c.CHILD_NS )
+			where ( c.ROOT_OBJECT_NS = :namespace )
 				and c.A_STATUS = 'NORMAL'
 		", [
-			':type_name' => $typeName,
 			':namespace' => $namespace,
 		]);
 	}
 
-	public static function fetchRefs($namespace, $childNamespace, $primaryKey, $params = []) { // TODO: $params: limit, total
+	public static function fetchRefs($namespace, $primaryKey, $childNamespace, $params = []) { // TODO: $params: limit, total
 		if (!$namespace) throw new Exception("Missing namespace");
 		if (!$childNamespace) throw new Exception("Missing child namespace");
 		if (!$primaryKey) throw new Exception("Missing primary key");
+
+		$typeName = Api_WfsNs::typeName($childNamespace);
+		$refTable = ACL::getRefTable($namespace, $typeName);
+		if (V::get('total', false, $params)) {
+			return DB::getPDO()->fetchValue(" select count(*) as cnt from `{$refTable}` where PRIMARY_KEY = :primary_key and A_STATUS not in ('DELETED') ", [ ':primary_key' => $primaryKey ]);
+		}
 		throw new Exception("TODO: fetch refs from '{$namespace}' where primaryKey = '{$primaryKey}'");
 	}
 

+ 33 - 5
SE/se-lib/Core/AclHelper.php

@@ -270,10 +270,8 @@ class Core_AclHelper {// Helper class for Acl
 				$backRefLabel = $backRef['namespace']; // TODO: get DESC from Zasoby
 				$backRefShort = explode("/", $backRefLabel);
 				$backRefShort = array_pop($backRefShort);
-				$backRefShort = (strlen($backRefShort) > 20) ? substr($backRefShort, 0, 20) . "..." : $backRefShort;
+				$backRefShort = (strlen($backRefShort) > 28) ? substr($backRefShort, 0, 28) . "..." : $backRefShort;
 
-				// 'namespace' => 'default_db/BI_audit_KRS/BI_audit_KRS',
-				// 'idInstance' => '24'
 				try {
 					$totalBackRefs = ACL::fetchBackRefs($acl->getNamespace(), $id, $backRef['namespace'], [ 'total' => true ]);
 				} catch (Exception $e) {
@@ -289,8 +287,38 @@ class Core_AclHelper {// Helper class for Acl
 						'childRefNS' => $acl->getNamespace(),
 						'childRefPK' => $id,
 					]),
-					'title' => "Wyszukaj powiązania z '{$backRefLabel}'",
-					'label' => "Wyszukaj powiązania z '{$backRefShort}' <span class=\"badge\">{$totalBackRefs}</span>",
+					'title' => "Powiązania od '{$backRefLabel}'",
+					'label' => "Powiązania od '{$backRefShort}' <span class=\"badge\">{$totalBackRefs}</span>",
+				];
+			}
+		}
+		if (count($partsNs) > 2) { // is AntAcl
+			$refList = ACL::getRefList($ns);
+			DBG::log($refList, 'array', "\$refList");
+			foreach ($refList as $refInfo) { // [ namespace, idInstance ]
+				$refLabel = $refInfo['namespace']; // TODO: get DESC from Zasoby
+				$refShortLabel = explode("/", $refLabel);
+				$refShortLabel = array_pop($refShortLabel);
+				$refShortLabel = (strlen($refShortLabel) > 28) ? substr($refShortLabel, 0, 28) . "..." : $refShortLabel;
+
+				try {
+					$totalRefs = ACL::fetchRefs($acl->getNamespace(), $id, $refInfo['namespace'], [ 'total' => true ]);
+				} catch (Exception $e) {
+					DBG::log($e);
+					continue;
+				}
+				DBG::log($totalRefs, 'array', "\$totalRefs {$refInfo['namespace']} pk({$id})");
+
+				$rowFunList[] = [
+					'ico' => 'glyphicon glyphicon-random',
+					'href' => Router::getRoute('ViewTableAjax')->getLink('', [
+						'namespace' => $refInfo['namespace'],
+						'backRefNS' => $acl->getNamespace(),
+						'backRefPK' => $id,
+						'backRefField' => Api_WfsNs::typeName($refInfo['namespace']),
+					]),
+					'title' => "Powiązania do '{$refLabel}'",
+					'label' => "Powiązania do '{$refShortLabel}' <span class=\"badge\">{$totalRefs}</span>",
 				];
 			}
 		}

+ 51 - 36
SE/se-lib/Route/UrlAction/BiAuditGenerate.php

@@ -495,7 +495,8 @@ function validate() {
 					$this->showPowiazaniaList();
 					break;
 				case "BI_audit_KRS":
-					$this->importKrsToPracownicySearch($this->SOURCE['ID']);
+				case "BI_audit_MSIG":
+					$this->importToPracownicySearch($this->SOURCE['ID']);
 					break;
 				case "BI_audit_KRS_person":
 					$this->showKrsForKrsPerson();
@@ -513,21 +514,26 @@ function validate() {
 		}
 	}
 
-	private function importKrsToPracownicy() {
+	private function importToPracownicy() {
 		$action = V::get('action', '', $_POST);
 		switch ($action) {
 			case "search":
-				$this->importKrsToPracownicySearch();
+				$this->importToPracownicySearch();
 				break;
-			default: $this->importKrsToPracownicyForm();
+			default: $this->importToPracownicyForm();
 		}
 	}
 
-	private function importKrsToPracownicyForm() {
+	private $tableDesc = ['BI_audit_KRS' => 'KRS', 'BI_audit_MSIG' => 'MSiG'];
+
+	private function importToPracownicyForm() {
+		$TABLE = $this->SOURCE['TABLE'];
+		$DESC = $this->tableDesc[$TABLE];
+		
 ?>
 <div class="container" style="margin-top:20px">
   <legend>
-    Importowanie podmiotów z KRS do tabel kontrahentów i pracowników
+    Importowanie podmiotów z <?=$DESC?> do tabel kontrahentów i pracowników
   </legend>
   <div class="form-group">
     <div class="col-sm-12">
@@ -570,7 +576,10 @@ function validate() {
 <?php
 	}
 
-	private function importKrsToPracownicySearch($krsId = null) {
+	private function importToPracownicySearch($krsId = null) {
+		$TABLE = $this->SOURCE['TABLE'];
+		$DESC = $this->tableDesc[$TABLE];
+
 		$formItems = [
 			"nazwa" => 'like',
 			"krs" => '=',
@@ -581,24 +590,24 @@ function validate() {
 		try {
 			$subaction = V::get('subaction', '', $_POST);
 			switch ($subaction) {
-				case "listKrsPerson":
+				case "listPerson":
 					$krsId = V::get('krsId', 0, $_POST, int);
 					break;
-				case "addKrsPersonToPracownicy":
+				case "addPersonToPracownicy":
 					$krsId = V::get('krsId', 0, $_POST, int);
 					$personId = V::get('personId', [], $_POST);
 					if (!$personId) throw new Exception("Błąd formularza");
-					$query = "insert into BI_audit_ENERGA_PRACOWNICY (source, imiona, nazwisko, pesel) select 'KRS', imiona, nazwisko, pesel from BI_audit_KRS_person where ID in (" . implode(", ", $personId) . ")";
+					$query = "insert into BI_audit_ENERGA_PRACOWNICY (source, imiona, nazwisko, pesel) select 'KRS', imiona, nazwisko, pesel from {$TABLE}_person where ID in (" . implode(", ", $personId) . ")";
 					DB::getPDO()->query($query);
 					SE_Layout::alert('success', "Pomyślnie zaimportowano " . count($personId) . " pracownik" . ((count($personId) == 1) ? "a" : "ów"));
 					break;
-				case "addKrsToKontrahenci":
+				case "addToKontrahenci":
 					$krsId = V::get('krsId', 0, $_POST, int);
 					if (!$krsId) throw new Exception("Błąd formularza");
-					$query = "select count(*) from BI_audit_ENERGA_RUM_KONTRAHENCI kh join BI_audit_KRS krs on (kh.NIP = krs.nip or kh.REGON = krs.regon or kh.KRS = krs.krs) where krs.ID = '{$krsId}'";
+					$query = "select count(*) from BI_audit_ENERGA_RUM_KONTRAHENCI kh join {$TABLE} krs on (kh.NIP = krs.nip or kh.REGON = krs.regon or kh.KRS = krs.krs) where krs.ID = '{$krsId}'";
 					$kontrahentExists = DB::getPDO()->fetchValue($query);
 					if ($kontrahentExists) throw new Exception("Podmiot znajduje się już w tabeli kontrahentów");
-					$query = "insert into BI_audit_ENERGA_RUM_KONTRAHENCI (Tytul_dokumentu, Pelna_nazwa_kontrahenta, REGON, NIP, KRS) select 'ZaImportowano z KRS', nazwa, regon, nip, krs from BI_audit_KRS where ID = ".$krsId." ";
+					$query = "insert into BI_audit_ENERGA_RUM_KONTRAHENCI (Tytul_dokumentu, Pelna_nazwa_kontrahenta, REGON, NIP, KRS) select 'ZaImportowano z {$DESC}', nazwa, regon, nip, krs from {$TABLE} where ID = ".$krsId." ";
 					DB::getPDO()->query($query);
 					SE_Layout::alert('success', "Pomyślnie zaimportowano kontrahenta");
 					break;
@@ -621,15 +630,15 @@ function validate() {
 			}
 		} catch (Exception $e) {
 			SE_Layout::alert('danger', $e->getMessage());
-			$this->importKrsToPracownicyForm();
+			$this->importToPracownicyForm();
 			return;
 		}
 
-		$query = "select * from `BI_audit_KRS` where " . implode(" and ", $where) . "order by ID limit 1001";
+		$query = "select * from `{$TABLE}` where " . implode(" and ", $where) . "order by ID limit 1001";
 		$result = DB::getPDO()->fetchAll($query);
 		if (count($result) == 1001) {
 			SE_Layout::alert('danger', 'Znaleziono zbyt wiele wyników. Doprecyzuj parametry wyszukiwania.');
-			$this->importKrsToPracownicyForm();
+			$this->importToPracownicyForm();
 			return;
 		} elseif (count($result) == 1) {
 			$krsId = $result[0]['ID'];
@@ -638,7 +647,7 @@ function validate() {
 <div class="container" style="margin-top:20px">
   <form method="post">
     <legend>
-      Importowanie podmiotów z KRS do tabel kontrahentów i pracowników
+      Importowanie podmiotów z <?=$DESC?> do tabel kontrahentów i pracowników
     </legend>
     <div class="form-group">
       <div class="col-sm-12">
@@ -718,7 +727,7 @@ function validate() {
 ?>
 	<input type="hidden" name="back" value="search"/>
         <div class="containter" style="text-align:center">
-          <button type="submit" class="btn btn-primary" name="subaction" value="listKrsPerson" onClick="return validateCompany(this)">Wybierz zaznaczony podmiot</button>
+          <button type="submit" class="btn btn-primary" name="subaction" value="listPerson" onClick="return validateCompany(this)">Wybierz zaznaczony podmiot</button>
           <a href="" class="btn btn-default">Powrót</a>
         </div>
       </div>
@@ -746,11 +755,11 @@ function validate() {
           <tbody>
 
 <?php
-			$query = "select count(*) from BI_audit_ENERGA_RUM_KONTRAHENCI kh join BI_audit_KRS krs on (kh.NIP = krs.nip or kh.REGON = krs.regon or kh.KRS = krs.krs) where krs.ID = '{$krsId}'";
+			$query = "select count(*) from BI_audit_ENERGA_RUM_KONTRAHENCI kh join {$TABLE} krs on (kh.NIP = krs.nip or kh.REGON = krs.regon or kh.KRS = krs.krs) where krs.ID = '{$krsId}'";
 			$kontrahentExists = DB::getPDO()->fetchValue($query);
 
-			$refKrsToKrsPerson = BiAuditRefTables::getRefTable('BI_audit_KRS', 'BI_audit_KRS_person', true);
-			$query = "select person.*, pracownicy.ID as pracownicyId from `{$refKrsToKrsPerson}` ref join `BI_audit_KRS_person` person on ref.REMOTE_PRIMARY_KEY = person.ID left join BI_audit_ENERGA_PRACOWNICY pracownicy on person.pesel = pracownicy.pesel where ref.PRIMARY_KEY = '{$krsId}'";
+			$refToPerson = BiAuditRefTables::getRefTable($TABLE, "{$TABLE}_person", true);
+			$query = "select person.*, pracownicy.ID as pracownicyId from `{$refToPerson}` ref join `{$TABLE}_person` person on ref.REMOTE_PRIMARY_KEY = person.ID left join BI_audit_ENERGA_PRACOWNICY pracownicy on person.pesel = pracownicy.pesel where ref.PRIMARY_KEY = '{$krsId}'";
 			$result = DB::getPDO()->fetchAll($query);
 			if (!$result) echo '<tr><td align="center" colspan="5">Nie znaleziono osób powiązanych z podmiotem</td></tr>';
 			else {
@@ -782,8 +791,8 @@ function validate() {
     </div>-->
     <div class="form-group">
       <div class="col-sm-12" style="text-align: center;">
-        <button type="submit" class="btn btn-primary" name="subaction" value="addKrsToKontrahenci"<?=($kontrahentExists ? " disabled" : "")?>>Dodaj firmę do tabeli kontrahentów</button>
-        <button type="submit" class="btn btn-primary" name="subaction" value="addKrsPersonToPracownicy" onClick="return validatePerson(this)">Dodaj zaznaczone osoby do tabeli pracowników</button>
+        <button type="submit" class="btn btn-primary" name="subaction" value="addToKontrahenci"<?=($kontrahentExists ? " disabled" : "")?>>Dodaj firmę do tabeli kontrahentów</button>
+        <button type="submit" class="btn btn-primary" name="subaction" value="addPersonToPracownicy" onClick="return validatePerson(this)">Dodaj zaznaczone osoby do tabeli pracowników</button>
         <input type="hidden" name="krsId" value="<?=$krsId?>"/>
         <input type="hidden" name="REFERER" value="<?=$this->REFERER?>"/>
 <?php
@@ -926,6 +935,7 @@ function validateCompany(source) {
 		if (($ID = V::get('ID_BI_audit_ENERGA_RUM_KONTRAHENCI_POWIAZANIA', 0, $_GET, 'int')) > 0) $this->SOURCE['TABLE'] = 'BI_audit_ENERGA_RUM_KONTRAHENCI_POWIAZANIA';
 		elseif (($ID = V::get('ID_BI_audit_ENERGA_PRACOWNICY', 0, $_GET, 'int')) > 0) $this->SOURCE['TABLE'] = 'BI_audit_ENERGA_PRACOWNICY';
 		elseif (($ID = V::get('ID_BI_audit_KRS', 0, $_GET, 'int')) > 0) $this->SOURCE['TABLE'] = 'BI_audit_KRS';
+		elseif (($ID = V::get('ID_BI_audit_MSIG', 0, $_GET, 'int')) > 0) $this->SOURCE['TABLE'] = 'BI_audit_MSIG';
 		elseif (($ID = V::get('ID_BI_audit_KRS_person', 0, $_GET, 'int')) > 0) $this->SOURCE['TABLE'] = 'BI_audit_KRS_person';
 		if ($this->SOURCE) {
 			$this->SOURCE['ID'] = $ID;
@@ -934,7 +944,8 @@ function validateCompany(source) {
 		elseif ($TABLE = V::get('_fromNamespace', '', $_GET)) {
 			switch ($TABLE) {
 				case "default_db/BI_audit_ENERGA_PRACOWNICY":
-					$this->importKrsToPracownicy();
+					$this->SOURCE['TABLE'] = 'BI_audit_KRS';
+					$this->importToPracownicy();
 					break;
 				default: SE_Layout::alert('danger', 'Błąd parametru');
 			}
@@ -1981,7 +1992,7 @@ SQL;
 			DB::getPDO()->update('BI_audit_ENERGA_RUM_KONTRAHENCI_POWIAZANIA', "ID", $ID, $sqlArr);
 
 			$BiAuditPowiazania->run();
-			if (!$BiAuditPowiazania->powiazaniaFound()) throw new Exception("Nie znaleziono żadnych powiązań");
+			//if (!$BiAuditPowiazania->powiazaniaFound()) throw new Exception("Nie znaleziono żadnych powiązań");
 			//file_put_contents($xmlFile, $BiAuditPowiazania->asXml());
 
 			$sqlArr = ['FILE_STATUS_info' => 'Generuję raporty PDF i HTML'];
@@ -2219,8 +2230,8 @@ class BiAuditPowiazania {
 	private $results = [];
 	private $items_results = [];
 	private $relations = [];
-	private $srcTables = ['BI_audit_ENERGA_PRACOWNICY', ['BI_audit_POWIAZANIA_OD', 'BI_audit_POWIAZANIA_OBIEKTY']];
-	private $destTables = ['BI_audit_ENERGA_RUM_KONTRAHENCI', 'BI_audit_KW_requested_person', ['BI_audit_POWIAZANIA_DO', 'BI_audit_POWIAZANIA_OBIEKTY']];
+	private $srcTables = ['BI_audit_ENERGA_PRACOWNICY']; //, ['BI_audit_POWIAZANIA_OD', 'BI_audit_POWIAZANIA_OBIEKTY']];
+	private $destTables = ['BI_audit_ENERGA_RUM_KONTRAHENCI', 'BI_audit_KW_requested_person']; //, ['BI_audit_POWIAZANIA_DO', 'BI_audit_POWIAZANIA_OBIEKTY']];
 	private $step = 0;
 	private $tasksDirLocation;
 	private $progressFile;
@@ -2515,10 +2526,10 @@ class BiAuditPowiazania {
 
 	private function saveResults() {
 		self::saveToLog("Zapisuję wyliczone dane do pliku");
-		if (!$this->results) {
-			self::saveToLog("Brak wyliczonych danych - niczego nie zapisaono");
-			return false;
-		}
+//		if (!$this->results) {
+//			self::saveToLog("Brak wyliczonych danych - niczego nie zapisaono");
+//			return false;
+//		}
 		$dataFile = "{$this->tasksDirLocation}/generatePowiazania-{$this->ID}.data";
 		$data = base64_encode(gzcompress(json_encode(['results' => $this->results, 'fidRow' => $this->fidRow])));
 		file_put_contents($dataFile, $data);
@@ -2594,7 +2605,8 @@ class BiAuditPowiazania {
 //			$results[] = array_map(function ($resultKey) {return $this->results[$resultKey];}, $resultKeys);
 		}
 
-		$this->splittedResults = $results;
+		if ($results) $this->splittedResults = $results;
+		else $this->splittedResults[] = $this->results;
 		$this->progress['summary']['reportsCount'] = count($results);
 	}
 
@@ -2765,8 +2777,9 @@ class BiAuditPowiazania {
 	public function asXml($resultsPart = null) {
 		self::saveToLog("Generuję plik XML ({$resultsPart})");
 		if (!$this->results) {
-			self::saveToLog("Brak wyników (#1), nie wygenerowano pliku XML ({$resultsPart})");
-			return null;
+			self::saveToLog("Brak wyników (#1), wygenerowano pusty plik XML ({$resultsPart})");
+//			self::saveToLog("Brak wyników (#1), nie wygenerowano pliku XML ({$resultsPart})");
+//			return null;
 		}
 		if (!isset($this->items_results[$resultsPart])) $this->generateItemsResults($resultsPart);
 		if (!isset($this->items_results[$resultsPart])) {
@@ -2825,8 +2838,10 @@ class BiAuditPowiazania {
 		$ditamapFile = "/Library/Server/Web/Data/Sites/Default/SE/schema/WPS_Functions/default_db/CRM_PROCES_tree/temp/relations-{$id_part}/relations-{$id_part}.ditamap";
 		$pdfFile = "/Library/Server/Web/Data/Sites/Default/SE/schema/WPS_Functions/default_db/CRM_PROCES_tree/temp/relations-{$id_part}/pdf/relations-{$id_part}.pdf";
 		$htmlDir = "/Library/Server/Web/Data/Sites/Default/SE/schema/WPS_Functions/default_db/CRM_PROCES_tree/temp/relations-{$id_part}/html";
+		$htmlFile = "{$htmlDir}/relations-{$id_part}.html";
 
-		if (!file_exists($xmlFile)) $this->saveXml($resultsPart);
+		//if (!file_exists($xmlFile))
+			$this->saveXml($resultsPart);
 		if (!file_exists($xmlFile)) {
 			$sqlArr['FILE_STATUS_info'] .= ", ale nie udało się utworzyć plików XML, PDF i HTML";
 			self::saveToLog("Nie wygenerowano plików XML, PDF oraz HTML - problem z wygenerowaniem pliku XML ({$resultsPart})");
@@ -2858,7 +2873,7 @@ class BiAuditPowiazania {
 
 		self::saveToLog("Generuję pliki HTML ({$resultsPart})");
 		self::exec("cd \"/Library/Server/Web/Data/Sites/Default/SE/schema/WPS_Functions/default_db/CRM_PROCES_tree/temp/relations-{$id_part}\" && /Library/Server/Web/Data/Sites/Default/SE/stuff/dita-ot-2.3.3/bin/dita -o html -i relations-{$id_part}.ditamap -f tocjs");
-		if (file_exists($htmlDir) && is_dir($htmlDir)) {
+		if (file_exists($htmlDir) && is_dir($htmlDir) && file_exists($htmlFile)) {
 			self::exec("cd \"/Library/Server/Web/Data/Sites/Default/SE/schema/WPS_Functions/default_db/CRM_PROCES_tree/temp/relations-{$id_part}\" && zip -r \"{$htmlZipDestFile}\" html");
 			if (file_exists($htmlDestDir)) self::exec("rm -rf \"{$htmlDestDir}\"");
 			self::exec("mv \"{$htmlDir}\" \"{$htmlDestDir}\"");

+ 13 - 12
SE/se-lib/V.php

@@ -566,26 +566,27 @@ EOF';
 			$child = $dom->createElement($node);
 			if (!$parent) $parent = $dom;
 			if (is_array($data)) {
-				foreach ($data as $key => $value) {
-					if ((string)$key === '@attributes') {
-						foreach ($value as $attrName => $attrValue) {
-							$attr = $dom->createAttribute($attrName);
-							$attr->value = $attrValue;
-							$child->appendChild($attr);
+				if ($data) {
+					foreach ($data as $key => $value) {
+						if ((string)$key === '@attributes') {
+							foreach ($value as $attrName => $attrValue) {
+								$attr = $dom->createAttribute($attrName);
+								$attr->value = $attrValue;
+								$child->appendChild($attr);
+							}
+						} else {
+							if (is_numeric($key)) $arrayToXML_rec($value, $dom, $node, $parent);
+							else $arrayToXML_rec($value, $dom, $key, $child);
 						}
-					} else {
-						if (is_numeric($key)) $arrayToXML_rec($value, $dom, $node, $parent);
-						else $arrayToXML_rec($value, $dom, $key, $child);
 					}
-				}
+				} else $parent->appendChild($child);
 			} else {
 				if ($data) {
 					if ($data == htmlspecialchars($data)) $child->nodeValue = $data;
 					else $child->appendChild($dom->createCDATASection($data));
 				} else $parent->appendChild($child);
 			}
-			//if ($child->hasChildNodes())
-				$parent->appendChild($child);
+			if ($child->hasChildNodes()) $parent->appendChild($child);
 		};
 
 		if (!is_array($array)) throw new Exception("First argument need to be an array");