Skip to content

Commit

Permalink
implement a reverse router match to find targets for partial urls tar…
Browse files Browse the repository at this point in the history
…gets
  • Loading branch information
Haehnchen committed Mar 29, 2024
1 parent 8f370c3 commit 12a4402
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -149,46 +149,60 @@ public static Collection<Route> findRoutesByPath(@NotNull Project project, @NotN
}

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

Pattern placeholderMatcher = null;

for (Route route : RouteHelper.getAllRoutes(project).values()) {
String routePath = route.getPath();
if (routePath == null) {
continue;
}

if (path.equalsIgnoreCase(routePath)) {
if (routePath.contains(searchPath)) {
targets.addAll(Arrays.asList(getMethodsOnControllerShortcut(project, route.getController())));
continue;
}

if (placeholderMatcher == null) {
placeholderMatcher = Pattern.compile("\\{[\\w-]+}");
}
// String string = "|"; visibility debug
String string = Character.toString((char) 156);

String routePathPlaceholderNeutral = routePath.replaceAll("\\{([^}]*)}", string);
String match = null;
int startIndex = -1;

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

// /foo/{foo} => // \Q/foo/\E{foo}
StringBuilder quoteWrapped = new StringBuilder();
int lastRegMatch = 0;
while (matcher.find()) {
int start = matcher.start();
quoteWrapped.append(Pattern.quote(routePath.substring(lastRegMatch, start))).append("[\\w-]+");
lastRegMatch = matcher.end();
int i1 = routePathPlaceholderNeutral.indexOf(text);
if (i1 >= 0) {
match = routePathPlaceholderNeutral.substring(i1);
startIndex = text.length();
break;
}
}

String substring = routePath.substring(lastRegMatch);
if (!substring.isEmpty()) {
quoteWrapped.append(Pattern.quote(substring));
if (match == null) {
continue;
}

if (Pattern.matches(quoteWrapped.toString(), path)) {
targets.addAll(Arrays.asList(getMethodsOnControllerShortcut(project, route.getController())));
// find a pattern match: left to right
int endIndex = match.length();
for (int i = startIndex + 1; i <= endIndex; i++) {
String substring = match.substring(0, i);

String regex = substring.replace(string, "[\\w-]+");
Matcher matcher = Pattern.compile(regex).matcher(searchPath);
if (matcher.matches()) {
targets.addAll(Arrays.asList(getMethodsOnControllerShortcut(project, route.getController())));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,14 @@ public void testGetMethodsForPathWithPlaceholderMatch() {

PsiElement[] targets2 = RouteHelper.getMethodsForPathWithPlaceholderMatch(getProject(), "/foo_bar/foobar/edit/foo/foo/foo");
assertTrue(Arrays.stream(targets2).anyMatch(psiElement -> psiElement instanceof Method && "indexFooBarEditAction".equals(((Method) psiElement).getName())));

// /foobar/edit/{id}/foo/{foo}
PsiElement[] targets3 = RouteHelper.getMethodsForPathWithPlaceholderMatch(getProject(), "esolve/me/12/foo");
assertTrue(Arrays.stream(targets3).anyMatch(psiElement -> psiElement instanceof Method && "resolveMe".equals(((Method) psiElement).getName())));

PsiElement[] targets4 = RouteHelper.getMethodsForPathWithPlaceholderMatch(getProject(), "/edit/");
assertTrue(Arrays.stream(targets4).anyMatch(psiElement -> psiElement instanceof Method && "fooAction".equals(((Method) psiElement).getName())));
assertTrue(Arrays.stream(targets4).anyMatch(psiElement -> psiElement instanceof Method && "indexFooBarEditAction".equals(((Method) psiElement).getName())));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ public function indexAction()
public function fooAction()
{
}

/**
* @Route("/resolve/me/{id<\d>}/foobar/item", name="my_foo_resolve_me")
*/
public function resolveMe()
{
}
}

class InvokeController
Expand Down

0 comments on commit 12a4402

Please sign in to comment.