PHP SQLク゚リゞェネレヌタヌ

箄1幎半前に、Web開発を始めたした。 関数型プログラミングから始めたした。 玄半幎前、私はOOPに切り替え、MVCデザむンアヌキテクチャの䜿甚を開始したした。 デヌタベヌスずのすべおの通信ず䜜業が1぀のクラスを介しお実行されるため、最近、デヌタベヌスずの䜜業を最適化するタスクが発生したした。 これは、手動でSQLク゚リを蚘述する必芁があったため、䞍䟿でした。 タスクは2段階に分けられたした。



  1. デヌタベヌスに接続するクラスを䜜成したす
  2. デヌタを操䜜するためのモデルクラスを䜜成する


最初のタスクは非垞に迅速に解決されたした。 それを実装するために、Singletonデザむンパタヌンを䜿甚したした。

2番目のタスクを実装するには、もう少し時間が必芁でした。 基本は、サむト䞊のシンプルなニュヌス管理モゞュヌルでした。 このモゞュヌルの圹割には、レコヌドの遞択、䜜成、削陀、および曎新の暙準機胜セットが含たれおいたした。 モデルクラスは、デヌタベヌスぞの接続を実際に䜜成するDataBaseクラスを継承したす。 たた、このクラスは、 DML操䜜の sqlコヌドを生成したす 。 DataBaseクラスは抜象であり、すべおの子クラスにDMLメ゜ッドを実装する必芁がありたす。

以䞋は、Newsモゞュヌルの管理を担圓する抜象メ゜ッドのセットです。



//  abstract public function getRecords($what='*',$where=NULL, $limit=NULL, $order=NULL,$join=NULL,$debug=false); //  abstract function addRecord($data=array(),$debug=false); // (-) abstract function deleteRecords($table, $where=NULL,$debug=false); // (-) abstract function setRecords($table,$what,$where,$debug=false); //  abstract function query($sql);
      
      





次に、各抜象メ゜ッドに぀いお詳しく説明したす。 これらのメ゜ッドの実装に぀いおは、Newsモデルのクラスを説明するずきに以䞋に瀺したす。

入力パラメヌタヌのいく぀かは繰り返されるため、本圓に必芁でない限り、それらを再説明したせん。



GetRecordsメ゜ッド


このメ゜ッドを䜿甚するず、SQLの条件に適合するレコヌドのセットを取埗できたす。





AddRecordメ゜ッド


このメ゜ッドを䜿甚するず、テヌブルにレコヌドを远加できたす。



DeleteRecordsメ゜ッド


このメ゜ッドを䜿甚するず、テヌブルからレコヌドを削陀できたす。



SetRecordsメ゜ッド


このメ゜ッドを䜿甚するず、指定した条件に埓っおテヌブル内のレコヌドを曎新できたす。



ク゚リ方法


このメ゜ッドを䜿甚するず、非暙準のク゚リを実行できたす。 これを行うには、メ゜ッドにパラメヌタヌずしおsqlク゚リを枡すだけです。



ク゚リのDMLタむプは、SELECT、INSERT、UPDATE、DELETEの4぀のタむプで構成されおいるこずを倚くの人が知っおいるず思いたす。 これらのク゚リを生成するには、条件付きでいく぀かの郚分に分割する必芁がありたす。

1SELECTク゚リは、WHAT、JOIN、WHERE、ORDER、LIMIT、GROUP、HAVINGに分かれおいたす。

2INSERTリク゚スト䜕

3UPDATEク゚リWHAT、WHERE

4ク゚リの削陀WHERE。

リク゚ストのこれらの郚分を個別に生成し、それらを結合するだけでよいこずがわかりたした。 これらのパヌツをDataBaseクラスで生成するために、この䟋のようにNewsモゞュヌルだけでなく、他のモゞュヌルにも共通するメ゜ッドが䜜成されたした。



これらの方法をより詳现に怜蚎しおください。



CheckWhatメ゜ッド


このメ゜ッドぞの唯䞀の入力は、SELECTを䜿甚しお遞択するか、UPDATEを䜿甚しお曎新する必芁がある倀の連想配列です。

