Skip to content

Commit bd703f6

Browse files
committed
[Symfony 3.4] Add support for "controller" keyword for configuring routes controllers #1023
1 parent 9df9e24 commit bd703f6

17 files changed

+297
-89
lines changed

src/fr/adrienbrault/idea/symfony2plugin/config/xml/XmlHelper.java

+27
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,33 @@ public static PsiElementPattern.Capture<XmlTag> getInsideTagPattern(String... in
324324
return XmlPatterns.psiElement(XmlTag.class).withName(XmlPatterns.string().oneOf(insideTagName));
325325
}
326326

327+
/**
328+
* <route id="foo" controller="Foo:Demo:hello"/>
329+
*
330+
* <route id="foo" path="/blog/{slug}">
331+
* <default key="_controller">Foo:Demo:hello</default>
332+
* </route>
333+
*/
334+
public static ElementPattern<PsiElement> getRouteControllerPattern() {
335+
return PlatformPatterns.or(getRouteControllerKeywordPattern(), getRouteDefaultWithKeyAttributePattern("_controller"));
336+
}
337+
338+
/**
339+
* <route id="foo" controller="Foo:Demo:hello"/>
340+
*/
341+
private static XmlAttributeValuePattern getRouteControllerKeywordPattern() {
342+
return XmlPatterns
343+
.xmlAttributeValue()
344+
.withParent(XmlPatterns
345+
.xmlAttribute("controller")
346+
.withParent(XmlPatterns
347+
.xmlTag().withName("route")
348+
)
349+
).inside(
350+
XmlHelper.getInsideTagPattern("route")
351+
).inFile(XmlHelper.getXmlFilePattern());
352+
}
353+
327354
/**
328355
* <route id="foo" path="/blog/{slug}">
329356
* <default key="_controller">Foo:Demo:hello</default>

src/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlCompletionContributor.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ public void addCompletions(@NotNull CompletionParameters parameters,
188188
extend(CompletionType.BASIC, YamlElementPatternHelper.getSingleLineScalarKey("mappedBy", "inversedBy"), new OrmRelationCompletionProvider());
189189
extend(CompletionType.BASIC, YamlElementPatternHelper.getOrmSingleLineScalarKey("referencedColumnName"), new ReferencedColumnCompletionProvider());
190190

191-
extend(CompletionType.BASIC, YamlElementPatternHelper.getSingleLineScalarKey("_controller"), new ControllerCompletionProvider());
191+
extend(CompletionType.BASIC, YamlElementPatternHelper.getSingleLineScalarKey("_controller", "controller"), new ControllerCompletionProvider());
192+
192193
extend(CompletionType.BASIC, YamlElementPatternHelper.getSingleLineScalarKey("resource"), new SymfonyBundleFileCompletionProvider("Resources/config", "Controller"));
193194
extend(CompletionType.BASIC, YamlElementPatternHelper.getSingleLineScalarKey("resource"), new DirectoryScopeCompletionProvider());
194195

src/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlGoToKnownDeclarationHandler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int i, Edit
4444

4545
List<PsiElement> results = new ArrayList<>();
4646

47-
if(YamlElementPatternHelper.getSingleLineScalarKey("_controller").accepts(psiElement)) {
47+
if(YamlElementPatternHelper.getSingleLineScalarKey("_controller", "controller").accepts(psiElement)) {
4848
this.getControllerGoto(psiElement, results);
4949
}
5050

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

+54-27
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,6 @@ public static Collection<StubIndexedRoute> getYamlRouteDefinitions(@NotNull YAML
641641
}
642642

643643
indexedRoutes.add(route);
644-
645-
646644
}
647645

648646
return indexedRoutes;
@@ -658,11 +656,13 @@ public static Collection<StubIndexedRoute> getXmlRouteDefinitions(XmlFile psiFil
658656

659657
Collection<StubIndexedRoute> indexedRoutes = new ArrayList<>();
660658

661-
/**
659+
/*
662660
* <routes>
663661
* <route id="foo" path="/blog/{slug}" methods="GET">
664662
* <default key="_controller">Foo</default>
665663
* </route>
664+
*
665+
* <route id="foo" path="/blog/{slug}" methods="GET" controller="AppBundle:Blog:list"/>
666666
* </routes>
667667
*/
668668
for(XmlTag xmlTag: PsiTreeUtil.getChildrenOfTypeAsList(psiFile.getFirstChild(), XmlTag.class)) {
@@ -672,40 +672,34 @@ public static Collection<StubIndexedRoute> getXmlRouteDefinitions(XmlFile psiFil
672672
XmlAttribute xmlAttribute = servicesTag.getAttribute("id");
673673
if(xmlAttribute != null) {
674674
String attrValue = xmlAttribute.getValue();
675-
if(StringUtils.isNotBlank(attrValue)) {
675+
if(attrValue != null && StringUtils.isNotBlank(attrValue)) {
676676

677-
StubIndexedRoute e = new StubIndexedRoute(attrValue);
677+
StubIndexedRoute route = new StubIndexedRoute(attrValue);
678678
String pathAttribute = servicesTag.getAttributeValue("path");
679679
if(pathAttribute == null) {
680680
pathAttribute = servicesTag.getAttributeValue("pattern");
681681
}
682682

683683
if(pathAttribute != null && StringUtils.isNotBlank(pathAttribute) ) {
684-
e.setPath(pathAttribute);
684+
route.setPath(pathAttribute);
685685
}
686686

687687
String methods = servicesTag.getAttributeValue("methods");
688688
if(methods != null && StringUtils.isNotBlank(methods)) {
689689
String[] split = methods.replaceAll(" +", "").toLowerCase().split("\\|");
690690
if(split.length > 0) {
691-
e.addMethod(split);
691+
route.addMethod(split);
692692
}
693693
}
694694

695-
for(XmlTag subTag :servicesTag.getSubTags()) {
696-
if("default".equalsIgnoreCase(subTag.getName())) {
697-
String keyValue = subTag.getAttributeValue("key");
698-
if(keyValue != null && "_controller".equals(keyValue)) {
699-
String actionName = subTag.getValue().getTrimmedText();
700-
if(StringUtils.isNotBlank(actionName)) {
701-
e.setController(normalizeRouteController(actionName));
702-
}
703-
}
704-
}
695+
// <route><default key="_controller"/></route>
696+
// <route controller="AppBundle:Blog:list"/>
697+
String controller = getXmlController(servicesTag);
698+
if(controller != null) {
699+
route.setController(normalizeRouteController(controller));
705700
}
706701

707-
indexedRoutes.add(e);
708-
702+
indexedRoutes.add(route);
709703
}
710704
}
711705
}
@@ -716,20 +710,49 @@ public static Collection<StubIndexedRoute> getXmlRouteDefinitions(XmlFile psiFil
716710
return indexedRoutes;
717711
}
718712

713+
/**
714+
* <route controller="Foo"/>
715+
* <route>
716+
* <default key="_controller">Foo</default>
717+
* </route>
718+
*/
719719
@Nullable
720-
private static String getYamlController(YAMLKeyValue psiElement) {
721-
/*
722-
* foo:
723-
* defaults: { _controller: "Bundle:Foo:Bar" }
724-
* defaults:
725-
* _controller: "Bundle:Foo:Bar"
726-
*/
720+
public static String getXmlController(@NotNull XmlTag serviceTag) {
721+
for(XmlTag subTag :serviceTag.getSubTags()) {
722+
if("default".equalsIgnoreCase(subTag.getName())) {
723+
String keyValue = subTag.getAttributeValue("key");
724+
if(keyValue != null && "_controller".equals(keyValue)) {
725+
String actionName = subTag.getValue().getTrimmedText();
726+
if(StringUtils.isNotBlank(actionName)) {
727+
return actionName;
728+
}
729+
}
730+
}
731+
}
732+
733+
String controller = serviceTag.getAttributeValue("controller");
734+
if(controller != null && StringUtils.isNotBlank(controller)) {
735+
return controller;
736+
}
737+
738+
return null;
739+
}
727740

741+
/**
742+
* Find controller definition in yaml structure
743+
*
744+
* foo:
745+
* defaults: { _controller: "Bundle:Foo:Bar" }
746+
* defaults:
747+
* _controller: "Bundle:Foo:Bar"
748+
* controller: "Bundle:Foo:Bar"
749+
*/
750+
@Nullable
751+
public static String getYamlController(@NotNull YAMLKeyValue psiElement) {
728752
YAMLKeyValue yamlKeyValue = YamlHelper.getYamlKeyValue(psiElement, "defaults");
729753
if(yamlKeyValue != null) {
730754
final YAMLValue container = yamlKeyValue.getValue();
731755
if(container instanceof YAMLMapping) {
732-
733756
YAMLKeyValue yamlKeyValueController = YamlHelper.getYamlKeyValue(container, "_controller", true);
734757
if(yamlKeyValueController != null) {
735758
String valueText = yamlKeyValueController.getValueText();
@@ -738,7 +761,11 @@ private static String getYamlController(YAMLKeyValue psiElement) {
738761
}
739762
}
740763
}
764+
}
741765

766+
String controller = YamlHelper.getYamlKeyValueAsString(psiElement, "controller");
767+
if(controller != null && StringUtils.isNotBlank(controller)) {
768+
return controller;
742769
}
743770

744771
return null;
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,66 @@
11
package fr.adrienbrault.idea.symfony2plugin.routing;
22

33
import com.intellij.psi.*;
4+
import com.intellij.psi.xml.XmlAttribute;
5+
import com.intellij.psi.xml.XmlText;
46
import com.intellij.util.ProcessingContext;
57
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
68
import fr.adrienbrault.idea.symfony2plugin.config.xml.XmlHelper;
79
import fr.adrienbrault.idea.symfony2plugin.util.controller.ControllerIndex;
10+
import org.apache.commons.lang.StringUtils;
811
import org.jetbrains.annotations.NotNull;
912

1013
/**
1114
* @author Daniel Espendiller <daniel@espendiller.net>
1215
*/
1316
public class RouteXmlReferenceContributor extends PsiReferenceContributor {
14-
1517
@Override
16-
public void registerReferenceProviders(PsiReferenceRegistrar registrar) {
17-
18+
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
1819
registrar.registerReferenceProvider(
19-
XmlHelper.getRouteDefaultWithKeyAttributePattern("_controller"),
20+
XmlHelper.getRouteControllerPattern(),
2021
new PsiReferenceProvider() {
2122
@NotNull
2223
@Override
2324
public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) {
24-
2525
if(!Symfony2ProjectComponent.isEnabled(psiElement)) {
2626
return new PsiReference[0];
2727
}
2828

2929
return new PsiReference[] {
3030
new RouteActionReference(psiElement)
3131
};
32-
3332
}
3433
}
3534
);
3635

3736
}
3837

3938
private static class RouteActionReference extends PsiPolyVariantReferenceBase<PsiElement> {
40-
41-
public RouteActionReference(PsiElement psiElement) {
39+
private RouteActionReference(PsiElement psiElement) {
4240
super(psiElement);
4341
}
4442

4543
@NotNull
4644
@Override
4745
public ResolveResult[] multiResolve(boolean b) {
46+
PsiElement element = getElement();
47+
PsiElement parent = element.getParent();
48+
49+
String text = null;
50+
if(parent instanceof XmlText) {
51+
// <route><default key="_controller">Fo<caret>o\Bar</default></route>
52+
text = parent.getText();
53+
} else if(parent instanceof XmlAttribute) {
54+
// <route controller=""/>
55+
text = ((XmlAttribute) parent).getValue();
56+
}
57+
58+
if(text == null || StringUtils.isBlank(text)) {
59+
return new ResolveResult[0];
60+
}
61+
4862
return PsiElementResolveResult.createResults(
49-
RouteHelper.getMethodsOnControllerShortcut(getElement().getProject(), getElement().getText())
63+
RouteHelper.getMethodsOnControllerShortcut(getElement().getProject(), text)
5064
);
5165
}
5266

@@ -56,5 +70,4 @@ public Object[] getVariants() {
5670
return ControllerIndex.getControllerLookupElements(getElement().getProject()).toArray();
5771
}
5872
}
59-
6073
}

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

+9-18
Original file line numberDiff line numberDiff line change
@@ -47,31 +47,22 @@ public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNu
4747

4848
}
4949

50-
private void attachRouteActions(XmlTag xmlTag, @NotNull Collection<LineMarkerInfo> lineMarkerInfos) {
51-
50+
private void attachRouteActions(@NotNull XmlTag xmlTag, @NotNull Collection<LineMarkerInfo> lineMarkerInfos) {
5251
if(!Pattern.getRouteTag().accepts(xmlTag)) {
5352
return;
5453
}
5554

56-
for(XmlTag subTag : xmlTag.getSubTags()) {
57-
if("default".equalsIgnoreCase(subTag.getName())) {
58-
XmlAttribute xmlAttr = subTag.getAttribute("key");
59-
if(xmlAttr != null && "_controller".equals(xmlAttr.getValue())) {
60-
String actionName = subTag.getValue().getTrimmedText();
61-
if(StringUtils.isNotBlank(actionName)) {
62-
PsiElement[] methods = RouteHelper.getMethodsOnControllerShortcut(xmlTag.getProject(), actionName);
63-
if(methods.length > 0) {
64-
NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder.create(Symfony2Icons.TWIG_CONTROLLER_LINE_MARKER).
65-
setTargets(methods).
66-
setTooltipText("Navigate to action");
55+
String controller = RouteHelper.getXmlController(xmlTag);
56+
if(controller != null) {
57+
PsiElement[] methods = RouteHelper.getMethodsOnControllerShortcut(xmlTag.getProject(), controller);
58+
if(methods.length > 0) {
59+
NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder.create(Symfony2Icons.TWIG_CONTROLLER_LINE_MARKER).
60+
setTargets(methods).
61+
setTooltipText("Navigate to action");
6762

68-
lineMarkerInfos.add(builder.createLineMarkerInfo(xmlTag));
69-
}
70-
}
71-
}
63+
lineMarkerInfos.add(builder.createLineMarkerInfo(xmlTag));
7264
}
7365
}
74-
7566
}
7667

7768
@Nullable

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

+17-28
Original file line numberDiff line numberDiff line change
@@ -77,37 +77,26 @@ private void attachEntityClass(Collection<LineMarkerInfo> lineMarkerInfos, PsiEl
7777
}
7878
}
7979

80+
/**
81+
* Find controller definition in yaml structor
82+
*
83+
* foo:
84+
* defaults: { _controller: "Bundle:Foo:Bar" }
85+
* controller: "Bundle:Foo:Bar"
86+
*/
8087
private void attachRouteActions(Collection<LineMarkerInfo> lineMarkerInfos, PsiElement psiElement) {
81-
82-
/*
83-
* foo:
84-
* defaults: { _controller: "Bundle:Foo:Bar" }
85-
* defaults:
86-
* _controller: "Bundle:Foo:Bar"
87-
*/
88-
if(psiElement instanceof YAMLKeyValue && psiElement.getParent() instanceof YAMLMapping) {
89-
YAMLKeyValue yamlKeyValue = YamlHelper.getYamlKeyValue((YAMLKeyValue) psiElement, "defaults");
90-
if(yamlKeyValue != null) {
91-
final YAMLValue container = yamlKeyValue.getValue();
92-
if(container instanceof YAMLMapping) {
93-
94-
YAMLKeyValue yamlKeyValueController = YamlHelper.getYamlKeyValue(container, "_controller", true);
95-
if(yamlKeyValueController != null) {
96-
PsiElement[] methods = RouteHelper.getMethodsOnControllerShortcut(psiElement.getProject(), yamlKeyValueController.getValueText());
97-
if(methods.length > 0) {
98-
NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder.create(Symfony2Icons.TWIG_CONTROLLER_LINE_MARKER).
99-
setTargets(methods).
100-
setTooltipText("Navigate to action");
101-
102-
lineMarkerInfos.add(builder.createLineMarkerInfo(psiElement));
103-
}
104-
105-
}
106-
88+
if(psiElement instanceof YAMLKeyValue) {
89+
String yamlController = RouteHelper.getYamlController((YAMLKeyValue) psiElement);
90+
if(yamlController != null) {
91+
PsiElement[] methods = RouteHelper.getMethodsOnControllerShortcut(psiElement.getProject(), yamlController);
92+
if(methods.length > 0) {
93+
NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder.create(Symfony2Icons.TWIG_CONTROLLER_LINE_MARKER).
94+
setTargets(methods).
95+
setTooltipText("Navigate to action");
96+
97+
lineMarkerInfos.add(builder.createLineMarkerInfo(psiElement));
10798
}
108-
10999
}
110-
111100
}
112101
}
113102

src/fr/adrienbrault/idea/symfony2plugin/routing/inspection/ControllerMethodInspection.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private void visitYaml(final ProblemsHolder holder, PsiFile psiFile) {
5454
psiFile.acceptChildren(new PsiRecursiveElementWalkingVisitor() {
5555
@Override
5656
public void visitElement(PsiElement element) {
57-
if(YamlElementPatternHelper.getSingleLineScalarKey("_controller").accepts(element)) {
57+
if(YamlElementPatternHelper.getSingleLineScalarKey("_controller", "controller").accepts(element)) {
5858
String text = PsiElementUtils.trimQuote(element.getText());
5959
if(StringUtils.isNotBlank(text)) {
6060
InspectionUtil.inspectController(element, text, holder, new YamlLazyRouteName(element));
@@ -70,7 +70,7 @@ private void visitXml(final ProblemsHolder holder, PsiFile psiFile) {
7070
psiFile.acceptChildren(new PsiRecursiveElementWalkingVisitor() {
7171
@Override
7272
public void visitElement(PsiElement element) {
73-
if(XmlHelper.getRouteDefaultWithKeyAttributePattern("_controller").accepts(element)) {
73+
if(XmlHelper.getRouteControllerPattern().accepts(element)) {
7474
String text = PsiElementUtils.trimQuote(element.getText());
7575
if(StringUtils.isNotBlank(text)) {
7676
InspectionUtil.inspectController(element, text, holder, new XmlLazyRouteName(element));

0 commit comments

Comments
 (0)