/** * Constructor * * @param Zend_Db_Adapter_Abstract $adapter */ public function __construct(Zend_Db_Adapter_Abstract $adapter = null) { return parent::__construct($adapter); }
/** * Converts PHP code into SQL code * * @param string $phpCode Code to convert * @return string */ private function _convertToSql($phpCode) { // Some fast cleaning $phpCode = str_replace('return ', '', $phpCode); $phpCode = str_replace(';', '', $phpCode); // Adapter functions $adapterFunctions = $this->_adapter->getFunctions(); // Go parse! $tokens = token_get_all('<?php ' . $phpCode . '?>'); $stack = array(); $tokenId = 0; $depth = 0; for ($i = 0; $i < count($tokens); $i++) { // Ignore token? $ignoreToken = false; // Token details $previousToken = $i > 0 ? $tokens[$i - 1] : null; $token = $tokens[$i]; $nextToken = $i < count($tokens) - 1 ? $tokens[$i + 1] : null; // Parse token if (is_array($token)) { switch ($token[0]) { case T_OPEN_TAG: case T_CLOSE_TAG: $ignoreToken = true; break; case T_STRING: if (in_array($token[1], $adapterFunctions)) { // It is an adapter function! $stack[$tokenId]['token'] = '$this->_adapter->' . $token[1]; $stack[$tokenId]['type'] = self::T_FUNCTION; } else { if (in_array($token[1], self::$_internalFunctions)) { // If it is a PHP function, let's take a lucky // shot and expect the syntax to be the same... $stack[$tokenId]['token'] = $token[1]; $stack[$tokenId]['type'] = self::T_FUNCTION; } else { // Probably some sort of constant / property name if (!is_null($previousToken) && is_array($previousToken) && $previousToken[0] == T_OBJECT_OPERATOR) { $stack[$tokenId]['token'] = $this->_adapter->quoteIdentifier($token[1]) . '\''; $stack[$tokenId]['type'] = self::T_PROPERTY; } else { $stack[$tokenId]['token'] = '\'' . $token[1] . '\''; $stack[$tokenId]['type'] = self::T_CONSTANT; } } } break; case T_VARIABLE: $stack[$tokenId]['token'] = $this->_adapter->quote($token[1]); $stack[$tokenId]['type'] = self::T_VARIABLE; break; case T_OBJECT_OPERATOR: if (!is_null($previousToken) && is_array($previousToken) && $previousToken[0] == T_VARIABLE) { $stack[$tokenId - 1]['token'] = '\'' . addslashes($stack[$tokenId - 1]['token']) . '.'; $ignoreToken = true; } else { $stack[$tokenId]['token'] = '\'.\''; } $stack[$tokenId]['type'] = self::T_OBJECT_OPERATOR; break; case T_IS_IDENTICAL: case T_IS_EQUAL: $stack[$tokenId]['token'] = '\' ' . $this->_adapter->operator('=') . ' \''; $stack[$tokenId]['type'] = self::T_OPERATOR; break; case T_IS_NOT_EQUAL: case T_IS_NOT_IDENTICAL: $stack[$tokenId]['token'] = '\' ' . $this->_adapter->operator('!=') . ' \''; $stack[$tokenId]['type'] = self::T_OPERATOR; break; case T_IS_GREATER_OR_EQUAL: $stack[$tokenId]['token'] = '\' ' . $this->_adapter->operator('>=') . ' \''; $stack[$tokenId]['type'] = self::T_OPERATOR; break; case T_IS_SMALLER_OR_EQUAL: $stack[$tokenId]['token'] = '\' ' . $this->_adapter->operator('<=') . ' \''; $stack[$tokenId]['type'] = self::T_OPERATOR; break; case T_BOOLEAN_AND: case T_LOGICAL_AND: $stack[$tokenId]['token'] = '\' ' . $this->_adapter->operand('AND') . ' \''; $stack[$tokenId]['type'] = self::T_OPERAND; break; case T_BOOLEAN_OR: case T_LOGICAL_OR: $stack[$tokenId]['token'] = '\' ' . $this->_adapter->operand('OR') . ' \''; $stack[$tokenId]['type'] = self::T_OPERAND; break; default: $stack[$tokenId]['token'] = '\'' . $token[1] . '\''; $stack[$tokenId]['type'] = self::T_DEFAULT; break; } } else { // Simple token if ($token != '(' && $token != ')') { $stack[$tokenId]['token'] = $token; $stack[$tokenId]['type'] = self::T_SIMPLE; if ($token == ',') { $stack[$tokenId]['type'] = self::T_ARGUMENT; } else { if ($token == '+' || $token == '-' || $token == '*' || $token == '/' || $token == '%' || $token == '.') { $stack[$tokenId]['token'] = '\'' . $this->_adapter->operator($token) . '\''; $stack[$tokenId]['type'] = self::T_ARITHMETIC; } else { if ($token == '>' || $token == '<') { $stack[$tokenId]['token'] = '\' ' . $this->_adapter->operator($token) . ' \''; $stack[$tokenId]['type'] = self::T_OPERATOR; } } } } else { $stack[$tokenId]['token'] = ''; $stack[$tokenId]['type'] = self::T_START_STOP; } } // Token metadata if (!$ignoreToken) { // Depth if (!is_array($token) && $token == '(') { $depth++; } if (!is_array($token) && $token == ')') { $depth--; } $stack[$tokenId]['depth'] = $depth; // Identifier $tokenId++; } } // Display tree /* foreach ($stack as $node) { for ($i = 0; $i <= $node['depth']; $i++) { echo "| "; } echo $node['type'] . ' - ' . $node['token'] . "\r\n"; } die(); */ // Build compilation string $compileCode = ''; $functionDepth = array(); $depth = 0; for ($i = 0; $i < count($stack); $i++) { // Token details $previousToken = $i > 0 ? $stack[$i - 1] : null; $token = $stack[$i]; $nextToken = $i < count($stack) - 1 ? $stack[$i + 1] : null; // Regular token if ($token['depth'] == $depth && $token['type'] != self::T_START_STOP) { $compileCode .= $token['token']; } // Start/stop if ($token['depth'] > $depth && $token['type'] == self::T_START_STOP && !is_null($previousToken) && $previousToken['type'] == self::T_FUNCTION) { $compileCode .= '('; $functionDepth[$depth] = self::T_FUNCTION; } else { if ($token['depth'] < $depth && $token['type'] == self::T_START_STOP && $functionDepth[$token['depth']] == self::T_FUNCTION) { $compileCode .= ')'; } else { if ($token['depth'] > $depth && $token['type'] == self::T_START_STOP) { $compileCode .= '\'(\''; $functionDepth[$depth] = self::T_START_STOP; } else { if ($token['depth'] < $depth && $token['type'] == self::T_START_STOP) { $compileCode .= '\')\''; } } } } // Next token needs concatenation? if (!is_null($nextToken) && $nextToken['type'] != self::T_ARGUMENT) { if (!($token['type'] == self::T_FUNCTION && $nextToken['type'] == self::T_START_STOP) && !(!is_null($previousToken) && $previousToken['type'] == self::T_FUNCTION && $token['type'] == self::T_START_STOP) && !($token['type'] == self::T_ARGUMENT) && !(!is_null($nextToken) && $nextToken['type'] == self::T_START_STOP && isset($functionDepth[$nextToken['depth']]) && $functionDepth[$nextToken['depth']] == self::T_FUNCTION) && !($token['type'] == self::T_VARIABLE && !is_null($nextToken) && $nextToken['type'] == self::T_PROPERTY)) { $compileCode .= ' . '; } } // Depth if ($token['depth'] < $depth) { unset($functionDepth[$token['depth']]); } $depth = $token['depth']; } // Compile $compileCode = '$compileCode = ' . $compileCode . ';'; eval($compileCode); return $compileCode; }