. */ class sgbd_xml extends abstract_sgbd{ public static function getInstance($sConfig){ return self::_getInstance(__CLASS__,$sConfig); } public function findMany($tSql,$sClassRow){ $tRows=$this->query($this->bind($tSql),$sClassRow); if(!$tRows){ return null; } return $tRows; } public function findManySimple($tSql,$sClassRow){ return $this->findMany($tSql,$sClassRow); } public function findOne($tSql,$sClassRow){ $tRs=$this->query($this->bind($tSql),$sClassRow); if(empty($tRs)){ return null; } return $tRs[0]; } public function findOneSimple($tSql,$sClassRow){ return $this->findOne($tSql,$sClassRow); } public function execute($tSql){ return $this->query($this->bind($tSql)); } public function update($sTable,$tProperty,$tWhere){ $iId=$this->getIdFromTab($tWhere); $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.xml'; $oXml=simplexml_load_file($sFile); $tXml=(array) $oXml; //remove index $this->removeRowFromAllIndex($sTable,$tXml); foreach($tProperty as $sVar => $sVal){ $tXml[$sVar]=(string)$sVal; } //add in index $this->addRowInAllIndex($sTable,$tXml); $this->save($tXml,$sFile); } public function insert($sTable,$tProperty){ $iId=$this->getMaxId($sTable); $tMax=array('max'=>($iId+1)); $tProperty['id']=$iId; $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.xml'; $this->save($tProperty,$sFile); $sFileMax=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/max.xml'; $this->save($tMax,$sFileMax); $this->addRowInAllIndex($sTable,$tProperty); return $iId; } public function delete($sTable,$tWhere){ $iId=$this->getIdFromTab($tWhere); $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.xml'; $oXml=simplexml_load_file($sFile); $tXml=(array) $oXml; //remove index $this->removeRowFromAllIndex($sTable,$tXml); unlink($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.xml'); } public function getListColumn($sTable){ $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/structure.xml'; $oXml=simplexml_load_file($sFile); $tXml=(array)$oXml; return $tXml['colonne']; } public function getListTable(){ $oDir=new _dir( $this->_tConfig[$this->_sConfig.'.database']); $tDir=$oDir->getList(); $tSDir=array(); foreach($tDir as $oDir){ $tSDir[]= $oDir->getName(); } return $tSDir; } private function query($sReq,$sClassRow){ //traitement de la requete $sReq $sReq=trim($sReq); $this->_sReq=$sReq; if(substr($sReq,0,6)== 'SELECT'){ $tReq=$this->explainSql($sReq); //count $bCount=false; $iCount=0; if(isset($tReq['select']) and preg_match('/COUNT\(/i',$tReq['select'])){ $bCount=true; } $tCritere=$this->findListCritere($tReq); $sTable=trim($tReq['from']); //UTILISATION D UN INDEX $tSqlFieldEqual=array_keys($tCritere); $sIndexToUse=$this->findIndexForTable($sTable,$tSqlFieldEqual); $tObj=array(); //UTILISATION D UN INDEX if($sIndexToUse!=''){ $tObj=$this->findWithTableIndex($sClassRow,$sTable,$sIndexToUse,$tCritere); }elseif($tSqlFieldEqual==array('=id')){ $sFilename=$this->_tConfig[$this->_sConfig.'.database']; $sFilename.=$sTable.'/'.(string)$tCritere['=id'].'.xml'; $tRow=(array)simplexml_load_file($sFilename,null,LIBXML_NOCDATA); $oRow=new $sClassRow($tRow); $tObj[]=$oRow; }else{ $tObj=$this->findInTableWithCritere($sClassRow,$sTable,$tCritere); } //count if($bCount){ $iCount=count($tObj); return array($iCount); }else if(isset($tReq['order']) and $tObj!=null){ return $this->sortResult($tObj,$tReq); }else{ return $tObj; } } } private function explainSql($sReq){ if( preg_match_all('/^SELECT(?.*)FROM(?.*)ORDER BY(?.*)/i',$sReq,$tResult,PREG_SET_ORDER) or preg_match_all('/^SELECT(?.*)FROM(?.*)/i',$sReq,$tResult,PREG_SET_ORDER) ){ if(isset($tResult[0]['where']) and preg_match('/ or /i',$tResult[0]['where'])){ $this->erreur('Requete non supportee : '.$sReq.$msg); }elseif(isset($tResult[0]['order']) and !preg_match('/\s[ASC|DESC]/i',trim($tResult[0]['order'])) ){ $this->erreur('Il faut definir un sens de tri: ASC ou DESC dans la requete'.$sReq.$msg); }else{ return $tResult[0]; } }else{ $msg="\n\n"; $msg.="Le driver xml gere les requetes de type : \n"; $msg.="- SELECT liste_des_champs FROM ma_table WHERE champ=valeur ORDER BY champ DESC/ASC \n"; $msg.="- SELECT liste_des_champs FROM ma_table ORDER BY champ DESC/ASC \n"; $msg.="- SELECT liste_des_champs FROM ma_table WHERE champ=valeur \n"; $msg.="- SELECT liste_des_champs FROM ma_table \n"; $msg.=" la clause where accepte uniquement champ=valeur, champ!=valeur et AND \n"; $this->erreur('Requete non supportee : '.$sReq.$msg); } } private function findListCritere($tReq){ $tCritere=array(); if(isset($tReq['where'])){ if(preg_match('/ and /i',$tReq['where'])){ $tWhere=preg_split('/ AND /i',$tReq['where']); foreach($tWhere as $sWhereVal){ if(preg_match('/!=/',$sWhereVal)){ list($sVar,$sVal)=preg_split('/!=/',$sWhereVal); $tCritere[trim($sVar)]='!'.trim($sVal); }elseif(preg_match('/=/',$sWhereVal)){ list($sVar,$sVal)=preg_split('/=/',$sWhereVal); $tCritere[trim($sVar)]='='.trim($sVal); } } }else{ if(preg_match('/!=/',$tReq['where'])){ list($sVar,$sVal)=preg_split('/!=/',$tReq['where']); $tCritere[trim($sVar)]='!'.trim($sVal); }elseif(preg_match('/=/',$tReq['where'])){ list($sVar,$sVal)=preg_split('/=/',$tReq['where']); $tCritere[trim($sVar)]='='.trim($sVal); } } } return $tCritere; } private function sortResult($tObj,$tReq){ list($sChamp,$sSens)=preg_split('/ /',trim($tReq['order'])); $tTri=array(); $tIdObj=array(); foreach($tObj as $i => $oObj){ $tIdObj[ $i ]=$oObj; $tTri[ $i ]=(string)$oObj->$sChamp; } if($sSens=='DESC'){ arsort($tTri); }else{ asort($tTri); } $tOrderedObj=array(); $tId= array_keys($tTri); foreach($tId as $id){ $tOrderedObj[]=$tIdObj[$id]; } return $tOrderedObj; } private function findIndexForTable($sTable,$tSqlFieldEqual){ $oDirIndex=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index'); if($oDirIndex->exist()){ $tFileIndex=$oDirIndex->getListDir(); foreach($tFileIndex as $oFileIndex){ $tFieldIndex=$this->getFieldsFromIndex($oFileIndex->getName()); foreach($tSqlFieldEqual as $sSqlFieldEqual){ if( $sSqlFieldEqual[0]=='=' and !in_array(substr($sSqlFieldEqual,1),$tFieldIndex) or $sSqlFieldEqual[0]=='!' and in_array(substr($sSqlFieldEqual,1),$tFieldIndex) ){ continue 2; } } return $oFileIndex->getName(); } } return null; } private function findWithTableIndex($sClassRow,$sTable,$sIndexToUse,$tCritere){ $sDirIndex=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndexToUse; $tFieldIndex=preg_split('/\./',$sIndexToUse); $oDirIndex=new _dir($sDirIndex); $tFileIndex=$oDirIndex->getListFile(); $tObj=array(); foreach($tFileIndex as $oFileIndex){ $sFileIndex=trim($oFileIndex->getName()); $tRow=$this->getRowValueFromIndex($sFileIndex,$tFieldIndex); foreach($tCritere as $sCritereField => $sCritereVal){ if(!isset($tRow[$sCritereField]) or ( ($sCritereVal[0]=='=' and (string)$sCritereVal!=(string)'='.$tRow[$sCritereField]) or ($sCritereVal[0]=='!' and (string)$sCritereVal==(string)'!'.$tRow[$sCritereField]) ) ){ continue 2; } } $tMatchedFile=file( $sDirIndex.'/'.$sFileIndex ); foreach($tMatchedFile as $sMatchedFile){ $sMatchedFile=trim($sMatchedFile); $sFilename=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$sMatchedFile; $tRow=(array)simplexml_load_file($sFilename,null,LIBXML_NOCDATA); $oRow=new $sClassRow($tRow); $tObj[]=$oRow; } } return $tObj; } private function findInTableWithCritere($sClassRow,$sTable,$tCritere){ $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable); $tFile=$oDir->getListFile(); $tObj=array(); foreach($tFile as $oFile){ if( in_array($oFile->getName(),array('structure.xml','max.xml'))){ continue; } $tRow=(array)simplexml_load_file($oFile->getAdresse(),null,LIBXML_NOCDATA); foreach($tCritere as $sCritereField => $sCritereVal){ if(!isset($tRow[$sCritereField]) or ( ($sCritereVal[0]=='=' and (string)$sCritereVal!=(string)'='.$tRow[$sCritereField]) or ($sCritereVal[0]=='!' and (string)$sCritereVal==(string)'!'.$tRow[$sCritereField]) ) ){ continue 2; } } $oRow=new $sClassRow($tRow); $tObj[]=$oRow; } return $tObj; } public function quote($sVal){ return $sVal; } public function getWhereAll(){ return '1=1'; } private function getFieldsFromIndex($sIndex){ $tFields=preg_split('/\./',substr($sIndex,0,-6));//field.field.index return $tFields; } private function getRowValueFromIndex($sFileIndex,$tFieldIndex){ $tValue=preg_split('/####/',substr($sFileIndex,0,-4) ); $tRow=array(); foreach($tFieldIndex as $i => $var){ $tRow[$var]=$tValue[$i]; } return $tRow; } private function getFileIndexFromTab($sIndex,$tRow){ $tFields=$this->getFieldsFromIndex($sIndex); $sFileIndex=''; foreach($tFields as $sField){ $sFileIndex.=$tRow[$sField]; $sFileIndex.='####'; } return $sFileIndex.'.csv'; } public function generateIndexForTable($sTable,$sIndex){ $tFields=$this->getFieldsFromIndex($sIndex); $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable); $tFile=$oDir->getListFile(); $tIndexContent=array(); foreach($tFile as $oFile){ if($oFile->getName() == 'structure.xml'){ continue;} if($oFile->getName() == 'max.xml'){ continue;} $tRow=(array)simplexml_load_file($oFile->getAdresse(),null,LIBXML_NOCDATA); $sKey=''; foreach($tFields as $sField){ $sKey.=$tRow[$sField]; $sKey.='####'; } $tIndexContent[$sKey][]=$tRow['id'].'.xml'; } $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex); foreach($oDir->getListFile() as $oFile){ $oFile->delete(); } foreach($tIndexContent as $sKey => $tFile){ $oFile=new _file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sKey.'.csv'); $oFile->setContent(implode($tFile,"\n")); $oFile->save(); } } private function addRowInAllIndex($sTable,$tProperty){ $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index'); if($oDir->exist()){ $tDirIndex=$oDir->getListDir(); foreach($tDirIndex as $oDirIndex){ $this->addRowInIndex($sTable,$tProperty,$oDirIndex->getName()); } } } private function addRowInIndex($sTable,$tProperty,$sIndex){ $sFileIndex=$this->getFileIndexFromTab($sIndex,$tProperty); $oFile=new _file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sFileIndex); $oFile->addContent($tProperty['id'].'.xml'); $oFile->save('a'); } private function removeRowFromAllIndex($sTable,$tProperty){ $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index'); if($oDir->exist()){ $tDirIndex=$oDir->getListDir(); foreach($tDirIndex as $oDirIndex){ $this->removeRowFromIndex($sTable,$tProperty,$oDirIndex->getName()); } } } private function removeRowFromIndex($sTable,$tProperty,$sIndex){ $sFileIndex=$this->getFileIndexFromTab($sIndex,$tProperty); if(!file_exists($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sFileIndex)){ return; } $tLine=file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sFileIndex); $tContent=array(); foreach($tLine as $sLine){ $sLine=trim($sLine); if($sLine==$tProperty['id'].'.xml'){ continue; } $tContent[]=$sLine; } $oFile=new _file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sFileIndex); $oFile->setContent(implode("\n",$tContent)); $oFile->save(); } private function getIdFromTab($tId){ if(is_array($tId)){ return current($tId); }else{ return $tId; } } private function save($tProperty,$sFichier){ $oFile=new _file($sFichier); $sRet="\n"; $sXml=''.$sRet; $sXml.='
'.$sRet; foreach($tProperty as $sVar => $sVal){ $sXml.='<'.$sVar.'>'.$sRet; } $sXml.='
'.$sRet; $oFile->write($sXml); } private function getMaxId($sTable){ $oXml=simplexml_load_file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/max.xml'); return (int)$oXml->max; } }