Skip to content

Commit 5bd3b78

Browse files
committed
support Symfony 3.3 class short in yaml and xml method tag scope
1 parent 766f148 commit 5bd3b78

File tree

9 files changed

+202
-76
lines changed

9 files changed

+202
-76
lines changed

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

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import fr.adrienbrault.idea.symfony2plugin.dic.ParameterResolverConsumer;
1313
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1414
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
15+
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
1516
import fr.adrienbrault.idea.symfony2plugin.util.yaml.visitor.ParameterVisitor;
1617
import org.apache.commons.lang.StringUtils;
1718
import org.jetbrains.annotations.NotNull;
@@ -461,7 +462,7 @@ public static Map<String, String> getFileParameterMap(XmlFile psiFile) {
461462
* @return raw class attribute value
462463
*/
463464
@Nullable
464-
public static String getServiceDefinitionClass(PsiElement psiInsideService) {
465+
public static String getServiceDefinitionClass(@NotNull PsiElement psiInsideService) {
465466

466467
// search for parent service definition
467468
XmlTag callXmlTag = PsiTreeUtil.getParentOfType(psiInsideService, XmlTag.class);
@@ -470,20 +471,35 @@ public static String getServiceDefinitionClass(PsiElement psiInsideService) {
470471
return null;
471472
}
472473

473-
XmlAttribute classAttribute = xmlTag.getAttribute("class");
474-
if(classAttribute == null) {
475-
return null;
474+
return getClassFromServiceDefinition(xmlTag);
475+
}
476+
477+
/**
478+
* Extract service class for class or id attribute on shortcut
479+
*
480+
* <service id="foo" class="Foobar"/> => Foobar
481+
* <service class="Foobar"/> => Foobar
482+
*/
483+
@Nullable
484+
private static String getClassFromServiceDefinition(@NotNull XmlTag xmlTag) {
485+
String classAttribute = xmlTag.getAttributeValue("class");
486+
if(StringUtils.isNotBlank(classAttribute)) {
487+
return classAttribute;
476488
}
477489

478-
String value = classAttribute.getValue();
479-
if(StringUtils.isNotBlank(value)) {
480-
return value;
490+
String id = xmlTag.getAttributeValue("id");
491+
if(id == null || StringUtils.isBlank(id) || !YamlHelper.isClassServiceId(id)) {
492+
return null;
481493
}
482494

483-
return null;
495+
return id;
484496
}
485497

486-
498+
/**
499+
* Get class factory method attribute
500+
*
501+
* <factory class="FooBar" method="cre<caret>ate"/>
502+
*/
487503
@Nullable
488504
public static PhpClass getPhpClassForClassFactory(@NotNull XmlAttributeValue xmlAttributeValue) {
489505
String method = xmlAttributeValue.getValue();

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

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -375,36 +375,35 @@ protected void addCompletions(@NotNull CompletionParameters parameters, Processi
375375
}
376376
}
377377

378+
/**
379+
* tags:
380+
* - { method: 'foobar' }
381+
*/
378382
private class ServiceCallsMethodTestCompletion extends CompletionProvider<CompletionParameters> {
379383

380384
protected void addCompletions(@NotNull CompletionParameters completionParameters, ProcessingContext processingContext, @NotNull CompletionResultSet completionResultSet) {
381-
382385
if(!Symfony2ProjectComponent.isEnabled(completionParameters.getPosition())) {
383386
return;
384387
}
385388

386389
PsiElement psiElement = completionParameters.getPosition();
387-
YAMLCompoundValue yamlCompoundValue = PsiTreeUtil.getParentOfType(psiElement, YAMLCompoundValue.class);
388-
if(yamlCompoundValue == null) {
389-
return;
390-
}
391-
392-
yamlCompoundValue = PsiTreeUtil.getParentOfType(yamlCompoundValue, YAMLCompoundValue.class);
393-
if(yamlCompoundValue == null) {
394-
return;
395-
}
396390

397-
addYamlClassMethods(yamlCompoundValue, completionResultSet, "class");
391+
String serviceDefinitionClassFromTagMethod = YamlHelper.getServiceDefinitionClassFromTagMethod(psiElement);
398392

393+
if(serviceDefinitionClassFromTagMethod != null) {
394+
PhpClass phpClass = ServiceUtil.getResolvedClassDefinition(psiElement.getProject(), serviceDefinitionClassFromTagMethod);
395+
if(phpClass != null) {
396+
PhpElementsUtil.addClassPublicMethodCompletion(completionResultSet, phpClass);
397+
}
398+
}
399399
}
400-
401400
}
402401

403402
private class ServiceClassMethodInsideScalarKeyCompletion extends CompletionProvider<CompletionParameters> {
404403

405404
private String yamlArrayKeyName;
406405

407-
public ServiceClassMethodInsideScalarKeyCompletion(String yamlArrayKeyName) {
406+
ServiceClassMethodInsideScalarKeyCompletion(String yamlArrayKeyName) {
408407
this.yamlArrayKeyName = yamlArrayKeyName;
409408
}
410409

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
import com.intellij.patterns.StandardPatterns;
88
import com.intellij.psi.PsiElement;
99
import com.intellij.psi.PsiFile;
10-
import com.intellij.psi.util.PsiTreeUtil;
11-
import com.intellij.util.Consumer;
1210
import com.jetbrains.php.lang.psi.elements.Method;
1311
import com.jetbrains.php.lang.psi.elements.PhpClass;
1412
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
@@ -23,7 +21,6 @@
2321
import org.apache.commons.lang.StringUtils;
2422
import org.jetbrains.annotations.NotNull;
2523
import org.jetbrains.annotations.Nullable;
26-
import org.jetbrains.yaml.psi.YAMLCompoundValue;
2724
import org.jetbrains.yaml.psi.YAMLKeyValue;
2825
import org.jetbrains.yaml.psi.YAMLScalar;
2926

@@ -214,12 +211,11 @@ private void getTagMethodGoto(PsiElement psiElement, List<PsiElement> results) {
214211
return;
215212
}
216213

217-
String classValue = YamlHelper.getServiceDefinitionClass(psiElement);
214+
String classValue = YamlHelper.getServiceDefinitionClassFromTagMethod(psiElement);
218215
if(classValue == null) {
219216
return;
220217
}
221218

222-
223219
PhpClass phpClass = ServiceUtil.getResolvedClassDefinition(psiElement.getProject(), classValue);
224220
if(phpClass == null) {
225221
return;
@@ -229,7 +225,6 @@ private void getTagMethodGoto(PsiElement psiElement, List<PsiElement> results) {
229225
if(method != null) {
230226
results.add(method);
231227
}
232-
233228
}
234229

235230
private void attachResourceBundleGoto(PsiElement psiElement, List<PsiElement> results) {

src/fr/adrienbrault/idea/symfony2plugin/config/yaml/inspection/EventMethodCallInspection.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
1313
import com.intellij.psi.util.PsiTreeUtil;
1414
import com.intellij.psi.xml.XmlFile;
15-
import com.intellij.util.Consumer;
1615
import com.jetbrains.php.lang.parser.PhpElementTypes;
1716
import com.jetbrains.php.lang.psi.PhpFile;
1817
import com.jetbrains.php.lang.psi.elements.Method;
@@ -116,7 +115,7 @@ private void visitYamlMethodTagKey(@NotNull final PsiElement psiElement, @NotNul
116115
return;
117116
}
118117

119-
String classValue = YamlHelper.getServiceDefinitionClass(psiElement);
118+
String classValue = YamlHelper.getServiceDefinitionClassFromTagMethod(psiElement);
120119
if(classValue == null) {
121120
return;
122121
}

src/fr/adrienbrault/idea/symfony2plugin/util/yaml/YamlHelper.java

Lines changed: 68 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -482,28 +482,36 @@ public static boolean isRoutingFile(PsiFile psiFile) {
482482
* - "@twig"
483483
* - '@twig'
484484
* tags:
485-
* - { name: routing.loader, method: "crossHint<cursor>" }
485+
* - { name: routing.loader, method: "crossHint<caret>" }
486486
*
487+
* ClassName\Foo:
488+
* tags:
489+
* - { method: "crossHint<caret>" }
487490
*/
488491
@Nullable
489-
public static String getServiceDefinitionClass(PsiElement psiElement) {
490-
491-
YAMLHashImpl yamlCompoundValue = PsiTreeUtil.getParentOfType(psiElement, YAMLHashImpl.class);
492-
if(yamlCompoundValue == null) {
493-
return null;
494-
}
495-
496-
YAMLMapping yamlMapping = PsiTreeUtil.getParentOfType(yamlCompoundValue, YAMLMapping.class);
497-
if(yamlMapping == null) {
498-
return null;
499-
}
500-
501-
YAMLKeyValue aClass = yamlMapping.getKeyValueByKey("class");
502-
if(aClass == null) {
503-
return null;
492+
public static String getServiceDefinitionClassFromTagMethod(@NotNull PsiElement psiElement) {
493+
PsiElement yamlScalar = psiElement.getParent();
494+
if(yamlScalar instanceof YAMLScalar) {
495+
PsiElement yamlKeyValue = yamlScalar.getParent();
496+
if(yamlKeyValue instanceof YAMLKeyValue) {
497+
// "{ method: '' }"
498+
PsiElement yamlMapping = ((YAMLKeyValue) yamlKeyValue).getParentMapping();
499+
if(yamlMapping != null) {
500+
PsiElement yamlSequenceItem = yamlMapping.getParent();
501+
if(yamlSequenceItem instanceof YAMLSequenceItem) {
502+
PsiElement yamlSequence = yamlSequenceItem.getParent();
503+
if(yamlSequence instanceof YAMLSequence) {
504+
PsiElement yamlKeyValueTags = yamlSequence.getParent();
505+
if(yamlKeyValueTags instanceof YAMLKeyValue) {
506+
return getClassFromServiceDefinition((YAMLKeyValue) yamlKeyValueTags);
507+
}
508+
}
509+
}
510+
}
511+
}
504512
}
505513

506-
return aClass.getValueText();
514+
return null;
507515
}
508516

509517
/**
@@ -991,6 +999,42 @@ public static void visitServiceCall(@NotNull YAMLScalar yamlScalar, @NotNull Con
991999
}
9921000
}
9931001

1002+
/**
1003+
* Get class from server definition; supports shortcut
1004+
*
1005+
* service.id:
1006+
* class: MyClass
1007+
*
1008+
* MyClass: ~
1009+
*/
1010+
private static String getClassFromServiceDefinition(@NotNull YAMLKeyValue yamlKeyValue) {
1011+
YAMLMapping parentMapping = yamlKeyValue.getParentMapping();
1012+
1013+
if(parentMapping != null) {
1014+
YAMLKeyValue classKeyValue = parentMapping.getKeyValueByKey("class");
1015+
if (classKeyValue != null) {
1016+
String valueText = classKeyValue.getValueText();
1017+
if (StringUtils.isNotBlank(valueText)) {
1018+
return valueText;
1019+
}
1020+
} else {
1021+
// named services; key is our class name
1022+
PsiElement yamlMapping = yamlKeyValue.getParent();
1023+
if(yamlMapping instanceof YAMLMapping) {
1024+
PsiElement parent = yamlMapping.getParent();
1025+
if(parent instanceof YAMLKeyValue) {
1026+
String keyText = ((YAMLKeyValue) parent).getKeyText();
1027+
if(StringUtils.isNotBlank(keyText) && !keyText.contains(".") && PhpNameUtil.isValidNamespaceFullName(keyText)) {
1028+
return keyText;
1029+
}
1030+
}
1031+
}
1032+
}
1033+
}
1034+
1035+
return null;
1036+
}
1037+
9941038
/**
9951039
* service_name:
9961040
* class: FOOBAR
@@ -1027,35 +1071,13 @@ public static void visitServiceCallArgument(@NotNull YAMLScalar yamlScalar, @Not
10271071
if(StringUtils.isNotBlank(methodName)) {
10281072
PsiElement callYamlKeyValue = callYamlSeq.getContext();
10291073
if(callYamlKeyValue instanceof YAMLKeyValue) {
1030-
YAMLMapping parentMapping = ((YAMLKeyValue) callYamlKeyValue).getParentMapping();
1031-
if(parentMapping != null) {
1032-
YAMLKeyValue classKeyValue = parentMapping.getKeyValueByKey("class");
1033-
if (classKeyValue != null) {
1034-
String valueText = classKeyValue.getValueText();
1035-
if (StringUtils.isNotBlank(valueText)) {
1036-
consumer.consume(new ParameterVisitor(
1037-
valueText,
1038-
methodName,
1039-
PsiElementUtils.getPrevSiblingsOfType(argumentSequenceItem, PlatformPatterns.psiElement(YAMLSequenceItem.class)).size())
1040-
);
1041-
}
1042-
} else {
1043-
// named services; key is our class name
1044-
PsiElement yamlMapping = callYamlKeyValue.getParent();
1045-
if(yamlMapping instanceof YAMLMapping) {
1046-
PsiElement parent = yamlMapping.getParent();
1047-
if(parent instanceof YAMLKeyValue) {
1048-
String keyText = ((YAMLKeyValue) parent).getKeyText();
1049-
if(!keyText.contains(".") && PhpNameUtil.isValidNamespaceFullName(keyText)) {
1050-
consumer.consume(new ParameterVisitor(
1051-
keyText,
1052-
methodName,
1053-
PsiElementUtils.getPrevSiblingsOfType(argumentSequenceItem, PlatformPatterns.psiElement(YAMLSequenceItem.class)).size())
1054-
);
1055-
}
1056-
}
1057-
}
1058-
}
1074+
String classFromServiceDefinition = getClassFromServiceDefinition((YAMLKeyValue) callYamlKeyValue);
1075+
if(classFromServiceDefinition != null) {
1076+
consumer.consume(new ParameterVisitor(
1077+
classFromServiceDefinition,
1078+
methodName,
1079+
PsiElementUtils.getPrevSiblingsOfType(argumentSequenceItem, PlatformPatterns.psiElement(YAMLSequenceItem.class)).size())
1080+
);
10591081
}
10601082
}
10611083
}

tests/fr/adrienbrault/idea/symfony2plugin/tests/config/xml/XmlHelperTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,27 @@ public void testVisitServiceCallArgumentParameter() {
7676
ContainerUtil.find(results, parameter -> "arg2".equals(parameter.getName()))
7777
);
7878
}
79+
80+
/**
81+
* @see XmlHelper#getServiceDefinitionClass
82+
*/
83+
public void testGetServiceDefinitionClass() {
84+
myFixture.configureByText(XmlFileType.INSTANCE, "" +
85+
"<service class=\"Foo\\Bar\">\n" +
86+
" <tag type=\"service\" method=\"ma<caret>iler\" />\n" +
87+
"</service>"
88+
);
89+
90+
PsiElement psiElement = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
91+
assertEquals("Foo\\Bar", XmlHelper.getServiceDefinitionClass(psiElement));
92+
93+
myFixture.configureByText(XmlFileType.INSTANCE, "" +
94+
"<service id=\"Foo\\Bar\">\n" +
95+
" <tag type=\"service\" method=\"ma<caret>iler\" />\n" +
96+
"</service>"
97+
);
98+
99+
psiElement = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
100+
assertEquals("Foo\\Bar", XmlHelper.getServiceDefinitionClass(psiElement));
101+
}
79102
}

tests/fr/adrienbrault/idea/symfony2plugin/tests/config/yaml/YamlCompletionContributorTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,33 @@ public void testThatMethodOfClassAreCompleted() {
233233
" - [ '<caret>' ]\n",
234234
"setBar"
235235
);
236+
237+
assertCompletionContains(YAMLFileType.YML, "" +
238+
"services:\n" +
239+
" Foo\\Bar:\n" +
240+
" calls:\n" +
241+
" - [ '<caret>' ]\n",
242+
"setBar"
243+
);
244+
}
245+
246+
public void testThatMethodOfEventTagsAreCompleted() {
247+
assertCompletionContains(YAMLFileType.YML, "" +
248+
"services:\n" +
249+
" foobar:\n" +
250+
" class: Foo\\Bar\n" +
251+
" tags:\n" +
252+
" - { method: <caret> }\n",
253+
"setBar"
254+
);
255+
256+
assertCompletionContains(YAMLFileType.YML, "" +
257+
"services:\n" +
258+
" Foo\\Bar:\n" +
259+
" tags:\n" +
260+
" - { method: <caret> }\n",
261+
"setBar"
262+
);
236263
}
237264

238265
public void testCompletionForServiceKeyAsClass() {

tests/fr/adrienbrault/idea/symfony2plugin/tests/config/yaml/YamlGoToKnownDeclarationHandlerTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,25 @@ public void testNavigateForCallsMethodIsProvided() {
9696
);
9797
}
9898

99+
public void testNavigateForCallsEventMethodIsProvided() {
100+
assertNavigationMatch("services.yml", "" +
101+
"services:\n" +
102+
" foobar:\n" +
103+
" class: Foo\\Bar\n" +
104+
" tags:\n" +
105+
" - { method: set<caret>Bar }\n" +
106+
PlatformPatterns.psiElement(PhpClass.class)
107+
);
108+
109+
assertNavigationMatch("services.yml", "" +
110+
"services:\n" +
111+
" Foo\\Bar:\n" +
112+
" tags:\n" +
113+
" - { method: set<caret>Bar }\n" +
114+
PlatformPatterns.psiElement(PhpClass.class)
115+
);
116+
}
117+
99118
public void testThatNavigationForControllerInvokeMethodIsAvailable() {
100119
myFixture.configureByText(PhpFileType.INSTANCE, "<?php\n" +
101120
"class Foobar\n" +

0 commit comments

Comments
 (0)