Skip to content

Commit cccca23

Browse files
committed
provide service class linemarker for prototype resource of xml files
1 parent dd320c6 commit cccca23

File tree

7 files changed

+133
-14
lines changed

7 files changed

+133
-14
lines changed

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

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.jetbrains.php.lang.psi.elements.Parameter;
1616
import com.jetbrains.php.lang.psi.elements.PhpClass;
1717
import fr.adrienbrault.idea.symfony2plugin.dic.ParameterResolverConsumer;
18+
import fr.adrienbrault.idea.symfony2plugin.dic.container.util.ServiceContainerUtil;
1819
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1920
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
2021
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
@@ -23,8 +24,7 @@
2324
import org.jetbrains.annotations.NotNull;
2425
import org.jetbrains.annotations.Nullable;
2526

26-
import java.util.HashMap;
27-
import java.util.Map;
27+
import java.util.*;
2828

2929
/**
3030
* @author Daniel Espendiller <daniel@espendiller.net>
@@ -834,4 +834,42 @@ public static boolean isXmlFileExtension(@NotNull PsiFile psiFile) {
834834
VirtualFile virtualFile = psiFile.getVirtualFile();
835835
return virtualFile == null || !"xml".equalsIgnoreCase(virtualFile.getExtension());
836836
}
837+
838+
/**
839+
* <prototype exclude="../src/{DependencyInjection,Entity,Tests,Kernel.php}">"
840+
* <exclude>../foobar</exclude>"
841+
* </prototype>"
842+
*/
843+
public static @NotNull Collection<PhpClass> getNamespaceResourcesClasses(@NotNull XmlTag xmlTag) {
844+
String namespace = xmlTag.getAttributeValue("namespace");
845+
if (StringUtils.isBlank(namespace)) {
846+
return Collections.emptyList();
847+
}
848+
849+
String resource = xmlTag.getAttributeValue("resource");
850+
if (StringUtils.isBlank(resource)) {
851+
return Collections.emptyList();
852+
}
853+
854+
Set<String> excludes = new HashSet<>();
855+
String exclude = xmlTag.getAttributeValue("exclude");
856+
if (StringUtils.isNotBlank(exclude)) {
857+
excludes.add(exclude);
858+
}
859+
860+
for (XmlTag excludeTag : xmlTag.findSubTags("exclude")) {
861+
String text = excludeTag.getValue().getText();
862+
if (StringUtils.isNotBlank(text)) {
863+
excludes.add(text);
864+
}
865+
}
866+
867+
return ServiceContainerUtil.getPhpClassFromResources(
868+
xmlTag.getProject(),
869+
namespace,
870+
xmlTag.getContainingFile().getVirtualFile(),
871+
List.of(resource),
872+
excludes
873+
);
874+
}
837875
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/attribute/value/XmlTagAttributeValue.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
import org.jetbrains.annotations.NotNull;
66
import org.jetbrains.annotations.Nullable;
77

8-
import java.util.Arrays;
9-
import java.util.Collection;
10-
import java.util.Collections;
8+
import java.util.*;
119
import java.util.stream.Collectors;
1210

1311
/**
@@ -25,11 +23,26 @@ public XmlTagAttributeValue(@NotNull XmlTag xmlTag) {
2523
@NotNull
2624
@Override
2725
public Collection<String> getStringArray(@NotNull String key) {
26+
Set<String> values = new HashSet<>();
27+
2828
String string = getString(key);
29+
if (StringUtils.isNotBlank(string)) {
30+
values.add(string);
31+
}
32+
33+
// <prototype exclude="../src/{DependencyInjection,Entity,Tests,Kernel.php}">"
34+
// <exclude>../foobar</exclude>"
35+
// </prototype>"
36+
if (key.equals("exclude")) {
37+
for (XmlTag excludeTag : xmlTag.findSubTags(key)) {
38+
String text = excludeTag.getValue().getText();
39+
if (StringUtils.isNotBlank(text)) {
40+
values.add(text);
41+
}
42+
}
43+
}
2944

30-
return string != null
31-
? Collections.singleton(string)
32-
: Collections.emptyList();
45+
return values;
3346
}
3447

3548
@Nullable

src/main/java/fr/adrienbrault/idea/symfony2plugin/dic/linemarker/XmlLineMarkerProvider.java

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import com.intellij.codeInsight.daemon.LineMarkerInfo;
44
import com.intellij.codeInsight.daemon.LineMarkerProvider;
55
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
6+
import com.intellij.icons.AllIcons;
7+
import com.intellij.openapi.util.NotNullLazyValue;
68
import com.intellij.patterns.XmlPatterns;
79
import com.intellij.patterns.XmlTagPattern;
810
import com.intellij.psi.PsiElement;
@@ -46,17 +48,42 @@ public void collectSlowLineMarkers(@NotNull List<? extends PsiElement> psiElemen
4648
continue;
4749
}
4850

51+
if(!XmlHelper.getXmlTagNameLeafStartPattern().accepts(psiElement)) {
52+
continue;
53+
}
54+
4955
PsiElement xmlTag = psiElement.getParent();
50-
if(!(xmlTag instanceof XmlTag) || !getServiceIdPattern().accepts(xmlTag)) {
56+
if(!(xmlTag instanceof XmlTag)) {
5157
continue;
5258
}
5359

54-
if(lazyDecoratedParentServiceValues == null) {
55-
lazyDecoratedParentServiceValues = new LazyDecoratedParentServiceValues(psiElement.getProject());
60+
if (getServiceIdPattern().accepts(xmlTag)) {
61+
if(lazyDecoratedParentServiceValues == null) {
62+
lazyDecoratedParentServiceValues = new LazyDecoratedParentServiceValues(psiElement.getProject());
63+
}
64+
65+
// <services><service id="foo"/></services>
66+
visitServiceId(psiElement, (XmlTag) xmlTag, result, lazyDecoratedParentServiceValues);
67+
68+
continue;
5669
}
5770

58-
// <services><service id="foo"/></services>
59-
visitServiceId(psiElement, (XmlTag) xmlTag, result, lazyDecoratedParentServiceValues);
71+
if (getPrototypeNamespacePattern().accepts(xmlTag)) {
72+
String namespace = ((XmlTag) xmlTag).getAttributeValue("namespace");
73+
if (StringUtils.isBlank(namespace)) {
74+
continue;
75+
}
76+
77+
String resource = ((XmlTag) xmlTag).getAttributeValue("resource");
78+
if (StringUtils.isBlank(resource)) {
79+
continue;
80+
}
81+
82+
result.add(NavigationGutterIconBuilder.create(AllIcons.Modules.SourceRoot)
83+
.setTargets(NotNullLazyValue.lazy(() -> XmlHelper.getNamespaceResourcesClasses((XmlTag) xmlTag)))
84+
.setTooltipText("Navigate to class")
85+
.createLineMarkerInfo(psiElement));
86+
}
6087
}
6188
}
6289

@@ -115,4 +142,14 @@ private static XmlTagPattern.Capture getServiceIdPattern() {
115142
XmlHelper.getInsideTagPattern("services")
116143
).inFile(XmlHelper.getXmlFilePattern());
117144
}
145+
146+
/**
147+
* <prototype namespace="App\" resource="../src/*" exclude="../src/{DependencyInjection,Entity,Tests,Kernel.php}"/>
148+
*/
149+
private static XmlTagPattern.Capture getPrototypeNamespacePattern() {
150+
return XmlPatterns.xmlTag().withName("prototype")
151+
.withChild(XmlPatterns.xmlAttribute().withName("namespace")).inside(
152+
XmlHelper.getInsideTagPattern("services")
153+
).inFile(XmlHelper.getXmlFilePattern());
154+
}
118155
}

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
package fr.adrienbrault.idea.symfony2plugin.tests.config.xml;
22

