diff --git a/CHANGELOG.md b/CHANGELOG.md index 258ba6980..9b7c06c2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,12 @@ * "Go to GraphQL resolver class" line marke in scope of GraphQL schema type arguments * RequireJS mapping support (reference navigation, completion) * Plugin class methods generation - * Plugin declaration inspection in scope of Plugin Class + * Plugin declaration inspection in scope of a Plugin Class * MFTF support (reference navigation, completion) * Fixed support of 2020.* versions of IDE's * Create a New Magento 2 Module action * Code Inspection: Duplicated Observer Usage in events XML + * Create a Plugin class for a class public method action 0.3.0 ============= diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index 10b1a6b8f..b1dc4920a 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -40,15 +40,15 @@ @@ -57,7 +57,9 @@ - + + + @@ -120,6 +122,7 @@ + diff --git a/resources/fileTemplates/code/Magento Module DI Xml Plugin.xml.ft b/resources/fileTemplates/code/Magento Module DI Xml Plugin.xml.ft new file mode 100644 index 000000000..062b13b67 --- /dev/null +++ b/resources/fileTemplates/code/Magento Module DI Xml Plugin.xml.ft @@ -0,0 +1,8 @@ +#if (${TYPE}) + +#end + +#if (${TYPE}) + +#end \ No newline at end of file diff --git a/resources/fileTemplates/code/Magento Module DI Xml Plugin.xml.html b/resources/fileTemplates/code/Magento Module DI Xml Plugin.xml.html new file mode 100644 index 000000000..078962598 --- /dev/null +++ b/resources/fileTemplates/code/Magento Module DI Xml Plugin.xml.html @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/resources/fileTemplates/code/Magento Plugin After Method.php.html b/resources/fileTemplates/code/Magento Plugin After Method.php.html index 441ec06bf..c9772c943 100644 --- a/resources/fileTemplates/code/Magento Plugin After Method.php.html +++ b/resources/fileTemplates/code/Magento Plugin After Method.php.html @@ -1,3 +1,9 @@ + diff --git a/resources/fileTemplates/code/Magento Plugin Around Method.php.html b/resources/fileTemplates/code/Magento Plugin Around Method.php.html index 6fce54b9c..a5ab1d7cf 100644 --- a/resources/fileTemplates/code/Magento Plugin Around Method.php.html +++ b/resources/fileTemplates/code/Magento Plugin Around Method.php.html @@ -1,3 +1,9 @@ +
diff --git a/resources/fileTemplates/code/Magento Plugin Before Method.php.html b/resources/fileTemplates/code/Magento Plugin Before Method.php.html index d3536bbb7..e09fede85 100644 --- a/resources/fileTemplates/code/Magento Plugin Before Method.php.html +++ b/resources/fileTemplates/code/Magento Plugin Before Method.php.html @@ -1,3 +1,9 @@ +
diff --git a/resources/fileTemplates/internal/Magento Module DI Xml.xml.ft b/resources/fileTemplates/internal/Magento Module DI Xml.xml.ft new file mode 100644 index 000000000..5de0638f6 --- /dev/null +++ b/resources/fileTemplates/internal/Magento Module DI Xml.xml.ft @@ -0,0 +1,3 @@ + + + diff --git a/resources/inspectionDescriptions/PluginInspection.html b/resources/inspectionDescriptions/PluginInspection.html index e51e3d4fd..e4ec88c5a 100644 --- a/resources/inspectionDescriptions/PluginInspection.html +++ b/resources/inspectionDescriptions/PluginInspection.html @@ -1,3 +1,9 @@ +

Plugins can not be used with the following:

