1*8c551fd7SAndreas Gohr<?php 2*8c551fd7SAndreas Gohr 3*8c551fd7SAndreas Gohrnamespace dokuwiki\plugin\struct\meta; 4*8c551fd7SAndreas Gohr 5*8c551fd7SAndreas Gohr/** 6*8c551fd7SAndreas Gohr * Class QueryBuilder 7*8c551fd7SAndreas Gohr * @package dokuwiki\plugin\struct\meta 8*8c551fd7SAndreas Gohr */ 9*8c551fd7SAndreas Gohrclass QueryBuilder { 10*8c551fd7SAndreas Gohr 11*8c551fd7SAndreas Gohr /** @var array placeholder -> values */ 12*8c551fd7SAndreas Gohr protected $values = array(); 13*8c551fd7SAndreas Gohr /** @var array (alias -> statement */ 14*8c551fd7SAndreas Gohr protected $select = array(); 15*8c551fd7SAndreas Gohr /** @var array (alias -> statement) */ 16*8c551fd7SAndreas Gohr protected $from = array(); 17*8c551fd7SAndreas Gohr /** @var QueryBuilderWhere */ 18*8c551fd7SAndreas Gohr protected $where; 19*8c551fd7SAndreas Gohr 20*8c551fd7SAndreas Gohr /** 21*8c551fd7SAndreas Gohr * QueryBuilder constructor. 22*8c551fd7SAndreas Gohr */ 23*8c551fd7SAndreas Gohr public function __construct() { 24*8c551fd7SAndreas Gohr $this->where = new QueryBuilderWhere(); 25*8c551fd7SAndreas Gohr } 26*8c551fd7SAndreas Gohr 27*8c551fd7SAndreas Gohr /** 28*8c551fd7SAndreas Gohr * Adds a column to select 29*8c551fd7SAndreas Gohr * 30*8c551fd7SAndreas Gohr * If the alias already exists, the current statement for that alias will be overwritten. 31*8c551fd7SAndreas Gohr * 32*8c551fd7SAndreas Gohr * @param string $tablealias The table to select from 33*8c551fd7SAndreas Gohr * @param string $column The column to select 34*8c551fd7SAndreas Gohr * @param string $alias Under whichname to slect the column. blank for column name 35*8c551fd7SAndreas Gohr */ 36*8c551fd7SAndreas Gohr public function addSelectColumn($tablealias, $column, $alias = '') { 37*8c551fd7SAndreas Gohr if($alias === '') $alias = $column; 38*8c551fd7SAndreas Gohr if(!isset($this->from[$tablealias])) throw new StructException('Table Alias does not exist'); 39*8c551fd7SAndreas Gohr $this->select[$alias] = "$tablealias.$column AS $alias"; 40*8c551fd7SAndreas Gohr } 41*8c551fd7SAndreas Gohr 42*8c551fd7SAndreas Gohr /** 43*8c551fd7SAndreas Gohr * Add a new select statement (the column part of it) 44*8c551fd7SAndreas Gohr * 45*8c551fd7SAndreas Gohr * Basically the same as @see addSelectColumn but accepts any statement. This is useful to 46*8c551fd7SAndreas Gohr * select things like fixed strings or more complex function calls, but the correctness will not 47*8c551fd7SAndreas Gohr * be checked. 48*8c551fd7SAndreas Gohr * 49*8c551fd7SAndreas Gohr * If the alias already exists, the current statement for that alias will be overwritten. 50*8c551fd7SAndreas Gohr * 51*8c551fd7SAndreas Gohr * @param string $statement 52*8c551fd7SAndreas Gohr * @param string $alias 53*8c551fd7SAndreas Gohr */ 54*8c551fd7SAndreas Gohr public function addSelectStatement($statement, $alias) { 55*8c551fd7SAndreas Gohr $this->select[$alias] = "$statement AS $alias"; 56*8c551fd7SAndreas Gohr } 57*8c551fd7SAndreas Gohr 58*8c551fd7SAndreas Gohr /** 59*8c551fd7SAndreas Gohr * Adds the the table to the FROM statement part 60*8c551fd7SAndreas Gohr * 61*8c551fd7SAndreas Gohr * @param string $table the table to add 62*8c551fd7SAndreas Gohr * @param string $alias alias for the table, blank for table name 63*8c551fd7SAndreas Gohr */ 64*8c551fd7SAndreas Gohr public function addTable($table, $alias = '') { 65*8c551fd7SAndreas Gohr if($alias === '') $alias = $table; 66*8c551fd7SAndreas Gohr if(isset($this->from[$alias])) throw new StructException('Table Alias exists'); 67*8c551fd7SAndreas Gohr $this->from[$alias] = "$table AS $alias"; 68*8c551fd7SAndreas Gohr } 69*8c551fd7SAndreas Gohr 70*8c551fd7SAndreas Gohr /** 71*8c551fd7SAndreas Gohr * Adds a LEFT JOIN clause to the FROM statement part, sorted at the correct spot 72*8c551fd7SAndreas Gohr * 73*8c551fd7SAndreas Gohr * @param string $leftalias the alias of the left table you're joining on, has to exist already 74*8c551fd7SAndreas Gohr * @param string $righttable the right table to be joined 75*8c551fd7SAndreas Gohr * @param string $rightalias an alias for the right table, blank for table name 76*8c551fd7SAndreas Gohr * @param string $onclause the ON clause condition the join is based on 77*8c551fd7SAndreas Gohr */ 78*8c551fd7SAndreas Gohr public function addLeftJoin($leftalias, $righttable, $rightalias, $onclause) { 79*8c551fd7SAndreas Gohr if($rightalias === '') $rightalias = $righttable; 80*8c551fd7SAndreas Gohr if(!isset($this->from[$leftalias])) throw new StructException('Table Alias does not exist'); 81*8c551fd7SAndreas Gohr if(isset($this->from[$rightalias])) throw new StructException('Table Alias already exists'); 82*8c551fd7SAndreas Gohr 83*8c551fd7SAndreas Gohr $pos = array_search($leftalias, array_keys($this->from)); 84*8c551fd7SAndreas Gohr $statement = "LEFT OUTER JOIN $righttable AS $rightalias ON $onclause"; 85*8c551fd7SAndreas Gohr $this->from = $this->array_insert($this->from, array($rightalias => $statement), $pos+1); 86*8c551fd7SAndreas Gohr } 87*8c551fd7SAndreas Gohr 88*8c551fd7SAndreas Gohr /** 89*8c551fd7SAndreas Gohr * Returns the current WHERE filters and allows to set new ones 90*8c551fd7SAndreas Gohr * 91*8c551fd7SAndreas Gohr * @return QueryBuilderWhere 92*8c551fd7SAndreas Gohr */ 93*8c551fd7SAndreas Gohr public function getFilters() { 94*8c551fd7SAndreas Gohr return $this->where; 95*8c551fd7SAndreas Gohr } 96*8c551fd7SAndreas Gohr 97*8c551fd7SAndreas Gohr /** 98*8c551fd7SAndreas Gohr * Adds a value to the statement 99*8c551fd7SAndreas Gohr * 100*8c551fd7SAndreas Gohr * This function returns the name of the placeholder you have to use in your statement 101*8c551fd7SAndreas Gohr * 102*8c551fd7SAndreas Gohr * @param mixed $value 103*8c551fd7SAndreas Gohr * @return string 104*8c551fd7SAndreas Gohr */ 105*8c551fd7SAndreas Gohr public function addValue($value) { 106*8c551fd7SAndreas Gohr static $count = 0; 107*8c551fd7SAndreas Gohr $count++; 108*8c551fd7SAndreas Gohr 109*8c551fd7SAndreas Gohr $placeholder = ":!!val$count!!:"; // sqlite plugin does not support named parameters, yet so we have simulate it 110*8c551fd7SAndreas Gohr $this->values[$placeholder] = $value; 111*8c551fd7SAndreas Gohr return $placeholder; 112*8c551fd7SAndreas Gohr } 113*8c551fd7SAndreas Gohr 114*8c551fd7SAndreas Gohr /** 115*8c551fd7SAndreas Gohr * Creates a new table alias that has not been used before 116*8c551fd7SAndreas Gohr * 117*8c551fd7SAndreas Gohr * @return string 118*8c551fd7SAndreas Gohr */ 119*8c551fd7SAndreas Gohr public function generateTableAlias() { 120*8c551fd7SAndreas Gohr static $count = 0; 121*8c551fd7SAndreas Gohr $count++; 122*8c551fd7SAndreas Gohr return "T$count"; 123*8c551fd7SAndreas Gohr } 124*8c551fd7SAndreas Gohr 125*8c551fd7SAndreas Gohr /** 126*8c551fd7SAndreas Gohr * Returns the complete SQL statement and the values to apply 127*8c551fd7SAndreas Gohr * 128*8c551fd7SAndreas Gohr * @return array 129*8c551fd7SAndreas Gohr */ 130*8c551fd7SAndreas Gohr public function getSQL() { 131*8c551fd7SAndreas Gohr $sql = 132*8c551fd7SAndreas Gohr 'SELECT ' . join(",\n", $this->select) . "\n" . 133*8c551fd7SAndreas Gohr ' FROM ' . join(",\n", $this->from) . "\n" . 134*8c551fd7SAndreas Gohr ' WHERE ' . $this->where->toSQL() . "\n"; 135*8c551fd7SAndreas Gohr 136*8c551fd7SAndreas Gohr return $this->fixPlaceholders($sql); 137*8c551fd7SAndreas Gohr } 138*8c551fd7SAndreas Gohr 139*8c551fd7SAndreas Gohr /** 140*8c551fd7SAndreas Gohr * Replaces the named placeholders with ? placeholders 141*8c551fd7SAndreas Gohr * 142*8c551fd7SAndreas Gohr * Until the sqlite plugin can use named placeholder properly 143*8c551fd7SAndreas Gohr * 144*8c551fd7SAndreas Gohr * @param string $sql 145*8c551fd7SAndreas Gohr * @return array 146*8c551fd7SAndreas Gohr */ 147*8c551fd7SAndreas Gohr protected function fixPlaceholders($sql) { 148*8c551fd7SAndreas Gohr $vals = array(); 149*8c551fd7SAndreas Gohr 150*8c551fd7SAndreas Gohr while(preg_match('/(:!!val\d+!!:)/', $sql, $m)) { 151*8c551fd7SAndreas Gohr $pl = $m[1]; 152*8c551fd7SAndreas Gohr $sql = preg_replace("/$pl/", '?', 1); 153*8c551fd7SAndreas Gohr $vals[] = $this->values[$pl]; 154*8c551fd7SAndreas Gohr } 155*8c551fd7SAndreas Gohr 156*8c551fd7SAndreas Gohr return array($sql, $vals); 157*8c551fd7SAndreas Gohr } 158*8c551fd7SAndreas Gohr 159*8c551fd7SAndreas Gohr /** 160*8c551fd7SAndreas Gohr * Insert an array into another array at a given position in an associative array 161*8c551fd7SAndreas Gohr * 162*8c551fd7SAndreas Gohr * @param array $array The initial array 163*8c551fd7SAndreas Gohr * @param array $pairs The array to insert 164*8c551fd7SAndreas Gohr * @param string $key_pos The position at which to insert 165*8c551fd7SAndreas Gohr * @link https://gist.github.com/scribu/588429 simplified 166*8c551fd7SAndreas Gohr * @return array 167*8c551fd7SAndreas Gohr */ 168*8c551fd7SAndreas Gohr protected function array_insert($array, $pairs, $key_pos) { 169*8c551fd7SAndreas Gohr $result = array_slice($array, 0, $key_pos); 170*8c551fd7SAndreas Gohr $result = array_merge($result, $pairs); 171*8c551fd7SAndreas Gohr $result = array_merge($result, array_slice($array, $key_pos)); 172*8c551fd7SAndreas Gohr return $result; 173*8c551fd7SAndreas Gohr } 174*8c551fd7SAndreas Gohr} 175*8c551fd7SAndreas Gohr 176