Lexer.php 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. *
  15. * This software consists of voluntary contributions made by many individuals
  16. * and is licensed under the LGPL. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Doctrine\ORM\Query;
  20. /**
  21. * Scans a DQL query for tokens.
  22. *
  23. * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
  24. * @author Janne Vanhala <jpvanhal@cc.hut.fi>
  25. * @author Roman Borschel <roman@code-factory.org>
  26. * @since 2.0
  27. */
  28. class Lexer extends \Doctrine\Common\Lexer
  29. {
  30. // All tokens that are not valid identifiers must be < 100
  31. const T_NONE = 1;
  32. const T_INTEGER = 2;
  33. const T_STRING = 3;
  34. const T_INPUT_PARAMETER = 4;
  35. const T_FLOAT = 5;
  36. const T_CLOSE_PARENTHESIS = 6;
  37. const T_OPEN_PARENTHESIS = 7;
  38. const T_COMMA = 8;
  39. const T_DIVIDE = 9;
  40. const T_DOT = 10;
  41. const T_EQUALS = 11;
  42. const T_GREATER_THAN = 12;
  43. const T_LOWER_THAN = 13;
  44. const T_MINUS = 14;
  45. const T_MULTIPLY = 15;
  46. const T_NEGATE = 16;
  47. const T_PLUS = 17;
  48. const T_OPEN_CURLY_BRACE = 18;
  49. const T_CLOSE_CURLY_BRACE = 19;
  50. // All tokens that are also identifiers should be >= 100
  51. const T_IDENTIFIER = 100;
  52. const T_ALL = 101;
  53. const T_AND = 102;
  54. const T_ANY = 103;
  55. const T_AS = 104;
  56. const T_ASC = 105;
  57. const T_AVG = 106;
  58. const T_BETWEEN = 107;
  59. const T_BOTH = 108;
  60. const T_BY = 109;
  61. const T_CASE = 110;
  62. const T_COALESCE = 111;
  63. const T_COUNT = 112;
  64. const T_DELETE = 113;
  65. const T_DESC = 114;
  66. const T_DISTINCT = 115;
  67. const T_EMPTY = 116;
  68. const T_ESCAPE = 117;
  69. const T_EXISTS = 118;
  70. const T_FALSE = 119;
  71. const T_FROM = 120;
  72. const T_GROUP = 121;
  73. const T_HAVING = 122;
  74. const T_IN = 123;
  75. const T_INDEX = 124;
  76. const T_INNER = 125;
  77. const T_INSTANCE = 126;
  78. const T_IS = 127;
  79. const T_JOIN = 128;
  80. const T_LEADING = 129;
  81. const T_LEFT = 130;
  82. const T_LIKE = 131;
  83. const T_MAX = 132;
  84. const T_MEMBER = 133;
  85. const T_MIN = 134;
  86. const T_NOT = 135;
  87. const T_NULL = 136;
  88. const T_NULLIF = 137;
  89. const T_OF = 138;
  90. const T_OR = 139;
  91. const T_ORDER = 140;
  92. const T_OUTER = 141;
  93. const T_SELECT = 142;
  94. const T_SET = 143;
  95. const T_SIZE = 144;
  96. const T_SOME = 145;
  97. const T_SUM = 146;
  98. const T_TRAILING = 147;
  99. const T_TRUE = 148;
  100. const T_UPDATE = 149;
  101. const T_WHEN = 150;
  102. const T_WHERE = 151;
  103. const T_WITH = 153;
  104. const T_PARTIAL = 154;
  105. const T_MOD = 155;
  106. /**
  107. * Creates a new query scanner object.
  108. *
  109. * @param string $input a query string
  110. */
  111. public function __construct($input)
  112. {
  113. $this->setInput($input);
  114. }
  115. /**
  116. * @inheritdoc
  117. */
  118. protected function getCatchablePatterns()
  119. {
  120. return array(
  121. '[a-z_\\\][a-z0-9_\:\\\]*[a-z0-9_]{1}',
  122. '(?:[0-9]+(?:[\.][0-9]+)*)(?:e[+-]?[0-9]+)?',
  123. "'(?:[^']|'')*'",
  124. '\?[0-9]*|:[a-z]{1}[a-z0-9_]{0,}'
  125. );
  126. }
  127. /**
  128. * @inheritdoc
  129. */
  130. protected function getNonCatchablePatterns()
  131. {
  132. return array('\s+', '(.)');
  133. }
  134. /**
  135. * @inheritdoc
  136. */
  137. protected function getType(&$value)
  138. {
  139. $type = self::T_NONE;
  140. // Recognizing numeric values
  141. if (is_numeric($value)) {
  142. return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
  143. ? self::T_FLOAT : self::T_INTEGER;
  144. }
  145. // Differentiate between quoted names, identifiers, input parameters and symbols
  146. if ($value[0] === "'") {
  147. $value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));
  148. return self::T_STRING;
  149. } else if (ctype_alpha($value[0]) || $value[0] === '_') {
  150. $name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($value);
  151. if (defined($name)) {
  152. $type = constant($name);
  153. if ($type > 100) {
  154. return $type;
  155. }
  156. }
  157. return self::T_IDENTIFIER;
  158. } else if ($value[0] === '?' || $value[0] === ':') {
  159. return self::T_INPUT_PARAMETER;
  160. } else {
  161. switch ($value) {
  162. case '.': return self::T_DOT;
  163. case ',': return self::T_COMMA;
  164. case '(': return self::T_OPEN_PARENTHESIS;
  165. case ')': return self::T_CLOSE_PARENTHESIS;
  166. case '=': return self::T_EQUALS;
  167. case '>': return self::T_GREATER_THAN;
  168. case '<': return self::T_LOWER_THAN;
  169. case '+': return self::T_PLUS;
  170. case '-': return self::T_MINUS;
  171. case '*': return self::T_MULTIPLY;
  172. case '/': return self::T_DIVIDE;
  173. case '!': return self::T_NEGATE;
  174. case '{': return self::T_OPEN_CURLY_BRACE;
  175. case '}': return self::T_CLOSE_CURLY_BRACE;
  176. default:
  177. // Do nothing
  178. break;
  179. }
  180. }
  181. return $type;
  182. }
  183. }