diff --git a/src/com/magento/idea/magento2plugin/actions/generation/CreateAPluginAction.java b/src/com/magento/idea/magento2plugin/actions/generation/CreateAPluginAction.java new file mode 100644 index 000000000..380ef26f9 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/CreateAPluginAction.java @@ -0,0 +1,105 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.editor.Caret; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.jetbrains.php.lang.psi.PhpFile; +import com.jetbrains.php.lang.psi.elements.Method; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import com.magento.idea.magento2plugin.MagentoIcons; +import com.magento.idea.magento2plugin.actions.generation.dialog.CreateAPluginDialog; +import com.magento.idea.magento2plugin.util.GetFirstClassOfFile; +import com.magento.idea.magento2plugin.util.magento.plugin.IsPluginAllowedForMethod; +import org.jetbrains.annotations.NotNull; +import com.magento.idea.magento2plugin.project.Settings; + +public class CreateAPluginAction extends DumbAwareAction { + public static String ACTION_NAME = "Create A Plugin..."; + public static String ACTION_DESCRIPTION = "Create a new Magento 2 plugin for the class"; + private final IsPluginAllowedForMethod isPluginAllowed; + private final GetFirstClassOfFile getFirstClassOfFile; + private Method targetMethod; + private PhpClass targetClass; + + public CreateAPluginAction() { + super(ACTION_NAME, ACTION_DESCRIPTION, MagentoIcons.MODULE); + this.isPluginAllowed = IsPluginAllowedForMethod.getInstance(); + this.getFirstClassOfFile = GetFirstClassOfFile.getInstance(); + } + + public void update(AnActionEvent event) { + targetClass = null; + targetMethod = null; + Project project = event.getData(PlatformDataKeys.PROJECT); + if (Settings.isEnabled(project)) { + Pair pair = this.findPhpClass(event); + PsiFile psiFile = pair.getFirst(); + PhpClass phpClass = pair.getSecond(); + targetClass = phpClass; + if (!(psiFile instanceof PhpFile) || phpClass.isFinal() || this.targetMethod == null) { + this.setStatus(event, false); + return; + } + } else { + this.setStatus(event, false); + return; + } + this.setStatus(event, true); + } + + private void setStatus(AnActionEvent event, boolean status) { + event.getPresentation().setVisible(status); + event.getPresentation().setEnabled(status); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + CreateAPluginDialog.open(e.getProject(), this.targetMethod, this.targetClass); + } + + @Override + public boolean isDumbAware() { + return false; + } + + private Pair findPhpClass(@NotNull AnActionEvent event) { + PsiFile psiFile = event.getData(PlatformDataKeys.PSI_FILE); + + PhpClass phpClass = null; + if (psiFile instanceof PhpFile) { + phpClass = getFirstClassOfFile.execute((PhpFile) psiFile); + fetchTargetMethod(event, psiFile, phpClass); + } + + return Pair.create(psiFile, phpClass); + } + + private void fetchTargetMethod(@NotNull AnActionEvent event, PsiFile psiFile, PhpClass phpClass) { + Caret caret = event.getData(PlatformDataKeys.CARET); + if (caret == null) { + return; + } + int offset = caret.getOffset(); + PsiElement element = psiFile.findElementAt(offset); + if (element == null) { + return; + } + if (element instanceof Method && element.getParent() == phpClass && isPluginAllowed.check((Method)element)) { + this.targetMethod = (Method)element; + return; + } + PsiElement parent = element.getParent(); + if (parent instanceof Method && parent.getParent() == phpClass && isPluginAllowed.check((Method)parent)) { + this.targetMethod = (Method)parent; + } + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/MagentoGenerateAroundMethodAction.java b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateAfterMethodAction.java similarity index 73% rename from src/com/magento/idea/magento2plugin/actions/generation/MagentoGenerateAroundMethodAction.java rename to src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateAfterMethodAction.java index 948a250a6..0e5288952 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/MagentoGenerateAroundMethodAction.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateAfterMethodAction.java @@ -14,15 +14,14 @@ import com.jetbrains.php.lang.psi.elements.PhpClass; import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginMethodData; import com.magento.idea.magento2plugin.actions.generation.generator.MagentoPluginMethodsGenerator; +import com.magento.idea.magento2plugin.magento.files.Plugin; import org.jetbrains.annotations.NotNull; -public class MagentoGenerateAroundMethodAction extends CodeInsightAction { - public static final String MAGENTO_PLUGIN_AROUND_METHOD_TEMPLATE_NAME = "Magento Plugin Around Method"; - - private final MagentoGeneratePluginMethodHandlerBase myHandler = new MagentoGeneratePluginMethodHandlerBase(MagentoPluginMethodData.Type.AROUND) { +public class PluginGenerateAfterMethodAction extends CodeInsightAction { + private final PluginGeneratePluginMethodHandlerBase myHandler = new PluginGeneratePluginMethodHandlerBase(Plugin.PluginType.after) { protected MagentoPluginMethodData[] createPluginMethods(PhpClass currentClass, Method method, Key targetClassKey) { return (new MagentoPluginMethodsGenerator(currentClass, method, targetClassKey) - .createPluginMethods(MAGENTO_PLUGIN_AROUND_METHOD_TEMPLATE_NAME, MagentoPluginMethodData.Type.AROUND)); + .createPluginMethods(Plugin.PluginType.after)); } }; diff --git a/src/com/magento/idea/magento2plugin/actions/generation/MagentoGenerateAfterMethodAction.java b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateAroundMethodAction.java similarity index 74% rename from src/com/magento/idea/magento2plugin/actions/generation/MagentoGenerateAfterMethodAction.java rename to src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateAroundMethodAction.java index 335c42cff..52042c359 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/MagentoGenerateAfterMethodAction.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateAroundMethodAction.java @@ -14,15 +14,14 @@ import com.jetbrains.php.lang.psi.elements.PhpClass; import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginMethodData; import com.magento.idea.magento2plugin.actions.generation.generator.MagentoPluginMethodsGenerator; +import com.magento.idea.magento2plugin.magento.files.Plugin; import org.jetbrains.annotations.NotNull; -public class MagentoGenerateAfterMethodAction extends CodeInsightAction { - public static final String MAGENTO_PLUGIN_AFTER_METHOD_TEMPLATE_NAME = "Magento Plugin After Method"; - - private final MagentoGeneratePluginMethodHandlerBase myHandler = new MagentoGeneratePluginMethodHandlerBase(MagentoPluginMethodData.Type.AFTER) { +public class PluginGenerateAroundMethodAction extends CodeInsightAction { + private final PluginGeneratePluginMethodHandlerBase myHandler = new PluginGeneratePluginMethodHandlerBase(Plugin.PluginType.around) { protected MagentoPluginMethodData[] createPluginMethods(PhpClass currentClass, Method method, Key targetClassKey) { return (new MagentoPluginMethodsGenerator(currentClass, method, targetClassKey) - .createPluginMethods(MAGENTO_PLUGIN_AFTER_METHOD_TEMPLATE_NAME, MagentoPluginMethodData.Type.AFTER)); + .createPluginMethods(Plugin.PluginType.around)); } }; diff --git a/src/com/magento/idea/magento2plugin/actions/generation/MagentoGenerateBeforeMethodAction.java b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateBeforeMethodAction.java similarity index 73% rename from src/com/magento/idea/magento2plugin/actions/generation/MagentoGenerateBeforeMethodAction.java rename to src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateBeforeMethodAction.java index 221e0ebca..e38faa8c4 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/MagentoGenerateBeforeMethodAction.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateBeforeMethodAction.java @@ -13,16 +13,15 @@ import com.jetbrains.php.lang.psi.elements.PhpClass; import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginMethodData; import com.magento.idea.magento2plugin.actions.generation.generator.MagentoPluginMethodsGenerator; +import com.magento.idea.magento2plugin.magento.files.Plugin; import org.jetbrains.annotations.NotNull; import com.intellij.openapi.util.Key; -public class MagentoGenerateBeforeMethodAction extends CodeInsightAction { - public static final String MAGENTO_PLUGIN_BEFORE_METHOD_TEMPLATE_NAME = "Magento Plugin Before Method"; - - private final MagentoGeneratePluginMethodHandlerBase myHandler = new MagentoGeneratePluginMethodHandlerBase(MagentoPluginMethodData.Type.BEFORE) { +public class PluginGenerateBeforeMethodAction extends CodeInsightAction { + private final PluginGeneratePluginMethodHandlerBase myHandler = new PluginGeneratePluginMethodHandlerBase(Plugin.PluginType.before) { protected MagentoPluginMethodData[] createPluginMethods(PhpClass currentClass, Method method, Key targetClassKey) { return (new MagentoPluginMethodsGenerator(currentClass, method, targetClassKey) - .createPluginMethods(MAGENTO_PLUGIN_BEFORE_METHOD_TEMPLATE_NAME, MagentoPluginMethodData.Type.BEFORE)); + .createPluginMethods(Plugin.PluginType.before)); } }; diff --git a/src/com/magento/idea/magento2plugin/actions/generation/MagentoGeneratePluginMethodHandlerBase.java b/src/com/magento/idea/magento2plugin/actions/generation/PluginGeneratePluginMethodHandlerBase.java similarity index 67% rename from src/com/magento/idea/magento2plugin/actions/generation/MagentoGeneratePluginMethodHandlerBase.java rename to src/com/magento/idea/magento2plugin/actions/generation/PluginGeneratePluginMethodHandlerBase.java index d3d37ace0..50fdbfba1 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/MagentoGeneratePluginMethodHandlerBase.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/PluginGeneratePluginMethodHandlerBase.java @@ -4,7 +4,6 @@ */ package com.magento.idea.magento2plugin.actions.generation; -import com.intellij.application.options.CodeStyle; import com.intellij.codeInsight.hint.HintManager; import com.intellij.ide.util.MemberChooser; import com.intellij.lang.LanguageCodeInsightActionHandler; @@ -16,14 +15,10 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.tree.IElementType; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.php.codeInsight.PhpCodeInsightUtil; -import com.jetbrains.php.lang.PhpLangUtil; -import com.jetbrains.php.lang.PhpLanguage; import com.jetbrains.php.lang.actions.PhpNamedElementNode; -import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment; import com.jetbrains.php.lang.lexer.PhpTokenTypes; import com.jetbrains.php.lang.parser.PhpElementTypes; import com.jetbrains.php.lang.parser.PhpStubElementTypes; @@ -34,17 +29,27 @@ import java.util.*; import com.magento.idea.magento2plugin.actions.generation.ImportReferences.PhpClassReferenceResolver; import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginMethodData; +import com.magento.idea.magento2plugin.actions.generation.generator.MagentoPluginMethodsGenerator; +import com.magento.idea.magento2plugin.actions.generation.util.CodeStyleSettings; +import com.magento.idea.magento2plugin.actions.generation.util.CollectInsertedMethods; +import com.magento.idea.magento2plugin.actions.generation.util.FillTextBufferWithPluginMethods; +import com.magento.idea.magento2plugin.magento.files.Plugin; import com.magento.idea.magento2plugin.util.GetPhpClassByFQN; import com.magento.idea.magento2plugin.util.magento.plugin.GetTargetClassNamesByPluginClassName; +import com.magento.idea.magento2plugin.util.magento.plugin.IsPluginAllowedForMethod; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public abstract class MagentoGeneratePluginMethodHandlerBase implements LanguageCodeInsightActionHandler { +public abstract class PluginGeneratePluginMethodHandlerBase implements LanguageCodeInsightActionHandler { + private CollectInsertedMethods collectInsertedMethods; public String type; + public FillTextBufferWithPluginMethods fillTextBuffer; - public MagentoGeneratePluginMethodHandlerBase(MagentoPluginMethodData.Type type) { + public PluginGeneratePluginMethodHandlerBase(Plugin.PluginType type) { this.type = type.toString(); + this.fillTextBuffer = FillTextBufferWithPluginMethods.getInstance(); + this.collectInsertedMethods = CollectInsertedMethods.getInstance(); } public boolean isValidFor(Editor editor, PsiFile file) { @@ -61,14 +66,14 @@ public boolean isValidFor(Editor editor, PsiFile file) { return !targetClassNames.isEmpty(); } - public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { - PhpFile phpFile = (PhpFile)file; - PhpClass currentClass = PhpCodeEditUtil.findClassAtCaret(editor, phpFile); - Key targetClassKey = Key.create("original.target"); - if (currentClass == null) { + public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile pluginFile) { + PhpFile pluginPhpFile = (PhpFile)pluginFile; + PhpClass pluginClass = PhpCodeEditUtil.findClassAtCaret(editor, pluginPhpFile); + Key targetClassKey = Key.create(MagentoPluginMethodsGenerator.originalTargetKey); + if (pluginClass == null) { return; } - PhpNamedElementNode[] fieldsToShow = this.targetMethods(currentClass, targetClassKey); + PhpNamedElementNode[] fieldsToShow = this.targetMethods(pluginClass, targetClassKey); if (fieldsToShow.length == 0) { if (ApplicationManager.getApplication().isHeadlessEnvironment()) { return; @@ -76,83 +81,43 @@ public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull Ps HintManager.getInstance().showErrorHint(editor, this.getErrorMessage()); return; } - PhpNamedElementNode[] members = this.chooseMembers(fieldsToShow, true, file.getProject()); + PhpNamedElementNode[] members = this.chooseMembers(fieldsToShow, true, pluginFile.getProject()); if (members == null || members.length == 0) { return; } - int insertPos = getSuitableEditorPosition(editor, phpFile); - CommonCodeStyleSettings settings = CodeStyle.getLanguageSettings(file, PhpLanguage.INSTANCE); - boolean currLineBreaks = settings.KEEP_LINE_BREAKS; - int currBlankLines = settings.KEEP_BLANK_LINES_IN_CODE; - settings.KEEP_LINE_BREAKS = false; - settings.KEEP_BLANK_LINES_IN_CODE = 0; + int insertPos = getSuitableEditorPosition(editor, pluginPhpFile); + + CodeStyleSettings codeStyleSettings = new CodeStyleSettings(pluginPhpFile); + codeStyleSettings.adjustBeforeWrite(); ApplicationManager.getApplication().runWriteAction(() -> { Set insertedMethodsNames = new THashSet(); PhpClassReferenceResolver resolver = new PhpClassReferenceResolver(); StringBuffer textBuf = new StringBuffer(); - PhpPsiElement scope = PhpCodeInsightUtil.findScopeForUseOperator(currentClass); + PhpPsiElement scope = PhpCodeInsightUtil.findScopeForUseOperator(pluginClass); for (PhpNamedElementNode member : members) { PsiElement method = member.getPsiElement(); - MagentoPluginMethodData[] pluginMethods = this.createPluginMethods(currentClass, (Method) method, targetClassKey); - for (MagentoPluginMethodData pluginMethod : pluginMethods) { - insertedMethodsNames.add(pluginMethod.getMethod().getName()); - PhpDocComment comment = pluginMethod.getDocComment(); - if (comment != null) { - textBuf.append(comment.getText()); - } - Method targetMethod = pluginMethod.getTargetMethod(); - Parameter[] parameters = targetMethod.getParameters(); - Collection processElements = new ArrayList<>(Arrays.asList(parameters)); - resolver.processElements(processElements); - PsiElement targetClass = (PsiElement) pluginMethod.getTargetMethod().getUserData(targetClassKey); - resolver.processElement(targetClass); - PhpReturnType returnType = targetMethod.getReturnType(); - if (returnType != null) { - resolver.processElement(returnType); - } - - textBuf.append('\n'); - textBuf.append(pluginMethod.getMethod().getText()); - } + MagentoPluginMethodData[] pluginMethods = this.createPluginMethods(pluginClass, (Method) method, targetClassKey); + fillTextBuffer.execute(targetClassKey, insertedMethodsNames, resolver, textBuf, pluginMethods); } - if (textBuf.length() > 0 && insertPos >= 0) { - editor.getDocument().insertString(insertPos, textBuf); - int endPos = insertPos + textBuf.length(); - CodeStyleManager.getInstance(project).reformatText(phpFile, insertPos, endPos); - PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); - } - if (!insertedMethodsNames.isEmpty()) { - List insertedMethods = collectInsertedMethods(file, currentClass.getNameCS(), insertedMethodsNames); - if (scope != null && insertedMethods != null) { - resolver.importReferences(scope, insertedMethods); - } - } + insertPluginMethodsToFile(project, editor, pluginFile, pluginClass, insertPos, insertedMethodsNames, resolver, textBuf, scope); }); - settings.KEEP_LINE_BREAKS = currLineBreaks; - settings.KEEP_BLANK_LINES_IN_CODE = currBlankLines; + codeStyleSettings.restore(); } - @Nullable - private static List collectInsertedMethods(@NotNull PsiFile file, @NotNull CharSequence className, @NotNull Set methodNames) { - if (!(file instanceof PhpFile)) { - return null; + private void insertPluginMethodsToFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile pluginFile, PhpClass pluginClass, int insertPos, Set insertedMethodsNames, PhpClassReferenceResolver resolver, StringBuffer textBuf, PhpPsiElement scope) { + if (textBuf.length() > 0 && insertPos >= 0) { + editor.getDocument().insertString(insertPos, textBuf); + int endPos = insertPos + textBuf.length(); + CodeStyleManager.getInstance(project).reformatText(pluginFile, insertPos, endPos); + PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); } - PhpClass phpClass = PhpPsiUtil.findClass((PhpFile) file, (aClass) -> PhpLangUtil.equalsClassNames(aClass.getNameCS(), className)); - if (phpClass == null) { - return null; - } else { - List insertedMethods = new ArrayList(); - Method[] ownMethods = phpClass.getOwnMethods(); - - for (Method method : ownMethods) { - if (methodNames.contains(method.getNameCS())) { - insertedMethods.add(method); - } + if (!insertedMethodsNames.isEmpty()) { + List insertedMethods = collectInsertedMethods.execute(pluginFile, pluginClass.getNameCS(), insertedMethodsNames); + if (scope != null && insertedMethods != null) { + resolver.importReferences(scope, insertedMethods); } - - return insertedMethods; } } @@ -170,7 +135,7 @@ public boolean startInWriteAction() { protected PhpNamedElementNode[] chooseMembers(PhpNamedElementNode[] members, boolean allowEmptySelection, Project project) { PhpNamedElementNode[] nodes = fixOrderToBeAsOriginalFiles(members).toArray(new PhpNamedElementNode[members.length]); if (!ApplicationManager.getApplication().isHeadlessEnvironment()) { - MagentoGeneratePluginMethodHandlerBase.MyMemberChooser chooser = new MagentoGeneratePluginMethodHandlerBase.MyMemberChooser(nodes, allowEmptySelection, project); + PluginGeneratePluginMethodHandlerBase.MyMemberChooser chooser = new PluginGeneratePluginMethodHandlerBase.MyMemberChooser(nodes, allowEmptySelection, project); chooser.setTitle("Choose Methods"); chooser.setCopyJavadocVisible(false); chooser.show(); @@ -198,7 +163,7 @@ protected PhpNamedElementNode[] targetMethods(@NotNull PhpClass phpClass, Key currentMethods = currentClass.getMethods(); String methodName = method.getName(); - String methodPrefix = type.toLowerCase(); + String methodPrefix = type; String methodSuffix = methodName.substring(0, 1).toUpperCase() + methodName.substring(1); String pluginMethodName = methodPrefix.concat(methodSuffix); for (Method currentMethod: currentMethods) { diff --git a/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginDiXmlData.java b/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginDiXmlData.java new file mode 100644 index 000000000..e7a8318c4 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginDiXmlData.java @@ -0,0 +1,56 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.data; + +import com.jetbrains.php.lang.psi.elements.PhpClass; + +public class MagentoPluginDiXmlData { + private String area; + private String pluginModule; + private PhpClass targetClass; + private final String sortOrder; + private final String pluginName; + private String pluginFqn; + + public MagentoPluginDiXmlData( + String area, + String pluginModule, + PhpClass targetClass, + String sortOrder, + String pluginName, + String pluginFqn + ) { + this.area = area; + this.pluginModule = pluginModule; + this.targetClass = targetClass; + this.sortOrder = sortOrder; + this.pluginName = pluginName; + this.pluginFqn = pluginFqn; + } + + public String getArea() { + return area; + } + + public String getPluginModule() { + return pluginModule; + } + + public PhpClass getTargetClass() { + return targetClass; + } + + public String getPluginName() { + return pluginName; + } + + public String getSortOrder() { + return sortOrder; + } + + public String getPluginFqn() { + return pluginFqn; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginFileData.java b/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginFileData.java new file mode 100644 index 000000000..6efa9ac3b --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginFileData.java @@ -0,0 +1,71 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.data; + +import com.jetbrains.php.lang.psi.elements.Method; +import com.jetbrains.php.lang.psi.elements.PhpClass; + +public class MagentoPluginFileData { + private String pluginDirectory; + private String pluginClassName; + private String pluginType; + private String pluginModule; + private PhpClass targetClass; + private Method targetMethod; + private String pluginFqn; + private String namespace; + + public MagentoPluginFileData( + String pluginDirectory, + String pluginClassName, + String pluginType, + String pluginModule, + PhpClass targetClass, + Method targetMethod, + String pluginFqn, + String namespace + ) { + this.pluginDirectory = pluginDirectory; + this.pluginClassName = pluginClassName; + this.pluginType = pluginType; + this.pluginModule = pluginModule; + this.targetClass = targetClass; + this.targetMethod = targetMethod; + this.pluginFqn = pluginFqn; + this.namespace = namespace; + } + + public String getPluginClassName() { + return pluginClassName; + } + + public String getPluginDirectory() { + return pluginDirectory; + } + + public String getPluginType() { + return pluginType; + } + + public String getPluginModule() { + return pluginModule; + } + + public PhpClass getTargetClass() { + return targetClass; + } + + public Method getTargetMethod() { + return targetMethod; + } + + public String getPluginFqn() { + return pluginFqn; + } + + public String getNamespace() { + return namespace; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginMethodData.java b/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginMethodData.java index 03af87f53..8e945b7f7 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginMethodData.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/data/MagentoPluginMethodData.java @@ -6,23 +6,17 @@ import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment; import com.jetbrains.php.lang.psi.elements.Method; -import com.jetbrains.php.lang.psi.elements.PhpClass; -import org.jetbrains.annotations.NotNull; public class MagentoPluginMethodData { - private final PhpClass pluginClass; private final PhpDocComment docComment; private final Method method; private final Method targetMethod; - private final MagentoPluginMethodData.Type pluginType; - public MagentoPluginMethodData(Method targetMethod, PhpClass pluginClass, PhpDocComment docComment, Method method, @NotNull MagentoPluginMethodData.Type pluginType) { + public MagentoPluginMethodData(Method targetMethod, PhpDocComment docComment, Method method) { super(); - this.pluginClass = pluginClass; this.docComment = docComment; this.method = method; this.targetMethod = targetMethod; - this.pluginType = pluginType; } public PhpDocComment getDocComment() { @@ -33,24 +27,7 @@ public Method getMethod() { return this.method; } - public PhpClass getPluginClass() { - return this.pluginClass; - } - public Method getTargetMethod() { return this.targetMethod; } - - public Type getPluginType() { - return pluginType; - } - - public static enum Type { - AROUND, - AFTER, - BEFORE; - - private Type() { - } - } } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/CreateAPluginDialog.form b/src/com/magento/idea/magento2plugin/actions/generation/dialog/CreateAPluginDialog.form new file mode 100644 index 000000000..ea05d6de4 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/CreateAPluginDialog.form @@ -0,0 +1,199 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/CreateAPluginDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/CreateAPluginDialog.java new file mode 100644 index 000000000..d21ed0f43 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/CreateAPluginDialog.java @@ -0,0 +1,188 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.dialog; + +import com.intellij.openapi.project.Project; +import com.jetbrains.php.lang.psi.elements.Method; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginDiXmlData; +import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginFileData; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.CreateAPluginDialogValidator; +import com.magento.idea.magento2plugin.actions.generation.generator.MagentoPluginClassGenerator; +import com.magento.idea.magento2plugin.actions.generation.generator.MagentoPluginDiXmlGenerator; +import com.magento.idea.magento2plugin.indexes.ModuleIndex; +import com.magento.idea.magento2plugin.magento.files.Plugin; +import com.magento.idea.magento2plugin.magento.packages.Package; +import com.magento.idea.magento2plugin.ui.FilteredComboBox; +import org.jetbrains.annotations.NotNull; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.io.File; +import java.util.List; + +public class CreateAPluginDialog extends JDialog { + @NotNull + private final Project project; + private Method targetMethod; + private PhpClass targetClass; + @NotNull + private final CreateAPluginDialogValidator validator; + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JTextField pluginClassName; + private JLabel pluginClassNameLabel; + private JTextField pluginDirectory; + private JLabel pluginDirectoryName; + private JLabel selectPluginModule; + private JComboBox pluginType; + private JLabel pluginTypeLabel; + private FilteredComboBox pluginModule; + private JComboBox pluginArea; + private JLabel pluginAreaLabel; + private JTextField pluginName; + private JLabel pluginNameLabel; + private JTextField pluginSortOrder; + private JLabel pluginSortOrderLabel; + + public CreateAPluginDialog(@NotNull Project project, Method targetMethod, PhpClass targetClass) { + this.project = project; + this.targetMethod = targetMethod; + this.targetClass = targetClass; + this.validator = CreateAPluginDialogValidator.getInstance(this); + + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); + pushToMiddle(); + fillPluginTypeOptions(); + fillTargetAreaOptions(); + + buttonOK.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onOK(); + } + }); + + buttonCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }); + + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + contentPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + } + + private void fillPluginTypeOptions() { + for (Plugin.PluginType pluginPrefixType: Plugin.PluginType.values()) { + pluginType.addItem(pluginPrefixType.toString()); + } + } + + private void fillTargetAreaOptions() { + for(Package.Areas area: Package.Areas.values()) { + pluginArea.addItem(area.toString()); + } + } + + private void pushToMiddle() { + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + this.setLocation(dim.width / 2 -this.getSize().width / 2, dim.height / 2 - this.getSize().height / 2); + } + + private void onOK() { + if (!validator.validate(project)) { + return; + } + new MagentoPluginClassGenerator(new MagentoPluginFileData( + getPluginDirectory(), + getPluginClassName(), + getPluginType(), + getPluginModule(), + targetClass, + targetMethod, + getPluginClassFqn(), + getNamespace() + ), project).generate(); + + new MagentoPluginDiXmlGenerator(new MagentoPluginDiXmlData( + getPluginArea(), + getPluginModule(), + targetClass, + getPluginSortOrder(), + getPluginName(), + getPluginClassFqn() + ), project).generate(); + + this.setVisible(false); + } + + public String getPluginName() { + return this.pluginName.getText().trim(); + } + + public String getPluginSortOrder() { + return this.pluginSortOrder.getText().trim(); + } + + public String getPluginClassName() { + return this.pluginClassName.getText().trim(); + } + + public String getPluginDirectory() { + return this.pluginDirectory.getText().trim(); + } + + public String getPluginArea() { + return this.pluginArea.getSelectedItem().toString(); + } + + public String getPluginType() { + return this.pluginType.getSelectedItem().toString(); + } + + public String getPluginModule() { + return this.pluginModule.getSelectedItem().toString(); + } + + private void onCancel() { + this.setVisible(false); + } + + public static void open(@NotNull Project project, Method targetMethod, PhpClass targetClass) { + CreateAPluginDialog dialog = new CreateAPluginDialog(project, targetMethod, targetClass); + dialog.pack(); + dialog.setVisible(true); + } + + private void createUIComponents() { + List allModulesList = ModuleIndex.getInstance(project).getEditableModuleNames(); + + this.pluginModule = new FilteredComboBox(allModulesList); + } + + private String getNamespace() { + String targetModule = getPluginModule(); + String namespace = targetModule.replace(Package.VENDOR_MODULE_NAME_SEPARATOR, Package.FQN_SEPARATOR); + namespace = namespace.concat(Package.FQN_SEPARATOR); + return namespace.concat(getPluginDirectory().replace(File.separator, Package.FQN_SEPARATOR)); + } + + private String getPluginClassFqn() { + return getNamespace().concat(Package.FQN_SEPARATOR).concat(getPluginClassName()); + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.java index fa3cdd74d..a27593fe0 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.java @@ -11,13 +11,14 @@ import com.intellij.psi.PsiFile; import com.magento.idea.magento2plugin.actions.generation.NewModuleAction; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.NewMagentoModuleDialogValidator; -import com.magento.idea.magento2plugin.actions.generation.generator.DirectoryGenerator; -import com.magento.idea.magento2plugin.actions.generation.generator.FileFromTemplateGenerator; +import com.magento.idea.magento2plugin.actions.generation.generator.util.DirectoryGenerator; +import com.magento.idea.magento2plugin.actions.generation.generator.util.FileFromTemplateGenerator; import com.magento.idea.magento2plugin.actions.generation.generator.data.ModuleDirectoriesData; +import com.magento.idea.magento2plugin.actions.generation.util.NavigateToCreatedFile; import com.magento.idea.magento2plugin.magento.files.ComposerJson; import com.magento.idea.magento2plugin.magento.files.ModuleXml; import com.magento.idea.magento2plugin.magento.files.RegistrationPhp; -import com.magento.idea.magento2plugin.magento.packages.MagentoPackages; +import com.magento.idea.magento2plugin.magento.packages.Package; import com.magento.idea.magento2plugin.util.CamelCaseToHyphen; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,6 +42,7 @@ public class NewMagentoModuleDialog extends JDialog { private final FileFromTemplateGenerator fileFromTemplateGenerator; private final NewMagentoModuleDialogValidator validator; private final CamelCaseToHyphen camelCaseToHyphen; + private final NavigateToCreatedFile navigateToCreatedFile; private JPanel contentPane; private JButton buttonOK; private JButton buttonCancel; @@ -64,6 +66,7 @@ public NewMagentoModuleDialog(@NotNull Project project, @NotNull PsiDirectory in this.fileFromTemplateGenerator = FileFromTemplateGenerator.getInstance(project); this.camelCaseToHyphen = CamelCaseToHyphen.getInstance(); this.validator = NewMagentoModuleDialogValidator.getInstance(this); + this.navigateToCreatedFile = NavigateToCreatedFile.getInstance(); detectPackageName(initialBaseDir); setContentPane(contentPane); setModal(true); @@ -98,7 +101,7 @@ public void actionPerformed(ActionEvent e) { private void detectPackageName(@NotNull PsiDirectory initialBaseDir) { PsiDirectory parentDir = initialBaseDir.getParent(); - if (parentDir != null && parentDir.toString().endsWith(MagentoPackages.PACKAGES_ROOT)) { + if (parentDir != null && parentDir.toString().endsWith(Package.PACKAGES_ROOT)) { packageName.setVisible(false); packageNameLabel.setVisible(false); this.detectedPackageName = initialBaseDir.getName(); @@ -130,7 +133,9 @@ private void generateFiles() { if (registrationPhp == null) { return; } - fileFromTemplateGenerator.generate(ModuleXml.getInstance(), attributes, moduleDirectoriesData.getModuleEtcDirectory(), NewModuleAction.ACTION_NAME); + PsiFile moduleXml = fileFromTemplateGenerator.generate(ModuleXml.getInstance(), attributes, moduleDirectoriesData.getModuleEtcDirectory(), NewModuleAction.ACTION_NAME); + + navigateToCreatedFile.navigate(project, moduleXml); } public String getPackageName() { diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/CreateAPluginDialogValidator.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/CreateAPluginDialogValidator.java new file mode 100644 index 000000000..bc70a8cc3 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/CreateAPluginDialogValidator.java @@ -0,0 +1,92 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.dialog.validator; + +import com.intellij.openapi.project.Project; +import com.magento.idea.magento2plugin.actions.generation.dialog.CreateAPluginDialog; +import com.magento.idea.magento2plugin.indexes.ModuleIndex; +import com.magento.idea.magento2plugin.util.Regex; +import javax.swing.*; +import java.util.List; + +public class CreateAPluginDialogValidator { + private static CreateAPluginDialogValidator INSTANCE = null; + private CreateAPluginDialog dialog; + + public static CreateAPluginDialogValidator getInstance(CreateAPluginDialog dialog) { + if (null == INSTANCE) { + INSTANCE = new CreateAPluginDialogValidator(); + } + INSTANCE.dialog = dialog; + return INSTANCE; + } + + public boolean validate(Project project) + { + String errorTitle = "Error"; + String pluginClassName = dialog.getPluginClassName(); + if (pluginClassName.length() == 0) { + JOptionPane.showMessageDialog(null, "Plugin Class Name must not be empty.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (!pluginClassName.matches(Regex.ALPHANUMERIC)) { + JOptionPane.showMessageDialog(null, "Plugin Class Name must contain letters and numbers only.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (!Character.isUpperCase(pluginClassName.charAt(0)) && !Character.isDigit(pluginClassName.charAt(0))) { + JOptionPane.showMessageDialog(null, "Plugin Class Name must start from a number or a capital letter", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + String pluginDirectory = dialog.getPluginDirectory(); + if (pluginDirectory.length() == 0) { + JOptionPane.showMessageDialog(null, "Plugin Directory must not be empty.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (!pluginDirectory.matches(Regex.DIRECTORY)) { + JOptionPane.showMessageDialog(null, "Plugin Directory is not valid.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + String pluginName = dialog.getPluginName(); + if (pluginName.length() == 0) { + JOptionPane.showMessageDialog(null, "Plugin Name must not be empty.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (!pluginName.matches(Regex.IDENTIFIER)) { + JOptionPane.showMessageDialog(null, "Plugin Name must contain letters, numbers, dashes, and underscores only.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + String sortOrder = dialog.getPluginSortOrder(); + if (sortOrder.length() == 0) { + JOptionPane.showMessageDialog(null, "Sort Order must not be empty.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (!sortOrder.matches(Regex.NUMERIC)) { + JOptionPane.showMessageDialog(null, "Sort Order must contain numbers only.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + String pluginModule = dialog.getPluginModule(); + if (pluginModule.length() == 0) { + JOptionPane.showMessageDialog(null, "Plugin Module must not be empty.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + List allModulesList = ModuleIndex.getInstance(project).getEditableModuleNames(); + if (!allModulesList.contains(pluginModule)) { + JOptionPane.showMessageDialog(null, "No such module '".concat(pluginModule).concat("'."), errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + return true; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginClassGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginClassGenerator.java new file mode 100644 index 000000000..b9bfed8c2 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginClassGenerator.java @@ -0,0 +1,181 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.generator; + +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.impl.source.tree.LeafPsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.php.codeInsight.PhpCodeInsightUtil; +import com.jetbrains.php.lang.psi.PhpFile; +import com.jetbrains.php.lang.psi.elements.Method; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import com.jetbrains.php.lang.psi.elements.PhpPsiElement; +import com.magento.idea.magento2plugin.actions.generation.CreateAPluginAction; +import com.magento.idea.magento2plugin.actions.generation.ImportReferences.PhpClassReferenceResolver; +import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginFileData; +import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginMethodData; +import com.magento.idea.magento2plugin.actions.generation.generator.util.DirectoryGenerator; +import com.magento.idea.magento2plugin.actions.generation.generator.util.FileFromTemplateGenerator; +import com.magento.idea.magento2plugin.actions.generation.util.CodeStyleSettings; +import com.magento.idea.magento2plugin.actions.generation.util.CollectInsertedMethods; +import com.magento.idea.magento2plugin.actions.generation.util.FillTextBufferWithPluginMethods; +import com.magento.idea.magento2plugin.actions.generation.util.NavigateToCreatedFile; +import com.magento.idea.magento2plugin.indexes.ModuleIndex; +import com.magento.idea.magento2plugin.magento.files.Plugin; +import com.magento.idea.magento2plugin.magento.packages.MagentoPhpClass; +import com.magento.idea.magento2plugin.util.GetFirstClassOfFile; +import com.magento.idea.magento2plugin.util.GetPhpClassByFQN; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import javax.swing.*; +import java.io.File; +import java.util.Collection; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +public class MagentoPluginClassGenerator { + private final NavigateToCreatedFile navigateToCreatedFile; + private MagentoPluginFileData pluginFileData; + private Project project; + private final FillTextBufferWithPluginMethods fillTextBuffer; + private final CollectInsertedMethods collectInsertedMethods; + private final DirectoryGenerator directoryGenerator; + private final FileFromTemplateGenerator fileFromTemplateGenerator; + private final GetFirstClassOfFile getFirstClassOfFile; + + public MagentoPluginClassGenerator(@NotNull MagentoPluginFileData pluginFileData, Project project) { + this.directoryGenerator = DirectoryGenerator.getInstance(); + this.fileFromTemplateGenerator = FileFromTemplateGenerator.getInstance(project); + this.getFirstClassOfFile = GetFirstClassOfFile.getInstance(); + this.fillTextBuffer = FillTextBufferWithPluginMethods.getInstance(); + this.collectInsertedMethods = CollectInsertedMethods.getInstance(); + this.pluginFileData = pluginFileData; + this.project = project; + this.navigateToCreatedFile = NavigateToCreatedFile.getInstance(); + } + + public void generate() + { + WriteCommandAction.runWriteCommandAction(project, () -> { + PhpClass pluginClass = GetPhpClassByFQN.getInstance(project).execute(pluginFileData.getPluginFqn()); + if (pluginClass == null) { + pluginClass = createPluginClass(); + } + if (pluginClass == null) { + JOptionPane.showMessageDialog(null, "Plugin Class cant be created!", "Error", JOptionPane.ERROR_MESSAGE); + return; + } + + Key targetClassKey = Key.create(MagentoPluginMethodsGenerator.originalTargetKey); + Method targetMethod = pluginFileData.getTargetMethod(); + targetMethod.putUserData(targetClassKey, pluginFileData.getTargetClass()); + MagentoPluginMethodsGenerator pluginGenerator = new MagentoPluginMethodsGenerator(pluginClass, targetMethod, targetClassKey); + + MagentoPluginMethodData[] pluginMethodData = pluginGenerator.createPluginMethods(getPluginType()); + if (checkIfMethodExist(pluginClass, pluginMethodData)){ + JOptionPane.showMessageDialog(null, "Plugin method already exist!", "Error", JOptionPane.ERROR_MESSAGE); + return; + } + + Set insertedMethodsNames = new THashSet(); + PhpClassReferenceResolver resolver = new PhpClassReferenceResolver(); + StringBuffer textBuf = new StringBuffer(); + + fillTextBuffer.execute(targetClassKey, insertedMethodsNames, resolver, textBuf, pluginMethodData); + + PsiFile pluginFile = pluginClass.getContainingFile(); + CodeStyleSettings codeStyleSettings = new CodeStyleSettings((PhpFile) pluginFile); + codeStyleSettings.adjustBeforeWrite(); + + int insertPos = getInsertPos(pluginClass); + PhpPsiElement scope = PhpCodeInsightUtil.findScopeForUseOperator(pluginClass); + + if (textBuf.length() > 0 && insertPos >= 0) { + PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project); + Document document = psiDocumentManager.getDocument(pluginFile); + document.insertString(insertPos, textBuf); + int endPos = insertPos + textBuf.length() + 1; + CodeStyleManager.getInstance(project).reformatText(pluginFile, insertPos, endPos); + psiDocumentManager.commitDocument(document); + } + if (!insertedMethodsNames.isEmpty()) { + List insertedMethods = collectInsertedMethods.execute(pluginFile, pluginClass.getNameCS(), insertedMethodsNames); + if (scope != null && insertedMethods != null) { + resolver.importReferences(scope, insertedMethods); + } + } + codeStyleSettings.restore(); + navigateToCreatedFile.navigate(project, pluginFile); + }); + } + + private boolean checkIfMethodExist(PhpClass pluginClass, MagentoPluginMethodData[] pluginMethodData) { + Collection currentPluginMethods = pluginClass.getMethods(); + for (Method currentPluginMethod: currentPluginMethods) { + for (MagentoPluginMethodData pluginMethod: pluginMethodData) { + if (pluginMethod.getMethod().getName().equals(currentPluginMethod.getName())){ + continue; + } + return true; + } + } + return false; + } + + private PhpClass createPluginClass() { + PsiDirectory parentDirectory = ModuleIndex.getInstance(project).getModuleDirectoryByModuleName(getPluginModule()); + String[] pluginDirectories = pluginFileData.getPluginDirectory().split(File.separator); + for (String pluginDirectory: pluginDirectories) { + parentDirectory = directoryGenerator.findOrCreateSubdirectory(parentDirectory, pluginDirectory); + } + + Properties attributes = getAttributes(); + PsiFile pluginFile = fileFromTemplateGenerator.generate(Plugin.getInstance(pluginFileData.getPluginClassName()), attributes, parentDirectory, CreateAPluginAction.ACTION_NAME); + if (pluginFile == null) { + return null; + } + return getFirstClassOfFile.execute((PhpFile) pluginFile); + } + + private Properties getAttributes() { + Properties attributes = new Properties(); + this.fillAttributes(attributes); + return attributes; + } + + private void fillAttributes(Properties attributes) { + attributes.setProperty("NAME", pluginFileData.getPluginClassName()); + attributes.setProperty("NAMESPACE", pluginFileData.getNamespace()); + } + + public Plugin.PluginType getPluginType() { + return Plugin.getPluginTypeByString(pluginFileData.getPluginType()); + } + + public String getPluginModule() { + return pluginFileData.getPluginModule(); + } + + private int getInsertPos(PhpClass pluginClass) { + int insertPos = -1; + LeafPsiElement[] leafElements = PsiTreeUtil.getChildrenOfType(pluginClass, LeafPsiElement.class); + for (LeafPsiElement leafPsiElement: leafElements) { + if (!leafPsiElement.getText().equals(MagentoPhpClass.CLOSING_TAG)) { + continue; + } + insertPos = leafPsiElement.getTextOffset(); + } + return insertPos; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginDiXmlGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginDiXmlGenerator.java new file mode 100644 index 000000000..8bf4a817d --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginDiXmlGenerator.java @@ -0,0 +1,183 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.generator; + +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.*; +import com.intellij.xml.util.XmlUtil; +import com.jetbrains.php.lang.PhpLangUtil; +import com.magento.idea.magento2plugin.actions.generation.CreateAPluginAction; +import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginDiXmlData; +import com.magento.idea.magento2plugin.actions.generation.generator.util.DirectoryGenerator; +import com.magento.idea.magento2plugin.actions.generation.generator.util.FileFromTemplateGenerator; +import com.magento.idea.magento2plugin.actions.generation.generator.util.GetCodeTemplate; +import com.magento.idea.magento2plugin.indexes.ModuleIndex; +import com.magento.idea.magento2plugin.magento.files.ModuleDiXml; +import com.magento.idea.magento2plugin.magento.packages.Package; +import com.magento.idea.magento2plugin.util.magento.FileBasedIndexUtil; +import com.magento.idea.magento2plugin.xml.XmlPsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import java.io.IOException; +import java.util.*; + +public class MagentoPluginDiXmlGenerator { + private final FileFromTemplateGenerator fileFromTemplateGenerator; + private final DirectoryGenerator directoryGenerator; + private final GetCodeTemplate getCodeTemplate; + private MagentoPluginDiXmlData pluginFileData; + private Project project; + + public MagentoPluginDiXmlGenerator(@NotNull MagentoPluginDiXmlData pluginFileData, Project project) { + this.pluginFileData = pluginFileData; + this.project = project; + this.fileFromTemplateGenerator = FileFromTemplateGenerator.getInstance(project); + this.directoryGenerator = DirectoryGenerator.getInstance(); + this.getCodeTemplate = GetCodeTemplate.getInstance(project); + } + + public void generate() + { + PsiFile diXmlFile = findOrCreateDiXml(); + XmlAttributeValue typeAttributeValue = getTypeAttributeValue((XmlFile) diXmlFile); + boolean isPluginDeclared = false; + boolean isTypeDeclared = false; + if (typeAttributeValue != null) { + isTypeDeclared = true; + isPluginDeclared = isPluginDeclared(typeAttributeValue); + } + if (isPluginDeclared) { + return; + } + boolean finalIsTypeDeclared = isTypeDeclared; + WriteCommandAction.runWriteCommandAction(project, () -> { + StringBuffer textBuf = new StringBuffer(); + try { + textBuf.append(getCodeTemplate.execute(ModuleDiXml.TEMPLATE_PLUGIN, getAttributes(finalIsTypeDeclared))); + } catch (IOException e) { + e.printStackTrace(); + return; + } + + int insertPos = finalIsTypeDeclared + ? getEndPositionOfTag(PsiTreeUtil.getParentOfType(typeAttributeValue, XmlTag.class)) + : getRootInsertPosition((XmlFile) diXmlFile); + if (textBuf.length() > 0 && insertPos >= 0) { + PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project); + Document document = psiDocumentManager.getDocument(diXmlFile); + document.insertString(insertPos, textBuf); + int endPos = insertPos + textBuf.length() + 1; + CodeStyleManager.getInstance(project).reformatText(diXmlFile, insertPos, endPos); + psiDocumentManager.commitDocument(document); + } + }); + } + + private boolean isPluginDeclared(XmlAttributeValue typeAttributeValue) { + XmlTag xmlTag = PsiTreeUtil.getParentOfType(typeAttributeValue, XmlTag.class); + XmlTag[] xmlTags = PsiTreeUtil.getChildrenOfType(xmlTag, XmlTag.class); + if (xmlTags == null) { + return false; + } + for (XmlTag child: xmlTags) { + if (!child.getName().equals(ModuleDiXml.PLUGIN_TAG_NAME)) { + continue; + } + XmlAttribute[] xmlAttributes = PsiTreeUtil.getChildrenOfType(child, XmlAttribute.class); + for (XmlAttribute xmlAttribute: xmlAttributes) { + if (!xmlAttribute.getName().equals(ModuleDiXml.PLUGIN_TYPE_ATTRIBUTE)) { + continue; + } + String declaredClass = PhpLangUtil.toPresentableFQN(xmlAttribute.getValue()); + if (declaredClass.equals(pluginFileData.getPluginFqn())) { + return true; + } + } + } + + return false; + } + + private XmlAttributeValue getTypeAttributeValue(XmlFile diXml) { + Collection pluginTypes = XmlPsiTreeUtil.findAttributeValueElements(diXml, ModuleDiXml.PLUGIN_TYPE_TAG, ModuleDiXml.PLUGIN_TYPE_ATTR_NAME); + String pluginClassFqn = pluginFileData.getTargetClass().getPresentableFQN(); + for (XmlAttributeValue pluginType: pluginTypes) { + if (!PhpLangUtil.toPresentableFQN(pluginType.getValue()).equals(pluginClassFqn)) { + continue; + } + return pluginType; + } + + return null; + } + + private Properties getAttributes(boolean isTypeDeclared) { + Properties attributes = new Properties(); + this.fillAttributes(attributes, isTypeDeclared); + return attributes; + } + + private void fillAttributes(Properties attributes, boolean isTypeDeclared) { + if (!isTypeDeclared) { + attributes.setProperty("TYPE", pluginFileData.getTargetClass().getPresentableFQN()); + } + attributes.setProperty("NAME", pluginFileData.getPluginName()); + attributes.setProperty("PLUGIN_TYPE", pluginFileData.getPluginFqn()); + attributes.setProperty("PLUGIN_NAME", pluginFileData.getPluginName()); + attributes.setProperty("SORT_ORDER", pluginFileData.getSortOrder()); + } + + private PsiFile findOrCreateDiXml() { + PsiDirectory parentDirectory = ModuleIndex.getInstance(project).getModuleDirectoryByModuleName(pluginFileData.getPluginModule()); + ArrayList pluginDirectories = new ArrayList<>(); + pluginDirectories.add(Package.MODULE_BASE_AREA_DIR); + if (!getArea().equals(Package.Areas.base)) { + pluginDirectories.add(getArea().toString()); + } + for (String pluginDirectory: pluginDirectories) { + parentDirectory = directoryGenerator.findOrCreateSubdirectory(parentDirectory, pluginDirectory); + } + ModuleDiXml moduleDiXml = new ModuleDiXml(); + PsiFile diXml = FileBasedIndexUtil.findModuleConfigFile( + moduleDiXml.getFileName(), + getArea(), + pluginFileData.getPluginModule(), + project + ); + if (diXml == null) { + diXml = fileFromTemplateGenerator.generate(moduleDiXml, new Properties(), parentDirectory, CreateAPluginAction.ACTION_NAME); + } + return diXml; + } + + public Package.Areas getArea() { + return Package.getAreaByString(pluginFileData.getArea()); + } + + private int getRootInsertPosition(XmlFile xmlFile) { + int insertPos = -1; + XmlTag rootTag = xmlFile.getRootTag(); + if (rootTag == null) { + return insertPos; + } + return getEndPositionOfTag(rootTag); + } + + private int getEndPositionOfTag(XmlTag tag) { + PsiElement tagEnd = XmlUtil.getTokenOfType(tag, XmlTokenType.XML_END_TAG_START); + if (tagEnd == null) { + return -1; + } + + return tagEnd.getTextOffset(); + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginMethodsGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginMethodsGenerator.java index f42ef7fb4..fd9e79b45 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginMethodsGenerator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/MagentoPluginMethodsGenerator.java @@ -16,33 +16,36 @@ import com.jetbrains.php.lang.psi.elements.*; import com.jetbrains.php.lang.psi.resolve.types.PhpType; import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginMethodData; +import com.magento.idea.magento2plugin.magento.files.Plugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.regex.Pattern; public class MagentoPluginMethodsGenerator { + public static String originalTargetKey = "original.target"; @NotNull - private final PhpClass myCurrentClass; + private final PhpClass pluginClass; @NotNull private final Method myMethod; @NotNull private final PhpClass myTargetClass; - public MagentoPluginMethodsGenerator(@NotNull PhpClass myCurrentClass, @NotNull Method method, Key targetClassKey) { + public MagentoPluginMethodsGenerator(@NotNull PhpClass pluginClass, @NotNull Method method, Key targetClassKey) { super(); - this.myCurrentClass = myCurrentClass; + this.pluginClass = pluginClass; this.myMethod = method; this.myTargetClass = (PhpClass)Objects.requireNonNull(method.getUserData(targetClassKey)); } @NotNull - public MagentoPluginMethodData[] createPluginMethods(@NotNull String templateName, @NotNull MagentoPluginMethodData.Type type) { + public MagentoPluginMethodData[] createPluginMethods(@NotNull Plugin.PluginType type) { List pluginMethods = new ArrayList(); - PhpClass currentClass = this.myCurrentClass; + String templateName = Plugin.getMethodTemplateByPluginType(type); + PhpClass currentClass = this.pluginClass; if (currentClass != null) { - Properties attributes = this.getAccessMethodAttributes(PhpCodeInsightUtil.findScopeForUseOperator(this.myMethod), templateName, type); - String methodTemplate = PhpCodeUtil.getCodeTemplate(templateName, attributes, this.myCurrentClass.getProject()); + Properties attributes = this.getAccessMethodAttributes(PhpCodeInsightUtil.findScopeForUseOperator(this.myMethod), type); + String methodTemplate = PhpCodeUtil.getCodeTemplate(templateName, attributes, this.pluginClass.getProject()); PhpClass dummyClass = PhpCodeUtil.createClassFromMethodTemplate(currentClass, currentClass.getProject(), methodTemplate); if (dummyClass != null) { PhpDocComment currDocComment = null; @@ -51,31 +54,28 @@ public MagentoPluginMethodData[] createPluginMethods(@NotNull String templateNam if (child instanceof PhpDocComment) { currDocComment = (PhpDocComment)child; } else if (child instanceof Method) { - pluginMethods.add(new MagentoPluginMethodData(myMethod, currentClass, currDocComment, (Method)child, type)); + pluginMethods.add(new MagentoPluginMethodData(myMethod, currDocComment, (Method)child)); currDocComment = null; } } } } - MagentoPluginMethodData[] magentoPluginMethodData = pluginMethods.toArray(new MagentoPluginMethodData[0]); - - return magentoPluginMethodData; + return pluginMethods.toArray(new MagentoPluginMethodData[0]); } - private Properties getAccessMethodAttributes(@Nullable PhpPsiElement scopeForUseOperator, String templateName, @NotNull MagentoPluginMethodData.Type type) { + private Properties getAccessMethodAttributes(@Nullable PhpPsiElement scopeForUseOperator, @NotNull Plugin.PluginType type) { Properties attributes = new Properties(); - String typeHint = this.fillAttributes(scopeForUseOperator, attributes, templateName, type); + String typeHint = this.fillAttributes(scopeForUseOperator, attributes, type); this.addTypeHintsAndReturnType(attributes, typeHint); return attributes; } @NotNull - private String fillAttributes(@Nullable PhpPsiElement scopeForUseOperator, Properties attributes, String templateName, @NotNull MagentoPluginMethodData.Type type) { + private String fillAttributes(@Nullable PhpPsiElement scopeForUseOperator, Properties attributes, @NotNull Plugin.PluginType type) { String fieldName = this.myMethod.getName(); - String methodPrefix = type.toString().toLowerCase(); String methodSuffix = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); - String pluginMethodName = methodPrefix.concat(methodSuffix); + String pluginMethodName = type.toString().concat(methodSuffix); attributes.setProperty("NAME", pluginMethodName); PhpReturnType targetMethodReturnType = myMethod.getReturnType(); @@ -97,7 +97,7 @@ private String fillAttributes(@Nullable PhpPsiElement scopeForUseOperator, Prope } private void addTypeHintsAndReturnType(Properties attributes, String typeHint) { - Project project = this.myCurrentClass.getProject(); + Project project = this.pluginClass.getProject(); if (PhpLanguageFeature.SCALAR_TYPE_HINTS.isSupported(project) && isDocTypeConvertable(typeHint)) { attributes.setProperty("SCALAR_TYPE_HINT", convertDocTypeToHint(project, typeHint)); } @@ -138,7 +138,7 @@ private static String convertDocTypeToHint(Project project, String typeHint) { return hint; } - private String getParameterDoc(Collection parameters, @NotNull MagentoPluginMethodData.Type type, Project project) { + private String getParameterDoc(Collection parameters, @NotNull Plugin.PluginType type, Project project) { StringBuilder sb = new StringBuilder(); PhpReturnType returnType = myMethod.getReturnType(); @@ -163,10 +163,10 @@ private String getParameterDoc(Collection parameters, @NotNull Magen } sb.append('$').append(paramName); - if (type.equals(MagentoPluginMethodData.Type.AROUND) && i == 0) { + if (type.equals(Plugin.PluginType.around) && i == 0) { sb.append("\n* @param callable $proceed"); } - if (type.equals(MagentoPluginMethodData.Type.AFTER) && i == 0) { + if (type.equals(Plugin.PluginType.after) && i == 0) { if (returnType != null) { if (returnType.getText().equals("void")) { sb.append("\n* @param null $result"); @@ -179,7 +179,7 @@ private String getParameterDoc(Collection parameters, @NotNull Magen } } - if (!type.equals(MagentoPluginMethodData.Type.BEFORE) && returnType != null) { + if (!type.equals(Plugin.PluginType.before) && returnType != null) { if (returnType.getText().equals("void")) { sb.append("\n* @return void"); } else { @@ -189,7 +189,7 @@ private String getParameterDoc(Collection parameters, @NotNull Magen return sb.toString(); } - protected String getParameterList(Collection parameters, @NotNull MagentoPluginMethodData.Type type) { + protected String getParameterList(Collection parameters, @NotNull Plugin.PluginType type) { StringBuilder buf = new StringBuilder(); PhpReturnType returnType = myMethod.getReturnType(); Iterator iterator = parameters.iterator(); @@ -215,14 +215,14 @@ protected String getParameterList(Collection parameters, @NotNull Ma } buf.append("$").append(paramName); } - if (type.equals(MagentoPluginMethodData.Type.AFTER) && i == 0){ + if (type.equals(Plugin.PluginType.after) && i == 0){ if (returnType != null && !returnType.getText().equals("void")) { buf.append(", ").append(returnType.getText()).append(" $result"); } else { buf.append(", $result"); } } - if (type.equals(MagentoPluginMethodData.Type.AROUND) && i == 0){ + if (type.equals(Plugin.PluginType.around) && i == 0){ buf.append(", callable $proceed"); } i++; @@ -231,9 +231,9 @@ protected String getParameterList(Collection parameters, @NotNull Ma return buf.toString(); } - protected String getReturnVariables(@NotNull MagentoPluginMethodData.Type type) { + protected String getReturnVariables(@NotNull Plugin.PluginType type) { StringBuilder buf = new StringBuilder(); - if (type.equals(MagentoPluginMethodData.Type.AFTER)) { + if (type.equals(Plugin.PluginType.after)) { return buf.append("$result").toString(); } Parameter[] parameters = myMethod.getParameters(); @@ -258,7 +258,7 @@ protected String getReturnVariables(@NotNull MagentoPluginMethodData.Type type) @Nullable private String getTypeHint(@NotNull PhpNamedElement element) { - PhpType filedType = element.getType().global(this.myCurrentClass.getProject()); + PhpType filedType = element.getType().global(this.pluginClass.getProject()); Set typeStrings = filedType.getTypes(); String typeString = null; if (typeStrings.size() == 1) { @@ -294,7 +294,7 @@ private String convertTypeToString(@NotNull PhpNamedElement element, Set } private String getFieldTypeString(PhpNamedElement element, @NotNull PhpType type) { - return PhpDocUtil.getTypePresentation(this.myCurrentClass.getProject(), type, PhpCodeInsightUtil.findScopeForUseOperator(element)); + return PhpDocUtil.getTypePresentation(this.pluginClass.getProject(), type, PhpCodeInsightUtil.findScopeForUseOperator(element)); } private static PhpType filterNullCaseInsensitive(PhpType filedType) { diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/DirectoryGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/DirectoryGenerator.java similarity index 99% rename from src/com/magento/idea/magento2plugin/actions/generation/generator/DirectoryGenerator.java rename to src/com/magento/idea/magento2plugin/actions/generation/generator/util/DirectoryGenerator.java index a2037adaa..ba26a3023 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/DirectoryGenerator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/DirectoryGenerator.java @@ -2,7 +2,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -package com.magento.idea.magento2plugin.actions.generation.generator; +package com.magento.idea.magento2plugin.actions.generation.generator.util; import com.intellij.openapi.application.WriteAction; import com.intellij.psi.PsiDirectory; diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/FileFromTemplateGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FileFromTemplateGenerator.java similarity index 95% rename from src/com/magento/idea/magento2plugin/actions/generation/generator/FileFromTemplateGenerator.java rename to src/com/magento/idea/magento2plugin/actions/generation/generator/util/FileFromTemplateGenerator.java index 83d270524..80bdd87d0 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/FileFromTemplateGenerator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FileFromTemplateGenerator.java @@ -2,7 +2,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -package com.magento.idea.magento2plugin.actions.generation.generator; +package com.magento.idea.magento2plugin.actions.generation.generator.util; import com.intellij.ide.fileTemplates.DefaultTemplatePropertiesProvider; import com.intellij.ide.fileTemplates.FileTemplate; @@ -56,7 +56,6 @@ public PsiFile generate(@NotNull ModuleFileInterface moduleFile, @NotNull Proper } catch (IncorrectOperationException | IOException var9) { exceptionRef.set(var9.getMessage()); } - }; ApplicationManager.getApplication().runWriteAction(run); }, actionName, null); @@ -72,7 +71,7 @@ public PsiFile generate(@NotNull ModuleFileInterface moduleFile, @NotNull Proper private PsiFile createFile(@NotNull ModuleFileInterface moduleFile, @NotNull String filePath, @NotNull PsiDirectory baseDir, @NotNull Properties attributes) throws IOException, IncorrectOperationException { List path = StringUtil.split(filePath.replace(File.separator, "/"), "/"); String fileName = path.get(path.size() - 1); - PsiFile fileTemplate = createFileFromTemplate(getTestTemplateManager(), baseDir, moduleFile.getTemplate(), attributes, fileName, moduleFile.getLanguage()); + PsiFile fileTemplate = createFileFromTemplate(getTemplateManager(), baseDir, moduleFile.getTemplate(), attributes, fileName, moduleFile.getLanguage()); if (fileTemplate == null) { throw new IncorrectOperationException("Template not found!"); } else { @@ -116,7 +115,7 @@ public void fillDefaultProperties(@NotNull FileTemplateManager templateManager, } } - public FileTemplateManager getTestTemplateManager() { + public FileTemplateManager getTemplateManager() { return FileTemplateManager.getInstance(project); } } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/GetCodeTemplate.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/GetCodeTemplate.java new file mode 100644 index 000000000..0553e8649 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/GetCodeTemplate.java @@ -0,0 +1,32 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.generator.util; + +import com.intellij.ide.fileTemplates.FileTemplate; +import com.intellij.ide.fileTemplates.FileTemplateManager; +import com.intellij.openapi.project.Project; +import java.io.IOException; +import java.util.Properties; + +public class GetCodeTemplate { + private static GetCodeTemplate INSTANCE = null; + private Project project; + + public static GetCodeTemplate getInstance(Project project) { + if (null == INSTANCE) { + INSTANCE = new GetCodeTemplate(project); + } + + return INSTANCE; + } + GetCodeTemplate (Project project) { + this.project = project; + } + + public String execute(String templateName, Properties properties) throws IOException { + FileTemplate fileTemplate = FileTemplateManager.getInstance(project).getCodeTemplate(templateName); + return fileTemplate.getText(properties); + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/util/CodeStyleSettings.java b/src/com/magento/idea/magento2plugin/actions/generation/util/CodeStyleSettings.java new file mode 100644 index 000000000..d9a517f4e --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/util/CodeStyleSettings.java @@ -0,0 +1,34 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.util; + +import com.intellij.application.options.CodeStyle; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.jetbrains.php.lang.PhpLanguage; +import com.jetbrains.php.lang.psi.PhpFile; + +public class CodeStyleSettings { + private PhpFile phpFile; + private boolean currLineBreaks; + private int currBlankLines; + private CommonCodeStyleSettings settings; + + public CodeStyleSettings(PhpFile phpFile){ + this.phpFile = phpFile; + this.settings = CodeStyle.getLanguageSettings(this.phpFile, PhpLanguage.INSTANCE); + } + + public void adjustBeforeWrite() { + this.currLineBreaks = settings.KEEP_LINE_BREAKS; + this.currBlankLines = settings.KEEP_BLANK_LINES_IN_CODE; + settings.KEEP_LINE_BREAKS = false; + settings.KEEP_BLANK_LINES_IN_CODE = 0; + }; + + public void restore() { + settings.KEEP_LINE_BREAKS = currLineBreaks; + settings.KEEP_BLANK_LINES_IN_CODE = currBlankLines; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/util/CollectInsertedMethods.java b/src/com/magento/idea/magento2plugin/actions/generation/util/CollectInsertedMethods.java new file mode 100644 index 000000000..566549a29 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/util/CollectInsertedMethods.java @@ -0,0 +1,51 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.util; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.jetbrains.php.lang.PhpLangUtil; +import com.jetbrains.php.lang.psi.PhpFile; +import com.jetbrains.php.lang.psi.PhpPsiUtil; +import com.jetbrains.php.lang.psi.elements.Method; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class CollectInsertedMethods { + private static CollectInsertedMethods INSTANCE = null; + + public static CollectInsertedMethods getInstance() { + if (null == INSTANCE) { + INSTANCE = new CollectInsertedMethods(); + } + return INSTANCE; + } + + @Nullable + public List execute(@NotNull PsiFile file, @NotNull CharSequence className, @NotNull Set methodNames) { + if (!(file instanceof PhpFile)) { + return null; + } + PhpClass phpClass = PhpPsiUtil.findClass((PhpFile) file, (aClass) -> PhpLangUtil.equalsClassNames(aClass.getNameCS(), className)); + if (phpClass == null) { + return null; + } else { + List insertedMethods = new ArrayList(); + Method[] ownMethods = phpClass.getOwnMethods(); + + for (Method method : ownMethods) { + if (methodNames.contains(method.getNameCS())) { + insertedMethods.add(method); + } + } + + return insertedMethods; + } + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java b/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java new file mode 100644 index 000000000..ff01d11a4 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java @@ -0,0 +1,53 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.util; + +import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiElement; +import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment; +import com.jetbrains.php.lang.psi.elements.Method; +import com.jetbrains.php.lang.psi.elements.Parameter; +import com.jetbrains.php.lang.psi.elements.PhpReturnType; +import com.magento.idea.magento2plugin.actions.generation.ImportReferences.PhpClassReferenceResolver; +import com.magento.idea.magento2plugin.actions.generation.data.MagentoPluginMethodData; +import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; + +public class FillTextBufferWithPluginMethods { + private static FillTextBufferWithPluginMethods INSTANCE = null; + + public static FillTextBufferWithPluginMethods getInstance() { + if (null == INSTANCE) { + INSTANCE = new FillTextBufferWithPluginMethods(); + } + return INSTANCE; + } + + public void execute(@NotNull Key targetClassKey, Set insertedMethodsNames, @NotNull PhpClassReferenceResolver resolver, @NotNull StringBuffer textBuf, @NotNull MagentoPluginMethodData[] pluginMethods) { + for (MagentoPluginMethodData pluginMethod : pluginMethods) { + insertedMethodsNames.add(pluginMethod.getMethod().getName()); + PhpDocComment comment = pluginMethod.getDocComment(); + if (comment != null) { + textBuf.append(comment.getText()); + } + Method targetMethod = pluginMethod.getTargetMethod(); + Parameter[] parameters = targetMethod.getParameters(); + Collection processElements = new ArrayList<>(Arrays.asList(parameters)); + resolver.processElements(processElements); + PsiElement targetClass = (PsiElement) pluginMethod.getTargetMethod().getUserData(targetClassKey); + resolver.processElement(targetClass); + PhpReturnType returnType = targetMethod.getReturnType(); + if (returnType != null) { + resolver.processElement(returnType); + } + + textBuf.append('\n'); + textBuf.append(pluginMethod.getMethod().getText()); + } + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/util/NavigateToCreatedFile.java b/src/com/magento/idea/magento2plugin/actions/generation/util/NavigateToCreatedFile.java new file mode 100644 index 000000000..f90a8c421 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/util/NavigateToCreatedFile.java @@ -0,0 +1,30 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.util; + +import com.intellij.ide.util.PsiNavigationSupport; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +public class NavigateToCreatedFile { + private static NavigateToCreatedFile INSTANCE = null; + + public static NavigateToCreatedFile getInstance() { + if (null == INSTANCE) { + INSTANCE = new NavigateToCreatedFile(); + } + return INSTANCE; + } + + public void navigate(@NotNull Project project, @NotNull PsiFile createdFile) { + VirtualFile virtualFile = createdFile.getVirtualFile(); + if (virtualFile == null) { + return; + } + PsiNavigationSupport.getInstance().createNavigatable(project, virtualFile, -1).navigate(false); + } +} diff --git a/src/com/magento/idea/magento2plugin/indexes/ModuleIndex.java b/src/com/magento/idea/magento2plugin/indexes/ModuleIndex.java new file mode 100644 index 000000000..b82ea7031 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/indexes/ModuleIndex.java @@ -0,0 +1,77 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.indexes; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiManager; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.indexing.FileBasedIndex; +import com.jetbrains.php.lang.PhpFileType; +import com.magento.idea.magento2plugin.magento.packages.Package; +import com.magento.idea.magento2plugin.stubs.indexes.ModuleNameIndex; +import com.magento.idea.magento2plugin.util.RegExUtil; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class ModuleIndex { + + private static ModuleIndex INSTANCE; + + private Project project; + + private ModuleIndex() { + } + + public static ModuleIndex getInstance(final Project project) { + if (null == INSTANCE) { + INSTANCE = new ModuleIndex(); + } + INSTANCE.project = project; + + return INSTANCE; + } + + public List getEditableModuleNames() { + FileBasedIndex index = FileBasedIndex + .getInstance(); + List allModulesList = new ArrayList<>(); + Collection allModules = index.getAllKeys(ModuleNameIndex.KEY, project); + for (String moduleName : allModules) { + if (!moduleName.matches(RegExUtil.Magento.MODULE_NAME)) { + continue; + } + Collection files = index.getContainingFiles(ModuleNameIndex.KEY, moduleName, GlobalSearchScope.getScopeRestrictedByFileTypes( + GlobalSearchScope.allScope(project), + PhpFileType.INSTANCE + )); + if (files.isEmpty()) { + continue; + } + VirtualFile virtualFile = files.iterator().next(); + if (virtualFile.getPath().contains(Package.VENDOR)) { + continue; + } + + allModulesList.add(moduleName); + } + Collections.sort(allModulesList); + return allModulesList; + } + + public PsiDirectory getModuleDirectoryByModuleName(String moduleName) { + FileBasedIndex index = FileBasedIndex + .getInstance(); + Collection files = index.getContainingFiles(ModuleNameIndex.KEY, moduleName, GlobalSearchScope.getScopeRestrictedByFileTypes( + GlobalSearchScope.allScope(project), + PhpFileType.INSTANCE + )); + VirtualFile virtualFile = files.iterator().next(); + return PsiManager.getInstance(project).findDirectory(virtualFile.getParent()); + } +} diff --git a/src/com/magento/idea/magento2plugin/inspections/php/PluginInspection.java b/src/com/magento/idea/magento2plugin/inspections/php/PluginInspection.java index 4c2789b73..183eced1b 100644 --- a/src/com/magento/idea/magento2plugin/inspections/php/PluginInspection.java +++ b/src/com/magento/idea/magento2plugin/inspections/php/PluginInspection.java @@ -19,6 +19,7 @@ import com.jetbrains.php.lang.psi.elements.PhpClass; import com.jetbrains.php.lang.psi.visitors.PhpElementVisitor; import com.magento.idea.magento2plugin.inspections.php.util.PhpClassImplementsInterfaceUtil; +import com.magento.idea.magento2plugin.magento.files.Plugin; import com.magento.idea.magento2plugin.util.GetPhpClassByFQN; import com.magento.idea.magento2plugin.util.magento.plugin.GetTargetClassNamesByPluginClassName; import org.jetbrains.annotations.NotNull; @@ -37,22 +38,19 @@ public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder problemsHolder, bo private static final String pluginOnConstructorMethodProblemDescription = "You can't declare a plugin for a __construct method!"; private static final String redundantParameterProblemDescription = "Redundant parameter"; private static final String possibleTypeIncompatibilityProblemDescription = "Possible type incompatibility. Consider changing the parameter according to the target method."; - private static final String aroundPluginPrefix = "around"; - private static final String beforePluginPrefix = "before"; - private static final String afterPluginPrefix = "after"; private final Integer beforePluginExtraParamsStart = 2; private final Integer afterAndAroundPluginExtraParamsStart = 3; private String getPluginPrefix(Method pluginMethod) { String pluginMethodName = pluginMethod.getName(); - if (pluginMethodName.startsWith(aroundPluginPrefix)) { - return aroundPluginPrefix; + if (pluginMethodName.startsWith(Plugin.PluginType.around.toString())) { + return Plugin.PluginType.around.toString(); } - if (pluginMethodName.startsWith(beforePluginPrefix)) { - return beforePluginPrefix; + if (pluginMethodName.startsWith(Plugin.PluginType.before.toString())) { + return Plugin.PluginType.before.toString(); } - if (pluginMethodName.startsWith(afterPluginPrefix)) { - return afterPluginPrefix; + if (pluginMethodName.startsWith(Plugin.PluginType.after.toString())) { + return Plugin.PluginType.after.toString(); } return null; @@ -106,7 +104,7 @@ private void checkTargetClass(PsiElement currentClassNameIdentifier, PhpClass ta } private void checkTargetMethod(Method pluginMethod, String targetClassMethodName, Method targetMethod) { - if (targetClassMethodName.equals("__construct")) { + if (targetClassMethodName.equals(Plugin.constructMethodName)) { problemsHolder.registerProblem(pluginMethod.getNameIdentifier(), pluginOnConstructorMethodProblemDescription, ProblemHighlightType.ERROR); } if (targetMethod.isFinal()) { @@ -115,7 +113,7 @@ private void checkTargetMethod(Method pluginMethod, String targetClassMethodName if (targetMethod.isStatic()) { problemsHolder.registerProblem(pluginMethod.getNameIdentifier(), pluginOnStaticMethodProblemDescription, ProblemHighlightType.ERROR); } - if (!targetMethod.getAccess().toString().equals("public")) { + if (!targetMethod.getAccess().toString().equals(Plugin.publicAccess)) { problemsHolder.registerProblem(pluginMethod.getNameIdentifier(), pluginOnNotPublicMethodProblemDescription, ProblemHighlightType.ERROR); } } @@ -139,13 +137,13 @@ private void checkParametersCompatibility(Method pluginMethod, String pluginPref } continue; } - if (index == 2 && pluginPrefix.equals(aroundPluginPrefix)) { + if (index == 2 && pluginPrefix.equals(Plugin.PluginType.around.toString())) { if (!checkTypeIncompatibility("callable", declaredType, phpIndex)) { problemsHolder.registerProblem(pluginMethodParameter, PhpBundle.message("inspection.wrong_param_type", new Object[]{declaredType, "callable"}), ProblemHighlightType.ERROR); } continue; } - if (index == 2 && pluginPrefix.equals(afterPluginPrefix) && + if (index == 2 && pluginPrefix.equals(Plugin.PluginType.after.toString()) && !targetMethod.getDeclaredType().toString().equals("void")) { if (declaredType.isEmpty() || targetMethod.getDeclaredType().toString().isEmpty()) { continue; @@ -158,7 +156,7 @@ private void checkParametersCompatibility(Method pluginMethod, String pluginPref } continue; } - if (index == 2 && pluginPrefix.equals(afterPluginPrefix) && + if (index == 2 && pluginPrefix.equals(Plugin.PluginType.after.toString()) && targetMethod.getDeclaredType().toString().equals("void")) { if (declaredType.isEmpty()) { continue; @@ -168,7 +166,7 @@ private void checkParametersCompatibility(Method pluginMethod, String pluginPref } continue; } - int targetParameterKey = index - (pluginPrefix.equals(beforePluginPrefix) ? + int targetParameterKey = index - (pluginPrefix.equals(Plugin.PluginType.before.toString()) ? beforePluginExtraParamsStart : afterAndAroundPluginExtraParamsStart); if (targetMethodParameters.length <= targetParameterKey) { diff --git a/src/com/magento/idea/magento2plugin/inspections/xml/ObserverDeclarationInspection.java b/src/com/magento/idea/magento2plugin/inspections/xml/ObserverDeclarationInspection.java index a29b8727a..e953ff85d 100644 --- a/src/com/magento/idea/magento2plugin/inspections/xml/ObserverDeclarationInspection.java +++ b/src/com/magento/idea/magento2plugin/inspections/xml/ObserverDeclarationInspection.java @@ -19,7 +19,7 @@ import com.jetbrains.php.lang.inspections.PhpInspection; import com.magento.idea.magento2plugin.indexes.EventIndex; import com.magento.idea.magento2plugin.magento.files.ModuleXml; -import com.magento.idea.magento2plugin.magento.packages.MagentoPackages; +import com.magento.idea.magento2plugin.magento.packages.Package; import org.jetbrains.annotations.NotNull; import java.net.MalformedURLException; import java.net.URL; @@ -254,22 +254,13 @@ private String getAreaFromFileDirectory(@NotNull PsiFile file) { String areaFromFileDirectory = file.getParent().getName(); - if (areaFromFileDirectory.equals("etc")) { - return MagentoPackages.AREA_BASE; + if (areaFromFileDirectory.equals(Package.MODULE_BASE_AREA_DIR)) { + return Package.Areas.base.toString(); } - List possibleAreas = new ArrayList<>(Arrays.asList( - MagentoPackages.AREA_ADMINHTML, - MagentoPackages.AREA_FRONTEND, - MagentoPackages.AREA_CRON, - MagentoPackages.AREA_API_REST, - MagentoPackages.AREA_API_SOAP, - MagentoPackages.AREA_GRAPHQL - )); - - for (String area: possibleAreas) { - if (area.equals(areaFromFileDirectory)) { - return area; + for (Package.Areas area: Package.Areas.values()) { + if (area.toString().equals(areaFromFileDirectory)) { + return area.toString(); } } diff --git a/src/com/magento/idea/magento2plugin/magento/files/ModuleDiXml.java b/src/com/magento/idea/magento2plugin/magento/files/ModuleDiXml.java new file mode 100644 index 000000000..973993809 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/files/ModuleDiXml.java @@ -0,0 +1,41 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.magento.files; + +import com.intellij.lang.Language; +import com.intellij.lang.xml.XMLLanguage; + +public class ModuleDiXml implements ModuleFileInterface { + public static String FILE_NAME = "di.xml"; + public static String TEMPLATE = "Magento Module DI Xml"; + public static String TEMPLATE_PLUGIN = "Magento Module DI Xml Plugin"; + public static String PLUGIN_TYPE_TAG = "type"; + public static String PLUGIN_TYPE_ATTRIBUTE = "type"; + public static String PLUGIN_TAG_NAME = "plugin"; + public static String PLUGIN_TYPE_ATTR_NAME = "name"; + private static ModuleDiXml INSTANCE = null; + + public static ModuleDiXml getInstance() { + if (null == INSTANCE) { + INSTANCE = new ModuleDiXml(); + } + return INSTANCE; + } + + @Override + public String getFileName() { + return FILE_NAME; + } + + @Override + public String getTemplate() { + return TEMPLATE; + } + + @Override + public Language getLanguage() { + return XMLLanguage.INSTANCE; + } +} diff --git a/src/com/magento/idea/magento2plugin/magento/files/Plugin.java b/src/com/magento/idea/magento2plugin/magento/files/Plugin.java new file mode 100644 index 000000000..61f0ff468 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/files/Plugin.java @@ -0,0 +1,83 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.magento.files; + +import com.intellij.lang.Language; +import com.jetbrains.php.lang.PhpLanguage; + +public class Plugin implements ModuleFileInterface { + public static String TEMPLATE = "PHP Class"; + public static final String BEFORE_METHOD_TEMPLATE_NAME = "Magento Plugin Before Method"; + public static final String AROUND_METHOD_TEMPLATE_NAME = "Magento Plugin Around Method"; + public static final String AFTER_METHOD_TEMPLATE_NAME = "Magento Plugin After Method"; + + public static enum PluginType { + before, + after, + around + } + + //forbidden target method + public static final String constructMethodName = "__construct"; + + //allowed methods access type + public static final String publicAccess = "public"; + + private static Plugin INSTANCE = null; + private String fileName; + + public static Plugin getInstance(String className) { + if (null == INSTANCE) { + INSTANCE = new Plugin(); + } + INSTANCE.setFileName(className.concat(".php")); + return INSTANCE; + } + + @Override + public String getFileName() { + return this.fileName; + } + + @Override + public String getTemplate() { + return TEMPLATE; + } + + @Override + public Language getLanguage() { + return PhpLanguage.INSTANCE; + } + + private void setFileName(String filename) { + this.fileName = filename; + }; + + public static String getMethodTemplateByPluginType(PluginType pluginType) + { + if (pluginType.equals(PluginType.after)) { + return AFTER_METHOD_TEMPLATE_NAME; + } + if (pluginType.equals(PluginType.before)) { + return BEFORE_METHOD_TEMPLATE_NAME; + } + if (pluginType.equals(PluginType.around)) { + return AROUND_METHOD_TEMPLATE_NAME; + } + return null; + } + + public static Plugin.PluginType getPluginTypeByString(String string) + { + for (Plugin.PluginType pluginType: Plugin.PluginType.values()) { + if (!pluginType.toString().equals(string)) + { + continue; + } + return pluginType; + } + return null; + } +} diff --git a/src/com/magento/idea/magento2plugin/magento/packages/MagentoPackages.java b/src/com/magento/idea/magento2plugin/magento/packages/MagentoPackages.java deleted file mode 100644 index 9a09eeb3b..000000000 --- a/src/com/magento/idea/magento2plugin/magento/packages/MagentoPackages.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -package com.magento.idea.magento2plugin.magento.packages; - -public class MagentoPackages { - public static String PACKAGES_ROOT = "app/code"; - public static String AREA_BASE = "base"; - public static String AREA_ADMINHTML = "adminhtml"; - public static String AREA_FRONTEND = "frontend"; - public static String AREA_CRON = "crontab"; - public static String AREA_API_REST = "webapi_rest"; - public static String AREA_API_SOAP = "webapi_soap"; - public static String AREA_GRAPHQL = "graphql"; -} diff --git a/src/com/magento/idea/magento2plugin/magento/packages/MagentoPhpClass.java b/src/com/magento/idea/magento2plugin/magento/packages/MagentoPhpClass.java new file mode 100644 index 000000000..bf588533a --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/packages/MagentoPhpClass.java @@ -0,0 +1,9 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.magento.packages; + +public class MagentoPhpClass { + public static String CLOSING_TAG = "}"; +} diff --git a/src/com/magento/idea/magento2plugin/magento/packages/Package.java b/src/com/magento/idea/magento2plugin/magento/packages/Package.java new file mode 100644 index 000000000..ac37b3fd4 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/packages/Package.java @@ -0,0 +1,37 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.magento.packages; + +import com.magento.idea.magento2plugin.magento.files.Plugin; + +public class Package { + public static String PACKAGES_ROOT = "app/code"; + public static String VENDOR = "vendor"; + public static String MODULE_BASE_AREA_DIR = "etc"; + public static String VENDOR_MODULE_NAME_SEPARATOR = "_"; + public static String FQN_SEPARATOR = "\\"; + + public static enum Areas { + base, + adminhtml, + frontend, + crontab, + webapi_rest, + webapi_soap, + graphql + } + + public static Package.Areas getAreaByString(String string) + { + for (Package.Areas areas: Package.Areas.values()) { + if (!areas.toString().equals(string)) + { + continue; + } + return areas; + } + return null; + } +} diff --git a/src/com/magento/idea/magento2plugin/ui/FilteredComboBox.java b/src/com/magento/idea/magento2plugin/ui/FilteredComboBox.java new file mode 100644 index 000000000..347711e54 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/ui/FilteredComboBox.java @@ -0,0 +1,62 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.ui; + +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.List; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + +public class FilteredComboBox extends JComboBox { + private List entries; + + public List getEntries() { + return entries; + } + + public FilteredComboBox(List entries) { + super(entries.toArray()); + this.entries = entries; + this.setEditable(true); + + final JTextField textfield = + (JTextField) this.getEditor().getEditorComponent(); + + textfield.addKeyListener(new KeyAdapter() { + public void keyReleased(KeyEvent ke) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + comboFilter(textfield.getText()); + } + }); + } + }); + + } + + public void comboFilter(String enteredText) { + List entriesFiltered = new ArrayList(); + + for (String entry : getEntries()) { + if (entry.toLowerCase().contains(enteredText.toLowerCase())) { + entriesFiltered.add(entry); + } + } + + if (entriesFiltered.size() > 0) { + this.setModel( + new DefaultComboBoxModel( + entriesFiltered.toArray())); + this.setSelectedItem(enteredText); + this.showPopup(); + } else { + this.hidePopup(); + } + } +} diff --git a/src/com/magento/idea/magento2plugin/util/GetFirstClassOfFile.java b/src/com/magento/idea/magento2plugin/util/GetFirstClassOfFile.java new file mode 100644 index 000000000..1d308b9c5 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/util/GetFirstClassOfFile.java @@ -0,0 +1,28 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.util; + +import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.php.lang.psi.PhpFile; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import org.jetbrains.annotations.Nullable; +import java.util.Collection; + +public class GetFirstClassOfFile { + private static GetFirstClassOfFile INSTANCE = null; + + public static GetFirstClassOfFile getInstance() { + if (null == INSTANCE) { + INSTANCE = new GetFirstClassOfFile(); + } + return INSTANCE; + } + + @Nullable + public PhpClass execute(PhpFile phpFile) { + Collection phpClasses = PsiTreeUtil.collectElementsOfType(phpFile, PhpClass.class); + return phpClasses.size() == 0 ? null : phpClasses.iterator().next(); + } +} diff --git a/src/com/magento/idea/magento2plugin/util/Regex.java b/src/com/magento/idea/magento2plugin/util/Regex.java index 5fe10d817..7566edf46 100644 --- a/src/com/magento/idea/magento2plugin/util/Regex.java +++ b/src/com/magento/idea/magento2plugin/util/Regex.java @@ -1,5 +1,5 @@ -/** - * Copyright © Dmytro Kvashnin. All rights reserved. +/* + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ package com.magento.idea.magento2plugin.util; @@ -8,4 +8,13 @@ public class Regex { public static final String ALPHANUMERIC = "[a-zA-Z0-9]*"; + + public static final String NUMERIC + = "[0-9]*"; + + public static final String IDENTIFIER + = "[a-zA-Z0-9_\\-]*"; + + public static final String DIRECTORY + = "^(?!\\/)[a-zA-Z0-9\\/]*[^\\/]$"; } diff --git a/src/com/magento/idea/magento2plugin/util/magento/FileBasedIndexUtil.java b/src/com/magento/idea/magento2plugin/util/magento/FileBasedIndexUtil.java index cb12b3741..31917ad28 100644 --- a/src/com/magento/idea/magento2plugin/util/magento/FileBasedIndexUtil.java +++ b/src/com/magento/idea/magento2plugin/util/magento/FileBasedIndexUtil.java @@ -6,12 +6,16 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.indexing.FileBasedIndex; import com.jetbrains.php.lang.PhpFileType; +import com.magento.idea.magento2plugin.magento.packages.Package; import com.magento.idea.magento2plugin.stubs.indexes.ModuleNameIndex; import com.magento.idea.magento2plugin.util.RegExUtil; +import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.regex.Matcher; @@ -43,6 +47,40 @@ public static Collection findViewVfsByModuleName(String moduleName, return viewVfs; } + public static PsiFile findModuleConfigFile(String virtualFieName, Package.Areas area, String moduleName, Project project) + { + Pattern pattern = Pattern.compile(RegExUtil.Magento.MODULE_NAME); + Matcher matcher = pattern.matcher(moduleName); + if (!matcher.find()) { + return null; + } + + Collection moduleVfs = + FileBasedIndex.getInstance().getContainingFiles(ModuleNameIndex.KEY, moduleName, + GlobalSearchScope.getScopeRestrictedByFileTypes( + GlobalSearchScope.allScope(project), + PhpFileType.INSTANCE + ) + ); + if (moduleVfs.isEmpty()) { + return null; + } + + VirtualFile moduleVf = moduleVfs.iterator().next(); + + String relativePath = File.separator.concat(Package.MODULE_BASE_AREA_DIR).concat(File.separator); + if (!area.equals(Package.Areas.base)) { + relativePath = relativePath.concat(area.toString()).concat(File.separator); + } + relativePath = relativePath.concat(virtualFieName); + + VirtualFile configFile = moduleVf.getParent().findFileByRelativePath(relativePath); + if (configFile == null) { + return null; + } + return PsiManager.getInstance(project).findFile(configFile); + } + public static Collection findViewVfsByModuleVf(VirtualFile moduleVf, Project project) { Collection viewVfs = new ArrayList<>(); diff --git a/src/com/magento/idea/magento2plugin/util/magento/plugin/IsPluginAllowedForMethod.java b/src/com/magento/idea/magento2plugin/util/magento/plugin/IsPluginAllowedForMethod.java new file mode 100644 index 000000000..9a99840c8 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/util/magento/plugin/IsPluginAllowedForMethod.java @@ -0,0 +1,37 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.util.magento.plugin; + +import com.jetbrains.php.lang.psi.elements.Method; +import com.magento.idea.magento2plugin.magento.files.Plugin; + +public class IsPluginAllowedForMethod { + private static IsPluginAllowedForMethod INSTANCE = null; + + public static IsPluginAllowedForMethod getInstance() { + if (null == INSTANCE) { + INSTANCE = new IsPluginAllowedForMethod(); + } + return INSTANCE; + } + + public boolean check(Method targetMethod) { + String targetMethodName = targetMethod.getName(); + if (targetMethodName.equals(Plugin.constructMethodName)) { + return false; + } + if (targetMethod.isFinal()) { + return false; + } + if (targetMethod.isStatic()) { + return false; + } + if (!targetMethod.getAccess().toString().equals(Plugin.publicAccess)) { + return false; + } + + return true; + } +}