ここで説明する $ whatパラメヌタ。

 protected function checkWhat($what) { if (is_array($what)) { foreach ($what as $k=>$v) { if (!is_numeric($k)) //      .  ,   prepare statement,   ,        SELECT  { $result['column'][]=$k."=?"; $result['params'][]=$v; } else { $result['column'][]=$v; } } $result['column']=implode(",",$result['column']); } return $result; }
      
      





ここではすべおがはっきりしおいるず思いたす。 配列をチェックし、配列のすべおの芁玠を走査し、ク゚リ文字列の䞀郚を構築したす。



CheckJoinメ゜ッド


ここで、$ joinパラメヌタに぀いお説明したす 。 たた、3぀以䞊のテヌブルを結合する必芁がある堎合、$結合パラメヌタヌを配列$ join1、$ join2、.....、$ joinNずしお衚すこずができたす

  //  Join  . protected function checkJoin($join) { if (is_array($join) && count($join)>0) { if (!is_array($join[0])) //   ,     join { $res[]=$this->addJoin($join[0],$join[1],$join[2],$join[3]); } else { //    ,    join $res=$this->addJoinArray($join); } return implode(" ",$res); } else { return false; } } // join protected function addJoin($type=' INNER ',$tables,$pseudoName,$rows) { if ($type!=='' && is_array($tables) && is_array($rows)) { $t0=$tables[0]; $t1=$tables[1]; if (is_array($pseudoName) && count($pseudoName)>0) //   ,    { $t0=$pseudoName[0]; $t1=$pseudoName[1]; } return $type." JOIN `".$tables[1]."` `".$pseudoName[1]."` ON `".$t0."`.`".$rows[0]."`=`".$t1."`.`".$rows[1]."`"; } else { return false; } } //   join` protected function addJoinArray($join) { if (is_array($join)) { foreach ($join as $j) { $res[]=$this->addJoin($j[0],$j[1],$j[2],$j[3]); } } return $res; }
      
      







CheckWhereメ゜ッド


このメ゜ッドは、リク゚ストのWHEREコンポヌネントのパラメヌタヌをチェックしたす。 ここで、$ whereパラメヌタに぀いお説明したす。

 protected function checkWhere($where) { if (!is_null($where) && is_array($where)) { foreach ($where as $k=>$v) { $part=$k.$v[0]; //     ''  '' if (!is_array($v[1])) //  ,   prepare statement { $part.="?"; $params[]=$v[1]; //     } else { //  ,     IN (array) $part.="(".implode(",",$v[1]).")"; } $res[]=$part; } $result['column']="WHERE ".implode(" AND ",$res); $result['params']=$params; } return $result; }
      
      







CheckLimitメ゜ッド


LIMITク゚リの述語を生成したす。 ここではすべおが非垞に簡単です。

 protected function checkLimit($limit) { $res=false; if (is_array($limit) && count($limit)>0) { $res=" LIMIT ".$limit['start']; if (isset($limit['count']) && $limit['count']!=='') //        { $res.=", ".$limit['count']; } } return $res; }
      
      







CheckOrderメ゜ッド


ORDER述語の生成。

 protected function checkOrder($order) { if (is_array($order) && count($order)>0) { foreach ($order as $row=>$dir) { $res[]=$row." ".$dir; } return "ORDER BY ".implode(",",$res); } else { return false; } }
      
      





これが、リク゚ストの䞻芁郚分を生成するために必芁なすべおのメ゜ッドです。 しかし、以来 WHEREおよびWHATなどのク゚リの郚分でprepareステヌトメントを䜿甚するため、これらの郚分のパラメヌタヌを結合しおPDOに枡す必芁がありたす。 このタスクのために、別のメ゜ッドを曞きたした



CheckParamsメ゜ッド


入力パラメヌタヌは2぀の配列です。 WHATおよびWHEREパラメヌタヌの配列。

 protected function checkParams($what,$where) { if (!isset($what) || !is_array($what)) { $params=$where; } else if (!isset($where) && !is_array($where)) { $params=$what; } else { $params=array_merge($what,$where); } return $params; }
      
      







SQLク゚リを構築する次のステップは、SQLコヌドの最終生成です。 このために、prepareSelectSQL、prepareInsertSQL、prepareDeleteSQL、prepareUpdateSQLの4぀のメ゜ッドを䜜成したした

これらの方法をより詳现に怜蚎しおください。



PrepareSelectSQLメ゜ッド


このメ゜ッドのパラメヌタヌは、getRecordsメ゜ッドのパラメヌタヌず䞀臎したす。 これは、$ what、$ where、$ limit、$ order、$ join、$ debugです。 これらのオプションに぀いお説明したす。

 protected function prepareSelectSQL($what=array('*'),$where=NULL, $limit=NULL, $order=NULL,$join=NULL,$debug=false) { $what=$this->checkWhat($what); $where=$this->checkWhere($where); $limit=$this->checkLimit($limit); $order=$this->checkOrder($order); $j=$this->checkJoin($join); $sql="SELECT ".$what['column']." FROM `".$this->table."` `tb` ".$j." ".$where['column']." ".$order." ".$limit; $params=$this->checkParams($what['params'],$where['params']); if ($debug) //  true,   sql      . { $this->sql=$sql; $this->params=$params; } return array('sql'=>$sql,'params'=>$params); //   sql   . }
      
      







PrepareInsertSQLメ゜ッド


この方法はより簡単です 限定された述語ずパラメヌタヌのセットを䜿甚したす

 protected function prepareInsertSQL($data,$table,$debug=false) { $params=$values=$column=array(); foreach ($data as $c=>$p) { $column[]=$c; //    $values[]="?"; //   prepare statement $params[]=$p; //    } $sql=" INSERT INTO `".$table."` (".implode(",",$column).") VALUES (".implode(',',$values).")"; if ($debug) { $this->sql=$sql; $this->params=$params; } return array('sql'=>$sql,'params'=>$params); }
      
      







PrepareDeleteSQLメ゜ッド


レコヌドを削陀する芁求。 WHERE述郚にはテヌブル名ず䞀連のパラメヌタヌを䜿甚したす。

  protected function prepareDeleteSQL($table,$where,$debug=false) { $where=$this->checkWhere($where); $sql="DELETE FROM `".$table."` ".$where['column']; $params=$this->checkParams($what,$where['params']); if ($debug) { $this->sql=$sql; $this->params=$params; } return array('sql'=>$sql,'params'=>$params); }
      
      







PrepareUpdateSQLメ゜ッド


テヌブル内のレコヌドを曎新するためのSQL芁求を生成したす。

  protected function prepareUpdateSQL($table,$what,$where,$debug=false) { $what=$this->checkWhat($what); $where=$this->checkWhere($where); $sql="UPDATE `".$table."` SET ".$what['column']." ".$where['column']; $params=$this->checkParams($what['params'],$where['params']); if ($debug) { $this->sql=$sql; $this->params=$params; } return array('sql'=>$sql,'params'=>$params); }
      
      







デヌタベヌスぞの接続ずDML SQLク゚リの生成を担圓するDataBaseクラスに぀いおは䞊蚘で説明したした。 以䞋は、このクラスの完党なコヌドです。

抜象クラスのデヌタベヌス
 <? abstract class DataBase { static private $_db=NULL; public $sql=''; public $params=array(); /* *  __construct  __clone  , *        new. * */ private function __construct() { return false; } private function __clone() { return false; } //  abstract public function getRecords($what='*',$where=NULL, $limit=NULL, $order=NULL,$join=NULL,$debug=false); //  abstract function addRecord($data=array(),$debug=false); // (-) abstract function deleteRecords($table, $where=NULL,$debug=false); // (-) abstract function setRecords($table,$what,$where,$debug=false); //  abstract function query($sql); /* *     .    , *     ,  , *       . *     PDOChild * */ public static function getInstance($registry) { if (is_null(self::$_db)) { self::$_db=new PDOchild($registry); } return self::$_db; } /* *  join  . * type -   join * tables -      * pseudoName -    * row -      * */ protected function addJoin($type=' INNER ',$tables,$pseudoName,$rows) { if ($type!=='' && is_array($tables) && is_array($rows)) { $t0=$tables[0]; $t1=$tables[1]; if (is_array($pseudoName) && count($pseudoName)>0) { $t0=$pseudoName[0]; $t1=$pseudoName[1]; } return $type." JOIN `".$tables[1]."` `".$pseudoName[1]."` ON `".$t0."`.`".$rows[0]."`=`".$t1."`.`".$rows[1]."`"; } else { return false; } } /* *   join   * join -   join array(join,join) * */ protected function addJoinArray($join) { if (is_array($join)) { foreach ($join as $j) { $res[]=$this->addJoin($j[0],$j[1],$j[2],$j[3]); } } return $res; } /* *  SELECT sql * what-        * where-      array(=>array(=,)) * limit-     array( , ) * order-  array (=>) * join-  join * debug-  true     sql   sql     params   * */ protected function prepareSelectSQL($what=array('*'),$where=NULL, $limit=NULL, $order=NULL,$join=NULL,$debug=false) { $what=$this->checkWhat($what); $where=$this->checkWhere($where); $limit=$this->checkLimit($limit); $order=$this->checkOrder($order); $j=$this->checkJoin($join); $sql="SELECT ".$what['column']." FROM `".$this->table."` `tb` ".$j." ".$where['column']." ".$order." ".$limit; $params=$this->checkParams($what['params'],$where['params']); if ($debug) { $this->sql=$sql; $this->params=$params; } return array('sql'=>$sql,'params'=>$params); } /* *  Insert sql * data-   -   * table-     * debug-  true     sql   sql     params   * */ protected function prepareInsertSQL($data,$table,$debug=false) { foreach ($data as $c=>$p) { $column[]=$c; $values[]="?"; $params[]=$p; } $sql=" INSERT INTO `".$table."` (".implode(",",$column).") VALUES (".implode(',',$values).")"; if ($debug) { $this->sql=$sql; $this->params=$params; } return array('sql'=>$sql,'params'=>$params); } /* *  Delete sql * where-    * table-      * debug-  true     sql   sql     params   * */ protected function prepareDeleteSQL($table,$where,$debug=false) { $where=$this->checkWhere($where); $sql="DELETE FROM `".$table."` ".$where['column']; $params=$this->checkParams($what,$where['params']); if ($debug) { $this->sql=$sql; $this->params=$params; } return array('sql'=>$sql,'params'=>$params); } /* *  Update sql * table-      * what -      * where-    * debug-  true     sql   sql     params   */ protected function prepareUpdateSQL($table,$what,$where,$debug=false) { $what=$this->checkWhat($what); $where=$this->checkWhere($where); $sql="UPDATE `".$table."` SET ".$what['column']." ".$where['column']; $params=$this->checkParams($what['params'],$where['params']); if ($debug) { $this->sql=$sql; $this->params=$params; } return array('sql'=>$sql,'params'=>$params); } /* *    join *   ,      ,    addJoin *  ,  addJoinArray *  join ,     * */ protected function checkJoin($join) { if (is_array($join) && count($join)>0) { if (!is_array($join[0])) { $res[]=$this->addJoin($join[0],$join[1],$join[2],$join[3]); } else { $res=$this->addJoinArray($join); } return implode(" ",$res); } else { return false; } } /* *    what *    . , *    =>?     prepare SQL * */ protected function checkWhat($what) { if (is_array($what)) { foreach ($what as $k=>$v) { if (!is_numeric($k)) { $result['column'][]=$k."=?"; $result['params'][]=$v; } else { $result['column'][]=$v; } } $result['column']=implode(",",$result['column']); } return $result; } /* *    Where *     , *    =>?     prepare SQL *  v[0](sign)= IN   value  ,    IN (array); *     LIKE,   . *       sql * */ protected function checkWhere($where) { if (!is_null($where) && is_array($where)) { foreach ($where as $k=>$v) { $part=$k.$v[0]; if (!is_array($v[1])) { $part.="?"; $params[]=$v[1]; } else { $part.="(".implode(",",$v[1]).")"; } $res[]=$part; } $result['column']="WHERE ".implode(" AND ",$res); $result['params']=$params; } return $result; } /* *    Limit *     , *   LIMIT  SQL *   LIMIT        * */ protected function checkLimit($limit) { if (is_array($limit) && count($limit)>0) { $res=" LIMIT ".$limit['start']; if (isset($limit['count']) && $limit['count']!=='') { $res.=", ".$limit['count']; } } return $res; } /* *    Order *     , *   ORDER  SQL *   ORDER * */ protected function checkOrder($order) { if (is_array($order) && count($order)>0) { foreach ($order as $row=>$dir) { $res[]=$row." ".$dir; } return "ORDER BY ".implode(",",$res); } else { return ''; } } /* *     prepare sql *      WHAT    WHERE. *    ,  prepare sql *    update, select, delete, insert *    what  where * */ protected function checkParams($what,$where) { if (!isset($what) || !is_array($what)) { $params=$where; } else if (!isset($where) && !is_array($where)) { $params=$what; } else { $params=array_merge($what,$where); } return $params; } } ?>
      
      







ここで、Newsモデルクラスに぀いお説明したす。 このクラスは、芪DataBaseクラスのすべおの抜象メ゜ッドず静的getObjectメ゜ッドを実装したす。 このメ゜ッドは、このクラスのオブゞェクトのむンスタンスを返したす。 このメ゜ッドは、newキヌワヌドを䜿甚しおNewsクラスのオブゞェクトを䜜成する必芁をなくすために䜜成されたした。 これは次のようなものです。

 $news=News::getObject()->getRecords(params);
      
      





このクラスの各メ゜ッドは、必芁なsqlク゚リゞェネレヌタヌを呌び出し、ク゚リを実行するために最終的なク゚リずパラメヌタヌをPDOに枡したす。 以䞋は、Newsモデルの完党なクラスコヌドです。

クラスニュヌス
 <? class News extends DataBase { public $table='news'; //  public $id_row='id'; // primary key public function __construct() { $registry=new Registry(); //     $this->db=parent::getInstance($registry); } //        public static function getObject() { return new News(); } //    . public function getRecords($what=array('*'),$where=NULL, $limit=NULL, $order=NULL,$join=NULL,$debug=false) { $data=$this->prepareSelectSQL($what,$where, $limit, $order,$join,$debug); $res=$this->db->prepare($data['sql']); $res->execute($data['params']); $result=$query->fetchAll(PDO::FETCH_OBJ); return $result; } public function addRecord($data=array(),$debug=false) { $data=$this->prepareInsertSQL($data,$this->table,$debug); $query=$this->db->prepare($data['sql']); return $query->execute($data['params'])); } public function deleteRecords($table, $where=NULL,$debug=false) { $data=$this->prepareDeleteSQL($table,$where,$debug); $query=$this->db->prepare($data['sql']); $result=$query->execute($data['params']); return $result; } public function setRecords($table,$what,$where,$debug=false) { $data=$this->prepareUpdateSQL($table,$what,$where,$debug); $query=$this->db->prepare($data['sql']); $result=$query->execute($data['params']); return $result; } public function query($sql) { $query=$this->db->prepare($sql); $query->execute(); $result=$query->fetchAll(PDO::FETCH_OBJ); return $result; } } ?>
      
      







原則ずしお、これは完了するこずができたす。 もちろん、GROUP BYおよびHAVING述語の生成を远加するこずもできたすが、私はそうしないこずにしたした。 私が明確に述べたク゚リを構築する原理は、䜿甚に問題はないず思いたす。 その結果、SQLク゚リを構築するメカニズムが埗られたした。これは、デヌタベヌス内の特定のテヌブル構造に関連付けられおおらず、さたざたなタむプのDML SQLク゚リに適甚できたす。 必芁に応じお、githubにリポゞトリを䜜成できたす。

メ゜ッドを改善するための批刀ず提案を聞いおうれしいです。



All Articles