- Fixed a bug introduced into PdoObject exception on latest commit. - Corrected the open() close() enclosure of query condition.
		
			
				
	
	
		
			328 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			328 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace Ulmus;
 | 
						|
 | 
						|
class QueryBuilder
 | 
						|
{
 | 
						|
    public Query\Where $where;
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Those are the parameters we are going to bind to PDO.
 | 
						|
     */
 | 
						|
    public array $parameters = [];
 | 
						|
    
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * Those values are to be inserted or updated
 | 
						|
     */
 | 
						|
    public array $values = [];
 | 
						|
 | 
						|
    public string $conditionOperator = Query\Where::CONDITION_AND;
 | 
						|
    
 | 
						|
    protected int $parameterIndex = 0;
 | 
						|
 | 
						|
    protected array $queryStack = [];
 | 
						|
 | 
						|
    public function select($field) : self
 | 
						|
    {
 | 
						|
        if ( null !== ( $select = $this->getFragment(Query\Select::class) ) ) {
 | 
						|
            $select->add($field);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            $select = new Query\Select();
 | 
						|
            $select->set($field);
 | 
						|
            $this->push($select);
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public function insert(array $fieldlist, string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
 | 
						|
    {
 | 
						|
        if ( null === $this->getFragment(Query\Insert::class) ) {    
 | 
						|
            if ( $schema ) {
 | 
						|
                $table = "\"$schema\".$table";
 | 
						|
            }
 | 
						|
 | 
						|
            if ( $database ) {
 | 
						|
                $table = "\"$database\".$table";
 | 
						|
            }
 | 
						|
            
 | 
						|
            $insert = new Query\Insert();
 | 
						|
            $this->push($insert);
 | 
						|
            
 | 
						|
            $insert->fieldlist = $fieldlist;
 | 
						|
            $insert->alias = $alias;
 | 
						|
            $insert->table = $table;
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function values(array $dataset) : self 
 | 
						|
    {
 | 
						|
        if ( null === ( $values = $this->getFragment(Query\Values::class) ) ) {
 | 
						|
            $values = new Query\Values($this);
 | 
						|
            $this->push($values);
 | 
						|
        }
 | 
						|
        
 | 
						|
        $values->add($dataset);
 | 
						|
        
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public function update(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
 | 
						|
    {
 | 
						|
        if ( ! $this->getFragment(Query\Update::class) ) {
 | 
						|
            if ( $schema ) {
 | 
						|
                $table = "\"$schema\".$table";
 | 
						|
            }
 | 
						|
            
 | 
						|
            if ( $database ) {
 | 
						|
                $table = "\"$database\".$table";
 | 
						|
            }
 | 
						|
 | 
						|
            $update = new Query\Update();
 | 
						|
            $this->push($update);
 | 
						|
            
 | 
						|
            $update->alias = $alias;
 | 
						|
            $update->table = $table;
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function set(array $dataset) : self 
 | 
						|
    {
 | 
						|
        
 | 
						|
        if ( null === ( $set = $this->getFragment(Query\Set::class) ) ) {
 | 
						|
            $set = new Query\Set($this);
 | 
						|
            $this->push($set);
 | 
						|
        }
 | 
						|
        
 | 
						|
        $set->set($dataset);
 | 
						|
        
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public function delete() : self
 | 
						|
    {
 | 
						|
        if ( ! $this->getFragment(Query\Delete::class) ) {
 | 
						|
            $this->push(new Query\Delete());
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function from(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
 | 
						|
    {
 | 
						|
        if ( $schema ) {
 | 
						|
            $table = "\"$schema\".$table";
 | 
						|
        }
 | 
						|
        
 | 
						|
        if ( $database ) {
 | 
						|
            $table = "$database.$table";
 | 
						|
        }
 | 
						|
 | 
						|
        if ( null !== ( $from = $this->getFragment(Query\From::class) ) ) {
 | 
						|
            $from->add($alias ? [ $alias => $table ] : $table);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            $from = new Query\From($this);
 | 
						|
            $this->push($from);
 | 
						|
            
 | 
						|
            $from->set($alias ? [ $alias => $table ] : [ $table ]);
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function open(string $condition = Query\Where::CONDITION_AND) : self
 | 
						|
    {
 | 
						|
        if ( null !== ($this->where ?? null) ) {
 | 
						|
            $this->where->conditionList[] = $new = new Query\Where($this, $condition);
 | 
						|
            $this->where = $new;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            $this->where = new Query\Where($this, $condition);
 | 
						|
            $this->push($this->where);
 | 
						|
            $this->where->conditionList[] = $new = new Query\Where($this, $condition);
 | 
						|
            $this->where = $new;
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function close() : self
 | 
						|
    {
 | 
						|
        if ( null !== ($this->where ?? null) && $this->where->parent ) {
 | 
						|
            
 | 
						|
            # if an enclosure was opened, and nothing done, we must remove the unused node
 | 
						|
            if ( empty($this->where->conditionList) && (count($this->where->parent->conditionList) === 1) ) {
 | 
						|
                unset($this->where->parent->conditionList);
 | 
						|
            }
 | 
						|
            
 | 
						|
            $this->where = $this->where->parent;
 | 
						|
        }
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function where($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
 | 
						|
    {
 | 
						|
        if ( $this->where ?? false ) {
 | 
						|
            $where = $this->where;
 | 
						|
        }
 | 
						|
        elseif ( null === ( $where = $this->getFragment(Query\Where::class) ) ) {
 | 
						|
            $this->where = $where = new Query\Where($this);
 | 
						|
            $this->push($where);
 | 
						|
        }
 | 
						|
        
 | 
						|
        $this->conditionOperator = $operator;
 | 
						|
        
 | 
						|
        $where->add($field, $value, $operator, $condition, $not);
 | 
						|
        
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function notWhere($field, $value, string $operator = Query\Where::CONDITION_AND) : self
 | 
						|
    {
 | 
						|
        return $this->where($field, $value, $operator, true);
 | 
						|
    }
 | 
						|
 | 
						|
    public function groupBy() : self
 | 
						|
    {
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function limit(int $value) : self
 | 
						|
    {
 | 
						|
        if ( null === $limit = $this->getFragment(Query\Limit::class) ) {
 | 
						|
            $limit = new Query\Limit();
 | 
						|
            $this->push($limit);
 | 
						|
        }
 | 
						|
 | 
						|
        $limit->set($value);
 | 
						|
        
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function offset(int $value) : self
 | 
						|
    {
 | 
						|
        if ( null === $offset = $this->getFragment(Query\Offset::class) ) {
 | 
						|
            $offset = new Query\Offset();
 | 
						|
            $this->push($offset);
 | 
						|
        }
 | 
						|
 | 
						|
        $offset->set($value);
 | 
						|
        
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function orderBy(string $field, ? string $direction = null) : self
 | 
						|
    {
 | 
						|
        if ( null === $orderBy = $this->getFragment(Query\OrderBy::class) ) {
 | 
						|
            $orderBy = new Query\OrderBy();
 | 
						|
            $this->push($orderBy);
 | 
						|
        }
 | 
						|
 | 
						|
        $orderBy->add($field, $direction);
 | 
						|
        
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function join(string $type, $table, $field, $value, bool $outer = false) : self
 | 
						|
    {
 | 
						|
        if ( null === $join = $this->getFragment(Query\Join::class) ) {
 | 
						|
            $join = new Query\Join();
 | 
						|
            $this->push($join);
 | 
						|
        }
 | 
						|
 | 
						|
        $join->add($type, $table, $field, $value);
 | 
						|
        
 | 
						|
        $join->outer = $outer;
 | 
						|
        
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
    /*
 | 
						|
      "LEFT JOIN PAI_DOS ON PAI_DOS.MATR = PAI_DOS_EMPL.MATR"
 | 
						|
      "LEFT JOIN PAI_DOS_2 ON PAI_DOS_2.MATR = PAI_DOS.MATR"
 | 
						|
      "LEFT JOIN PAI_CAND ON PAI_CAND.MATR = PAI_DOS.MATR"
 | 
						|
    
 | 
						|
      "LEFT JOIN PAI_TAB_CORP_EMPL ON PAI_TAB_CORP_EMPL.CORP_EMPL = PAI_DOS_EMPL.CORP_EMPL",
 | 
						|
      "LEFT JOIN PAI_TAB_LIEU_TRAV ON PAI_TAB_LIEU_TRAV.LIEU_TRAV = PAI_DOS_EMPL.LIEU_TRAV",
 | 
						|
      "LEFT JOIN PAI_TAB_BAT ON PAI_TAB_BAT.BAT = PAI_TAB_LIEU_TRAV.BAT"
 | 
						|
    */
 | 
						|
    public function push(Query\Fragment $queryFragment) : self
 | 
						|
    {
 | 
						|
        $this->queryStack[] = $queryFragment;
 | 
						|
        
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function render() : string
 | 
						|
    {
 | 
						|
        $sql = [];
 | 
						|
 | 
						|
        usort($this->queryStack, function($q1, $q2) {
 | 
						|
            return $q1->order <=> $q2->order;
 | 
						|
        });
 | 
						|
 | 
						|
        foreach($this->queryStack as $fragment) {
 | 
						|
            $sql[] = $fragment->render();
 | 
						|
        }
 | 
						|
 | 
						|
        return implode(" ", $sql);
 | 
						|
    }
 | 
						|
    
 | 
						|
    public function reset() : void
 | 
						|
    {
 | 
						|
        $this->parameters = $this->values = $this->queryStack = [];
 | 
						|
        $this->conditionOperator = Query\Where::CONDITION_AND;
 | 
						|
        $this->parameterIndex = 0;
 | 
						|
 | 
						|
        unset($this->where);
 | 
						|
    }
 | 
						|
 | 
						|
    public function getFragment(string $class) : ? Query\Fragment
 | 
						|
    {
 | 
						|
        foreach($this->queryStack as $item) {
 | 
						|
            if ( get_class($item) === $class ) {
 | 
						|
                return $item;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return null;
 | 
						|
    }
 | 
						|
 | 
						|
    public function removeFragment(Query\Fragment $fragment) : void
 | 
						|
    {
 | 
						|
        foreach($this->queryStack as $key => $item) {
 | 
						|
            if ( $item === $fragment ) {
 | 
						|
                unset($this->queryStack[$key]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    public function __toString() : string
 | 
						|
    {
 | 
						|
        return $this->render();
 | 
						|
    }
 | 
						|
 | 
						|
    public function addParameter($value, string $key = null) : string 
 | 
						|
    {
 | 
						|
        if ( $key === null ) {
 | 
						|
            $key = ":p" . $this->parameterIndex++;
 | 
						|
        }
 | 
						|
 | 
						|
        $this->parameters[$key] = $value;
 | 
						|
        
 | 
						|
        return $key;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public function addValues(array $values) : void
 | 
						|
    {
 | 
						|
        $this->values = $values;
 | 
						|
    }
 | 
						|
}
 |