Files
Metadata_PHP/metadata/tree/treetools.php
2020-08-11 18:04:59 +06:00

527 lines
24 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
function getSQLFromP0(){
echo '+++wwwwwwwww++++++';
}
/**
* Обвернуть строку в кавычки в соответствии с типом.
* @param String $t Тип
* @param String $v Значение
* @return String Строка
*/
function getSQLValue($t,$v)
{
if($t=='object' && gettype($v)=='string') $t='string'; //Если id шники uuid
if($t=='object')
{ if (($v=='-1')||($v=='')) $v='NULL';
}else
if($t=='i4' || $t=='integer')
{ if($v=='') $v='NULL';
}else
if($t=='f8')
{ if($v=='')$v='NULL';
$v=str_replace(',','.',$v); //Разделитель целой и дробной части точка
}else
if($t=='b')
{ if($v=='') $v='NULL'; else
if($v=='1') $v='true'; else
if($v=='0') $v='false';
}else
if($t=='string' || $t=='dateTime' || $t=='date')
{ if($v=='')
{ $v='NULL';
}else
{ $v=str_replace('\'','\\\'',$v); //так как в SQL строку вставляется
$v='\''.$v.'\'';
}
}else
$v='\''.$v.'\'';
return $v;
}
/** Перенести параметры из родительского в sql строку дочернего элемента
* @param object $nParent Родительский узел
* @param object $nChild Дочерний узел
* @return string
*/
function getSQLFromP($nParent,$nChild)
{
if($nChild==null) return '';
$nPs=findNode($nParent, 'columns');
$nFs=findNode($nChild, 'filter');
//Переносим значения в фильтр
if($nFs!=null)
{
if($nPs!=null) $nP=$nPs->firstChild; else $nP=null;
while ($nP != null)
{
if ($nP->nodeName=='param')
{
$val=getCdata($nP)->nodeValue;
$nF=findNodeOnAttribute($nFs, 'column', 'pn', $nP->getAttribute("n"));
if($nF!=null) getCdata($nF)->nodeValue=$val;
}
$nP = $nP->nextSibling;
}
}
//Переносим значения в SQL запрос из фильтра
$sql=getCdataValue(findNode($nChild,'sql-query'));
$nFs=findNode($nChild, 'filter');
if($nFs!=null)
{ $nF=$nFs->firstChild;
while($nF != null)
{
if($nF->nodeName=='column')
{
$sql=str_replace('${'.$nF->getAttribute("n").'}',getSQLValue($nF->getAttribute("vt"),getCdata($nF)->nodeValue),$sql);
}
$nF=$nF->nextSibling;
}
}
return $sql;
}
//Функция по заданному пути выдаёт все под пути в виде асоциативного массива (тоесть + 1 уровень дерева)
//$db - PDO соединение с базой данных
//$path - путь "id дерева из XML; id записи из базы; id дерева из XML; id записи из базы;"
//$nParent - родительский узел нужен для рекурсии по умолчанию ставить null
function GetSubNodes($path,$nParent,&$title)
{
global $v_db;
if($nParent==null) return array();
$dt=''; //Разделитель для заголовка смотри ниже по тексту "->"
//По заданному пути спускаемся к нужному узлу дерева
$mas=split(';',$path);
for($i=0;$i<(count($mas)-1)/2;$i++)
{
$nChild=findNodeOnAttribute($nParent, 'type', 'id', $mas[$i*2]); //Ищем нужную ветку XML дерева
$sql=getSQLFromP($nParent,$nChild); //Выбираем параметры из родительского в дочерний потом из текущего в sql запрос
//Выполняем и ищем запись с нужным id
$res = $v_db->query($sql);
while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов
{
if($row[$nChild->getAttribute('ObjectID')]==$mas[$i*2+1])
{
$title.=$dt.$row[$nChild->getAttribute('c')]; //Чтоб отобразить заголовок в виде пути
$dt='->';
//Записываем параметры из текущей записи в параметры для передачи в в следующую итерацию
$nPs=findNode($nChild,'columns');
$nP=$nPs->firstChild;
while ($nP != null)
{
if ($nP->nodeName=='param')
getCdata($nP)->nodeValue=$row[$nP->getAttribute("n")];
$nP = $nP->nextSibling;
}
$nParent=$nChild;
break;
}
}
}
//Добрались до самого последнего элемента пути теперь выбераем из всех дочерних узлов
$result=array();
$nChild=$nParent->firstChild;
while ($nChild != null)
{
if($nChild->nodeName=='goto')
{
$nType=findFirstNodeOnAttribute($nChild->ownerDocument->documentElement,"type","id",$nChild->getAttribute("id"));
if($nType==null) { $nChild = $nChild->nextSibling; continue; }
}else $nType=$nChild;
if ($nType->nodeName=='type')
{
$sql=getSQLFromP($nParent,$nType);//Получаем SQL запрос перенося параметры из родительского в дочерний а потом в SQL дочернего
$res = $v_db->query($sql);
while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов
{
$cnt=count($result);
$result[$cnt]['name']=$row[$nType->getAttribute('c')];
$result[$cnt]['path']=$path.$nType->getAttribute('id').';'.$row[$nChild->getAttribute('ObjectID')].';';
}
}
$nChild = $nChild->nextSibling;
}
return $result;
}
//Из пути получить асоциативный массив заголовков + путь
//$path - путь "id дерева из XML; id записи из базы; id дерева из XML; id записи из базы;"
//$nParent - XML узел с которого будет начинаться поиск
//$db - База данных PDO
function getTXTPath($path,$nParent,$db)
{
$result=array(); $pos=0;
$mas=explode(';',$path);
for($i=0;$i<(count($mas)-1)/2;$i++)
{
$nChild=findNodeOnAttribute($nParent, 'type', 'id', $mas[$i*2]); //Ищем нужную ветку XML дерева
if($nChild==null) $nChild=findFirstNodeOnAttribute($nParent->ownerDocument->documentElement, 'type', 'id', $mas[$i*2]);
if($nChild==null) continue;
//print $nParent->ownerDocument->saveXML($nParent).'<br>';
$sql=getSQLFromP($nParent,$nChild); //Выбираем параметры из родительского в дочерний потом из текущего в sql запрос
if(gettype($_SESSION['USER_ID'])=='string')
$sql=str_replace('${user_id}',$_SESSION['USER_ID']=='' ? 'null' : '\''.$_SESSION['USER_ID'].'\'',$sql);
else
$sql=str_replace('${user_id}',$_SESSION['USER_ID']=='' ? 'null' : $_SESSION['USER_ID'],$sql);
//print $sql.'<br>';
//Выполняем и ищем запись с нужным id
$res = $db->query($sql);
while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов
{
if($row[$nChild->getAttribute('ObjectID')]==$mas[$i*2+1])
{
$result[$pos]['name']=$row[$nChild->getAttribute('c')];
$result[$pos]['path']=$mas[$i*2].';'.$mas[$i*2+1].';';
//Записываем параметры из текущей записи в параметры для передачи в в следующую итерацию
$nP=findNode($nChild, 'columns');
if($nP!=null) $nP=$nP->firstChild;
while ($nP != null)
{
if ($nP->nodeName=='param')
{
if(isset($row[$nP->getAttribute("n")]))
getCdata($nP)->nodeValue=$row[$nP->getAttribute("n")];
if(isset($row[$nP->getAttribute("n")]))
$result[$pos][$nP->getAttribute("n")]=$row[$nP->getAttribute("n")];
//getCdata($nP)->nodeValue=$row[$nP->getAttribute("n")];
//$result[$pos][$nP->getAttribute("n")]=$row[$nP->getAttribute("n")];
}
$nP = $nP->nextSibling;
}
$nParent=$nChild;
$pos++;
break;
}
}
}
return $result;
}
//получить путь по id дерева и по id записи в виде строки (поднимается вверх по дереву)
// $tid - id дерева
// $fid - id записи
// $nParent - родительский XML узел
// $db - Открытая база данных
function getPathOnId($tid,$fid,$nParent,$db)
{
if($nParent==null || $db==null) return '';
$str='';
$nChild=findFirstNodeOnAttribute($nParent, 'type', 'id', $tid);
if($nChild==null) return '';
//Пробуем найти родительский id по переданому
$nFs=findNode($nChild, 'filter');
$sql=findNode($nChild,'sql-query');
if($sql==null) return '';
$sql=getCdata($sql)->nodeValue;
if($nFs!=null)
{ $nF=$nFs->firstChild;
while($nF != null)
{
if($nF->nodeName=='column')
{
if($nF->getAttribute('n')==$nChild->getAttribute('ObjectID'))
getCdata($nF)->nodeValue=$fid;
else getCdata($nF)->nodeValue=''; //Очищаем фильтр
$sql=str_replace('${'.$nF->getAttribute("n").'}',getSQLValue($nF->getAttribute("vt"),getCdata($nF)->nodeValue),$sql);
}
$nF=$nF->nextSibling;
}
}
$res = $db->query($sql);
if($res->rowCount()>1) return ''; //В результ сете может быть только 1 запись так как фильтруем по id
while ($row = $res->fetch(PDO::FETCH_ASSOC))// $row - ассоциативный массив значений, ключи - названия столбцов
{
$fid=$row[$nChild->getAttribute('ParentID')];
//Мы не знаем id шник какого родителя ведь есть goto! (Для них должно выполняться условие их родитель всегда должен быть не пустым те. быть не на первом уровне вложенности)
$nGoto=findFirstNodeOnAttribute($nParent, 'goto', 'id', $tid);
if($nGoto!=null) $nGoto=$nGoto->parentNode;
if($nGoto!=null && $nGoto->nodeName=='type')
{
$sTmp=getPathOnId($nGoto->getAttribute('id'),$fid,$nParent,$db);
if($sTmp!='') //Не тупик ли
{
$str=$nChild->getAttribute('id').';'.$fid.';'.$str;
$str=$sTmp.$str;
break;
}
}
//Для случаяв если по goto не удалось пройтись
$nChild=$nChild->parentNode;
if($nChild!=null && $nChild->nodeName=='type' && $nChild->getAttribute('id')!='-1')
{
$str=$fid.';'.$str;
$str=$nChild->getAttribute('id').';'.$str;
$str=getPathOnId($nChild->getAttribute('id'),$fid,$nParent,$db).$str;
}
}
return $str;
}
//Получить XML дерево в виде строки (рекурсией в массив с заданным уровнем вложенности)
// $nParent - родительский XML узел
// $nParams - Первоначальные параметры фильтра (и для рекурсии)
// $db - соединение с базой данных
// $first - как вызванно через рекурсию или нет
// $path - путь к нужному узлу в виде "id node tree;id data;id node tree;id data;..."
function getTreeArray($nParent,$nParams,$db,$first,$path)
{
if($nParent==null || $db==null) return null;
$result='';
if($first) $result.='<?xml version="1.0" encoding="utf-8"?><metadata fn="2" htmlid="0">'."\n";
//Если параметры переданны как объект то парсим их в DOM дерево
if(gettype($nParams)=='string')
{
$doc = new DOMDocument();
try
{ $doc->loadXML('<metadata>'.$nParams.'</metadata>');
} catch (Exception $e)
{ $nParams=null;
}
$nParams = $doc->documentElement;
}
$mpath = explode(';', $path); //Путь к заветному узлу в виде массива
//перебераем все дочерние элементы и для каждого выполняем запрос c фильтрацией
$currNode = $nParent->firstChild; //из tree.xml
while ($currNode != null)
{
$tmpNode=$currNode; //если узел goto
if($tmpNode->nodeName=="goto") //если встретилась "зацикливалка"
{
$treeid=$tmpNode->getAttribute("id");
$tmpNode=findFirstNodeOnAttribute($tmpNode->ownerDocument->documentElement,"type","id",$treeid);
if($tmpNode==null) { $currNode = $currNode->nextSibling; continue; }
}
if($tmpNode->nodeName=="type" && $tmpNode->getAttribute("hide") != '1')
{
$treeid=$tmpNode->getAttribute("id"); //Идентификатор XML узла
//Пропускаем узлы которые не в заданном пути
if(!(count($mpath)>=3 && $mpath[0]!=$treeid))
{
$caption=$tmpNode->getAttribute("c"); //Название поля для заголовка
//$sql=getSQLFromP($nParent,$tmpNode);
$sql=getSQLFromP($nParams,$tmpNode);
if(gettype($_SESSION['USER_ID'])=='string')
$sql=str_replace('${user_id}',$_SESSION['USER_ID']=='' ? 'null' : '\''.$_SESSION['USER_ID'].'\'',$sql);
else
$sql=str_replace('${user_id}',$_SESSION['USER_ID']=='' ? 'null' : $_SESSION['USER_ID'],$sql);
$res=null;
try
{ $res=$db->query($sql);
} catch (Exception $e)
{ return null;
}
while ($row = $res->fetch(PDO::FETCH_ASSOC))
{
if(array_key_exists('id', $row)) $fid=$row['id']; else $fid=''; //id записи
if(count($mpath)>=3 && $mpath[1]!=$fid) continue; //Пропускаем записи которые не в пути
if(array_key_exists('icon_id', $row)) $iid=$row['icon_id']; else $iid=''; //id значка
if(array_key_exists($caption, $row)) $val=$row[$caption]; else $val=''; //Заголовок
$visible='';
if($tmpNode->getAttribute("visible")=="0") $visible=' visible="0" ';
//Для проверки есть ли дети составляем XML запрос и отправляем в вункцию как будто он пришел от клиента
//c - Есть ли под узлы по умолчанию есть
//fid - id записи
//iid - id иконки
//treeid - id ветки дерева
//ObjectID - название поля с уникальным идентификатором записи
//сохраняем параметры фильтра для дочерних элементов с текщим состоянием
//перебираем фильтры которые должны быть заполненны для каждого узла даные для фильтра беруться из результ сета
$rСol='<columns>'."\n";
//считываем название поля и находим данные в результсете
$nColumn = findFirstNode($tmpNode, 'columns'); //tree.xml
if($nColumn!=null) $nColumn=$nColumn->firstChild;
while ($nColumn != null)
{
if($nColumn->nodeName=="param")
{
$fname=$nColumn->getAttribute("n");
if(array_key_exists($fname, $row)) //Если поле есть в результсете
{ //getCdata($nColumn)->nodeValue=$row[$fname]; //Заполняем парамерт значением для рекурсии при следующей итерации затрётся
$fval=$row[$fname];
}else $fval=getCdataValue($nColumn);
$rСol.='<param n="'.$fname.'"><![CDATA['.$fval.']]></param>'."\n";
}
$nColumn = $nColumn->nextSibling;
}
$rСol.='</columns>'."\n";
$path='';
for($i=1;$i<(count($mpath)-1)/2;$i++) $path.=$mpath[i].';'.$mpath[i].';'; //Оставшийся путь минус текущий
// !!! Рекурсия !!!
$rSub=getTreeArray($tmpNode,$rСol,$db,false,$path);
$result.='<tree c="'.($rSub == '' ? '0' : '1').'" fid="'.$fid.'" iid="'.$iid.'" treeid="'.$treeid.'" t="'.$tmpNode->getAttribute("n").'" ObjectID="'.$tmpNode->getAttribute("ObjectID").'"'.$visible.'>'."\n";
$result.='<![CDATA['.$val.']]>'."\n";
$result.=$rСol;
$result.=$rSub;
$result.='</tree>'."\n";
$rSub='';
}
$res->closeCursor();
}
}
$currNode = $currNode->nextSibling;
}
if($first) $result.='</metadata>';
return $result; //XML строка
}
//Похожее на верхнее только получаем XML карту сайта
// $nParent - родительский XML узел
// $nParams - Первоначальные параметры фильтра (и для рекурсии)
// $db - соединение с базой данных
// $first - как вызванно через рекурсию или нет
function getSiteMap($nParent,$nParams,$db,$first,$path)
{
if($nParent==null || $db==null) return null;
$result='';
if($first) $result.='<?xml version="1.0" encoding="utf-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'."\n";
//Если параметры переданны как объект то парсим их в DOM дерево
if(gettype($nParams)=='string')
{
$doc = new DOMDocument();
try
{ $doc->loadXML('<metadata>'.$nParams.'</metadata>');
} catch (Exception $e)
{ $nParams=null;
}
$nParams = $doc->documentElement;
}
//перебераем все дочерние элементы и для каждого выполняем запрос c фильтрацией
$currNode = $nParent->firstChild; //из tree.xml
while ($currNode != null)
{
$tmpNode=$currNode; //если узел goto
if($tmpNode->nodeName=="goto") //если встретилась "зацикливалка"
{
$treeid=$tmpNode->getAttribute("id");
$tmpNode=findFirstNodeOnAttribute($tmpNode->ownerDocument->documentElement,"type","id",$treeid);
if($tmpNode==null) { $currNode = $currNode->nextSibling; continue; }
}
if($tmpNode->nodeName=="type")
{
$treeid=$tmpNode->getAttribute("id"); //Идентификатор XML узла
$sql=getSQLFromP($nParams,$tmpNode);
if(isset($_SESSION['USER_ID']))
{
if(gettype($_SESSION['USER_ID'])=='string')
$sql=str_replace('${user_id}',$_SESSION['USER_ID']=='' ? 'null' : '\''.$_SESSION['USER_ID'].'\'',$sql);
else
$sql=str_replace('${user_id}',$_SESSION['USER_ID']=='' ? 'null' : $_SESSION['USER_ID'],$sql);
}
$res=null;
try
{ $res=$db->query($sql);
} catch (Exception $e)
{ return null;
}
while ($row = $res->fetch(PDO::FETCH_ASSOC))
{
if(array_key_exists('id', $row)) { $fid=$row['id']; } else { $fid=''; } //id записи
if(array_key_exists('seq', $row)) { $date=date('Y-m-d',946620000+$row['seq']); } else { $date=date('Y-m-d'); } //Дата модификации страницы
if(array_key_exists('url', $row)) { $url=$row['url']; } else { $url=''; } //id записи
//сохраняем параметры фильтра для дочерних элементов с текщим состоянием
//перебираем фильтры которые должны быть заполненны для каждого узла даные для фильтра беруться из результ сета
$rСol='<columns>'."\n";
//считываем название поля и находим данные в результсете
$nColumn = findFirstNode($tmpNode, 'columns'); //tree.xml
if($nColumn!=null) $nColumn=$nColumn->firstChild;
while ($nColumn != null)
{
if($nColumn->nodeName=="param")
{
$fname=$nColumn->getAttribute("n");
if(array_key_exists($fname, $row)) //Если поле есть в результсете
{ //getCdata($nColumn)->nodeValue=$row[$fname]; //Заполняем парамерт значением для рекурсии при следующей итерации затрётся
$fval=$row[$fname];
}else
{ $fval=getCdataValue($nColumn);
}
$rСol.='<param n="'.$fname.'"><![CDATA['.$fval.']]></param>'."\n";
}
$nColumn = $nColumn->nextSibling;
}
$rСol.='</columns>'."\n";
if($url=='')
{ $url=getHashFromPath($path.$treeid.';'.$fid.';');
}
$result.=' <url>'."\n";
$result.=' <loc>http://'.$_SERVER["SERVER_NAME"].'/shop/'.$url.'.html</loc>'."\n";
$result.=' <lastmod>'.$date.'</lastmod>'."\n";
$result.=' <changefreq>daily</changefreq>'."\n";
$result.=' </url>'."\n";
// !!! Рекурсия !!!
$result.=getSiteMap($tmpNode,$rСol,$db,false,$path.$treeid.';'.$fid.';');
}
$res->closeCursor();
}
$currNode = $currNode->nextSibling;
}
if($first) $result.='</urlset>';
return $result; //XML строка
}