MkFramework
 All Data Structures Functions
sgbd_json.php
1 <?php
2 /*
3 This file is part of Mkframework.
4 
5 Mkframework is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License.
8 
9 Mkframework is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13 
14 You should have received a copy of the GNU Lesser General Public License
15 along with Mkframework. If not, see <http://www.gnu.org/licenses/>.
16 
17 */
18 class sgbd_json extends abstract_sgbd{
19 
20  public static function getInstance($sConfig){
21  return self::_getInstance(__CLASS__,$sConfig);
22  }
23 
24  public function findMany($tSql,$sClassRow){
25  $tRows=$this->query($this->bind($tSql),$sClassRow);
26 
27  if(!$tRows){
28  return null;
29  }
30 
31  return $tRows;
32  }
33  public function findManySimple($tSql,$sClassRow){
34  return $this->findMany($tSql,$sClassRow);
35  }
36  public function findOne($tSql,$sClassRow){
37  $tRs=$this->query($this->bind($tSql),$sClassRow);
38 
39  if(empty($tRs)){
40  return null;
41  }
42 
43  return $tRs[0];
44  }
45  public function findOneSimple($tSql,$sClassRow){
46  return $this->findOne($tSql,$sClassRow);
47  }
48  public function execute($tSql){
49  return $this->query($this->bind($tSql));
50  }
51 
52  public function update($sTable,$tProperty,$tWhere){
53  $iId=$this->getIdFromTab($tWhere);
54 
55  $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.json';
56  $oJson=$this->json_decode($sFile);
57  $tJson=(array) $oJson;
58 
59  //remove index
60  $this->removeRowFromAllIndex($sTable,$tJson);
61 
62  foreach($tProperty as $sVar => $sVal){
63  $oJson->$sVar=$sVal;
64  }
65 
66  //add in index
67  $this->addRowInAllIndex($sTable,$tJson);
68 
69  $this->save($oJson,$sFile);
70  }
71  public function insert($sTable,$tProperty){
72  $iId=$this->getMaxId($sTable);
73 
74  $iMax=($iId+1);
75 
76  $oJson=new stdclass;
77  $oJson->id=$iId;
78  foreach($tProperty as $sVar => $sVal){
79  $oJson->$sVar=$sVal;
80  }
81 
82 
83  $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.json';
84  $this->save($oJson,$sFile);
85 
86  $sFileMax=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/max.txt';
87  file_put_contents($sFileMax,$iMax);
88 
89  $this->addRowInAllIndex($sTable,$tProperty);
90 
91  return $iId;
92  }
93  public function delete($sTable,$tWhere){
94  $iId=$this->getIdFromTab($tWhere);
95 
96  $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.json';
97  $oJson=$this->json_decode($sFile);
98  $tJson=(array) $oJson;
99 
100  //remove index
101  $this->removeRowFromAllIndex($sTable,$tJson);
102 
103  unlink($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$iId.'.json');
104  }
105 
106  public function getListColumn($sTable){
107 
108  $sFile=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/structure.csv';
109  $sColumns=trim(file_get_contents($sFile));
110 
111  $tColumn=explode(';',$sColumns);
112 
113  return $tColumn;
114 
115  }
116  public function getListTable(){
117  $oDir=new _dir( $this->_tConfig[$this->_sConfig.'.database']);
118  $tDir=$oDir->getList();
119  $tSDir=array();
120  foreach($tDir as $oDir){
121  $tSDir[]= $oDir->getName();
122  }
123  return $tSDir;
124  }
125 
126  private function query($sReq,$sClassRow){
127  //traitement de la requete $sReq
128  $sReq=trim($sReq);
129  $this->_sReq=$sReq;
130 
131  if(substr($sReq,0,6)== 'SELECT'){
132 
133  $tReq=$this->explainSql($sReq);
134 
135  //count
136  $bCount=false;
137  $iCount=0;
138  if(isset($tReq['select']) and preg_match('/COUNT\(/i',$tReq['select'])){
139  $bCount=true;
140  }
141 
142  $tCritere=$this->findListCritere($tReq);
143 
144  $sTable=trim($tReq['from']);
145 
146  //UTILISATION D UN INDEX
147  $tSqlFieldEqual=array_keys($tCritere);
148 
149  $sIndexToUse=$this->findIndexForTable($sTable,$tSqlFieldEqual);
150 
151  $tObj=array();
152  //UTILISATION D UN INDEX
153  if($sIndexToUse!=''){
154  $tObj=$this->findWithTableIndex($sClassRow,$sTable,$sIndexToUse,$tCritere);
155 
156  }elseif($tSqlFieldEqual==array('=id')){
157  $sFilename=$this->_tConfig[$this->_sConfig.'.database'];
158  $sFilename.=$sTable.'/'.(string)$tCritere['=id'].'.json';
159 
160  $tRow=(array)$this->json_decode($sFilename);
161 
162  $oRow=new $sClassRow($tRow);
163  $tObj[]=$oRow;
164  }else{
165 
166  $tObj=$this->findInTableWithCritere($sClassRow,$sTable,$tCritere);
167 
168 
169  }
170  //count
171  if($bCount){
172  $iCount=count($tObj);
173  return array($iCount);
174  }else if(isset($tReq['order']) and $tObj!=null){
175  return $this->sortResult($tObj,$tReq);
176  }else{
177  return $tObj;
178  }
179  }
180 
181 
182 
183  }
184  private function explainSql($sReq){
185  if(
186  preg_match_all('/^SELECT(?<select>.*)FROM(?<from>.*)WHERE(?<where>.*)ORDER BY(?<order>.*)/i'
187  ,$sReq,$tResult,PREG_SET_ORDER)
188  or
189  preg_match_all('/^SELECT(?<select>.*)FROM(?<from>.*)ORDER BY(?<order>.*)/i',$sReq,$tResult,PREG_SET_ORDER)
190  or
191  preg_match_all('/^SELECT(?<select>.*)FROM(?<from>.*)WHERE(?<where>.*)/i',$sReq,$tResult,PREG_SET_ORDER)
192  or
193  preg_match_all('/^SELECT(?<select>.*)FROM(?<from>.*)/i',$sReq,$tResult,PREG_SET_ORDER)
194  ){
195  if(isset($tResult[0]['where']) and preg_match('/ or /i',$tResult[0]['where'])){
196  $this->erreur('Requete non supportee : '.$sReq.$msg);
197  }elseif(isset($tResult[0]['order']) and !preg_match('/\s[ASC|DESC]/i',trim($tResult[0]['order'])) ){
198  $this->erreur('Il faut definir un sens de tri: ASC ou DESC dans la requete'.$sReq.$msg);
199  }else{
200  return $tResult[0];
201  }
202  }else{
203  $msg="\n\n";
204  $msg.="Le driver xml gere les requetes de type : \n";
205  $msg.="- SELECT liste_des_champs FROM ma_table WHERE champ=valeur ORDER BY champ DESC/ASC \n";
206  $msg.="- SELECT liste_des_champs FROM ma_table ORDER BY champ DESC/ASC \n";
207  $msg.="- SELECT liste_des_champs FROM ma_table WHERE champ=valeur \n";
208  $msg.="- SELECT liste_des_champs FROM ma_table \n";
209  $msg.=" la clause where accepte uniquement champ=valeur, champ!=valeur et AND \n";
210 
211  $this->erreur('Requete non supportee : '.$sReq.$msg);
212  }
213  }
214  private function findListCritere($tReq){
215  $tCritere=array();
216 
217  if(isset($tReq['where'])){
218  if(preg_match('/ and /i',$tReq['where'])){
219  $tWhere=preg_split('/ AND /i',$tReq['where']);
220  foreach($tWhere as $sWhereVal){
221  if(preg_match('/!=/',$sWhereVal)){
222  list($sVar,$sVal)=preg_split('/!=/',$sWhereVal);
223  $tCritere[trim($sVar)]='!'.trim($sVal);
224  }elseif(preg_match('/=/',$sWhereVal)){
225  list($sVar,$sVal)=preg_split('/=/',$sWhereVal);
226  $tCritere[trim($sVar)]='='.trim($sVal);
227  }
228  }
229  }else{
230  if(preg_match('/!=/',$tReq['where'])){
231  list($sVar,$sVal)=preg_split('/!=/',$tReq['where']);
232  $tCritere[trim($sVar)]='!'.trim($sVal);
233  }elseif(preg_match('/=/',$tReq['where'])){
234  list($sVar,$sVal)=preg_split('/=/',$tReq['where']);
235  $tCritere[trim($sVar)]='='.trim($sVal);
236  }
237  }
238 
239  }
240  return $tCritere;
241  }
242  private function sortResult($tObj,$tReq){
243 
244  list($sChamp,$sSens)=preg_split('/ /',trim($tReq['order']));
245 
246  $tTri=array();
247  $tIdObj=array();
248  foreach($tObj as $i => $oObj){
249  $tIdObj[ $i ]=$oObj;
250  $tTri[ $i ]=(string)$oObj->$sChamp;
251  }
252 
253  if($sSens=='DESC'){
254  arsort($tTri);
255  }else{
256  asort($tTri);
257  }
258 
259  $tOrderedObj=array();
260  $tId= array_keys($tTri);
261  foreach($tId as $id){
262  $tOrderedObj[]=$tIdObj[$id];
263  }
264 
265  return $tOrderedObj;
266  }
267  private function findIndexForTable($sTable,$tSqlFieldEqual){
268  $oDirIndex=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index');
269  if($oDirIndex->exist()){
270  $tFileIndex=$oDirIndex->getListDir();
271  foreach($tFileIndex as $oFileIndex){
272  $tFieldIndex=$this->getFieldsFromIndex($oFileIndex->getName());
273 
274  foreach($tSqlFieldEqual as $sSqlFieldEqual){
275  if(
276  $sSqlFieldEqual[0]=='=' and !in_array(substr($sSqlFieldEqual,1),$tFieldIndex)
277  or
278  $sSqlFieldEqual[0]=='!' and in_array(substr($sSqlFieldEqual,1),$tFieldIndex)
279  ){
280  continue 2;
281  }
282  }
283 
284  return $oFileIndex->getName();
285  }
286  }
287  return null;
288  }
289  private function findWithTableIndex($sClassRow,$sTable,$sIndexToUse,$tCritere){
290  $sDirIndex=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndexToUse;
291 
292  $tFieldIndex=preg_split('/\./',$sIndexToUse);
293 
294  $oDirIndex=new _dir($sDirIndex);
295  $tFileIndex=$oDirIndex->getListFile();
296 
297  $tObj=array();
298  foreach($tFileIndex as $oFileIndex){
299  $sFileIndex=trim($oFileIndex->getName());
300 
301  $tRow=$this->getRowValueFromIndex($sFileIndex,$tFieldIndex);
302 
303  foreach($tCritere as $sCritereField => $sCritereVal){
304 
305  if(!isset($tRow[$sCritereField]) or
306  (
307  ($sCritereVal[0]=='=' and (string)$sCritereVal!=(string)'='.$tRow[$sCritereField])
308 
309  or
310 
311  ($sCritereVal[0]=='!' and (string)$sCritereVal==(string)'!'.$tRow[$sCritereField])
312  )
313  ){
314  continue 2;
315  }
316  }
317 
318  $tMatchedFile=file( $sDirIndex.'/'.$sFileIndex );
319  foreach($tMatchedFile as $sMatchedFile){
320  $sMatchedFile=trim($sMatchedFile);
321  $sFilename=$this->_tConfig[$this->_sConfig.'.database'].$sTable.'/'.$sMatchedFile;
322  $tRow=(array)$this->json_decode($sFilename);
323 
324  $oRow=new $sClassRow($tRow);
325  $tObj[]=$oRow;
326  }
327 
328  }
329  return $tObj;
330  }
331  private function findInTableWithCritere($sClassRow,$sTable,$tCritere){
332  $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable);
333  $tFile=$oDir->getListFile();
334 
335 
336  $tObj=array();
337  foreach($tFile as $oFile){
338  if( in_array($oFile->getName(),array('structure.csv','max.txt'))){ continue; }
339  $tRow=(array)$this->json_decode($oFile->getAdresse());
340 
341 
342  foreach($tCritere as $sCritereField => $sCritereVal){
343 
344  if(!isset($tRow[$sCritereField]) or
345  (
346  ($sCritereVal[0]=='=' and (string)$sCritereVal!=(string)'='.$tRow[$sCritereField])
347 
348  or
349 
350  ($sCritereVal[0]=='!' and (string)$sCritereVal==(string)'!'.$tRow[$sCritereField])
351  )
352  ){
353  continue 2;
354  }
355  }
356 
357 
358  $oRow=new $sClassRow($tRow);
359  $tObj[]=$oRow;
360 
361  }
362 
363  return $tObj;
364 
365 
366  }
367 
368  public function quote($sVal){
369  return $sVal;
370  }
371  public function getWhereAll(){
372  return '1=1';
373  }
374 
375  private function getFieldsFromIndex($sIndex){
376  $tFields=preg_split('/\./',substr($sIndex,0,-6));//field.field.index
377  return $tFields;
378  }
379  private function getRowValueFromIndex($sFileIndex,$tFieldIndex){
380  $tValue=preg_split('/####/',substr($sFileIndex,0,-4) );
381  $tRow=array();
382  foreach($tFieldIndex as $i => $var){
383  $tRow[$var]=$tValue[$i];
384  }
385  return $tRow;
386  }
387  private function getFileIndexFromTab($sIndex,$tRow){
388  $tFields=$this->getFieldsFromIndex($sIndex);
389  $sFileIndex='';
390  foreach($tFields as $sField){
391  $sFileIndex.=$tRow[$sField];
392  $sFileIndex.='####';
393  }
394  return $sFileIndex.'.csv';
395  }
396  public function generateIndexForTable($sTable,$sIndex){
397  $tFields=$this->getFieldsFromIndex($sIndex);
398 
399  $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable);
400  $tFile=$oDir->getListFile();
401 
402  $tIndexContent=array();
403 
404  foreach($tFile as $oFile){
405  if($oFile->getName() == 'structure.csv'){ continue;}
406  if($oFile->getName() == 'max.txt'){ continue;}
407 
408  $tRow=(array)$this->json_decode($oFile->getAdresse());
409 
410 
411 
412  $sKey='';
413  foreach($tFields as $sField){
414  $sKey.=$tRow[$sField];
415  $sKey.='####';
416  }
417  $tIndexContent[$sKey][]=$tRow['id'].'.json';
418 
419  }
420 
421  $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex);
422  foreach($oDir->getListFile() as $oFile){
423  $oFile->delete();
424  }
425 
426  foreach($tIndexContent as $sKey => $tFile){
427  $oFile=new _file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sKey.'.csv');
428  $oFile->setContent(implode($tFile,"\n"));
429  $oFile->save();
430  }
431  }
432  private function addRowInAllIndex($sTable,$tProperty){
433 
434  $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index');
435  if($oDir->exist()){
436  $tDirIndex=$oDir->getListDir();
437  foreach($tDirIndex as $oDirIndex){
438  $this->addRowInIndex($sTable,$tProperty,$oDirIndex->getName());
439  }
440  }
441  }
442  private function addRowInIndex($sTable,$tProperty,$sIndex){
443 
444  $sFileIndex=$this->getFileIndexFromTab($sIndex,$tProperty);
445 
446  $oFile=new _file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sFileIndex);
447  $oFile->addContent($tProperty['id'].'.json');
448  $oFile->save('a');
449  }
450  private function removeRowFromAllIndex($sTable,$tProperty){
451 
452  $oDir=new _dir($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index');
453  if($oDir->exist()){
454  $tDirIndex=$oDir->getListDir();
455  foreach($tDirIndex as $oDirIndex){
456  $this->removeRowFromIndex($sTable,$tProperty,$oDirIndex->getName());
457  }
458  }
459  }
460  private function removeRowFromIndex($sTable,$tProperty,$sIndex){
461 
462  $sFileIndex=$this->getFileIndexFromTab($sIndex,$tProperty);
463 
464  if(!file_exists($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sFileIndex)){
465  return;
466  }
467 
468  $tLine=file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sFileIndex);
469  $tContent=array();
470  foreach($tLine as $sLine){
471  $sLine=trim($sLine);
472  if($sLine==$tProperty['id'].'.json'){
473  continue;
474  }
475  $tContent[]=$sLine;
476  }
477 
478  $oFile=new _file($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/index/'.$sIndex.'/'.$sFileIndex);
479  $oFile->setContent(implode("\n",$tContent));
480  $oFile->save();
481  }
482 
483  private function getIdFromTab($tId){
484  if(is_array($tId)){
485  return current($tId);
486  }else{
487  return $tId;
488  }
489  }
490  private function save($oJson,$sFichier){
491 
492  $sJson=json_encode($oJson);
493 
494  file_put_contents($sFichier,$sJson);
495  }
496  private function getMaxId($sTable){
497  $iMax=trim(file_get_contents($this->_tConfig[$this->_sConfig.'.database'].$sTable.'/max.txt'));
498  return (int)$iMax;
499 
500  }
501 
502 
503  private function json_decode($sFile){
504  return json_decode(file_get_contents($sFile));
505  }
506 
507 
508 }