Skip to content

Commit 3633612

Browse files
authored
Merge pull request #1446 from Haehnchen/feature/named-arguments-controller
take "controller.service_arguments" for yaml named arguments of controller binding into account
2 parents 209549a + 4c92f56 commit 3633612

File tree

8 files changed

+121
-22
lines changed

8 files changed

+121
-22
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/codeInspection/service/TaggedExtendsInterfaceClassInspection.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,20 +115,16 @@ public void visitElement(PsiElement element) {
115115
PsiElement serviceKeyValue = yamlCompoundValue.getParent();
116116
if(serviceKeyValue instanceof YAMLKeyValue) {
117117
Set<String> tags = YamlHelper.collectServiceTags((YAMLKeyValue) serviceKeyValue);
118-
if(tags != null && tags.size() > 0) {
118+
if(tags.size() > 0) {
119119
registerTaggedProblems(element, tags, text, holder, this.lazyServiceCollector);
120120
}
121121
}
122-
123122
}
124123
}
125-
126124
}
127125

128-
129126
super.visitElement(element);
130127
}
131-
132128
}
133129

134130
private void registerTaggedProblems(@NotNull PsiElement source, @NotNull Set<String> tags, @NotNull String serviceClass, @NotNull ProblemsHolder holder, @NotNull ContainerCollectionResolver.LazyServiceCollector lazyServiceCollector) {

src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/container/util/ServiceContainerUtil.java

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.jetbrains.php.lang.psi.elements.Parameter;
2020
import com.jetbrains.php.lang.psi.elements.PhpClass;
2121
import fr.adrienbrault.idea.symfony2plugin.config.xml.XmlHelper;
22+
import fr.adrienbrault.idea.symfony2plugin.config.yaml.YamlElementPatternHelper;
2223
import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.AttributeValueInterface;
2324
import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.XmlTagAttributeValue;
2425
import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.YamlKeyValueAttributeValue;
@@ -29,10 +30,7 @@
2930
import fr.adrienbrault.idea.symfony2plugin.dic.container.visitor.ServiceConsumer;
3031
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
3132
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.ContainerIdUsagesStubIndex;
32-
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
33-
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
34-
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
35-
import fr.adrienbrault.idea.symfony2plugin.util.TimeSecondModificationTracker;
33+
import fr.adrienbrault.idea.symfony2plugin.util.*;
3634
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
3735
import fr.adrienbrault.idea.symfony2plugin.util.psi.PsiElementAssertUtil;
3836
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
@@ -43,6 +41,7 @@
4341
import org.jetbrains.yaml.psi.*;
4442

4543
import java.util.*;
44+
import java.util.function.Predicate;
4645
import java.util.stream.Collectors;
4746
import java.util.stream.Stream;
4847

@@ -421,18 +420,46 @@ public static Parameter getYamlNamedArgument(@NotNull PsiElement psiElement, @No
421420
*/
422421
public static void visitNamedArguments(@NotNull PsiFile psiFile, @NotNull Consumer<Parameter> processor) {
423422
if (psiFile instanceof YAMLFile) {
423+
Collection<Parameter> parameters = new HashSet<>();
424+
425+
// direct service definition
424426
for (PhpClass phpClass : YamlHelper.getPhpClassesInYamlFile((YAMLFile) psiFile, new ContainerCollectionResolver.LazyServiceCollector(psiFile.getProject()))) {
425427
Method constructor = phpClass.getConstructor();
426428
if (constructor == null) {
427429
continue;
428430
}
429431

430-
Arrays.stream(constructor.getParameters()).forEach(processor::consume);
432+
parameters.addAll(Arrays.asList(constructor.getParameters()));
431433
}
434+
435+
for (YAMLKeyValue taggedService : YamlHelper.getTaggedServices((YAMLFile) psiFile, "controller.service_arguments")) {
436+
PsiElement key = taggedService.getKey();
437+
if (key == null) {
438+
continue;
439+
}
440+
441+
String keyText = key.getText();
442+
if (StringUtils.isBlank(keyText)) {
443+
continue;
444+
}
445+
446+
// App\Controller\ => \App\Controller
447+
String namespace = StringUtils.strip(keyText, "\\");
448+
for (PhpClass phpClass : PhpIndexUtil.getPhpClassInsideNamespace(psiFile.getProject(), "\\" + namespace)) {
449+
// find all parameters on public methods; this are possible actions
450+
451+
// maybe filter actions and public methods in a suitable way?
452+
phpClass.getMethods().stream()
453+
.filter(method -> method.getAccess().isPublic() && !method.getName().startsWith("set"))
454+
.forEach(method -> Collections.addAll(parameters, method.getParameters()));
455+
}
456+
}
457+
458+
parameters.forEach(processor::consume);
432459
}
433460
}
434461

435-
/**
462+
/*
436463
* Symfony 3.3: "class" is optional; use service name for its it
437464
*
438465
* Foo\Bar:

src/main/java/fr/adrienbrault/idea/symfony2plugin/form/util/FormUtil.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,21 +222,20 @@ public static void attachFormAliasesCompletions(@NotNull PhpClass phpClass, @Not
222222
*/
223223
@NotNull
224224
public static Map<String, Set<String>> getTags(@NotNull YAMLFile yamlFile) {
225-
226225
Map<String, Set<String>> map = new HashMap<>();
226+
227227
for(YAMLKeyValue yamlServiceKeyValue : YamlHelper.getQualifiedKeyValuesInFile(yamlFile, "services")) {
228228
String serviceName = yamlServiceKeyValue.getName();
229229
Set<String> serviceTagMap = YamlHelper.collectServiceTags(yamlServiceKeyValue);
230-
if(serviceTagMap != null && serviceTagMap.size() > 0) {
230+
if(serviceTagMap.size() > 0) {
231231
map.put(serviceName, serviceTagMap);
232232
}
233233
}
234234

235235
return map;
236236
}
237237

238-
public static Map<String, Set<String>> getTags(XmlFile psiFile) {
239-
238+
public static Map<String, Set<String>> getTags(@NotNull XmlFile psiFile) {
240239
Map<String, Set<String>> map = new HashMap<>();
241240

242241
XmlDocumentImpl document = PsiTreeUtil.getChildOfType(psiFile, XmlDocumentImpl.class);

src/main/java/fr/adrienbrault/idea/symfony2plugin/intentions/yaml/YamlServiceTagIntention.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ private static Pair<PhpClass, Set<String>> invoke(@NotNull Project project, @Not
161161
Set<String> phpClassServiceTags = ServiceUtil.getPhpClassServiceTags(resolvedClassDefinition);
162162

163163
Set<String> strings = YamlHelper.collectServiceTags(serviceKeyValue);
164-
if(strings != null && strings.size() > 0) {
164+
if(strings.size() > 0) {
165165
for (String s : strings) {
166166
if(phpClassServiceTags.contains(s)) {
167167
phpClassServiceTags.remove(s);

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -625,23 +625,21 @@ public static YAMLKeyValue findServiceInContext(@NotNull PsiElement psiElement)
625625
* @param yamlKeyValue the service key value to find the "tags" key on
626626
* @return tag names
627627
*/
628-
@Nullable
628+
@NotNull
629629
public static Set<String> collectServiceTags(@NotNull YAMLKeyValue yamlKeyValue) {
630-
631630
YAMLKeyValue tagsKeyValue = YamlHelper.getYamlKeyValue(yamlKeyValue, "tags");
632631
if(tagsKeyValue == null) {
633-
return null;
632+
return Collections.emptySet();
634633
}
635634

636635
PsiElement tagsCompound = tagsKeyValue.getValue();
637636
if(!(tagsCompound instanceof YAMLSequence)) {
638-
return null;
637+
return Collections.emptySet();
639638
}
640639

641640
Set<String> tags = new HashSet<>();
642641

643642
for (YAMLSequenceItem yamlSequenceItem : ((YAMLSequence) tagsCompound).getItems()) {
644-
645643
YAMLValue value = yamlSequenceItem.getValue();
646644
if(value instanceof YAMLMapping) {
647645
// tags:
@@ -664,6 +662,26 @@ public static Set<String> collectServiceTags(@NotNull YAMLKeyValue yamlKeyValue)
664662
return tags;
665663
}
666664

665+
/**
666+
* acme_demo.form.type.gender:
667+
* class: espend\Form\TypeBundle\Form\FooType
668+
* tags:
669+
* - { name: foo }
670+
*/
671+
@NotNull
672+
public static Collection<YAMLKeyValue> getTaggedServices(@NotNull YAMLFile yamlFile, @NotNull String tag) {
673+
Collection<YAMLKeyValue> yamlKeyValues = new HashSet<>();
674+
675+
for (YAMLKeyValue yamlServiceKeyValue : YamlHelper.getQualifiedKeyValuesInFile(yamlFile, "services")) {
676+
Set<String> serviceTagMap = YamlHelper.collectServiceTags(yamlServiceKeyValue);
677+
if (serviceTagMap.contains(tag)) {
678+
yamlKeyValues.add(yamlServiceKeyValue);
679+
}
680+
}
681+
682+
return yamlKeyValues;
683+
}
684+
667685
/**
668686
* TODO: use visitor pattern for all tags, we are using them to often
669687
*/

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/dic/container/util/ServiceContainerUtilTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,22 @@
44
import com.intellij.openapi.util.Condition;
55
import com.intellij.psi.PsiElement;
66
import com.intellij.psi.PsiFile;
7+
import com.intellij.util.Consumer;
78
import com.intellij.util.containers.ContainerUtil;
9+
import com.jetbrains.php.lang.psi.elements.Parameter;
810
import fr.adrienbrault.idea.symfony2plugin.dic.container.ServiceInterface;
911
import fr.adrienbrault.idea.symfony2plugin.dic.container.ServiceSerializable;
1012
import fr.adrienbrault.idea.symfony2plugin.dic.container.dict.ServiceTypeHint;
1113
import fr.adrienbrault.idea.symfony2plugin.dic.container.util.ServiceContainerUtil;
1214
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
1315
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
1416
import org.jetbrains.annotations.NotNull;
17+
import org.jetbrains.yaml.psi.YAMLFile;
1518
import org.jetbrains.yaml.psi.YAMLScalar;
1619

1720
import java.util.Arrays;
1821
import java.util.Collection;
22+
import java.util.HashSet;
1923
import java.util.List;
2024

2125
/**
@@ -299,6 +303,26 @@ public void testGetXmlCallTypeHint() {
299303
assertEquals("setFoo", typeHint.getMethod().getName());
300304
}
301305

306+
public void testVisitNamedArguments() {
307+
PsiFile psiFile = myFixture.configureByText("test.yml", "" +
308+
"services:\n" +
309+
" NamedArgument\\Foobar:\n" +
310+
" arguments: []\n" +
311+
"" +
312+
" App\\Controller\\:\n" +
313+
" resource: '../src/Controller'\n" +
314+
" tags: ['controller.service_arguments']\n"
315+
);
316+
317+
Collection<String> arguments = new HashSet<>();
318+
ServiceContainerUtil.visitNamedArguments(psiFile, parameter -> arguments.add(parameter.getName()));
319+
320+
assertTrue(arguments.contains("foobar"));
321+
322+
assertTrue(arguments.contains("foobarString"));
323+
assertFalse(arguments.contains("private"));
324+
}
325+
302326
private static class MyStringServiceInterfaceCondition implements Condition<ServiceInterface> {
303327

304328
@NotNull

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/dic/container/util/fixtures/classes.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,18 @@ public function setFoo($foo, Foobar $foobar)
1212
{
1313
}
1414
}
15+
}
16+
17+
namespace App\Controller
18+
{
19+
class FoobarController
20+
{
21+
public function fooAction($fooEntity, string $foobarString)
22+
{
23+
}
24+
25+
private function fooPrivate($private)
26+
{
27+
}
28+
}
1529
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/util/yaml/YamlHelperLightTest.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.intellij.openapi.application.ApplicationInfo;
44
import com.intellij.psi.PsiElement;
5+
import com.intellij.psi.PsiFile;
56
import com.intellij.util.Function;
67
import com.intellij.util.containers.ContainerUtil;
78
import com.jetbrains.php.lang.psi.elements.Parameter;
@@ -192,14 +193,15 @@ public void testCollectServiceTagsForSymfony33TagsShortcut() {
192193
public void testCollectServiceTagsForSymfony33TagsShortcutInline() {
193194
YAMLKeyValue fromText = YamlPsiElementFactory.createFromText(getProject(), YAMLKeyValue.class, "" +
194195
"foo:\n" +
195-
" tags: [routing.loader_tags_3, routing.loader_tags_4]\n"
196+
" tags: [routing.loader_tags_3, routing.loader_tags_4, 'routing.loader_tags_5']\n"
196197
);
197198

198199
assertNotNull(fromText);
199200
Set<String> collection = YamlHelper.collectServiceTags(fromText);
200201

201202
assertContainsElements(collection, "routing.loader_tags_3");
202203
assertContainsElements(collection, "routing.loader_tags_4");
204+
assertContainsElements(collection, "routing.loader_tags_5");
203205
}
204206

205207
/**
@@ -551,6 +553,25 @@ public void testGetServiceDefinitionClassFromTagMethod() {
551553
assertEquals("ClassName\\Foo", YamlHelper.getServiceDefinitionClassFromTagMethod(psiElement));
552554
}
553555

556+
public void testGetTaggedServices() {
557+
PsiFile psiFile = myFixture.configureByText(YAMLFileType.YML, "" +
558+
"services:\n" +
559+
" foobar:\n" +
560+
" class: ClassName\\Foo\n" +
561+
" tags:\n" +
562+
" - { name: crossHint.test_222 }\n" +
563+
" foobar2:\n" +
564+
" class: ClassName\\Foo\n" +
565+
" tags: [ 'test.11' ]\n"
566+
);
567+
568+
Collection<YAMLKeyValue> taggedServices1 = YamlHelper.getTaggedServices((YAMLFile) psiFile, "crossHint.test_222");
569+
assertTrue(taggedServices1.stream().anyMatch(yamlKeyValue -> "foobar".equals(yamlKeyValue.getKey().getText())));
570+
571+
Collection<YAMLKeyValue> taggedServices2 = YamlHelper.getTaggedServices((YAMLFile) psiFile, "test.11");
572+
assertTrue(taggedServices2.stream().anyMatch(yamlKeyValue -> "foobar2".equals(yamlKeyValue.getKey().getText())));
573+
}
574+
554575
private int getIndentForTextContent(@NotNull String content) {
555576
return YamlHelper.getIndentSpaceForFile((YAMLFile) YamlPsiElementFactory.createDummyFile(
556577
getProject(),

0 commit comments

Comments
 (0)