PHP Classes

File: classes/database/db-parser.php

Recommend this page to a friend!
  Classes of Gonzalo Chumillas   Ses Query   classes/database/db-parser.php   Download  
File: classes/database/db-parser.php
Role: Class source
Content type: text/plain
Description: DBParser class
Class: Ses Query
Manipulate records retrieved with select queries
Author: By
Last change:
Date: 10 years ago
Size: 7,437 bytes
 

Contents

Class file image Download
<?php
/**
 * This file contains the DBParser class.
 *
 * @author Gonzalo Chumillas <gonzalo@soloproyectos.com>
 * @package database
 */

require_once dirname(__DIR__) . "/database/db-query.php";
require_once
dirname(__DIR__) . "/database/db-column.php";
require_once
dirname(__DIR__) . "/parser/parser.php";

/**
 * class DBParser
 *
 * This class parses an SQL sentence.
 *
 * @package database
 */
class DBParser extends Parser {
   
/**
     * A subset of reserved words
     * @var array
     */
   
private $reserved_words = array(
       
"from", "where", "on", "group", "having", "order", "limit", "union", "inner", "left", "right", "join", "and"
   
);
   
   
/**
     * @var DBQuery
     */
   
private $query;
   
   
/**
     * @param DBQuery $query
     * @param string $sql
     */
   
public function __construct($query, $sql) {
       
$this->query = $query;
       
parent::__construct($sql, Parser::UNGREEDY);
    }
   
   
/**
     * Is a reserved word?
     * @param string $word
     * @return string
     */
   
private function isReservedWord($str) {
       
$str = strtolower(trim($str));
        return
array_search($str, $this->reserved_words) !== FALSE;
    }
   
   
/**
     * Parses conditions individually.
     * @param int $offset0
     * @param int $offset1
     */
   
private function parseConditions($offset0, $offset1) {
       
$str = trim(substr($this->string, $offset0, $offset1 - $offset0));
       
$conditions = preg_split("/\s+and\s+/i", $str);
       
        foreach (
$conditions as $condition) {
           
$terms = explode("=", $condition);
            if (
count($terms) != 2) {
                continue;
            }
           
           
// parse columns
           
$columns = array();
            foreach (
$terms as $term) {
               
$t = new Tokenizer($term);
                if ( (list(
$value) = $t->str()) || (list($value) = $t->number()) ) {
                   
array_push($columns, $value);
                } else
                if (
$t->match("(`?(\w+)`?\s*\.\s*)?`?(\w+)`?", $matches)) {
                   
$table_name = trim($matches[2]);
                   
$column_name = trim($matches[3]);
                   
$column = $this->query->registerColumn($table_name, $column_name);
                   
array_push($columns, $column);
                }
            }
           
           
// links columns
           
foreach ($columns as $i => $column0) {
               
$column1 = $columns[($i + 1) % 2];
                if (
$column0 instanceof DBColumn) {
                    if (
$column1 instanceof DBColumn) {
                       
$column0->registerLink($column1);
                       
$column1->registerLink($column0);
                    } else {
                       
$column0->setDefaultValue($column1);
                    }
                   
                    break;
                }
            }
        }
    }
   
   
/**
     * Is the next an identifier?
     * @return array|boolean
     */
   
protected function identifier() {
        if (
$this->match("`([^`]+)`", $matches)) {
            return array(
$matches[2]);
        } else {
           
$offset = $this->offset;
           
            if (list(
$name) = $this->match("\w+")) {
                if (
$this->isReservedWord($name)) {
                   
$this->offset = $offset;
                } else {
                    return array(
$name);
                }
            }
        }
       
        return
FALSE;
    }
   
   
/**
     * Is the next a join clause?
     * @throws ParserError
     * @return array|boolean
     */
   
protected function join() {
       
// gets join type
       
if (!list($str) = $this->match("((inner|(left(\s+outer)?))\s+)?join\s+", $matches, Tokenizer::SEARCH_ANYWHERE|Tokenizer::OFFSET_CAPTURE)) {
            return
FALSE;
        }
       
$join_type = stripos($str, "inner") !== FALSE? DBTable::INNER_JOIN : DBTable::LEFT_JOIN;
       
$offset = $matches[0][1];
       
       
// gets table name
       
if (!list($table_name) = $this->is("identifier")) {
            throw new
ParserException($this, "Table name expected");
        }
       
       
// gets table alias
       
$table_alias = $table_name;
        if (
$this->eq("as")) {
            if (!list(
$table_alias) = $this->is("identifier")) {
                throw new
ParserException($this, "Table alias expected");
            }
        } else
        if (list(
$str) = $this->is("identifier")) {
           
$table_alias = $str;
        }
       
       
// register table
       
$table = $this->query->registerTable($table_alias, TRUE);
       
$table->setName($table_name);
       
$table->setJoinType($join_type);
       
       
// optional "on"
       
$this->eq("on");
       
        return array(
$offset);
    }
   
   
/**
     * Is the next a where clause?
     * @return array|boolean
     */
   
protected function where() {
        if (!
$this->match("where\s+", $matches, Tokenizer::SEARCH_ANYWHERE|Tokenizer::OFFSET_CAPTURE)) {
            return
FALSE;
        }
       
$offset = $matches[0][1];
       
        return array(
$offset);
    }
   
   
/**
     * Is the next whatever?
     * @return array|boolean
     */
   
protected function whatever() {
        if (
$this->match("(group|having|order|limit|union)\s+", $matches, Tokenizer::SEARCH_ANYWHERE|Tokenizer::OFFSET_CAPTURE)) {
            return array(
$matches[0][1]);
        }
       
        return array(
strlen($this->string));
    }
   
   
/**
     * Is the next a select?
     * @throws ParserError
     * @return array|boolean
     */
   
protected function select() {
       
$main_table = NULL;
       
        if (
$this->match("select.*from")) {
           
// gets table name
           
if (!list($table_name) = $this->is("identifier")) {
                throw new
ParserException($this, "Table name expected");
            }
           
           
// gets table alias
           
$table_alias = $table_name;
            if (
$this->eq("as")) {
                if (!list(
$table_alias) = $this->is("identifier")) {
                    throw new
ParserException($this, "Table alias expected");
                }
            } else
            if (list(
$str) = $this->is("identifier")) {
               
$table_alias = $str;
            }
           
           
// register main table
           
$main_table = $this->query->registerTable($table_alias, TRUE);
           
$main_table->setName($table_name);
           
$this->query->setMainTable($main_table);
           
           
// join clauses
           
$offset0 = $this->offset;
            while (list(
$offset1) = $this->is("join")) {
               
$this->parseConditions($offset0, $offset1);
               
$offset0 = $this->offset;
            }
           
           
// where clause
           
if (list($offset1) = $this->is("where")) {
               
$this->parseConditions($offset0, $offset1);
               
$offset0 = $this->offset;
            }
           
           
// whatever else
           
if (list($offset1) = $this->is("whatever")) {
               
$this->parseConditions($offset0, $offset1);
            }
        }
       
        return
$main_table != NULL && $main_table->getPrimaryKey() != NULL;
    }
   
   
/**
     * Parses the sql sentence.
     * @return array|boolean
     */
   
public function _parse() {
        return
$this->is("select");
    }
}