Skip to content

Commit 85c3196

Browse files
authored
Merge pull request #2310 from Haehnchen/feature/router-reverse
implement a reverse router match to find targets for partial urls targets
2 parents 8f370c3 + 12a4402 commit 85c3196

File tree

3 files changed

+50
-21
lines changed

3 files changed

+50
-21
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/routing/RouteHelper.java

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -149,46 +149,60 @@ public static Collection<Route> findRoutesByPath(@NotNull Project project, @NotN
149149
}
150150

151151
/**
152-
* "/foo/bar" => "/foo/{edit}"
152+
* Reverse routing matching, find any "incomplete" string inside the route pattern
153+
*
154+
* - "foo/bar" => "/foo/bar"
155+
* - "foo/12" => "/foo/{edit}"
156+
* - "ar/12/foo" => "/car/{edit}/foobar"
153157
*/
154158
@NotNull
155-
public static PsiElement[] getMethodsForPathWithPlaceholderMatch(@NotNull Project project, @NotNull String path) {
159+
public static PsiElement[] getMethodsForPathWithPlaceholderMatch(@NotNull Project project, @NotNull String searchPath) {
156160
Set<PsiElement> targets = new HashSet<>();
157161

158-
Pattern placeholderMatcher = null;
159-
160162
for (Route route : RouteHelper.getAllRoutes(project).values()) {
161163
String routePath = route.getPath();
162164
if (routePath == null) {
163165
continue;
164166
}
165167

166-
if (path.equalsIgnoreCase(routePath)) {
168+
if (routePath.contains(searchPath)) {
167169
targets.addAll(Arrays.asList(getMethodsOnControllerShortcut(project, route.getController())));
170+
continue;
168171
}
169172

170-
if (placeholderMatcher == null) {
171-
placeholderMatcher = Pattern.compile("\\{[\\w-]+}");
172-
}
173+
// String string = "|"; visibility debug
174+
String string = Character.toString((char) 156);
175+
176+
String routePathPlaceholderNeutral = routePath.replaceAll("\\{([^}]*)}", string);
177+
String match = null;
178+
int startIndex = -1;
173179

174-
Matcher matcher = placeholderMatcher.matcher(routePath);
180+
// find first common non pattern string, string on at 2 for no fetching all; right to left
181+
for (int i = 2; i < searchPath.length(); i++) {
182+
String text = searchPath.substring(0, searchPath.length() - i);
175183

176-
// /foo/{foo} => // \Q/foo/\E{foo}
177-
StringBuilder quoteWrapped = new StringBuilder();
178-
int lastRegMatch = 0;
179-
while (matcher.find()) {
180-
int start = matcher.start();
181-
quoteWrapped.append(Pattern.quote(routePath.substring(lastRegMatch, start))).append("[\\w-]+");
182-
lastRegMatch = matcher.end();
184+
int i1 = routePathPlaceholderNeutral.indexOf(text);
185+
if (i1 >= 0) {
186+
match = routePathPlaceholderNeutral.substring(i1);
187+
startIndex = text.length();
188+
break;
189+
}
183190
}
184191

185-
String substring = routePath.substring(lastRegMatch);
186-
if (!substring.isEmpty()) {
187-
quoteWrapped.append(Pattern.quote(substring));
192+
if (match == null) {
193+
continue;
188194
}
189195

190-
if (Pattern.matches(quoteWrapped.toString(), path)) {
191-
targets.addAll(Arrays.asList(getMethodsOnControllerShortcut(project, route.getController())));
196+
// find a pattern match: left to right
197+
int endIndex = match.length();
198+
for (int i = startIndex + 1; i <= endIndex; i++) {
199+
String substring = match.substring(0, i);
200+
201+
String regex = substring.replace(string, "[\\w-]+");
202+
Matcher matcher = Pattern.compile(regex).matcher(searchPath);
203+
if (matcher.matches()) {
204+
targets.addAll(Arrays.asList(getMethodsOnControllerShortcut(project, route.getController())));
205+
}
192206
}
193207
}
194208

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/RouteHelperTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,14 @@ public void testGetMethodsForPathWithPlaceholderMatch() {
519519

520520
PsiElement[] targets2 = RouteHelper.getMethodsForPathWithPlaceholderMatch(getProject(), "/foo_bar/foobar/edit/foo/foo/foo");
521521
assertTrue(Arrays.stream(targets2).anyMatch(psiElement -> psiElement instanceof Method && "indexFooBarEditAction".equals(((Method) psiElement).getName())));
522+
523+
// /foobar/edit/{id}/foo/{foo}
524+
PsiElement[] targets3 = RouteHelper.getMethodsForPathWithPlaceholderMatch(getProject(), "esolve/me/12/foo");
525+
assertTrue(Arrays.stream(targets3).anyMatch(psiElement -> psiElement instanceof Method && "resolveMe".equals(((Method) psiElement).getName())));
526+
527+
PsiElement[] targets4 = RouteHelper.getMethodsForPathWithPlaceholderMatch(getProject(), "/edit/");
528+
assertTrue(Arrays.stream(targets4).anyMatch(psiElement -> psiElement instanceof Method && "fooAction".equals(((Method) psiElement).getName())));
529+
assertTrue(Arrays.stream(targets4).anyMatch(psiElement -> psiElement instanceof Method && "indexFooBarEditAction".equals(((Method) psiElement).getName())));
522530
}
523531

524532
/**

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/routing/fixtures/RouteHelper.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ public function indexAction()
6464
public function fooAction()
6565
{
6666
}
67+
68+
/**
69+
* @Route("/resolve/me/{id<\d>}/foobar/item", name="my_foo_resolve_me")
70+
*/
71+
public function resolveMe()
72+
{
73+
}
6774
}
6875

6976
class InvokeController

0 commit comments

Comments
 (0)