8000 decouple Twig namespace loading and provide more default namespace wh… · Koc/idea-php-symfony2-plugin@06a5ac8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 06a5ac8

Browse files
committed
decouple Twig namespace loading and provide more default namespace which work without a compiled container Haehnchen#784 Haehnchen#654
1 parent 96bd875 commit 06a5ac8

File tree

10 files changed

+296
-29
lines changed

10 files changed

+296
-29
lines changed

META-INF/plugin.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,9 @@
604604

605605
<TwigNamespaceExtension implementation="fr.adrienbrault.idea.symfony2plugin.templating.path.JsonFileIndexTwigNamespaces"/>
606606
<TwigNamespaceExtension implementation="fr.adrienbrault.idea.symfony2plugin.templating.path.ConfigAddPathTwigNamespaces"/>
607+
<TwigNamespaceExtension implementation="fr.adrienbrault.idea.symfony2plugin.templating.path.ContainerTwigNamespaceExtension"/>
608+
<TwigNamespaceExtension implementation="fr.adrienbrault.idea.symfony2plugin.templating.path.GlobalAppTwigNamespaceExtension"/>
609+
<TwigNamespaceExtension implementation="fr.adrienbrault.idea.symfony2plugin.templating.path.BundleTwigNamespaceExtension"/>
607610

608611
6D40 <ServiceCollector implementation="fr.adrienbrault.idea.symfony2plugin.dic.DefaultServiceCollector"/>
609612

