Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
56.25% covered (warning)
56.25%
18 / 32
CRAP
60.80% covered (warning)
60.80%
183 / 301
sgbd_json
0.00% covered (danger)
0.00%
0 / 1
56.25% covered (warning)
56.25%
18 / 32
755.65
60.80% covered (warning)
60.80%
183 / 301
 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
2
100.00% covered (success)
100.00%
13 / 13
 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.33
84.00% covered (warning)
84.00%
21 / 25
 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.01
94.74% covered (success)
94.74%
18 / 19
 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 / 25
 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
1
100.00% covered (success)
100.00%
3 / 3
 getMaxId
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 json_decode
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
<?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_json 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.'.json';
        $oJson=$this->json_decode($sFile);
        $tJson=(array) $oJson;
        //remove index
        $this->removeRowFromAllIndex($sTable,$tJson);
        foreach($tProperty as $sVar => $sVal){
            $oJson->$sVar=$sVal;
        }
        //add in index
        $this->addRowInAllIndex($sTable,$tJson);
        $this->save($oJson,$sFile);
    }
    public function insert($sTable,$tProperty){
        $iId=$this->getMaxId($sTable);
        $iMax=($iId+1);
        $oJson=new stdclass;
        $oJson->id=$iId;
        foreach($tProperty as $sVar => $sVal){
            $oJson->$sVar=$sVal;
        }
        $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.json';
        $this->save($oJson,$sFile);
        $sFileMax=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/max.txt';
        file_put_contents($sFileMax,$iMax);
        $this->addRowInAllIndex($sTable,$tProperty);
        return $iId;
    }
    public function delete($sTable,$tWhere){
        $iId=$this->getIdFromTab($tWhere);
        $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.json';
        $oJson=$this->json_decode($sFile);
        $tJson=(array) $oJson;
        //remove index
        $this->removeRowFromAllIndex($sTable,$tJson);
        unlink($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.json');
    }
    public function getListColumn($sTable){
        $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/structure.csv';
        $sColumns=trim(file_get_contents($sFile));
        $tColumn=explode(';',$sColumns);
        return $tColumn;
    }
    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).'.json';
                if(file_exists($sFilename)){
                    $tRow=(array)$this->json_decode($sFilename);
                    $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(?<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)$this->json_decode($sFilename);
                $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.csv','max.txt'))){ continue; }
            $tRow=(array)$this->json_decode($oFile->getAdresse());
            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.csv'){ continue;}
            if($oFile->getName() == 'max.txt'){ continue;}
            $tRow=(array)$this->json_decode($oFile->getAdresse());
            $sKey='';
            foreach($tFields as $sField){
                $sKey.=$tRow[$sField];
                $sKey.='####';
            }
            $tIndexContent[$sKey][]=$tRow['id'].'.json';
        }
        $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'].'.json');
        $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'].'.json'){
                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($oJson,$sFichier){
        $sJson=json_encode($oJson);
        file_put_contents($sFichier,$sJson);
    }
    private function getMaxId($sTable){
        $iMax=trim(file_get_contents($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/max.txt'));
        return (int)$iMax;
    }
    private function json_decode($sFile){
        return json_decode(file_get_contents($sFile));
    }
}