| Conditions | 40 |
| Paths | > 20000 |
| Total Lines | 135 |
| Code Lines | 79 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | <?php |
||
| 95 | private static function compilePattern(Route $route, $pattern, $isHost) |
||
| 96 | { |
||
| 97 | $tokens = array(); |
||
| 98 | $variables = array(); |
||
| 99 | $matches = array(); |
||
| 100 | $pos = 0; |
||
| 101 | $defaultSeparator = $isHost ? '.' : '/'; |
||
| 102 | $useUtf8 = preg_match('//u', $pattern); |
||
| 103 | $needsUtf8 = $route->getOption('utf8'); |
||
| 104 | |||
| 105 | if (!$needsUtf8 && $useUtf8 && preg_match('/[\x80-\xFF]/', $pattern)) { |
||
| 106 | $needsUtf8 = true; |
||
| 107 | @trigger_error(sprintf('Using UTF-8 route patterns without setting the "utf8" option is deprecated since Symfony 3.2 and will throw a LogicException in 4.0. Turn on the "utf8" route option for pattern "%s".', $pattern), E_USER_DEPRECATED); |
||
| 108 | } |
||
| 109 | if (!$useUtf8 && $needsUtf8) { |
||
| 110 | throw new \LogicException(sprintf('Cannot mix UTF-8 requirements with non-UTF-8 pattern "%s".', $pattern)); |
||
| 111 | } |
||
| 112 | |||
| 113 | // Match all variables enclosed in "{}" and iterate over them. But we only want to match the innermost variable |
||
| 114 | // in case of nested "{}", e.g. {foo{bar}}. This in ensured because \w does not match "{" or "}" itself. |
||
| 115 | preg_match_all('#\{\w+\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); |
||
| 116 | foreach ($matches as $match) { |
||
| 117 | $varName = substr($match[0][0], 1, -1); |
||
| 118 | // get all static text preceding the current variable |
||
| 119 | $precedingText = substr($pattern, $pos, $match[0][1] - $pos); |
||
| 120 | $pos = $match[0][1] + strlen($match[0][0]); |
||
| 121 | |||
| 122 | if (!strlen($precedingText)) { |
||
| 123 | $precedingChar = ''; |
||
| 124 | } elseif ($useUtf8) { |
||
| 125 | preg_match('/.$/u', $precedingText, $precedingChar); |
||
| 126 | $precedingChar = $precedingChar[0]; |
||
| 127 | } else { |
||
| 128 | $precedingChar = substr($precedingText, -1); |
||
| 129 | } |
||
| 130 | $isSeparator = '' !== $precedingChar && false !== strpos(static::SEPARATORS, $precedingChar); |
||
| 131 | |||
| 132 | // A PCRE subpattern name must start with a non-digit. Also a PHP variable cannot start with a digit so the |
||
| 133 | // variable would not be usable as a Controller action argument. |
||
| 134 | if (preg_match('/^\d/', $varName)) { |
||
| 135 | throw new \DomainException(sprintf('Variable name "%s" cannot start with a digit in route pattern "%s". Please use a different name.', $varName, $pattern)); |
||
| 136 | } |
||
| 137 | if (in_array($varName, $variables)) { |
||
| 138 | throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName)); |
||
| 139 | } |
||
| 140 | |||
| 141 | if (strlen($varName) > self::VARIABLE_MAXIMUM_LENGTH) { |
||
| 142 | throw new \DomainException(sprintf('Variable name "%s" cannot be longer than %s characters in route pattern "%s". Please use a shorter name.', $varName, self::VARIABLE_MAXIMUM_LENGTH, $pattern)); |
||
| 143 | } |
||
| 144 | |||
| 145 | if ($isSeparator && $precedingText !== $precedingChar) { |
||
| 146 | $tokens[] = array('text', substr($precedingText, 0, -strlen($precedingChar))); |
||
| 147 | } elseif (!$isSeparator && strlen($precedingText) > 0) { |
||
| 148 | $tokens[] = array('text', $precedingText); |
||
| 149 | } |
||
| 150 | |||
| 151 | $regexp = $route->getRequirement($varName); |
||
| 152 | if (null === $regexp) { |
||
| 153 | $followingPattern = (string) substr($pattern, $pos); |
||
| 154 | // Find the next static character after the variable that functions as a separator. By default, this separator and '/' |
||
| 155 | // are disallowed for the variable. This default requirement makes sure that optional variables can be matched at all |
||
| 156 | // and that the generating-matching-combination of URLs unambiguous, i.e. the params used for generating the URL are |
||
| 157 | // the same that will be matched. Example: new Route('/{page}.{_format}', array('_format' => 'html')) |
||
| 158 | // If {page} would also match the separating dot, {_format} would never match as {page} will eagerly consume everything. |
||
| 159 | // Also even if {_format} was not optional the requirement prevents that {page} matches something that was originally |
||
| 160 | // part of {_format} when generating the URL, e.g. _format = 'mobile.html'. |
||
| 161 | $nextSeparator = self::findNextSeparator($followingPattern, $useUtf8); |
||
| 162 | $regexp = sprintf( |
||
| 163 | '[^%s%s]+', |
||
| 164 | preg_quote($defaultSeparator, self::REGEX_DELIMITER), |
||
| 165 | $defaultSeparator !== $nextSeparator && '' !== $nextSeparator ? preg_quote($nextSeparator, self::REGEX_DELIMITER) : '' |
||
| 166 | ); |
||
| 167 | if (('' !== $nextSeparator && !preg_match('#^\{\w+\}#', $followingPattern)) || '' === $followingPattern) { |
||
| 168 | // When we have a separator, which is disallowed for the variable, we can optimize the regex with a possessive |
||
| 169 | // quantifier. This prevents useless backtracking of PCRE and improves performance by 20% for matching those patterns. |
||
| 170 | // Given the above example, there is no point in backtracking into {page} (that forbids the dot) when a dot must follow |
||
| 171 | // after it. This optimization cannot be applied when the next char is no real separator or when the next variable is |
||
| 172 | // directly adjacent, e.g. '/{x}{y}'. |
||
| 173 | $regexp .= '+'; |
||
| 174 | } |
||
| 175 | } else { |
||
| 176 | if (!preg_match('//u', $regexp)) { |
||
| 177 | $useUtf8 = false; |
||
| 178 | } elseif (!$needsUtf8 && preg_match('/[\x80-\xFF]|(?<!\\\\)\\\\(?:\\\\\\\\)*+(?-i:X|[pP][\{CLMNPSZ]|x\{[A-Fa-f0-9]{3})/', $regexp)) { |
||
| 179 | $needsUtf8 = true; |
||
| 180 | @trigger_error(sprintf('Using UTF-8 route requirements without setting the "utf8" option is deprecated since Symfony 3.2 and will throw a LogicException in 4.0. Turn on the "utf8" route option for variable "%s" in pattern "%s".', $varName, $pattern), E_USER_DEPRECATED); |
||
| 181 | } |
||
| 182 | if (!$useUtf8 && $needsUtf8) { |
||
| 183 | throw new \LogicException(sprintf('Cannot mix UTF-8 requirement with non-UTF-8 charset for variable "%s" in pattern "%s".', $varName, $pattern)); |
||
| 184 | } |
||
| 185 | } |
||
| 186 | |||
| 187 | $tokens[] = array('variable', $isSeparator ? $precedingChar : '', $regexp, $varName); |
||
| 188 | $variables[] = $varName; |
||
| 189 | } |
||
| 190 | |||
| 191 | if ($pos < strlen($pattern)) { |
||
| 192 | $tokens[] = array('text', substr($pattern, $pos)); |
||
| 193 | } |
||
| 194 | |||
| 195 | // find the first optional token |
||
| 196 | $firstOptional = PHP_INT_MAX; |
||
| 197 | if (!$isHost) { |
||
| 198 | for ($i = count($tokens) - 1; $i >= 0; --$i) { |
||
| 199 | $token = $tokens[$i]; |
||
| 200 | if ('variable' === $token[0] && $route->hasDefault($token[3])) { |
||
| 201 | $firstOptional = $i; |
||
| 202 | } else { |
||
| 203 | break; |
||
| 204 | } |
||
| 205 | } |
||
| 206 | } |
||
| 207 | |||
| 208 | // compute the matching regexp |
||
| 209 | $regexp = ''; |
||
| 210 | for ($i = 0, $nbToken = count($tokens); $i < $nbToken; ++$i) { |
||
| 211 | $regexp .= self::computeRegexp($tokens, $i, $firstOptional); |
||
| 212 | } |
||
| 213 | $regexp = self::REGEX_DELIMITER.'^'.$regexp.'$'.self::REGEX_DELIMITER.'sD'.($isHost ? 'i' : ''); |
||
| 214 | |||
| 215 | // enable Utf8 matching if really required |
||
| 216 | if ($needsUtf8) { |
||
| 217 | $regexp .= 'u'; |
||
| 218 | for ($i = 0, $nbToken = count($tokens); $i < $nbToken; ++$i) { |
||
| 219 | if ('variable' === $tokens[$i][0]) { |
||
| 220 | $tokens[$i][] = true; |
||
| 221 | } |
||
| 222 | } |
||
| 223 | } |
||
| 224 | |||
| 225 | return array( |
||
| 226 | 'staticPrefix' => self::determineStaticPrefix($route, $tokens), |
||
| 227 | 'regex' => $regexp, |
||
| 228 | 'tokens' => array_reverse($tokens), |
||
| 229 | 'variables' => $variables, |
||
| 230 | ); |
||
| 317 |