Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
54.84% covered (warning)
54.84%
17 / 31
CRAP
60.66% covered (warning)
60.66%
185 / 305
sgbd_xml
0.00% covered (danger)
0.00%
0 / 1
54.84% covered (warning)
54.84%
17 / 31
749.13
60.66% covered (warning)
60.66%
185 / 305
 getInstance
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 findMany
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 findManySimple
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 findOne
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 findOneSimple
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 execute
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 update
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
11 / 11
 insert
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
9 / 9
 delete
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
7 / 7
 getListColumn
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 getListTable
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
7 / 7
 query
0.00% covered (danger)
0.00%
0 / 1
11.03
93.94% covered (success)
93.94%
31 / 33
 explainSql
0.00% covered (danger)
0.00%
0 / 1
9.37
83.33% covered (warning)
83.33%
20 / 24
 findListCritere
100.00% covered (success)
100.00%
1 / 1
8
100.00% covered (success)
100.00%
23 / 23
 sortResult
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
17 / 17
 findIndexForTable
0.00% covered (danger)
0.00%
0 / 1
42.33
18.75% covered (danger)
18.75%
3 / 16
 findWithTableIndex
0.00% covered (danger)
0.00%
0 / 1
90
0.00% covered (danger)
0.00%
0 / 27
 findInTableWithCritere
0.00% covered (danger)
0.00%
0 / 1
9
95.00% covered (success)
95.00%
19 / 20
 quote
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getWhereAll
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getFieldsFromIndex
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getRowValueFromIndex
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 6
 getFileIndexFromTab
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 7
 generateIndexForTable
0.00% covered (danger)
0.00%
0 / 1
56
0.00% covered (danger)
0.00%
0 / 27
 addRowInAllIndex
0.00% covered (danger)
0.00%
0 / 1
5.20
37.50% covered (danger)
37.50%
3 / 8
 addRowInIndex
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 5
 removeRowFromAllIndex
0.00% covered (danger)
0.00%
0 / 1
5.20
37.50% covered (danger)
37.50%
3 / 8
 removeRowFromIndex
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 15
 getIdFromTab
0.00% covered (danger)
0.00%
0 / 1
2.15
66.67% covered (warning)
66.67%
2 / 3
 save
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
10 / 10
 getMaxId
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
<?php
/*
This file is part of Mkframework.
Mkframework is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License.
Mkframework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Mkframework.  If not, see <http://www.gnu.org/licenses/>.
*/
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)
    {
       throw new Exception('method execute not available for this driver');
    }
    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') and substr((string)$tCritere['id'],0,1)=='=') {
                $sFilename=$this->_tConfig[$this->_sConfig.'.database'];
                $sFilename.=$sTable.'/'.substr((string)$tCritere['id'],1).'.xml';
                if(file_exists($sFilename)){
                    $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);
            } elseif (isset($tReq['order']) and $tObj!=null) {
                return $this->sortResult($tObj, $tReq);
            } else {
                return $tObj;
            }
        }
    }
    private function explainSql($sReq)
    {
        if (
            preg_match_all('/^SELECT(?<select>.*)FROM(?<from>.*)WHERE(?<where>.*)ORDER BY(?<order>.*)/i', $sReq, $tResult, PREG_SET_ORDER)
            or
            preg_match_all('/^SELECT(?<select>.*)FROM(?<from>.*)ORDER BY(?<order>.*)/i', $sReq, $tResult, PREG_SET_ORDER)
            or
            preg_match_all('/^SELECT(?<select>.*)FROM(?<from>.*)WHERE(?<where>.*)/i', $sReq, $tResult, PREG_SET_ORDER)
            or
            preg_match_all('/^SELECT(?<select>.*)FROM(?<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);
            } 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);
            } 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='<?xml version="1.0" encoding="ISO-8859-1"?>'.$sRet;
        $sXml.='<main>'.$sRet;
        foreach ($tProperty as $sVar => $sVal) {
            $sXml.='<'.$sVar.'><![CDATA['.$sVal.']]></'.$sVar.'>'.$sRet;
        }
        $sXml.='</main>'.$sRet;
        $oFile->write($sXml);
    }
    private function getMaxId($sTable)
    {
        $oXml=simplexml_load_file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/max.xml');
        return (int)$oXml->max;
    }
}