Skip to content

Commit 4723a61

Browse files
committed
Support for target plugin class and methods
1 parent 77fa261 commit 4723a61

File tree

2 files changed

+201
-0
lines changed

2 files changed

+201
-0
lines changed

resources/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.js.MagentoLibJsIndex" />
101101

102102
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.PluginLineMarkerProvider"/>
103+
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.PluginTargetLineMarkerProvider"/>
103104
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.ClassConfigurationLineMarkerProvider"/>
104105
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.WebApiLineMarkerProvider"/>
105106

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
package com.magento.idea.magento2plugin.php.linemarker;
6+
7+
import com.intellij.codeInsight.daemon.LineMarkerInfo;
8+
import com.intellij.codeInsight.daemon.LineMarkerProvider;
9+
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
10+
import com.intellij.icons.AllIcons;
11+
import com.intellij.psi.PsiElement;
12+
import com.jetbrains.php.PhpIndex;
13+
import com.jetbrains.php.lang.psi.elements.Method;
14+
import com.jetbrains.php.lang.psi.elements.PhpClass;
15+
import com.magento.idea.magento2plugin.magento.files.Plugin;
16+
import com.magento.idea.magento2plugin.project.Settings;
17+
import org.jetbrains.annotations.NotNull;
18+
import org.jetbrains.annotations.Nullable;
19+
import com.magento.idea.magento2plugin.util.magento.plugin.GetTargetClassNamesByPluginClassName;
20+
import com.intellij.psi.util.PsiTreeUtil;
21+
22+
import java.util.*;
23+
24+
public class PluginTargetLineMarkerProvider implements LineMarkerProvider {
25+
@Nullable
26+
@Override
27+
public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement psiElement) {
28+
return null;
29+
}
30+
31+
@Override
32+
public void collectSlowLineMarkers(@NotNull List<PsiElement> psiElements, @NotNull Collection<LineMarkerInfo> collection) {
33+
if (psiElements.size() > 0) {
34+
if (!Settings.isEnabled(psiElements.get(0).getProject())) {
35+
return;
36+
}
37+
}
38+
PluginClassCache pluginClassCache = new PluginClassCache();
39+
TargetClassesCollector TargetClassesCollector = new TargetClassesCollector(pluginClassCache);
40+
TargetMethodsCollector TargetMethodsCollector = new TargetMethodsCollector(pluginClassCache);
41+
42+
for (PsiElement psiElement : psiElements) {
43+
if (psiElement instanceof PhpClass || psiElement instanceof Method) {
44+
List<? extends PsiElement> results;
45+
46+
if (psiElement instanceof PhpClass) {
47+
results = TargetClassesCollector.collect((PhpClass) psiElement);
48+
if (results.size() > 0 ) {
49+
collection.add(NavigationGutterIconBuilder
50+
.create(AllIcons.Nodes.Class)
51+
.setTargets(results)
52+
.setTooltipText("Navigate to target class")
53+
.createLineMarkerInfo(PsiTreeUtil.getDeepestFirst(psiElement))
54+
);
55+
}
56+
} else {
57+
results = TargetMethodsCollector.collect((Method) psiElement);
58+
if (results.size() > 0 ) {
59+
collection.add(NavigationGutterIconBuilder
60+
.create(AllIcons.Nodes.Method)
61+
.setTargets(results)
62+
.setTooltipText("Navigate to target method")
63+
.createLineMarkerInfo(PsiTreeUtil.getDeepestFirst(psiElement))
64+
);
65+
}
66+
}
67+
68+
69+
}
70+
}
71+
}
72+
73+
private static class PluginClassCache {
74+
private HashMap<String, List<PhpClass>> pluginClassesMap = new HashMap<String, List<PhpClass>>();
75+
76+
List<PhpClass> getTargetClassesForPlugin(@NotNull PhpClass phpClass, @NotNull String classFQN) {
77+
List<PhpClass> results = new ArrayList<>();
78+
79+
if (pluginClassesMap.containsKey(classFQN)) {
80+
return pluginClassesMap.get(classFQN);
81+
}
82+
83+
GetTargetClassNamesByPluginClassName targetClassesService = GetTargetClassNamesByPluginClassName.getInstance(phpClass.getProject());
84+
ArrayList<String> targetClassNames = targetClassesService.execute(classFQN);
85+
86+
if (targetClassNames.size() == 0) {
87+
pluginClassesMap.put(classFQN, results);
88+
return results;
89+
}
90+
91+
PhpIndex phpIndex = PhpIndex.getInstance(phpClass.getProject());
92+
93+
for (String targetClassName : targetClassNames) {
94+
Collection<PhpClass> targets = phpIndex.getClassesByFQN(targetClassName);
95+
96+
results.addAll(targets);
97+
}
98+
99+
return results;
100+
}
101+
102+
List<PhpClass> getTargetClassesForPlugin(@NotNull PhpClass phpClass) {
103+
List<PhpClass> classesForPlugin = getTargetClassesForPlugin(phpClass, phpClass.getPresentableFQN());
104+
for (PhpClass parent: phpClass.getSupers()) {
105+
classesForPlugin.addAll(getTargetClassesForPlugin(parent));
106+
}
107+
108+
return classesForPlugin;
109+
}
110+
}
111+
112+
private static class TargetClassesCollector implements Collector<PhpClass, PhpClass> {
113+
private PluginTargetLineMarkerProvider.PluginClassCache pluginClassCache;
114+
115+
TargetClassesCollector(PluginTargetLineMarkerProvider.PluginClassCache pluginClassCache) {
116+
this.pluginClassCache = pluginClassCache;
117+
}
118+
119+
@Override
120+
public List<PhpClass> collect(@NotNull PhpClass psiElement) {
121+
return pluginClassCache.getTargetClassesForPlugin(psiElement);
122+
}
123+
}
124+
125+
private static class TargetMethodsCollector implements Collector<Method, Method> {
126+
private PluginTargetLineMarkerProvider.PluginClassCache pluginClassCache;
127+
128+
TargetMethodsCollector(PluginTargetLineMarkerProvider.PluginClassCache pluginClassCache) {
129+
this.pluginClassCache = pluginClassCache;
130+
}
131+
132+
@Override
133+
public List<Method> collect(@NotNull Method pluginMethod) {
134+
List<Method> results = new ArrayList<>();
135+
136+
/* Check if the method is a plugin */
137+
if (null == getPluginPrefix(pluginMethod)) {
138+
return results;
139+
}
140+
141+
PhpClass pluginClass = pluginMethod.getContainingClass();
142+
if (pluginClass == null) {
143+
return results;
144+
}
145+
146+
List<PhpClass> targetClasses = pluginClassCache.getTargetClassesForPlugin(pluginClass);
147+
if (targetClasses.size() == 0) {
148+
return results;
149+
}
150+
151+
for (PhpClass targetClass: targetClasses) {
152+
String pluginPrefix = getPluginPrefix(pluginMethod);
153+
String targetClassMethodName = getTargetMethodName(pluginMethod, pluginPrefix);
154+
if (targetClassMethodName == null) {
155+
continue;
156+
}
157+
158+
Method targetMethod = targetClass.findMethodByName(targetClassMethodName);
159+
if (targetMethod == null) {
160+
continue;
161+
}
162+
163+
results.add(targetMethod);
164+
}
165+
166+
return results;
167+
}
168+
169+
private String getTargetMethodName(Method pluginMethod, String pluginPrefix) {
170+
String pluginMethodName = pluginMethod.getName();
171+
String targetClassMethodName = pluginMethodName.
172+
replace(pluginPrefix, "");
173+
char firstCharOfTargetName = targetClassMethodName.charAt(0);
174+
int charType = Character.getType(firstCharOfTargetName);
175+
if (charType == Character.LOWERCASE_LETTER) {
176+
return null;
177+
}
178+
return Character.toLowerCase(firstCharOfTargetName) + targetClassMethodName.substring(1);
179+
}
180+
181+
private String getPluginPrefix(Method pluginMethod) {
182+
String pluginMethodName = pluginMethod.getName();
183+
if (pluginMethodName.startsWith(Plugin.PluginType.around.toString())) {
184+
return Plugin.PluginType.around.toString();
185+
}
186+
if (pluginMethodName.startsWith(Plugin.PluginType.before.toString())) {
187+
return Plugin.PluginType.before.toString();
188+
}
189+
if (pluginMethodName.startsWith(Plugin.PluginType.after.toString())) {
190+
return Plugin.PluginType.after.toString();
191+
}
192+
193+
return null;
194+
}
195+
}
196+
197+
private interface Collector<T extends PsiElement, K> {
198+
List<K> collect(@NotNull T psiElement);
199+
}
200+
}

0 commit comments

Comments
 (0)