8000 Fix route reference not showing in controller that is in a sub namesp… · Koc/idea-php-symfony2-plugin@a47d144 · GitHub
[go: up one dir, main page]

Skip to content

Commit a47d144

Browse files
committed
Fix route reference not showing in controller that is in a sub namespace on slashes Haehnchen#763; refactor and provide test cases for route controller name resolving
1 parent a87802b commit a47d144

File tree

9 files changed

+202
-74
lines changed

9 files changed

+202
-74
lines changed

src/fr/adrienbrault/idea/symfony2plugin/navigation/controller/RouteControllerRelatedGotoCollector.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,10 @@ public class RouteControllerRelatedGotoCollector implements ControllerActionGoto
1414

1515
@Override
1616
public void collectGotoRelatedItems(ControllerActionGotoRelatedCollectorParameter parameter) {
17-
18-
// find routes
19-
List<Route> routes = RouteHelper.getRoutesOnControllerAction(parameter.getMethod());
20-
if(routes != null) {
21-
for(Route route: routes) {
22-
PsiElement routeTarget = RouteHelper.getRouteNameTarget(parameter.getProject(), route.getName());
23-
if(routeTarget != null) {
24-
parameter.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(routeTarget, route.getName()).withIcon(Symfony2Icons.ROUTE, Symfony2Icons.ROUTE_LINE_MARKER));
25-
}
17+
for(Route route: RouteHelper.getRoutesOnControllerAction(parameter.getMethod())) {
18+
PsiElement routeTarget = RouteHelper.getRouteNameTarget(parameter.getProject(), route.getName());
19+
if(routeTarget != null) {
20+
parameter.add(new RelatedPopupGotoLineMarker.PopupGotoRelatedItem(routeTarget, route.getName()).withIcon(Symfony2Icons.ROUTE, Symfony2Icons.ROUTE_LINE_MARKER));
2621
}
2722
}
2823
}

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

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import com.intellij.psi.xml.XmlAttribute;
2020
import com.intellij.psi.xml.XmlFile;
2121
import com.intellij.psi.xml.XmlTag;
22-
import com.intellij.util.Processor;
2322
import com.intellij.util.containers.ContainerUtil;
2423
import com.intellij.util.indexing.FileBasedIndex;
2524
import com.intellij.util.indexing.FileBasedIndexImpl;
@@ -60,6 +59,7 @@
6059

6160
import java.io.File;
6261
import java.util.*;
62+
import java.util.stream.Collectors;
6363

6464
public class RouteHelper {
6565

@@ -514,38 +514,27 @@ private static String convertLanguageRouteName(String routeName) {
514514
* Foo\Bar::methodAction
515515
*/
516516
@Nullable
517-
public static String convertMethodToRouteControllerName(@NotNull Method method) {
518-
517+
private static String convertMethodToRouteControllerName(@NotNull Method method) {
519518
PhpClass phpClass = method.getContainingClass();
520519
if(phpClass == null) {
521520
return null;
522521
}
523522

524-
String className = phpClass.getPresentableFQN();
525-
if(className == null) {
526-
return null;
527-
}
528-
529-
return (className.startsWith("\\") ? className.substring(1) : className) + "::" + method.getName();
530-
523+
return StringUtils.stripStart(phpClass.getFQN(), "\\") + "::" + method.getName();
531524
}
532525

533526
/**
534527
* FooBundle:Bar::method
528+
* FooBundle:Bar\\Foo::method
535529
*/
536530
@Nullable
537531
public static String convertMethodToRouteShortcutControllerName(@NotNull Method method) {
538-
539532
PhpClass phpClass = method.getContainingClass();
540533
if(phpClass == null) {
541534
return null;
542535
}
543536

544-
String className = phpClass.getPresentableFQN();
545-
if(className == null) {
546-
return null;
547-
}
548-
537+
String className = StringUtils.stripStart(phpClass.getFQN(), "\\");
549538
int bundlePos = className.lastIndexOf("Bundle\\");
550539
if(bundlePos == -1) {
551540
return null;
@@ -555,16 +544,20 @@ public static String convertMethodToRouteShortcutControllerName(@NotNull Method
555544
if(symfonyBundle == null) {
556545
return null;
557546
}
547+
558548
String name = method.getName();
559549
String methodName = name.substring(0, name.length() - "Action".length());
560550

561-
String relative = symfonyBundle.getRelative(phpClass.getContainingFile().getVirtualFile(), true);
562-
if(relative == null) {
551+
// try to to find relative class name
552+
String controllerClass = className.toLowerCase();
553+
String bundleClass = StringUtils.stripStart(symfonyBundle.getNamespaceName(), "\\").toLowerCase();
554+
if(!controllerClass.startsWith(bundleClass)) {
563555
return null;
564556
}
565557

566-
if(relative.startsWith("Controller/")) {
567-
relative = relative.substring("Controller/".length());
558+
String relative = StringUtils.stripStart(phpClass.getFQN(), "\\").substring(bundleClass.length());
559+
if(relative.startsWith("Controller\\")) {
560+
relative = relative.substring("Controller\\".length());
568561
}
569562

570563
if(relative.endsWith("Controller")) {
@@ -578,20 +571,14 @@ public static VirtualFile[] getRouteDefinitionInsideFile(Project project, String
578571

579572
final List<VirtualFile> virtualFiles = new ArrayList<>();
580573

581-
FileBasedIndexImpl.getInstance().getFilesWithKey(RoutesStubIndex.KEY, new HashSet<>(Arrays.asList(routeNames)), new Processor<VirtualFile>() {
582-
@Override
583-
public boolean process(VirtualFile virtualFile) {
584-
virtualFiles.add(virtualFile);
585-
return true;
586-
}
574+
FileBasedIndexImpl.getInstance().getFilesWithKey(RoutesStubIndex.KEY, new HashSet<>(Arrays.asList(routeNames)), virtualFile -> {
575+
virtualFiles.add(virtualFile);
576+
return true;
587577
}, GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.allScope(project), YAMLFileType.YML, XmlFileType.INSTANCE));
588578

589-
FileBasedIndexImpl.getInstance().getFilesWithKey(AnnotationRoutesStubIndex.KEY, new HashSet<>(Arrays.asList(routeNames)), new Processor<VirtualFile>() {
590-
@Override
591-
public boolean process(VirtualFile virtualFile) {
592-
virtualFiles.add(virtualFile);
593-
return true;
594-
}
579+
FileBasedIndexImpl.getInstance().getFilesWithKey(AnnotationRoutesStubIndex.KEY, new HashSet<>(Arrays.asList(routeNames)), virtualFile -> {
580+
virtualFiles.add(virtualFile);
581+
return true;
595582
}, GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.allScope(project), PhpFileType.INSTANCE));
596583

597584
return virtualFiles.toArray(new VirtualFile[virtualFiles.size()]);
@@ -641,7 +628,7 @@ public static Collection<StubIndexedRoute> getYamlRouteDefinitions(@NotNull YAML
641628

642629
String controller = getYamlController(yamlKeyValue);
643630
if(controller != null) {
644-
route.setController(controller);
631+
route.setController(normalizeRouteController(controller));
645632
}
646633

647634
indexedRoutes.add(route);
@@ -702,7 +689,7 @@ public static Collection<StubIndexedRoute> getXmlRouteDefinitions(XmlFile psiFil
702689
if(keyValue != null && "_controller".equals(keyValue)) {
703690
String actionName = subTag.getValue().getTrimmedText();
704691
if(StringUtils.isNotBlank(actionName)) {
705-
e.setController(actionName);
692+
e.setController(normalizeRouteController(actionName));
706693
}
707694
}
708695
}
@@ -779,39 +766,28 @@ public static boolean isServiceController(@NotNull String shortcutName) {
779766
return !shortcutName.contains("::") && shortcutName.contains(":") && !shortcutName.contains("\\") && shortcutName.split(":").length == 2;
780767
}
781768

782-
@Nullable
769+
@NotNull
783770
public static List<Route> getRoutesOnControllerAction(@NotNull Method method) {
784-
785771
Set<String> routeNames = new HashSet<>();
786772

787-
String methodRouteActionName = RouteHelper.convertMethodToRouteControllerName(method);
788-
if(methodRouteActionName != null) {
789-
routeNames.add(methodRouteActionName);
790-
}
791-
792-
String shortcutName = RouteHelper.convertMethodToRouteShortcutControllerName(method);
793-
if(shortcutName != null) {
794-
routeNames.add(shortcutName);
795-
}
773+
ContainerUtil.addIfNotNull(routeNames, RouteHelper.convertMethodToRouteControllerName(method));
774+
ContainerUtil.addIfNotNull(routeNames, RouteHelper.convertMethodToRouteShortcutControllerName(method));
796775

797776
Map<String, Route> allRoutes = getAllRoutes(method.getProject());
798777
List<Route> routes = new ArrayList<>();
799778

800779
// resolve indexed routes
801780
if(routeNames.size() > 0) {
802-
for(Map.Entry<String, Route> routeEntry: allRoutes.entrySet()) {
803-
String controller = routeEntry.getValue().getController();
804-
if(controller != null && routeNames.contains(controller)) {
805-
routes.add(routeEntry.getValue());
806-
}
807-
}
781+
routes.addAll(allRoutes.values().stream()
782+
.filter(route -> route.getController() != null && routeNames.contains(route.getController()))
783+
.collect(Collectors.toList())
784+
);
808785
}
809786

810787
// search for services
811-
Collection<Route> methodMatch = ServiceRouteContainer.build(allRoutes).getMethodMatches(method);
812-
if(methodMatch.size() > 0) {
813-
routes.addAll(methodMatch);
814-
}
788+
routes.addAll(
789+
ServiceRouteContainer.build(allRoutes).getMethodMatches(method)
790+
);
815791

816792
return routes;
817793
}
@@ -1010,4 +986,8 @@ private static Map<String, Route> getAllRoutesProxy(@NotNull Project project) {
1010986
return routes;
1011987
}
1012988

1013-
}
989+
@NotNull
990+
private static String normalizeRouteController(@NotNull String string) {
991+
return string.replace("/", "\\");
992+
}
993+
}

src/fr/adrienbrault/idea/symfony2plugin/routing/dic/ServiceRouteContainer.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import fr.adrienbrault.idea.symfony2plugin.routing.RouteHelper;
88
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
99
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
10+
import org.apache.commons.lang.StringUtils;
1011
import org.jetbrains.annotations.NotNull;
1112

1213
import java.util.*;
@@ -47,20 +48,15 @@ public Set<String> getServiceNames() {
4748
}
4849

4950
@NotNull
50-
public Collection<Route> getMethodMatches(Method method) {
51-
51+
public Collection<Route> getMethodMatches(@NotNull Method method) {
5252
PhpClass originClass = method.getContainingClass();
5353
if(originClass == null) {
5454
return Collections.emptyList();
5555
}
5656

57-
String classFqn = originClass.getPresentableFQN();
58-
if(classFqn == null) {
59-
return Collections.emptyList();
60-
}
57+
String classFqn = StringUtils.stripStart(originClass.getFQN(), "\\");
6158

6259
Collection<Route> routes = new ArrayList<>();
63-
6460
for (Route route : this.routes) {
6561

6662
String serviceRoute = route.getController();

src/fr/adrienbrault/idea/symfony2plugin/util/dict/SymfonyBundle.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,29 @@
88
import com.intellij.psi.search.GlobalSearchScopes;
99
import com.jetbrains.php.lang.psi.elements.PhpClass;
1010
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
11+
import org.jetbrains.annotations.NotNull;
1112
import org.jetbrains.annotations.Nullable;
1213

1314
public class SymfonyBundle {
1415

15-
protected PhpClass phpClass;
16+
@NotNull
17+
final private PhpClass phpClass;
1618

17-
public SymfonyBundle(PhpClass phpClass) {
19+
public SymfonyBundle(@NotNull PhpClass phpClass) {
1820
this.phpClass = phpClass;
1921
}
2022

23+
@NotNull
2124
public PhpClass getPhpClass() {
2225
return this.phpClass;
2326
}
2427

28+
@NotNull
2529
public String getNamespaceName() {
2630
return this.phpClass.getNamespaceName();
2731
}
2832

33+
@NotNull
2934
public String getName() {
3035
return this.phpClass.getName();
3136
}

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

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@
77
import com.intellij.psi.PsiFileFactory;
88
import com.intellij.psi.xml.XmlFile;
99
import com.intellij.util.containers.ContainerUtil;
10+
import com.jetbrains.php.lang.psi.PhpPsiElementFactory;
11+
import com.jetbrains.php.lang.psi.elements.Method;
12+
import com.jetbrains.php.lang.psi.elements.PhpClass;
1013
import fr.adrienbrault.idea.symfony2plugin.routing.Route;
1114
import fr.adrienbrault.idea.symfony2plugin.routing.RouteHelper;
1215
import fr.adrienbrault.idea.symfony2plugin.stubs.dict.StubIndexedRoute;
1316
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
17+
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1418
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlPsiElementFactory;
1519
import org.jetbrains.annotations.NotNull;
1620
import org.jetbrains.yaml.psi.YAMLDocument;
@@ -228,6 +232,87 @@ public void testGetRoutesInsideUrlGeneratorFile() {
228232
assertNull(routes.get("_assetic_91dd2a8"));
229233
}
230234

235+
/**
236+
* @see fr.adrienbrault.idea.symfony2plugin.routing.RouteHelper#convertMethodToRouteShortcutControllerName
237+
*/
238+
public void testConvertMethodToRouteShortcutControllerName() {
239+
myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject("GetRoutesOnControllerAction.php"));
240+
241+
PhpClass phpClass = PhpPsiElementFactory.createPhpPsiFromText(getProject(), PhpClass.class, "<?php\n" +
242+
"namespace FooBar\\FooBundle\\Controller" +
243+
"{\n" +
244+
" class FooBarController\n" +
245+
" {\n" +
246+
" function fooAction() {}\n" +
247+
" }\n" +
248+
"}"
249+
);
250+
251+
Method fooAction = phpClass.findMethodByName("fooAction");
252+
assertNotNull(fooAction);
253+
254+
assertEquals("FooBarFooBundle:FooBar:foo", RouteHelper.convertMethodToRouteShortcutControllerName(fooAction));
255+
256+
phpClass = PhpPsiElementFactory.createPhpPsiFromText(getProject(), PhpClass.class, "<?php\n" +
257+
"namespace FooBar\\FooBundle\\Controller\\SubFolder" +
258+
"{\n" +
259+
" class SubController\n" +
260+
" {\n" +
261+
" function fooAction() {}\n" +
262+
" }\n" +
263+
"}"
264+
);
265+
266+
fooAction = phpClass.findMethodByName("fooAction");
267+
assertNotNull(fooAction);
268+
269+
assertEquals("FooBarFooBundle:SubFolder\\Sub:foo", RouteHelper.convertMethodToRouteShortcutControllerName(fooAction));
270+
}
271+
272+
/**
273+
* @see fr.adrienbrault.idea.symfony2plugin.routing.RouteHelper#getRoutesOnControllerAction
274+
*/
275+
public void testGetRoutesOnControllerAction() {
276+
myFixture.copyFileToProject("GetRoutesOnControllerAction.php");
277+
myFixture.copyFileToProject("GetRoutesOnControllerAction.routing.xml");
278+
myFixture.copyFileToProject("GetRoutesOnControllerAction.services.xml");
279+
280+
PhpClass phpClass = PhpPsiElementFactory.createPhpPsiFromText(getProject(), PhpClass.class, "<?php\n" +
281+
"namespace FooBar\\FooBundle\\Controller\\SubFolder" +
282+
"{\n" +
283+
" class FooBarController\n" +
284+
" {\n" +
285+
" function fooAction() {}\n" +
286+
" }\n" +
287+
"}"
288+
);
289+
290+
Method fooAction = phpClass.findMethodByName("fooAction");
291+
assertNotNull(fooAction);
292+
293+
List<Route> routesOnControllerAction = RouteHelper.getRoutesOnControllerAction(fooAction);
294+
295+
assertNotNull(ContainerUtil.find(routesOnControllerAction, route ->
296+
"xml_route_subfolder_backslash".equals(route.getName())
297+
));
298+
299+
assertNotNull(ContainerUtil.find(routesOnControllerAction, route ->
300+
"xml_route_subfolder_slash".equals(route.getName())
301+
));
302+
303+
assertNotNull(ContainerUtil.find(routesOnControllerAction, route ->
304+
"xml_route_subfolder_class_syntax".equals(route.getName())
305+
));
306+
307+
// controller as service
308+
Method indexAction = PhpElementsUtil.getClassMethod(getProject(), "Service\\Controller\\FooController", "indexAction");
309+
assertNotNull(indexAction);
310+
311+
assertNotNull(ContainerUtil.find(RouteHelper.getRoutesOnControllerAction(indexAction), route ->
312+
"xml_route_as_service".equals(route.getName())
313+
));
314+
}
315+
231316
/**
232317
* @see fr.adrienbrault.idea.symfony2plugin.routing.RouteHelper#getRoutesInsideUrlGeneratorFile
233318
*/
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
4+
namespace Symfony\Component\HttpKernel\Bundle
5+
{
6+
class Bundle{}
7+
}
8+
9+
namespace FooBar\FooBundle
10+
{
11+
use Symfony\Component\HttpKernel\Bundle\Bundle;
12+
13+
class FooBarFooBundle extends Bundle{}
14+
}
15+
16+
namespace Service\Controller
17+
{
18+
class FooController
19+
{
20+
public function indexAction() {}
21+
}
22+
}

0 commit comments

Comments
 (0)
0