Skip to content

Commit 2e38a37

Browse files
author
Vitaliy Boyko
committed
Merge branch '1.0.0-develop' of https://github.com/magento/magento2-phpstorm-plugin into setup_gradle
2 parents 02c3aa8 + e6eb9fe commit 2e38a37

36 files changed

+2572
-97
lines changed
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
namespace PHPSTORM_META {
4+
override(\Magento\Framework\ObjectManagerInterface::get(0), map(['' => '@']));
5+
override(\Magento\Framework\ObjectManagerInterface::create(0), map(['' => '@']));
6+
}

resources/META-INF/plugin.xml

+34-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<idea-plugin>
88
<id>com.magento.idea.magento2plugin</id>
99
<name>Magento PhpStorm</name>
10-
<version>0.3.0</version>
10+
<version>1.0.0</version>
1111
<vendor url="https://github.com/magento/magento2-phpstorm-plugin">Magento Inc.</vendor>
1212

1313
<description><![CDATA[
@@ -25,7 +25,7 @@
2525
</change-notes>
2626

2727
<!-- please see http://confluence.jetbrains.com/display/IDEADEV/Build+Number+Ranges for description -->
28-
<idea-version since-build="172"/>
28+
<idea-version since-build="193.4386.10"/>
2929

3030
<!-- please see http://confluence.jetbrains.com/display/IDEADEV/Plugin+Compatibility+with+IntelliJ+Platform+Products
3131
on how to target different products -->
@@ -35,6 +35,26 @@
3535
<depends>com.jetbrains.php</depends>
3636
<depends>JavaScript</depends>
3737
<depends>com.intellij.modules.platform</depends>
38+
<depends>com.intellij.lang.jsgraphql</depends>
39+
40+
<actions>
41+
<group id="MagentoGenerateGroup">
42+
<action id="MagentoGenerateBeforeMethodAction"
43+
class="com.magento.idea.magento2plugin.actions.generation.MagentoGenerateBeforeMethodAction"
44+
text="Magento Before Plugin..."
45+
description="Create Magento before plugin method."/>
46+
<action id="MagentoGenerateAfterMethodAction"
47+
class="com.magento.idea.magento2plugin.actions.generation.MagentoGenerateAfterMethodAction"
48+
text="Magento After Plugin..."
49+
description="Create Magento after plugin method."/>
50+
<action id="MagentoGenerateAroundMethodAction"
51+
class="com.magento.idea.magento2plugin.actions.generation.MagentoGenerateAroundMethodAction"
52+
text="Magento Around Plugin..."
53+
description="Create Magento around plugin method."/>
54+
<add-to-group group-id="PhpGenerateGroup" anchor="last"/>
55+
</group>
56+
57+
</actions>
3858

3959
<extensions defaultExtensionNs="com.intellij">
4060
<projectConfigurable instance="com.magento.idea.magento2plugin.project.SettingsForm"
@@ -67,12 +87,24 @@
6787
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.DataIndex" />
6888
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.PageIndex" />
6989
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.mftf.StepKeyIndex" />
90+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.graphql.GraphQlResolverIndex" />
91+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.js.RequireJsIndex" />
92+
<fileBasedIndex implementation="com.magento.idea.magento2plugin.stubs.indexes.js.MagentoLibJsIndex" />
7093

7194
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.PluginLineMarkerProvider"/>
7295
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.ClassConfigurationLineMarkerProvider"/>
7396
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.WebApiLineMarkerProvider"/>
97+
<codeInsight.lineMarkerProvider language="GraphQL" implementationClass="com.magento.idea.magento2plugin.graphql.linemarker.GraphQlResolverClassLineMarkerProvider"/>
98+
<codeInsight.lineMarkerProvider language="PHP" implementationClass="com.magento.idea.magento2plugin.php.linemarker.GraphQlResolverUsageLineMarkerProvider"/>
7499

75100
<directoryProjectConfigurator implementation="com.magento.idea.magento2plugin.project.ProjectDetector"/>
101+
102+
<libraryRoot id=".phpstorm.meta.php" path="/.phpstorm.meta.php/" runtime="false"/>
103+
104+
<localInspection language="PHP" groupPath="PHP"
105+
shortName="PluginInspection" displayName="Inspection for the Plugin declaration"
106+
groupName="Magento" enabledByDefault="true" level="ERROR"
107+
implementationClass="com.magento.idea.magento2plugin.inspections.php.PluginInspection"/>
76108
</extensions>
77109

78110
<application-components>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
package com.magento.idea.magento2plugin.actions.generation.ImportReferences;
6+
7+
import com.intellij.psi.PsiElement;
8+
import com.jetbrains.php.lang.psi.elements.*;
9+
import com.jetbrains.php.lang.psi.resolve.types.PhpType;
10+
import com.jetbrains.php.lang.psi.visitors.PhpElementVisitor;
11+
import java.util.Collection;
12+
import org.jetbrains.annotations.NotNull;
13+
14+
public abstract class PhpClassReferenceExtractor {
15+
private final PhpElementVisitor myCollectorVisitor = new PhpElementVisitor() {
16+
public void visitPhpClass(PhpClass phpClass) {
17+
PhpClassReferenceExtractor.this.processClassReference(phpClass);
18+
}
19+
20+
public void visitPhpParameter(Parameter parameter) {
21+
PhpClassReferenceExtractor.this.processParameterReference(parameter);
22+
}
23+
24+
public void visitPhpReturnType(PhpReturnType returnType) {
25+
PhpClassReferenceExtractor.this.processReturnTypeReference(returnType);
26+
}
27+
};
28+
29+
public PhpClassReferenceExtractor() {
30+
}
31+
32+
private void processClassReference(@NotNull PhpClass resolvedClass) {
33+
String name = resolvedClass.getName();
34+
this.processReference(name, resolvedClass.getFQN(), resolvedClass);
35+
}
36+
37+
private void processParameterReference(@NotNull Parameter parameter) {
38+
PhpType parameterType = parameter.getDeclaredType();
39+
if (parameterType.isEmpty() && !PhpType.isPrimitiveType(parameterType.toString())) {
40+
return;
41+
}
42+
String fqn = parameterType.toString();
43+
String name = getNameFromFqn(parameterType);
44+
this.processReference(name, fqn, parameter);
45+
}
46+
47+
public void processReturnTypeReference(PhpReturnType returnType) {
48+
PhpType parameterType = returnType.getDeclaredType();
49+
if (parameterType.isEmpty() && !PhpType.isPrimitiveType(parameterType.toString())) {
50+
return;
51+
}
52+
String fqn = parameterType.toString();
53+
String name = getNameFromFqn(parameterType);
54+
this.processReference(name, fqn, returnType);
55+
}
56+
57+
private String getNameFromFqn(PhpType parameterType) {
58+
String[] fqnArray = parameterType.toString().split("\\\\");
59+
return fqnArray[fqnArray.length - 1];
60+
}
61+
62+
protected abstract void processReference(@NotNull String name, @NotNull String fqn, @NotNull PsiElement identifier);
63+
64+
public void processElement(@NotNull PsiElement element) {
65+
element.accept(this.myCollectorVisitor);
66+
}
67+
68+
public void processElements(@NotNull Collection<? extends PsiElement> originalElements) {
69+
for (PsiElement element : originalElements) {
70+
this.processElement(element);
71+
}
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
package com.magento.idea.magento2plugin.actions.generation.ImportReferences;
6+
7+
import com.intellij.openapi.project.Project;
8+
import com.intellij.psi.PsiElement;
9+
import com.jetbrains.php.codeInsight.PhpCodeInsightUtil;
10+
import com.jetbrains.php.lang.PhpLangUtil;
11+
import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment;
12+
import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocType;
13+
import com.jetbrains.php.lang.lexer.PhpTokenTypes;
14+
import com.jetbrains.php.lang.psi.PhpPsiElementFactory;
15+
import com.jetbrains.php.lang.psi.PhpPsiUtil;
16+
import com.jetbrains.php.lang.psi.elements.ClassReference;
17+
import com.jetbrains.php.lang.psi.elements.PhpNamespace;
18+
import com.jetbrains.php.lang.psi.elements.PhpPsiElement;
19+
import com.jetbrains.php.lang.psi.elements.Statement;
20+
import com.jetbrains.php.lang.psi.resolve.types.PhpType;
21+
import com.jetbrains.php.refactoring.PhpAliasImporter;
22+
import gnu.trove.THashMap;
23+
import java.util.Iterator;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.Map.Entry;
27+
import org.jetbrains.annotations.NotNull;
28+
import org.jetbrains.annotations.Nullable;
29+
30+
public class PhpClassReferenceResolver extends PhpClassReferenceExtractor {
31+
private final PhpClassReferenceStorage myCandidatesToImportStorage = new PhpClassReferenceStorage();
32+
33+
public PhpClassReferenceResolver() {
34+
}
35+
36+
public void processElement(@NotNull PsiElement element) {
37+
super.processElement(element);
38+
}
39+
40+
protected void processReference(@NotNull String name, @NotNull String fqn, @NotNull PsiElement identifier) {
41+
if (!PhpType.isPrimitiveType(name)) {
42+
this.myCandidatesToImportStorage.processReference(name, fqn, identifier);
43+
}
44+
}
45+
46+
@Nullable
47+
private static String alreadyImported(@NotNull PhpPsiElement scopeHolder, @NotNull Map<String, String> aliases, @NotNull String fqn, @NotNull String name) {
48+
boolean isSameNamespace = PhpCodeInsightUtil.isSameNamespace(scopeHolder, fqn);
49+
if (isSameNamespace && PhpLangUtil.equalsClassNames(PhpLangUtil.toShortName(fqn), name)) {
50+
return name;
51+
}
52+
boolean isNonCompound = isNonCompoundUseName(scopeHolder, fqn, name);
53+
if (isNonCompound) {
54+
return name;
55+
}
56+
Iterator entryIterator = aliases.entrySet().iterator();
57+
58+
Entry alias;
59+
do {
60+
if (!entryIterator.hasNext()) {
61+
return null;
62+
}
63+
64+
alias = (Entry) entryIterator.next();
65+
} while (!PhpLangUtil.equalsClassNames((CharSequence) alias.getValue(), fqn));
66+
67+
return (String) alias.getKey();
68+
}
69+
70+
public static boolean isNonCompoundUseName(@NotNull PhpPsiElement scopeHolder, @NotNull String fqn, @NotNull String name) {
71+
String currentNamespaceName = scopeHolder instanceof PhpNamespace ? ((PhpNamespace)scopeHolder).getFQN() : "";
72+
return "\\".equals(currentNamespaceName) && PhpLangUtil.equalsClassNames(fqn, PhpLangUtil.toFQN(name));
73+
}
74+
75+
public void importReferences(@NotNull PhpPsiElement scopeHolder, @NotNull List<PsiElement> movedElements) {
76+
Map<String, String> referencesToReplace = this.importWithConflictResolve(scopeHolder);
77+
if (referencesToReplace.isEmpty()) {
78+
return;
79+
}
80+
PhpClassReferenceResolver.PhpClassReferenceRenamer renamer = new PhpClassReferenceResolver.PhpClassReferenceRenamer(scopeHolder.getProject(), referencesToReplace);
81+
renamer.processElements(movedElements);
82+
}
83+
84+
private Map<String, String> importWithConflictResolve(PhpPsiElement scopeHolder) {
85+
Map<String, String> aliases = PhpCodeInsightUtil.getAliasesInScope(scopeHolder);
86+
Map<String, String> referencesToReplace = new THashMap();
87+
boolean autoImport = PhpCodeInsightUtil.isAutoImportEnabled(scopeHolder);
88+
89+
for (String name : this.myCandidatesToImportStorage.getNames()) {
90+
String originalFqn = this.myCandidatesToImportStorage.getFqnByName(name);
91+
assert originalFqn != null;
92+
93+
String alias = alreadyImported(scopeHolder, aliases, originalFqn, name);
94+
if (alias != null) {
95+
if (!PhpLangUtil.equalsClassNames(name, alias)) {
96+
referencesToReplace.put(name, alias);
97+
}
98+
} else if (!autoImport) {
99+
referencesToReplace.put(name, originalFqn);
100+
} else {
101+
String importedFqn = aliases.get(name);
102+
if (!PhpLangUtil.equalsClassNames(importedFqn, originalFqn)) {
103+
if (importedFqn != null) {
104+
String originalName = PhpLangUtil.toShortName(originalFqn);
105+
String fqnForOriginalName = aliases.get(originalName);
106+
if (fqnForOriginalName != null && !PhpLangUtil.equalsClassNames(fqnForOriginalName, originalFqn)) {
107+
referencesToReplace.put(name, originalFqn);
108+
} else {
109+
referencesToReplace.put(name, originalName);
110+
if (fqnForOriginalName == null) {
111+
insertUseStatement(scopeHolder, originalName, originalFqn);
112+
}
113+
}
114+
} else {
115+
insertUseStatement(scopeHolder, name, originalFqn);
116+
}
117+
}
118+
}
119+
}
120+
121+
return referencesToReplace;
122+
}
123+
124+
private static void insertUseStatement(PhpPsiElement scopeHolder, String name, String originalFqn) {
125+
String originalName = PhpLangUtil.toShortName(originalFqn);
126+
if (PhpLangUtil.equalsClassNames(originalName, name)) {
127+
PhpAliasImporter.insertUseStatement(originalFqn, scopeHolder);
128+
return;
129+
}
130+
PhpAliasImporter.insertUseStatement(originalFqn, name, scopeHolder);
131+
}
132+
133+
private static class PhpClassReferenceRenamer extends PhpClassReferenceExtractor {
134+
private final Project myProject;
135+
private final Map<String, String> myRefToRename;
136+
137+
private PhpClassReferenceRenamer(Project project, @NotNull Map<String, String> replaceWithFqn) {
138+
super();
139+
this.myProject = project;
140+
this.myRefToRename = replaceWithFqn;
141+
}
142+
143+
protected void processReference(@NotNull String name, @NotNull String reference, @NotNull PsiElement identifier) {
144+
if (this.myRefToRename.containsKey(name)) {
145+
String fqn = this.myRefToRename.get(name);
146+
Object newReference;
147+
PsiElement oldReference;
148+
if (!PhpPsiUtil.isOfType(identifier, PhpTokenTypes.IDENTIFIER) && !(identifier instanceof ClassReference)) {
149+
newReference = PhpPsiElementFactory.createPhpDocType(this.myProject, fqn);
150+
oldReference = PhpPsiUtil.getParentByCondition(identifier, false, PhpDocType.INSTANCEOF, PhpDocComment.INSTANCEOF);
151+
} else {
152+
newReference = PhpPsiElementFactory.createClassReference(this.myProject, fqn);
153+
oldReference = PhpPsiUtil.getParentByCondition(identifier, false, ClassReference.INSTANCEOF, Statement.INSTANCEOF);
154+
}
155+
156+
assert oldReference != null;
157+
158+
PsiElement added = oldReference.addRange(((PsiElement)newReference).getFirstChild(), ((PsiElement)newReference).getLastChild());
159+
oldReference.deleteChildRange(oldReference.getFirstChild(), added.getPrevSibling());
160+
}
161+
}
162+
}
163+
}
164+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
package com.magento.idea.magento2plugin.actions.generation.ImportReferences;
6+
7+
import com.intellij.psi.PsiElement;
8+
import com.jetbrains.php.refactoring.importReferences.PhpClassReferenceExtractor;
9+
import gnu.trove.THashMap;
10+
import java.util.Map;
11+
import java.util.Set;
12+
import org.jetbrains.annotations.NotNull;
13+
import org.jetbrains.annotations.Nullable;
14+
15+
public class PhpClassReferenceStorage extends PhpClassReferenceExtractor {
16+
private final Map<String, String> myReferences = new THashMap();
17+
18+
public PhpClassReferenceStorage() {
19+
}
20+
21+
protected void processReference(@NotNull String name, @NotNull String fqn, @NotNull PsiElement identifier) {
22+
this.myReferences.put(name, fqn);
23+
}
24+
25+
@Nullable
26+
public String getFqnByName(@NotNull String name) {
27+
return this.myReferences.get(name);
28+
}
29+
30+
public Set<String> getNames() {
31+
return this.myReferences.keySet();
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
package com.magento.idea.magento2plugin.actions.generation;
6+
7+
import com.intellij.codeInsight.CodeInsightActionHandler;
8+
import com.intellij.codeInsight.actions.CodeInsightAction;
9+
import com.intellij.openapi.editor.Editor;
10+
import com.intellij.openapi.project.Project;
11+
import com.intellij.openapi.util.Key;
12+
import com.intellij.psi.PsiFile;
13+
import com.jetbrains.php.lang.psi.elements.Method;
14+
import com.jetbrains.php.lang.psi.elements.PhpClass;
15+
import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginMethodData;
16+
import com.magento.idea.magento2plugin.actions.generation.generator.MagentoPluginMethodsGenerator;
17+
import org.jetbrains.annotations.NotNull;
18+
19+
public class MagentoGenerateAfterMethodAction extends CodeInsightAction {
20+
public static final String MAGENTO_PLUGIN_AFTER_METHOD_TEMPLATE_NAME = "Magento Plugin After Method";
21+
22+
private final MagentoGeneratePluginMethodHandlerBase myHandler = new MagentoGeneratePluginMethodHandlerBase(MagentoPluginMethodData.Type.AFTER) {
23+
protected MagentoPluginMethodData[] createPluginMethods(PhpClass currentClass, Method method, Key<Object> targetClassKey) {
24+
return (new MagentoPluginMethodsGenerator(currentClass, method, targetClassKey)
25+
.createPluginMethods(MAGENTO_PLUGIN_AFTER_METHOD_TEMPLATE_NAME, MagentoPluginMethodData.Type.AFTER));
26+
}
27+
};
28+
29+
protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
30+
return this.myHandler.isValidFor(editor, file);
31+
}
32+
33+
@NotNull
34+
protected CodeInsightActionHandler getHandler() {
35+
return this.myHandler;
36+
}
37+
}

0 commit comments

Comments
 (0)