33
import com.intellij.ide.highlighter.XmlFileType;
4+
import com.intellij.openapi.vfs.VirtualFile;
45
import com.intellij.psi.PsiElement;
6+
import com.intellij.psi.PsiFile;
7+
import com.intellij.psi.PsiManager;
8+
import com.intellij.psi.util.PsiTreeUtil;
59
import com.intellij.psi.xml.XmlAttributeValue;
610
import com.intellij.psi.xml.XmlTag;
711
import com.intellij.util.containers.ContainerUtil;
812
import com.jetbrains.php.lang.psi.elements.Parameter;
13+
import com.jetbrains.php.lang.psi.elements.PhpClass;
14+
import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
915
import fr.adrienbrault.idea.symfony2plugin.config.xml.XmlHelper;
1016
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
1117

1218
import java.util.ArrayList;
1319
import java.util.Collection;
20+
import java.util.function.Predicate;
21+
import java.util.stream.Collectors;
1422

1523
/**
1624
* @author Daniel Espendiller <daniel@espendiller.net>
@@ -169,4 +177,23 @@ public void testGetArgumentIndexOnArgumentCount() {
169177
PsiElement psiElement = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
170178
assertEquals(1, XmlHelper.getArgumentIndex((XmlTag) psiElement.getParent()));
171179
}
180+
181+
/**
182+
* @see XmlHelper#getNamespaceResourcesClasses
183+
*/
184+
public void testGetNamespaceResourcesClasses() {
185+
myFixture.copyFileToProject("XmlHelper.php", "src/XmlHelper.php");
186+
VirtualFile service = myFixture.copyFileToProject("services.xml", "src/services.xml");
187+
188+
PsiFile file = PsiManager.getInstance(getProject()).findFile(service);
189+
190+
Collection<XmlTag> xmlTags = PsiTreeUtil.collectElementsOfType(file, XmlTag.class);
191+
192+
XmlTag xmlTag = xmlTags.stream().filter(xmlTag1 -> "prototype".equals(xmlTag1.getName())).findFirst().orElseThrow();
193+
Collection<String> namespaceResourcesClasses = XmlHelper.getNamespaceResourcesClasses(xmlTag).stream()
194+
.map(PhpNamedElement::getFQN)
195+
.collect(Collectors.toSet());
196+
197+
assertContainsElements(namespaceResourcesClasses, "\\Foo\\Bar");
198+
}
172199
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/xml/fixtures/services.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
<container>
33
<services>
44
<service id="foo.bar_factory" class="Foo\Bar"/>
5+
<prototype namespace="Foo\" resource="../src/*"/>
56
</services>
67
</container>

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/stubs/indexes/ServicesDefinitionStubIndexTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public void testThatResourceAndExcludeAttributesAreExtractedForXml() {
9595
assertEquals("App\\Xml\\", firstValue.getId());
9696
assertContainsElements(firstValue.getResource(), "../src/*");
9797
assertContainsElements(firstValue.getExclude(), "../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}");
98+
assertContainsElements(firstValue.getExclude(), "../src/foobar");
9899
}
99100

100101
public void testThatTagAreInIndexForYaml() {

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/stubs/indexes/fixtures/services.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535

3636
<prototype namespace="App\Xml\"
3737
resource="../src/*"
38-
exclude="../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}"/>
38+
exclude="../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}">
39+
<exclude>../src/foobar</exclude>
40+
</prototype>
3941

4042
<service id="foo.tagged.xml_type" class="AppBundle\Controller\DefaultController">
4143
<tag name="xml_type_tag"/>

0 commit comments

Comments
 (0)