# phpDox - Source of QueryParser.php

# Source of file QueryParser.php

Size: 3,049 Bytes - Last Modified: 2020-04-10T20:54:13-04:00

## src/QueryParser.php

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

    <?php declare(strict_types=1);

    /**

     * Query

     *

     * SQL Query Builder / Database Abstraction Layer

     *

     * PHP version 7.4

     *

     * @package     Query

     * @author      Timothy J. Warren <tim@timshomepage.net>

     * @copyright   2012 - 2020 Timothy J. Warren

     * @license     http://www.opensource.org/licenses/mit-license.html  MIT License

     * @link        https://git.timshomepage.net/aviat/Query

     * @version     3.0.0

     */

    namespace Query;

    use Query\Drivers\DriverInterface;

    /**

     * Utility Class to parse sql clauses for properly escaping identifiers

     */

    class QueryParser {

    	/**

    	 * DB Driver

    	 *

    	 * @var DriverInterface

    	 */

    	private DriverInterface $db;

    	/**

    	 * Regex patterns for various syntax components

    	 *

    	 * @var array

    	 */

    	private array $matchPatterns = [

    		'function' => '([a-zA-Z0-9_]+\((.*?)\))',

    		'identifier' => '([a-zA-Z0-9_-]+\.?)+',

    		'operator' => '=|AND|&&?|~|\|\|?|\^|/|>=?|<=?|-|%|OR|\+|NOT|\!=?|<>|XOR'

    	];

    	/**

    	 * Regex matches

    	 *

    	 * @var array

    	 */

    	public array $matches = [

    		'functions' => [],

    		'identifiers' => [],

    		'operators' => [],

    		'combined' => [],

    	];

    	/**

    	 * Constructor/entry point into parser

    	 *

    	 * @param DriverInterface $db

    	 */

    	public function __construct(DriverInterface $db)

    	{

    		$this->db = $db;

    	}

    	/**

    	 * Parser method for setting the parse string

    	 *

    	 * @param string $sql

    	 * @return array

    	 */

    	public function parseJoin(string $sql): array

    	{

    		// Get sql clause components

    		preg_match_all('`'.$this->matchPatterns['function'].'`', $sql, $this->matches['functions'], PREG_SET_ORDER);

    		preg_match_all('`'.$this->matchPatterns['identifier'].'`', $sql, $this->matches['identifiers'], PREG_SET_ORDER);

    		preg_match_all('`'.$this->matchPatterns['operator'].'`', $sql, $this->matches['operators'], PREG_SET_ORDER);

    		// Get everything at once for ordering

    		$fullPattern = '`'.$this->matchPatterns['function'].'+|'.$this->matchPatterns['identifier'].'|('.$this->matchPatterns['operator'].')+`i';

    		preg_match_all($fullPattern, $sql, $this->matches['combined'], PREG_SET_ORDER);

    		// Go through the matches, and get the most relevant matches

    		$this->matches = array_map([$this, 'filterArray'], $this->matches);

    		return $this->matches;

    	}

    	/**

    	 * Compiles a join condition after parsing

    	 *

    	 * @param string $condition

    	 * @return string

    	 */

    	public function compileJoin(string $condition): string

    	{

    		$parts = $this->parseJoin($condition);

    		$count = count($parts['identifiers']);

    		// Go through and quote the identifiers

    		for($i=0; $i <= $count; $i++)

    		{

    			if (in_array($parts['combined'][$i], $parts['identifiers']) && ! is_numeric($parts['combined'][$i]))

    			{

    				$parts['combined'][$i] = $this->db->quoteIdent($parts['combined'][$i]);

    			}

    		}

    		return implode('', $parts['combined']);

    	}

    	/**

    	 * Returns a more useful match array

    	 *

    	 * @param array $array

    	 * @return array

    	 */

    	protected function filterArray(array $array): array

    	{

    		$newArray = [];

    		foreach($array as $row)

    		{

    			$newArray[] =  (is_array($row)) ? $row[0] : $row;

    		}

    		return $newArray;

    	}

    }