src/fr/adrienbrault/idea/symfony2plugin/TwigHelper.java

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import com.intellij.psi.util.*;
1919
import com.intellij.util.containers.ContainerUtil;
2020
import com.intellij.util.indexing.FileBasedIndexImpl;
21-
import com.jetbrains.php.PhpIndex;
2221
import com.jetbrains.twig.TwigFile;
2322
import com.jetbrains.twig.TwigFileType;
2423
import com.jetbrains.twig.TwigLanguage;
@@ -34,7 +33,10 @@
3433
import fr.adrienbrault.idea.symfony2plugin.templating.assets.TwigNamedAssetsServiceParser;
3534
import fr.adrienbrault.idea.symfony2plugin.templating.dict.TemplateFileMap;
3635
import fr.adrienbrault.idea.symfony2plugin.templating.dict.TwigBlock;
37-
import fr.adrienbrault.idea.symfony2plugin.templating.path.*;
36+
import fr.adrienbrault.idea.symfony2plugin.templating.path.TwigNamespaceSetting;
37+
import fr.adrienbrault.idea.symfony2plugin.templating.path.TwigPath;
38+
import fr.adrienbrault.idea.symfony2plugin.templating.path.TwigPathContentIterator;
39+
import fr.adrienbrault.idea.symfony2plugin.templating.path.TwigPathIndex;
3840
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigTypeResolveUtil;
3941
import fr.adrienbrault.idea.symfony2plugin.templating.util.TwigUtil;
4042
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
@@ -402,38 +404,23 @@ public static List<TwigPath> getTwigNamespaces(@NotNull Project project) {
402404
@NotNull
403405
public static List<TwigPath> getTwigNamespaces(@NotNull Project project, boolean includeSettings) {
404406
List<TwigPath> twigPaths = new ArrayList<>();
405-
PhpIndex phpIndex = PhpIndex.getInstance(project);
406-
407-
TwigPathServiceParser twigPathServiceParser = ServiceXmlParserFactory.getInstance(project, TwigPathServiceParser.class);
408-
twigPaths.addAll(twigPathServiceParser.getTwigPathIndex().getTwigPaths());
409-
410-
String appDirectoryName = Settings.getInstance(project).directoryToApp + "/Resources/views";
411-
VirtualFile globalDirectory = VfsUtil.findRelativeFile(project.getBaseDir(), appDirectoryName.split("/"));
412-
if(globalDirectory != null) {
413-
twigPaths.add(new TwigPath(globalDirectory.getPath(), TwigPathIndex.MAIN, TwigPathIndex.NamespaceType.BUNDLE));
414-
}
415-
416-
Collection<SymfonyBundle> symfonyBundles = new SymfonyBundleUtil(phpIndex).getBundles();
417-
for (SymfonyBundle bundle : symfonyBundles) {
418-
PsiDirectory views = bundle.getSubDi F438 rectory("Resources", "views");
419-
if(views != null) {
420-
twigPaths.add(new TwigPath(views.getVirtualFile().getPath(), bundle.getName(), TwigPathIndex.NamespaceType.BUNDLE));
421-
}
422-
}
423407

424408
// load extension
425409
TwigNamespaceExtensionParameter parameter = new TwigNamespaceExtensionParameter(project);
426410
for (TwigNamespaceExtension namespaceExtension : EXTENSIONS.getExtensions()) {
427411
twigPaths.addAll(namespaceExtension.getNamespaces(parameter));
428412
}
429413

414+
// disable namespace explicitly disabled by user
430415
for(TwigPath twigPath: twigPaths) {
431416
TwigNamespaceSetting twigNamespaceSetting = findManagedTwigNamespace(project, twigPath);
432417
if(twigNamespaceSetting != null) {
433418
twigPath.setEnabled(false);
434419
}
435420
}
436421

422+
twigPaths = getUniqueTwigTemplatesList(twigPaths);
423+
437424
if(!includeSettings) {
438425
return twigPaths;
439426
}
@@ -443,14 +430,36 @@ public static List<TwigPath> getTwigNamespaces(@NotNull Project project, boolean
443430
for(TwigNamespaceSetting twigNamespaceSetting: twigNamespaceSettings) {
444431
if(twigNamespaceSetting.isCustom()) {
445432
twigPaths.add(new TwigPath(twigNamespaceSetting.getPath(), twigNamespaceSetting.getNamespace(), twigNamespaceSetting.getNamespaceType(), true).setEnabled(twigNamespaceSetting.isEnabled()));
446-
447433
}
448434
}
449435
}
450436

451437
return twigPaths;
452438
}
453439

440+
/**
441+
* Build a unique path + namespace + type list
442+
* normalize also windows linux path
443+
*/
444+
@NotNull
445+
public static List<TwigPath> getUniqueTwigTemplatesList(@NotNull Collection<TwigPath> origin) {
446+
List<TwigPath> twigPaths = new ArrayList<>();
447+
448+
Set<String> hashes = new HashSet<>();
449+
for (TwigPath twigPath : origin) {
450+
// normalize hash; for same path element
451+
// TODO: move to path object itself
452+
String hash = twigPath.getNamespaceType() + twigPath.getNamespace() + twigPath.getPath().replace("\\", "/");
453+
if(hashes.contains(hash)) {
454+
continue;
455+
}
456+
457+
twigPaths.add(twigPath);
458+
hashes.add(hash);
459+
}
460+
461+
return twigPaths;
462+
}
454463

455464
@Nullable
456465
public static String getTwigMethodString(@Nullable PsiElement transPsiElement) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package fr.adrienbrault.idea.symfony2plugin.templating.path;
2+
3+
import com.intellij.psi.PsiDirectory;
4+
import com.jetbrains.php.PhpIndex;
5+
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtension;
6+
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtensionParameter;
7+
import fr.adrienbrault.idea.symfony2plugin.util.SymfonyBundleUtil;
8+
import fr.adrienbrault.idea.symfony2plugin.util.dict.SymfonyBundle;
9+
import org.apache.commons.lang.StringUtils;
10+
import org.jetbrains.annotations.NotNull;
11+
12+
import java.util.ArrayList;
13+
import java.util.Collection;
14+
15+
/**
16+
* FooBundle/Resources/views/foo.html.twig => FooBundle:foo.html.twig
17+
* FooBundle/Resources/views/foo.html.twig => @Foo/foo.html.twig
18+
*
19+
* @author Daniel Espendiller <daniel@espendiller.net>
20+
*/
21+
public class BundleTwigNamespaceExtension implements TwigNamespaceExtension {
22+
@NotNull
23+
@Override
24+
public Collection<TwigPath> getNamespaces(@NotNull TwigNamespaceExtensionParameter parameter) {
25+
Collection<TwigPath> twigPaths = new ArrayList<>();
26+
27+
Collection<SymfonyBundle> symfonyBundles = new SymfonyBundleUtil(PhpIndex.getInstance(parameter.getProject())).getBundles();
28+
for (SymfonyBundle bundle : symfonyBundles) {
29+
PsiDirectory views = bundle.getSubDirectory("Resources", "views");
30+
if(views == null) {
31+
continue;
32+
}
33+
34+
// strip starting backslash to force relative path
35+
String path = StringUtils.stripStart(views.getVirtualFile().getPath(), "/");
36+
37+
String bundleName = bundle.getName();
38+
39+
twigPaths.add(new TwigPath(path, bundleName, TwigPathIndex.NamespaceType.BUNDLE));
40+
if(bundleName.endsWith("Bundle")) {
41+
twigPaths.add(new TwigPath(path, bundleName.substring(0, bundleName.length() - 6), TwigPathIndex.NamespaceType.ADD_PATH));
42+
}
43+
}
44+
45+
return twigPaths;
46+
}
47+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package fr.adrienbrault.idea.symfony2plugin.templating.path;
2+
3+
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtension;
4+
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtensionParameter;
5+
import fr.adrienbrault.idea.symfony2plugin.util.service.ServiceXmlParserFactory;
6+
import org.jetbrains.annotations.NotNull;
7+
8+
import java.util.ArrayList;
9+
import java.util.Collection;
10+
11+
/**
12+
* Collects path on compiled container: appDevDebugProjectContainer.xml
13+
*
14+
* <call method="addPath">
15+
* <argument>... ymfony\Bundle\FrameworkBundle/Resources/views</argument>
16+
* <argument>Framework</argument>
17+
* </call>
18+
*
19+
* @author Daniel Espendiller <daniel@espendiller.net>
20+
*/
21+
public class ContainerTwigNamespaceExtension implements TwigNamespaceExtension {
22+
@NotNull
23+
@Override
24+
public Collection<TwigPath> getNamespaces(@NotNull TwigNamespaceExtensionParameter parameter) {
25+
TwigPathServiceParser twigPathServiceParser = ServiceXmlParserFactory.getInstance(parameter.getProject(), TwigPathServiceParser.class);
26+
27+
return new ArrayList<>(
28+
twigPathServiceParser.getTwigPathIndex().getTwigPaths()
29+
);
30+
}
31+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package fr.adrienbrault.idea.symfony2plugin.templating.path;
2+
3+
import com.intellij.openapi.vfs.VfsUtil;
4+
import com.intellij.openapi.vfs.VirtualFile;
5+
import fr.adrienbrault.idea.symfony2plugin.Settings;
6+
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtension;
7+
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtensionParameter;
8+
import org.jetbrains.annotations.NotNull;
9+
10+
import java.util.Arrays;
11+
import java.util.Collection;
12+
import java.util.Collections;
13+
14+
/**
15+
* app/Resources/views/foo.html.twig => :foo.html.twig
16+
* app/Resources/views/foo.html.twig => foo.html.twig
17+
*
18+
* @author Daniel Espendiller <daniel@espendiller.net>
19+
*/
20+
public class GlobalAppTwigNamespaceExtension implements TwigNamespaceExtension {
21+
@NotNull
22+
@Override
23+
public Collection<TwigPath> getNamespaces(@NotNull TwigNamespaceExtensionParameter parameter) {
24+
String appDirectoryName = Settings.getInstance(parameter.getProject()).directoryToApp + "/Resources/views";
25+
VirtualFile baseDir = parameter.getProject().getBaseDir();
26+
27+
VirtualFile globalDirectory = VfsUtil.findRelativeFile(baseDir, appDirectoryName.split("/"));
28+
if(globalDirectory == null) {
29+
return Collections.emptyList();
30+
}
31+
32+
String path = globalDirectory.getPath();
33+
34+
return Arrays.asList(
35+
new TwigPath(path, TwigPathIndex.MAIN, TwigPathIndex.NamespaceType.BUNDLE),
36+
new TwigPath(path, TwigPathIndex.MAIN, TwigPathIndex.NamespaceType.ADD_PATH)
37+
);
38+
}
39+
}

src/fr/adrienbrault/idea/symfony2plugin/templating/path/TwigPath.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,40 @@
33
import com.intellij.openapi.project.Project;
44
import com.intellij.openapi.vfs.VfsUtil;
55
import com.intellij.openapi.vfs.VirtualFile;
6+
import org.jetbrains.annotations.NotNull;
67
import org.jetbrains.annotations.Nullable;
78

89
import java.io.File;
910
import java.text.Collator;
1011

1112
public class TwigPath implements Comparable<TwigPath> {
12-
13+
@NotNull
1314
private String path;
15+
16+
@NotNull
1417
private String namespace = TwigPathIndex.MAIN;
18+
19+
@NotNull
20+
private TwigPathIndex.NamespaceType namespaceType = TwigPathIndex.NamespaceType.ADD_PATH;
21+
1522
private boolean enabled = true;
1623
private boolean customPath = false;
1724

25+
@NotNull
1826
public TwigPathIndex.NamespaceType getNamespaceType() {
1927
return namespaceType;
2028
}
2129

22-
private TwigPathIndex.NamespaceType namespaceType = TwigPathIndex.NamespaceType.ADD_PATH;
23-
24-
public TwigPath(String path) {
30+
public TwigPath(@NotNull String path) {
2531
this.path = path;
2632
}
2733

28-
public TwigPath(String path, String namespace) {
34+
public TwigPath(@NotNull String path, @NotNull String namespace) {
2935
this.path = path;
3036
this.namespace = namespace;
3137
}
3238

33-
public TwigPath(String path, String namespace, TwigPathIndex.NamespaceType namespaceType, boolean customPath) {
39+
public TwigPath(@NotNull String path, @NotNull String namespace, @NotNull TwigPathIndex.NamespaceType namespaceType, boolean customPath) {
3440
this(path, namespace, namespaceType);
3541
this.customPath = customPath;
3642
}
@@ -47,11 +53,12 @@ public TwigPath clone() {
4753
return twigPath;
4854
}
4955

50-
public TwigPath(String path, String namespace, TwigPathIndex.NamespaceType namespaceType) {
56+
public TwigPath(@NotNull String path, @NotNull String namespace, @NotNull TwigPathIndex.NamespaceType namespaceType) {
5157
this(path, namespace);
5258
this.namespaceType = namespaceType;
5359
}
5460

61+
@NotNull
5562
public String getNamespace() {
5663
return namespace;
5764
}
@@ -85,6 +92,7 @@ public VirtualFile getDirectory(Project project) {
8592
return VfsUtil.findRelativeFile(relativePath, project.getBaseDir());
8693
}
8794

95+
@NotNull
8896
public String getPath() {
8997
return path;
9098
}
@@ -111,7 +119,7 @@ private VirtualFile getDirectory() {
111119
}
112120

113121
@Override
114-
public int compareTo(TwigPath twigPath) {
122+
public int compareTo(@NotNull TwigPath twigPath) {
115123
Collator collator = Collator.getInstance();
116124
collator.setStrength(Collator.SECONDARY);
117125
return collator.compare(this.getNamespace(), twigPath.getNamespace());

tests/fr/adrienbrault/idea/symfony2plugin/tests/TwigHelperLightTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import com.jetbrains.twig.elements.TwigTagWithFileReference;
1616
import fr.adrienbrault.idea.symfony2plugin.TwigHelper;
1717
import fr.adrienbrault.idea.symfony2plugin.templating.dict.TwigBlock;
18+
import fr.adrienbrault.idea.symfony2plugin.templating.path.TwigPath;
19+
import fr.adrienbrault.idea.symfony2plugin.templating.path.TwigPathIndex;
1820
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlPsiElementFactory;
1921
import org.apache.commons.lang.StringUtils;
2022
import org.jetbrains.annotations.NotNull;
@@ -199,6 +201,31 @@ public void testGetBlockTagPattern() {
199201
}
200202
}
201203

204+
/**
205+
* @see TwigHelper#getUniqueTwigTemplatesList
206+
*/
207+
public void testGetUniqueTwigTemplatesList() {
208+
assertSize(1, TwigHelper.getUniqueTwigTemplatesList(Arrays.asList(
209+
new TwigPath("path/", "path"),
210+
new TwigPath("path\\", "path")
211+
)));
212+
213+
assertSize(1, TwigHelper.getUniqueTwigTemplatesList(Arrays.asList(
214+
new TwigPath("path", "path"),
215+
new TwigPath("path", "path")
216+
)));
217+
218+
assertSize(2, TwigHelper.getUniqueTwigTemplatesList(Arrays.asList(
219+
new TwigPath("path/a", "path"),
220+
new TwigPath("foobar", "path")
221+
)));
222+
223+
assertSize(2, TwigHelper.getUniqueTwigTemplatesList(Arrays.asList(
224+
new TwigPath("path", "path", TwigPathIndex.NamespaceType.BUNDLE),
225+
new TwigPath("path", "path")
226+
)));
227+
}
228+
202229
private void assertEqual(Collection<String> c, String... values) {
203230
if(!StringUtils.join(c, ",").equals(StringUtils.join(Arrays.asList(values), ","))) {
204231
fail(String.format("Fail that '%s' is equal '%s'", StringUtils.join(c, ","), StringUtils.join(Arrays.asList(values), ",")));
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package fr.adrienbrault.idea.symfony2plugin.tests.templating.path;
2+
3+
import com.intellij.openapi.vfs.VirtualFile;
4+
import com.intellij.testFramework.VfsTestUtil;
5+
import com.intellij.util.containers.ContainerUtil;
6+
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtensionParameter;
7+
import fr.adrienbrault.idea.symfony2plugin.templating.path.BundleTwigNamespaceExtension;
8+
import fr.adrienbrault.idea.symfony2plugin.templating.path.TwigPath;
9+
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
10+
11+
import java.io.File;
12+
import java.util.Collection;
13+
14+
/**
15+
* @author Daniel Espendiller <daniel@espendiller.net>
16+
* @see fr.adrienbrault.idea.symfony2plugin.templating.path.BundleTwigNamespaceExtension
17+
*/
18+
public class BundleTwigNamespaceExtensionTest extends SymfonyLightCodeInsightFixtureTestCase {
19+
@Override
20+
public void setUp() throws Exception {
21+
super.setUp();
22+
23+
VirtualFile virtualFile = myFixture.copyFileToProject("classes.php");
24+
VfsTestUtil.createDir(virtualFile.getParent(), "Resources/views");
25+
}
26+
27+
public String getTestDataPath() {
28+
return new File(this.getClass().getResource("fixtures").getFile()).getAbsolutePath();
29+
}
30+
31+
public void testThatBundleNamespacesAreAdded() {
32+
Collection<TwigPath> namespaces = new BundleTwigNamespaceExtension()
33+
.getNamespaces(new TwigNamespaceExtensionParameter(getProject()));
34+
35+
assertNotNull(ContainerUtil.find(namespaces, twigPath ->
36+
"FooBundle".equals(twigPath.getNamespace()) && "src/Resources/views".equals(twigPath.getPath()))
37+
);
38+
39+
assertNotNull(ContainerUtil.find(namespaces, twigPath ->
40+
"Foo".equals(twigPath.getNamespace()) && "src/Resources/views".equals(twigPath.getPath()))
41+
);
42+
}
43+
}

0 commit comments

Comments
 (0)
0