From 8897c15ba4c09bd7ba611381d1fd1bb0a6962115 Mon Sep 17 00:00:00 2001 From: Mykola Donin Date: Tue, 22 Feb 2022 16:03:04 +0200 Subject: [PATCH 01/20] 828: rename inspection titles --- .../CallingDeprecatedMethod.html | 2 +- .../ExtendingDeprecatedClass.html | 2 +- .../ImplementedDeprecatedInterface.html | 2 +- .../ImportingDeprecatedClass.html | 2 +- .../ImportingDeprecatedInterface.html | 2 +- .../InheritedDeprecatedInterface.html | 2 +- .../OverridingDeprecatedConstant.html | 2 +- .../OverridingDeprecatedProperty.html | 2 +- .../UsingDeprecatedClass.html | 2 +- .../UsingDeprecatedConstant.html | 2 +- .../UsingDeprecatedInterface.html | 2 +- .../UsingDeprecatedProperty.html | 2 +- resources/uct/bundle/inspection.properties | 44 +++++++++---------- .../execution/GenerateUctReportCommand.java | 13 +++++- .../execution/output/UctReportOutputUtil.java | 5 ++- 15 files changed, 49 insertions(+), 37 deletions(-) diff --git a/resources/inspectionDescriptions/CallingDeprecatedMethod.html b/resources/inspectionDescriptions/CallingDeprecatedMethod.html index f4cb7d794..7b011cc34 100644 --- a/resources/inspectionDescriptions/CallingDeprecatedMethod.html +++ b/resources/inspectionDescriptions/CallingDeprecatedMethod.html @@ -1,6 +1,6 @@ -

[1439] Call Adobe Commerce @deprecated method: The deprecated method will be removed in upcoming versions. Consider relying on methods declared in API interfaces instead.

+

[1439] Call Magento Open Source|Adobe Commerce @deprecated method: The deprecated method will be removed in upcoming versions. Consider relying on methods declared in API interfaces instead.

diff --git a/resources/inspectionDescriptions/ExtendingDeprecatedClass.html b/resources/inspectionDescriptions/ExtendingDeprecatedClass.html index 735578a74..fd21d55a4 100644 --- a/resources/inspectionDescriptions/ExtendingDeprecatedClass.html +++ b/resources/inspectionDescriptions/ExtendingDeprecatedClass.html @@ -1,6 +1,6 @@ -

[1131] Extending from Adobe Commerce @deprecated class: The extended class will be removed in upcoming versions. Inheritance is not recommended way of extending Adobe Commerce functionality. Update code to use a class marked as @api.

+

[1131] Extending from Magento Open Source|Adobe Commerce @deprecated class: The extended class will be removed in upcoming versions. Inheritance is not recommended way of extending Magento Open Source|Adobe Commerce functionality. Update code to use a class marked as @api.

diff --git a/resources/inspectionDescriptions/ImplementedDeprecatedInterface.html b/resources/inspectionDescriptions/ImplementedDeprecatedInterface.html index dcc132bbe..c92dc7dfe 100644 --- a/resources/inspectionDescriptions/ImplementedDeprecatedInterface.html +++ b/resources/inspectionDescriptions/ImplementedDeprecatedInterface.html @@ -1,6 +1,6 @@ -

[1338] Implemented Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider removing the interface inheritance, using an interface marked as @api or an interface introduced within your implementation instead.

+

[1338] Implemented Magento Open Source|Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider removing the interface inheritance, using an interface marked as @api or an interface introduced within your implementation instead.

diff --git a/resources/inspectionDescriptions/ImportingDeprecatedClass.html b/resources/inspectionDescriptions/ImportingDeprecatedClass.html index 395fcca44..2b5c78e8d 100644 --- a/resources/inspectionDescriptions/ImportingDeprecatedClass.html +++ b/resources/inspectionDescriptions/ImportingDeprecatedClass.html @@ -1,6 +1,6 @@ -

[1132] Importing Adobe Commerce @deprecated class: The extended class will be removed in upcoming versions. Consider using Adobe Commerce class marked as @api instead.

+

[1132] Importing Magento Open Source|Adobe Commerce @deprecated class: The extended class will be removed in upcoming versions. Consider using Magento Open Source|Adobe Commerce class marked as @api instead.

diff --git a/resources/inspectionDescriptions/ImportingDeprecatedInterface.html b/resources/inspectionDescriptions/ImportingDeprecatedInterface.html index 3026e83a8..b87bf748e 100644 --- a/resources/inspectionDescriptions/ImportingDeprecatedInterface.html +++ b/resources/inspectionDescriptions/ImportingDeprecatedInterface.html @@ -1,6 +1,6 @@ -

[1332] Imported Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider using an interface or class marked as @api instead.

+

[1332] Imported Magento Open Source|Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider using an interface or class marked as @api instead.

\ No newline at end of file diff --git a/resources/inspectionDescriptions/InheritedDeprecatedInterface.html b/resources/inspectionDescriptions/InheritedDeprecatedInterface.html index 682eadc89..83732ecdb 100644 --- a/resources/inspectionDescriptions/InheritedDeprecatedInterface.html +++ b/resources/inspectionDescriptions/InheritedDeprecatedInterface.html @@ -1,6 +1,6 @@ -

[1337] Inherited from Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider removing the interface inheritance, using an interface marked as @api or an interface introduced within your implementation instead.

+

[1337] Inherited from Magento Open Source|Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider removing the interface inheritance, using an interface marked as @api or an interface introduced within your implementation instead.

diff --git a/resources/inspectionDescriptions/OverridingDeprecatedConstant.html b/resources/inspectionDescriptions/OverridingDeprecatedConstant.html index d3b9dfb30..3e6de44e7 100644 --- a/resources/inspectionDescriptions/OverridingDeprecatedConstant.html +++ b/resources/inspectionDescriptions/OverridingDeprecatedConstant.html @@ -1,6 +1,6 @@ -

[1235] Overriding Adobe Commerce @deprecated constant: The deprecated constant will be removed in upcoming versions. Consider using a constant marked as @api or a private constant within your implementation instead.

+

[1235] Overriding Magento Open Source|Adobe Commerce @deprecated constant: The deprecated constant will be removed in upcoming versions. Consider using a constant marked as @api or a private constant within your implementation instead.

diff --git a/resources/inspectionDescriptions/OverridingDeprecatedProperty.html b/resources/inspectionDescriptions/OverridingDeprecatedProperty.html index cc74490bb..5fc9bd27f 100644 --- a/resources/inspectionDescriptions/OverridingDeprecatedProperty.html +++ b/resources/inspectionDescriptions/OverridingDeprecatedProperty.html @@ -1,6 +1,6 @@ -

[1535] Overriding Adobe Commerce @deprecated property: The deprecated property will be removed in upcoming versions. Consider relying on methods declared in API interfaces or using a private property within your implementation instead.

+

[1535] Overriding Magento Open Source|Adobe Commerce @deprecated property: The deprecated property will be removed in upcoming versions. Consider relying on methods declared in API interfaces or using a private property within your implementation instead.

diff --git a/resources/inspectionDescriptions/UsingDeprecatedClass.html b/resources/inspectionDescriptions/UsingDeprecatedClass.html index fd5062e5e..26951b290 100644 --- a/resources/inspectionDescriptions/UsingDeprecatedClass.html +++ b/resources/inspectionDescriptions/UsingDeprecatedClass.html @@ -1,6 +1,6 @@ -

[1134] Using Adobe Commerce @deprecated class: The extended class will be removed in upcoming versions. Consider using Adobe Commerce class marked as @api instead.

+

[1134] Using Magento Open Source|Adobe Commerce @deprecated class: The extended class will be removed in upcoming versions. Consider using Magento Open Source|Adobe Commerce class marked as @api instead.

diff --git a/resources/inspectionDescriptions/UsingDeprecatedConstant.html b/resources/inspectionDescriptions/UsingDeprecatedConstant.html index 9b7133d4a..fe0cd280f 100644 --- a/resources/inspectionDescriptions/UsingDeprecatedConstant.html +++ b/resources/inspectionDescriptions/UsingDeprecatedConstant.html @@ -1,6 +1,6 @@ -

[1234] Using Adobe Commerce @deprecated constant: The deprecated constant will be removed in upcoming versions. Consider using a constant marked as @api or a private constant within your implementation instead.

+

[1234] Using Magento Open Source|Adobe Commerce @deprecated constant: The deprecated constant will be removed in upcoming versions. Consider using a constant marked as @api or a private constant within your implementation instead.

diff --git a/resources/inspectionDescriptions/UsingDeprecatedInterface.html b/resources/inspectionDescriptions/UsingDeprecatedInterface.html index 49a77b6be..6dd322c66 100644 --- a/resources/inspectionDescriptions/UsingDeprecatedInterface.html +++ b/resources/inspectionDescriptions/UsingDeprecatedInterface.html @@ -1,6 +1,6 @@ -

[1334] Used Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider using an interface or class marked as @api instead.

+

[1334] Used Magento Open Source|Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider using an interface or class marked as @api instead.

diff --git a/resources/inspectionDescriptions/UsingDeprecatedProperty.html b/resources/inspectionDescriptions/UsingDeprecatedProperty.html index 38a2d179c..e06e87bb6 100644 --- a/resources/inspectionDescriptions/UsingDeprecatedProperty.html +++ b/resources/inspectionDescriptions/UsingDeprecatedProperty.html @@ -1,6 +1,6 @@ -

[1534] Using Adobe Commerce @deprecated property: The deprecated method will be removed in upcoming versions. Consider relying on methods declared in API interfaces instead.

+

[1534] Using Magento Open Source|Adobe Commerce @deprecated property: The deprecated method will be removed in upcoming versions. Consider relying on methods declared in API interfaces instead.

diff --git a/resources/uct/bundle/inspection.properties b/resources/uct/bundle/inspection.properties index d51e8fdc2..acb6cbfe6 100644 --- a/resources/uct/bundle/inspection.properties +++ b/resources/uct/bundle/inspection.properties @@ -14,28 +14,28 @@ inspection.displayName.InheritedDeprecatedInterface=Inherited from @deprecated i inspection.displayName.ImplementedDeprecatedInterface=Implemented @deprecated interface inspection.displayName.CallingDeprecatedMethod=Call @deprecated method inspection.displayName.UsingDeprecatedProperty=Using @deprecated property -inspection.displayName.ImportingNonExistentClass=Importing non-existent Adobe Commerce class -inspection.displayName.ImportingNonExistentInterface=Importing non-existent Adobe Commerce interface -inspection.displayName.InheritedNonExistentInterface=Inherited non-existent Adobe Commerce interface -inspection.displayName.ImplementedNonExistentInterface=Implemented non-existent Adobe Commerce interface -inspection.displayName.ExtendedNonExistentClass=Extended non-existent Adobe Commerce class -inspection.displayName.OverriddenNonExistentConstant=Overridden non-existent Adobe Commerce constant -inspection.displayName.OverriddenNonExistentProperty=Overridden non-existent Adobe Commerce property -inspection.displayName.CalledNonExistentMethod=Call non-existent Adobe Commerce method -inspection.displayName.UsedNonExistentType=Used non-existent Adobe Commerce type -inspection.displayName.UsedNonExistentConstant=Used non-existent Adobe Commerce constant -inspection.displayName.UsedNonExistentProperty=Used non-existent Adobe Commerce property -inspection.displayName.ImportedNonApiClass=Imported non Adobe Commerce API class -inspection.displayName.ImportedNonApiInterface=Imported non Adobe Commerce API interface -inspection.displayName.CalledNonApiMethod=Called non Adobe Commerce API method -inspection.displayName.OverriddenNonApiConstant=Overridden non Adobe Commerce API constant -inspection.displayName.OverriddenNonApiProperty=Overridden non Adobe Commerce API property -inspection.displayName.UsedNonApiConstant=Used non Adobe Commerce API constant -inspection.displayName.UsedNonApiProperty=Used non Adobe Commerce API property -inspection.displayName.UsedNonApiType=Used non Adobe Commerce API type -inspection.displayName.ImplementedNonApiInterface=Implemented non Adobe Commerce API interface -inspection.displayName.ExtendedNonApiClass=Extended non Adobe Commerce API class -inspection.displayName.InheritedNonApiInterface=Inherited non Adobe Commerce API interface +inspection.displayName.ImportingNonExistentClass=Importing non-existent Magento Open Source|Adobe Commerce class +inspection.displayName.ImportingNonExistentInterface=Importing non-existent Magento Open Source|Adobe Commerce interface +inspection.displayName.InheritedNonExistentInterface=Inherited non-existent Magento Open Source|Adobe Commerce interface +inspection.displayName.ImplementedNonExistentInterface=Implemented non-existent Magento Open Source|Adobe Commerce interface +inspection.displayName.ExtendedNonExistentClass=Extended non-existent Magento Open Source|Adobe Commerce class +inspection.displayName.OverriddenNonExistentConstant=Overridden non-existent Magento Open Source|Adobe Commerce constant +inspection.displayName.OverriddenNonExistentProperty=Overridden non-existent Magento Open Source|Adobe Commerce property +inspection.displayName.CalledNonExistentMethod=Call non-existent Magento Open Source|Adobe Commerce method +inspection.displayName.UsedNonExistentType=Used non-existent Magento Open Source|Adobe Commerce type +inspection.displayName.UsedNonExistentConstant=Used non-existent Magento Open Source|Adobe Commerce constant +inspection.displayName.UsedNonExistentProperty=Used non-existent Magento Open Source|Adobe Commerce property +inspection.displayName.ImportedNonApiClass=Imported non Magento Open Source|Adobe Commerce API class +inspection.displayName.ImportedNonApiInterface=Imported non Magento Open Source|Adobe Commerce API interface +inspection.displayName.CalledNonApiMethod=Called non Magento Open Source|Adobe Commerce API method +inspection.displayName.OverriddenNonApiConstant=Overridden non Magento Open Source|Adobe Commerce API constant +inspection.displayName.OverriddenNonApiProperty=Overridden non Magento Open Source|Adobe Commerce API property +inspection.displayName.UsedNonApiConstant=Used non Magento Open Source|Adobe Commerce API constant +inspection.displayName.UsedNonApiProperty=Used non Magento Open Source|Adobe Commerce API property +inspection.displayName.UsedNonApiType=Used non Magento Open Source|Adobe Commerce API type +inspection.displayName.ImplementedNonApiInterface=Implemented non Magento Open Source|Adobe Commerce API interface +inspection.displayName.ExtendedNonApiClass=Extended non Magento Open Source|Adobe Commerce API class +inspection.displayName.InheritedNonApiInterface=Inherited non Magento Open Source|Adobe Commerce API interface inspection.displayName.PossibleDependencyOnImplDetails=Possible dependency on implementation details inspection.displayName.CalledNonInterfaceMethod=Called non-interface method customCode.warnings.deprecated.1131=[1131] Extended class ''{0}'' that is @deprecated in the ''{1}'' diff --git a/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java index 2418a8ad9..5c27b1709 100644 --- a/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java +++ b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.jetbrains.php.lang.psi.PhpFile; +import com.magento.idea.magento2plugin.util.magento.MagentoVersionUtil; import com.magento.idea.magento2uct.execution.output.ReportBuilder; import com.magento.idea.magento2uct.execution.output.Summary; import com.magento.idea.magento2uct.execution.output.UctReportOutputUtil; @@ -36,12 +37,15 @@ import com.magento.idea.magento2uct.util.inspection.SortDescriptorResultsUtil; import java.nio.file.Paths; import java.util.List; +import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @SuppressWarnings({"PMD.NPathComplexity", "PMD.ExcessiveImports", "PMD.CognitiveComplexity"}) public class GenerateUctReportCommand { + private static final String DEFAULT_MAGENTO_EDITION_LABEL = "Magento Open Source"; + private final Project project; private final OutputWrapper output; private final ProcessHandler process; @@ -99,6 +103,13 @@ public void execute() { ); final ReportBuilder reportBuilder = new ReportBuilder(project); final UctReportOutputUtil outputUtil = new UctReportOutputUtil(output); + final Pair version = MagentoVersionUtil.getVersionData( + project, + project.getBasePath() + ); + final String resolvedEdition = version.getSecond() == null + ? DEFAULT_MAGENTO_EDITION_LABEL + : version.getSecond(); ApplicationManager.getApplication().executeOnPooledThread(() -> { ApplicationManager.getApplication().runReadAction(() -> { @@ -154,7 +165,7 @@ public void execute() { } summary.trackProcessFinished(); summary.setProcessedModules(scanner.getModuleCount()); - outputUtil.printSummary(summary); + outputUtil.printSummary(summary, resolvedEdition); if (summary.getProcessedModules() == 0) { process.destroyProcess(); diff --git a/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java b/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java index cd370f81f..d68dced08 100644 --- a/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java +++ b/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java @@ -78,9 +78,10 @@ public void printIssue(final @NotNull ProblemDescriptor descriptor, final int co * Print summary information. * * @param summary Summary + * @param platformName String */ @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") - public void printSummary(final Summary summary) { + public void printSummary(final Summary summary, final String platformName) { if (summary.getProcessedModules() == 0) { stdout.print(stdout.wrapInfo("Couldn't find modules to analyse").concat("\n")); return; @@ -92,7 +93,7 @@ public void printSummary(final Summary summary) { final Map summaryMap = new LinkedHashMap<>(); summaryMap.put("Installed version", summary.getInstalledVersion()); - summaryMap.put("Adobe Commerce version", summary.getTargetVersion()); + summaryMap.put(platformName + " version", summary.getTargetVersion()); summaryMap.put("Running time", summary.getProcessRunningTime()); summaryMap.put("Checked modules", String.valueOf(summary.getProcessedModules())); summaryMap.put("Total warnings found", String.valueOf(summary.getPhpWarnings())); From ac1a97cdf4a719c6510d128381732cce6707057c Mon Sep 17 00:00:00 2001 From: Mykola Donin Date: Tue, 22 Feb 2022 16:36:53 +0200 Subject: [PATCH 02/20] 828: update code style --- .../idea/magento2uct/execution/GenerateUctReportCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java index 5c27b1709..eac800e06 100644 --- a/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java +++ b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java @@ -13,6 +13,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; @@ -37,7 +38,6 @@ import com.magento.idea.magento2uct.util.inspection.SortDescriptorResultsUtil; import java.nio.file.Paths; import java.util.List; -import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; From ab81ce10380fe21cb475469b57c7c1e4aefbc97a Mon Sep 17 00:00:00 2001 From: Mykola Donin Date: Mon, 28 Feb 2022 12:58:28 +0200 Subject: [PATCH 03/20] 414: Added Images support for Copy Magento Path --- .../actions/CopyMagentoPath.java | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/com/magento/idea/magento2plugin/actions/CopyMagentoPath.java b/src/com/magento/idea/magento2plugin/actions/CopyMagentoPath.java index 1e1bc0be5..1d381b0fd 100644 --- a/src/com/magento/idea/magento2plugin/actions/CopyMagentoPath.java +++ b/src/com/magento/idea/magento2plugin/actions/CopyMagentoPath.java @@ -15,8 +15,10 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.magento.idea.magento2plugin.util.magento.GetModuleNameByDirectoryUtil; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import javax.imageio.ImageIO; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,6 +29,8 @@ public class CopyMagentoPath extends CopyPathProvider { public static final String CSS_EXTENSION = "css"; private final List acceptedTypes = Arrays.asList(PHTML_EXTENSION, JS_EXTENSION, CSS_EXTENSION); + private static final List SUPPORTED_IMAGE_EXTENSIONS + = new ArrayList<>(Arrays.asList(ImageIO.getReaderFormatNames())); public static final String SEPARATOR = "::"; private int index; @@ -44,6 +48,15 @@ public class CopyMagentoPath extends CopyPathProvider { "web/" }; + /** + * Copy Magento Path actions for phtml, css, js, images extensions. + */ + public CopyMagentoPath() { + super(); + + SUPPORTED_IMAGE_EXTENSIONS.add("svg"); + } + @Override public void update(@NotNull final AnActionEvent event) { final VirtualFile virtualFile = event.getData(PlatformDataKeys.VIRTUAL_FILE); @@ -54,7 +67,8 @@ public void update(@NotNull final AnActionEvent event) { private boolean isNotValidFile(final VirtualFile virtualFile) { return virtualFile != null && virtualFile.isDirectory() - || virtualFile != null && !acceptedTypes.contains(virtualFile.getExtension()); + || virtualFile != null && !acceptedTypes.contains(virtualFile.getExtension()) + && !SUPPORTED_IMAGE_EXTENSIONS.contains(virtualFile.getExtension()); } @Override @@ -85,24 +99,23 @@ private boolean isNotValidFile(final VirtualFile virtualFile) { if (PHTML_EXTENSION.equals(virtualFile.getExtension())) { paths = templatePaths; } else if (JS_EXTENSION.equals(virtualFile.getExtension()) - || CSS_EXTENSION.equals(virtualFile.getExtension())) { + || CSS_EXTENSION.equals(virtualFile.getExtension()) + || SUPPORTED_IMAGE_EXTENSIONS.contains(virtualFile.getExtension())) { paths = webPaths; } else { return fullPath.toString(); } - int endIndex; try { - endIndex = getIndexOf(paths, fullPath, paths[++index]); - } catch (ArrayIndexOutOfBoundsException exception) { - // endIndex could not be found. - return ""; - } - final int offset = paths[index].length(); + final int endIndex = getIndexOf(paths, fullPath, paths[++index]); + final int offset = paths[index].length(); - fullPath.replace(0, endIndex + offset, ""); + fullPath.replace(0, endIndex + offset, ""); - return moduleName + SEPARATOR + fullPath; + return moduleName + SEPARATOR + fullPath; + } catch (ArrayIndexOutOfBoundsException exception) { + return fullPath.toString(); + } } /** From 11dbae84b42f4d46195fc51982b27a9963d0c801 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Mon, 7 Mar 2022 10:20:45 +0200 Subject: [PATCH 04/20] 409: Added arguments injection/replacement action --- resources/META-INF/plugin.xml | 3 + resources/magento2/validation.properties | 4 + .../InjectConstructorArgumentAction.java | 113 +++ .../generation/data/xml/DiArgumentData.java | 100 +++ .../generation/data/xml/DiArrayValueData.java | 235 +++++++ .../generation/dialog/AbstractDialog.java | 12 +- .../dialog/GatherArrayValuesDialog.form | 102 +++ .../dialog/GatherArrayValuesDialog.java | 235 +++++++ .../dialog/NewArgumentInjectionDialog.form | 460 ++++++++++++ .../dialog/NewArgumentInjectionDialog.java | 652 ++++++++++++++++++ .../validator/annotation/RuleRegistry.java | 3 + .../validator/rule/ExtendedNumericRule.java | 24 + .../code/ArgumentInjectionGenerator.java | 219 ++++++ .../code/util/DiXmlTagManipulatorUtil.java | 187 +++++ .../generator/util/CommitXmlFileUtil.java | 25 +- .../magento/packages/DiArgumentType.java | 133 ++++ .../idea/magento2plugin/util/RegExUtil.java | 3 + .../util/php/PhpPsiElementsUtil.java | 18 + 18 files changed, 2525 insertions(+), 3 deletions(-) create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/InjectConstructorArgumentAction.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/data/xml/DiArgumentData.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/data/xml/DiArrayValueData.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.form create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.form create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/ExtendedNumericRule.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/generator/code/ArgumentInjectionGenerator.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/generator/code/util/DiXmlTagManipulatorUtil.java create mode 100644 src/com/magento/idea/magento2plugin/magento/packages/DiArgumentType.java diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index a1fbfdee1..45ba1193a 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -126,6 +126,9 @@ + + + %value%"; + private static final String NULL_VALUE_ITEM_TEMPLATE = + ""; + + private final List items = new ArrayList<>(); + + /** + * Set items data. + * + * @param items List[DiArrayItemData] + */ + public void setItems(final List items) { + this.items.clear(); + this.items.addAll(items); + } + + /** + * Get items data. + * + * @return List[DiArrayItemData] + */ + public List getItems() { + return items; + } + + /** + * Get internal item by its path. + * + * @param path String divided by `:`. + * + * @return DiArrayItemData + */ + public DiArrayItemData getItemByPath(final String path) { + DiArrayItemData target = null; + final String[] parts = path.split(":"); + final String[] left = Arrays.copyOfRange(parts, 1, parts.length); + final String key = parts[0]; + + for (final DiArrayItemData item : getItems()) { + if (item.getName().equals(key)) { + target = item; + + if (left.length > 0) { + final DiArrayValueData childrenHolder = item.getChildren(); + + if (childrenHolder == null) { + break; + } + target = childrenHolder.getItemByPath(String.join(":", left)); + } + break; + } + } + + return target; + } + + @Override + public String toString() { + return buildArrayTree(this, 0); + } + + /** + * Convert to XML. + * + * @param data DiArrayValueData + * + * @return String + */ + public String convertToXml(final DiArrayValueData data) { + final StringBuilder stringBuilder = new StringBuilder(); + + for (final DiArrayItemData item : data.getItems()) { + String value = item.getValue(); + String template = ITEM_TEMPLATE; + + if (item.getType().equals(DiArgumentType.ARRAY) && item.hasChildren()) { + value = "\n" + convertToXml(item.getChildren()) + "\n"; + } else if (item.getType().equals(DiArgumentType.NULL)) { + template = NULL_VALUE_ITEM_TEMPLATE; + } + final String name = item.getName(); + final String type = item.getType().getArgumentType(); + + stringBuilder.append( + template + .replace("%name%", name) + .replace("%type%", type) + .replace("%value%", value) + ); + } + + return stringBuilder.toString(); + } + + private String buildArrayTree(final DiArrayValueData data, final int indentSize) { + final StringBuilder stringBuilder = new StringBuilder(); + + stringBuilder.append(indent(0)); + stringBuilder.append("["); + stringBuilder.append("\n"); + int currentItem = 0; + final int itemsCount = data.getItems().size(); + + for (final DiArrayItemData item : data.getItems()) { + stringBuilder.append(indent(indentSize + 1)); + String value = item.getValue(); + + if (item.getType().equals(DiArgumentType.STRING)) { + value = "'" + value + "'"; + } else if (item.getType().equals(DiArgumentType.ARRAY) && item.hasChildren()) { + value = buildArrayTree(item.getChildren(), indentSize + 1); + } else if (item.getType().equals(DiArgumentType.ARRAY) && !item.hasChildren()) { + value = "[]"; + } else if (item.getType().equals(DiArgumentType.BOOLEAN)) { + value = Arrays.asList("1", "true").contains(item.getValue()) ? "true" : "false"; + } else if (item.getType().equals(DiArgumentType.NULL)) { + value = "null"; + } + + stringBuilder + .append("'" + item.getName() + "'") + .append(" => ") + .append(value); + + if (currentItem != itemsCount - 1) { + stringBuilder.append(","); + } + stringBuilder.append("\n"); + currentItem++; + } + stringBuilder.append(indent(indentSize)); + stringBuilder.append("]"); + + return stringBuilder.toString(); + } + + private String indent(final int indentSize) { + return " ".repeat(Math.max(0, indentSize)); + } + + public static class DiArrayItemData { + + private DiArrayValueData children; + private final String name; + private final DiArgumentType type; + private final String value; + + /** + * DiArrayItemData DTO constructor. + * + * @param name String + * @param type DiArgumentType + * @param value DiArgumentType + */ + public DiArrayItemData( + final String name, + final DiArgumentType type, + final String value + ) { + this.name = name; + this.type = type; + this.value = value; + } + + /** + * Check if current item has children. + * + * @return boolean + */ + public boolean hasChildren() { + return children != null && !children.getItems().isEmpty(); + } + + /** + * Get children elements holder. + * + * @return DiArrayValueData + */ + public DiArrayValueData getChildren() { + return children; + } + + /** + * Set children elements holder. + * + * @param children DiArrayValueData + */ + public void setChildren(final DiArrayValueData children) { + this.children = children; + } + + /** + * Get item name. + * + * @return String + */ + public String getName() { + return name; + } + + /** + * Get item type. + * + * @return DiArgumentType + */ + public DiArgumentType getType() { + return type; + } + + /** + * Get item value. + * + * @return String + */ + public String getValue() { + return value; + } + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/AbstractDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/AbstractDialog.java index 395e2793f..1736a00a4 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/AbstractDialog.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/AbstractDialog.java @@ -6,6 +6,7 @@ package com.magento.idea.magento2plugin.actions.generation.dialog; import com.intellij.openapi.util.Pair; +import com.magento.idea.magento2plugin.actions.generation.data.ui.ComboBoxItemData; import com.magento.idea.magento2plugin.actions.generation.dialog.prompt.PlaceholderInitializerUtil; import com.magento.idea.magento2plugin.actions.generation.dialog.reflection.ExtractComponentFromFieldUtil; import com.magento.idea.magento2plugin.actions.generation.dialog.util.DialogFieldErrorUtil; @@ -209,8 +210,17 @@ private String resolveFieldValueByComponentType(final Field field) { } else if (component instanceof JComboBox) { if (((JComboBox) component).getSelectedIndex() == -1) { return ""; + } + final Object selectedItem = ((JComboBox) component).getSelectedItem(); + + if (selectedItem == null) { + return ""; + } + + if (selectedItem instanceof ComboBoxItemData) { + return ((ComboBoxItemData) selectedItem).getKey(); } else { - return ((JComboBox) component).getSelectedItem().toString(); + return selectedItem.toString(); } } else if (component instanceof JTextArea) { return ((JTextArea) component).getText(); diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.form b/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.form new file mode 100644 index 000000000..12fb4d29c --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.form @@ -0,0 +1,102 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.java new file mode 100644 index 000000000..04052a95a --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.java @@ -0,0 +1,235 @@ +/* + * 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.intellij.openapi.util.Pair; +import com.intellij.util.ui.UIUtil; +import com.magento.idea.magento2plugin.actions.generation.InjectConstructorArgumentAction; + +import java.awt.Color; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.KeyStroke; +import javax.swing.table.DefaultTableModel; + +import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArrayValueData; +import com.magento.idea.magento2plugin.bundles.ValidatorBundle; +import com.magento.idea.magento2plugin.magento.packages.DiArgumentType; +import com.magento.idea.magento2plugin.magento.packages.PropertiesTypes; +import com.magento.idea.magento2plugin.ui.table.TableGroupWrapper; +import org.jetbrains.annotations.NotNull; + +public class GatherArrayValuesDialog extends AbstractDialog { + + private static final String ITEM_NAME = "Name"; + private static final String ITEM_TYPE = "Type"; + private static final String ITEM_VALUE = "Value"; + + private final @NotNull Project project; + private DiArrayValueData arrayValueData; + + private TableGroupWrapper tableGroupWrapper; + + private JPanel contentPane; + private JButton buttonCancel; + private JButton buttonOK; + private JPanel itemsPane; + private JScrollPane itemsScrollPane; + private JTable itemsTable; + private JButton buttonAdd; + private JLabel itemsTableErrorMessage; + + /** + * Array values gathering dialog constructor. + * + * @param project Project + * @param arrayValueData DiArrayValueData + */ + public GatherArrayValuesDialog( + final @NotNull Project project, + final DiArrayValueData arrayValueData + ) { + super(); + + this.project = project; + this.arrayValueData = arrayValueData; + + setContentPane(contentPane); + setModal(true); + setTitle(InjectConstructorArgumentAction.GATHER_ARRAY_VALUES_ACTION_DESCRIPTION); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(event -> onOK()); + buttonCancel.addActionListener(event -> onCancel()); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(final WindowEvent event) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction( + event -> onCancel(), + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + + initTable(); + itemsTableErrorMessage.setVisible(false); + itemsTableErrorMessage.setText(""); + } + + /** + * Open a new array values gathering dialog. + * + * @param project Project + * @param arrayValueData DiArrayValueData + */ + public static void open( + final @NotNull Project project, + final DiArrayValueData arrayValueData + ) { + final GatherArrayValuesDialog dialog = new GatherArrayValuesDialog(project, arrayValueData); + dialog.pack(); + dialog.centerDialog(dialog); + dialog.setVisible(true); + } + + /** + * Fire process if all fields are valid. + */ + private void onOK() { + if (itemsTable.isEditing()) { + itemsTable.getCellEditor().stopCellEditing(); + } + final List items = extractItems(getTableModel()); + final Pair validationResult = validateItems(items); + + if (!validationResult.getFirst()) { + showErrorMessage(validationResult.getSecond()); + return; + } + arrayValueData.setItems(items); + exit(); + } + + @Override + protected void showErrorMessage(final @NotNull String errorMessage) { + itemsTableErrorMessage.setVisible(true); + itemsTableErrorMessage.setFont(UIUtil.getLabelFont(UIUtil.FontSize.SMALL)); + itemsTableErrorMessage.setForeground(new Color(252, 119, 83)); + itemsTableErrorMessage.setText(errorMessage); + } + + private void initTable() { + final List columns = new LinkedList<>(Arrays.asList( + ITEM_NAME, + ITEM_TYPE, + ITEM_VALUE + )); + final Map> sources = new HashMap<>(); + sources.put(ITEM_TYPE, DiArgumentType.getValueList()); + + tableGroupWrapper = new TableGroupWrapper( + itemsTable, + buttonAdd, + columns, + new HashMap<>(), + sources + ); + tableGroupWrapper.initTableGroup(); + } + + private Pair validateItems( + final List items + ) { + final ValidatorBundle validatorBundle = new ValidatorBundle(); + final List itemsNames = new ArrayList<>(); + + for (final DiArrayValueData.DiArrayItemData item : items) { + final DiArgumentType type = item.getType(); + final String value = item.getValue().trim(); + final String name = item.getName().trim(); + + if (name.isEmpty()) { + return new Pair<>( + Boolean.FALSE, + validatorBundle.message("validator.arrayValuesDialog.nameMustNotBeEmpty") + ); + } + itemsNames.add(name); + + final boolean isValid = type.isValid(value); + + if (!isValid) { + return new Pair<>( + Boolean.FALSE, + validatorBundle.message( + "validator.arrayValuesDialog.invalidValueForRowWithName", + value, + name + ) + ); + } + } + + if (itemsNames.stream().distinct().count() != itemsNames.size()) { + return new Pair<>( + Boolean.FALSE, + validatorBundle.message( + "validator.arrayValuesDialog.namesMustBeUnique" + ) + ); + } + + return new Pair<>(Boolean.TRUE, ""); + } + + private List extractItems( + final DefaultTableModel tableModel + ) { + final List items = new ArrayList<>(); + + for (int rowNumber = 0; rowNumber < tableModel.getRowCount(); rowNumber++) { + DiArrayValueData.DiArrayItemData item = new DiArrayValueData.DiArrayItemData( + tableModel.getValueAt(rowNumber, 0).toString(), + DiArgumentType.getByValue(tableModel.getValueAt(rowNumber, 1).toString()), + tableModel.getValueAt(rowNumber, 2).toString().trim() + ); + + items.add(item); + } + + return new ArrayList<>(items); + } + + /** + * Get table model. + * + * @return DefaultTableModel + */ + private DefaultTableModel getTableModel() { + return (DefaultTableModel) itemsTable.getModel(); + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.form b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.form new file mode 100644 index 000000000..01efe99ed --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.form @@ -0,0 +1,460 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java new file mode 100644 index 000000000..86a4c2092 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java @@ -0,0 +1,652 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.dialog; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComboBox; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.intellij.ui.EditorTextField; +import com.jetbrains.php.PhpIndex; +import com.jetbrains.php.completion.PhpCompletionUtil; +import com.jetbrains.php.lang.psi.elements.Field; +import com.jetbrains.php.lang.psi.elements.Parameter; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import com.jetbrains.php.lang.psi.elements.impl.ClassConstImpl; +import com.magento.idea.magento2plugin.actions.generation.InjectConstructorArgumentAction; +import com.magento.idea.magento2plugin.actions.generation.data.ui.ComboBoxItemData; +import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArgumentData; +import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArrayValueData; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.annotation.FieldValidation; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.annotation.RuleRegistry; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.ExtendedNumericRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.NotEmptyRule; +import com.magento.idea.magento2plugin.actions.generation.generator.code.ArgumentInjectionGenerator; +import com.magento.idea.magento2plugin.bundles.ValidatorBundle; +import com.magento.idea.magento2plugin.indexes.ModuleIndex; +import com.magento.idea.magento2plugin.magento.packages.Areas; +import com.magento.idea.magento2plugin.magento.packages.DiArgumentType; +import com.magento.idea.magento2plugin.ui.FilteredComboBox; +import com.magento.idea.magento2plugin.util.magento.GetModuleNameByDirectoryUtil; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.KeyStroke; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public class NewArgumentInjectionDialog extends AbstractDialog { + + private static final String TARGET_AREA = "Target Area"; + private static final String TARGET_MODULE = "Target Module"; + private static final String ARGUMENT_TYPE = "Argument Type"; + private static final String ARGUMENT_VALUE = "Argument Value"; + private static final String TYPE_VALUE = "Class/Interface"; + private static final String CONST_VALUE = "Target Constant"; + + private final @NotNull Project project; + private final String moduleName; + private final PhpClass targetClass; + private final Parameter targetParameter; + + private JPanel contentPane; + private JButton buttonCancel; + private JButton buttonOK; + private JTextField targetClassField; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, message = {NotEmptyRule.MESSAGE, TARGET_MODULE}) + private FilteredComboBox targetModule; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, message = {NotEmptyRule.MESSAGE, TARGET_AREA}) + private JComboBox targetArea; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, message = {NotEmptyRule.MESSAGE, ARGUMENT_TYPE}) + private JComboBox argumentType; + + private JTextField targetArgument; + + private JPanel objectValuePane; + private JRadioButton noneRB; + private JRadioButton proxyRB; + private JRadioButton factoryRB; + private EditorTextField objectValue; + private String customObjectValue; + + private JPanel stringValuePane; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, + message = {NotEmptyRule.MESSAGE, ARGUMENT_VALUE}) + private JTextField stringValue; + + private JPanel booleanValuePane; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, + message = {NotEmptyRule.MESSAGE, ARGUMENT_VALUE}) + private JComboBox booleanValue; + + private JPanel numberValuePane; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, + message = {NotEmptyRule.MESSAGE, ARGUMENT_VALUE}) + @FieldValidation(rule = RuleRegistry.EXTENDED_NUMERIC, + message = {ExtendedNumericRule.MESSAGE, ARGUMENT_VALUE}) + private JTextField numberValue; + + private JPanel initParameterValuePane; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, message = {NotEmptyRule.MESSAGE, TYPE_VALUE}) + private EditorTextField initParameterTypeValue; + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, message = {NotEmptyRule.MESSAGE, CONST_VALUE}) + private JComboBox initParameterConstValue; + + private JPanel constantValuePane; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, message = {NotEmptyRule.MESSAGE, TYPE_VALUE}) + private EditorTextField constantTypeValue; + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, message = {NotEmptyRule.MESSAGE, CONST_VALUE}) + private JComboBox constantValue; + + private JPanel arrayValuePane; + private JComboBox subArrayKey; + private JButton addArrayValueBtn; + private JTextArea arrayView; + + final DiArrayValueData arrayValues; + + // labels + private JLabel argumentTypeLabel;//NOPMD + private JLabel targetModuleLabel;//NOPMD + private JLabel targetAreaLabel;//NOPMD + private JLabel targetClassLabel;//NOPMD + private JLabel targetArgumentLabel;//NOPMD + private JLabel customObjectValueLabel;//NOPMD + private JLabel stringValueLabel;//NOPMD + private JLabel booleanValueLabel;//NOPMD + private JLabel numberValueLabel;//NOPMD + private JLabel initParameterTypeValueLabel;//NOPMD + private JLabel initParameterConstValueLabel;//NOPMD + private JLabel constantTypeValueLabel;//NOPMD + private JLabel constantValueLabel;//NOPMD + private JLabel subArrayKeyLabel;//NOPMD + + /** + * New argument injection dialog constructor. + * + * @param project Project + * @param directory PsiDirectory + * @param targetClass PhpClass + * @param parameter Parameter + */ + public NewArgumentInjectionDialog( + final @NotNull Project project, + final @NotNull PsiDirectory directory, + final @NotNull PhpClass targetClass, + final @NotNull Parameter parameter + ) { + super(); + + this.project = project; + this.targetClass = targetClass; + this.targetParameter = parameter; + this.moduleName = GetModuleNameByDirectoryUtil.execute(directory, project); + arrayValues = new DiArrayValueData(); + + setContentPane(contentPane); + setModal(true); + setTitle(InjectConstructorArgumentAction.ACTION_DESCRIPTION); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(event -> onOK()); + buttonCancel.addActionListener(event -> onCancel()); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(final WindowEvent event) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction( + event -> onCancel(), + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + + addComponentListener(new FocusOnAFieldListener(() -> targetModule.requestFocusInWindow())); + + targetClassField.setText(targetClass.getPresentableFQN()); + targetArgument.setText(targetParameter.getName()); + + // make all value panes invisible + objectValuePane.setVisible(false); + stringValuePane.setVisible(false); + booleanValuePane.setVisible(false); + numberValuePane.setVisible(false); + initParameterValuePane.setVisible(false); + constantValuePane.setVisible(false); + arrayValuePane.setVisible(false); + + subArrayKeyLabel.setVisible(false); + subArrayKey.setVisible(false); + + objectValue.setEnabled(false); + + argumentType.addItemListener(event -> { + if (!(event.getItem() instanceof ComboBoxItemData)) { + return; + } + final ComboBoxItemData selectedItem = (ComboBoxItemData) event.getItem(); + changeViewBySelectedArgumentType(selectedItem.getKey()); + }); + + final ActionListener objectTypeGroupActionListener = event -> { + if (!(argumentType.getSelectedItem() instanceof ComboBoxItemData)) { + return; + } + final ComboBoxItemData item = (ComboBoxItemData) argumentType.getSelectedItem(); + changeViewBySelectedArgumentType(item.getKey()); + }; + noneRB.addActionListener(objectTypeGroupActionListener); + proxyRB.addActionListener(objectTypeGroupActionListener); + factoryRB.addActionListener(objectTypeGroupActionListener); + + final Disposable disposable = new Disposable() { + @Override + public @NonNls String toString() { + return NewArgumentInjectionDialog.this.toString(); + } + + @Override + public void dispose() { + NewArgumentInjectionDialog.this.dispose(); + } + }; + + PhpCompletionUtil.installClassCompletion( + objectValue, + "", + disposable, + (clazz) -> !clazz.isFinal() + && !PhpCompletionUtil.hasNamespace(clazz, "\\___PHPSTORM_HELPERS") + ); + + objectValue.addDocumentListener(new DocumentListener() { + @Override + public void documentChanged(final @NotNull DocumentEvent event) { + if (noneRB.isSelected()) { + customObjectValue = objectValue.getText().trim(); + } + } + }); + + PhpCompletionUtil.installClassCompletion( + initParameterTypeValue, + "", + disposable, + (clazz) -> !clazz.isFinal() + && !PhpCompletionUtil.hasNamespace(clazz, "\\___PHPSTORM_HELPERS") + ); + + initParameterTypeValue.addDocumentListener( + new DocumentListener() { + @Override + public void documentChanged(final @NotNull DocumentEvent event) { + populateInitParameterTypeConstants(); + } + } + ); + + PhpCompletionUtil.installClassCompletion( + constantTypeValue, + "", + disposable, + (clazz) -> !clazz.isFinal() + && !PhpCompletionUtil.hasNamespace(clazz, "\\___PHPSTORM_HELPERS") + ); + + constantTypeValue.addDocumentListener( + new DocumentListener() { + @Override + public void documentChanged(final @NotNull DocumentEvent event) { + populateConstantTypeConstants(); + } + } + ); + + addArrayValueBtn.addActionListener(event -> { + final DiArrayValueData requestedArrayValues = new DiArrayValueData(); + GatherArrayValuesDialog.open(project, requestedArrayValues); + + if (!requestedArrayValues.getItems().isEmpty()) { + if (arrayValues.getItems().isEmpty()) { + arrayValues.setItems(requestedArrayValues.getItems()); + } else { + if (subArrayKey.getSelectedItem() == null) { + return; + } + final String subArrayName = ((ComboBoxItemData) subArrayKey + .getSelectedItem()).getKey(); + + if (subArrayName.isEmpty()) { + arrayValues.setItems(requestedArrayValues.getItems()); + } else { + final DiArrayValueData.DiArrayItemData parentItem = arrayValues + .getItemByPath( + subArrayName + ); + if (parentItem != null) { + parentItem.setChildren(requestedArrayValues); + } + } + } + populateSubArrayKeyCombobox(); + final String arrayRepresentation = arrayValues.toString(); + + if (!arrayRepresentation.isEmpty()) { + arrayView.setText(arrayRepresentation); + } + } + }); + } + + /** + * Open a new argument injection dialog. + * + * @param project Project + * @param directory PsiDirectory + * @param targetClass PhpClass + * @param parameter Parameter + */ + public static void open( + final @NotNull Project project, + final @NotNull PsiDirectory directory, + final @NotNull PhpClass targetClass, + final @NotNull Parameter parameter + ) { + final NewArgumentInjectionDialog dialog = + new NewArgumentInjectionDialog(project, directory, targetClass, parameter); + dialog.pack(); + dialog.centerDialog(dialog); + dialog.setVisible(true); + } + + /** + * Fire generation process if all fields are valid. + */ + private void onOK() { + if (validateFormFields()) { + final DiArgumentData data = getDialogDataObject(); + + if (data == null) { + return; + } + final ArgumentInjectionGenerator generator = new ArgumentInjectionGenerator( + data, + project + ); + + final PsiFile generatedFile = generator.generate( + InjectConstructorArgumentAction.ACTION_NAME, + true + ); + + if (generatedFile == null) { + if (generator.getGenerationErrorMessage() == null) { + showErrorMessage( + new ValidatorBundle().message( + "validator.file.cantBeCreated", + "DI XML file" + ) + ); + } else { + showErrorMessage( + new ValidatorBundle().message( + "validator.file.cantBeCreatedWithException", + "DI XML file", + generator.getGenerationErrorMessage() + ) + ); + } + } + exit(); + } + } + + /** + * Create custom components and fill their entries. + */ + @SuppressWarnings({"PMD.UnusedPrivateMethod", "PMD.AvoidInstantiatingObjectsInLoops"}) + private void createUIComponents() { + targetModule = new FilteredComboBox(new ModuleIndex(project).getEditableModuleNames()); + targetArea = new ComboBox<>(); + argumentType = new ComboBox<>(); + booleanValue = new ComboBox<>(); + initParameterConstValue = new ComboBox<>(); + constantValue = new ComboBox<>(); + subArrayKey = new ComboBox<>(); + + for (final Areas area : Areas.values()) { + targetArea.addItem(new ComboBoxItemData(area.toString(), area.toString())); + } + + argumentType.addItem( + new ComboBoxItemData("", " --- Select Type --- ") + ); + + for (final DiArgumentType type : DiArgumentType.values()) { + argumentType.addItem( + new ComboBoxItemData(type.getArgumentType(), type.getArgumentType()) + ); + } + objectValue = new EditorTextField("", project, FileTypes.PLAIN_TEXT); + + booleanValue.addItem(new ComboBoxItemData("", " --- Select Value --- ")); + booleanValue.addItem(new ComboBoxItemData("false", "False")); + booleanValue.addItem(new ComboBoxItemData("true", "True")); + + initParameterConstValue.addItem(new ComboBoxItemData("", " --- Select Constant --- ")); + constantValue.addItem(new ComboBoxItemData("", " --- Select Constant --- ")); + + initParameterTypeValue = new EditorTextField("", project, FileTypes.PLAIN_TEXT); + constantTypeValue = new EditorTextField("", project, FileTypes.PLAIN_TEXT); + } + + private void populateInitParameterTypeConstants() { + final String type = initParameterTypeValue.getText().trim(); + + if (type.isEmpty()) { + return; + } + final List constants = getConstantsNames(type); + + if (constants.isEmpty()) { + return; + } + initParameterConstValue.removeAllItems(); + initParameterConstValue.addItem(new ComboBoxItemData("", " --- Select Constant --- ")); + + for (final String constantName : constants) { + initParameterConstValue.addItem(new ComboBoxItemData(constantName, constantName)); + } + } + + private void populateConstantTypeConstants() { + final String type = constantTypeValue.getText().trim(); + + if (type.isEmpty()) { + return; + } + final List constants = getConstantsNames(type); + + if (constants.isEmpty()) { + return; + } + constantValue.removeAllItems(); + constantValue.addItem(new ComboBoxItemData("", " --- Select Constant --- ")); + + for (final String constantName : constants) { + constantValue.addItem(new ComboBoxItemData(constantName, constantName)); + } + } + + private List getConstantsNames(final @NotNull String fqn) { + final List result = new ArrayList<>(); + final PhpIndex phpIndex = PhpIndex.getInstance(project); + + final Collection interfaces = phpIndex.getInterfacesByFQN(fqn); + final Collection classes = phpIndex.getClassesByFQN(fqn); + PhpClass clazz = null; + + if (!interfaces.isEmpty()) { + clazz = interfaces.iterator().next(); + } else if (!classes.isEmpty()) { + clazz = classes.iterator().next(); + } + + if (clazz == null) { + return result; + } + + for (final Field field : clazz.getOwnFields()) { + if (!(field instanceof ClassConstImpl)) { + continue; + } + result.add(field.getName()); + } + + return result; + } + + private void populateSubArrayKeyCombobox() { + if (arrayValues.getItems().isEmpty()) { + subArrayKeyLabel.setVisible(false); + subArrayKey.setVisible(false); + return; + } + subArrayKey.removeAllItems(); + subArrayKey.addItem(new ComboBoxItemData("", " --- Top Array --- ")); + populateSubArrayKeyCombobox(arrayValues, ""); + + if (subArrayKey.getItemCount() > 1) { + subArrayKeyLabel.setVisible(true); + subArrayKey.setVisible(true); + } + } + + private void populateSubArrayKeyCombobox(final DiArrayValueData data, final String parentKey) { + for (final DiArrayValueData.DiArrayItemData item : data.getItems()) { + if (item.getType().equals(DiArgumentType.ARRAY)) { + final String key = parentKey.isEmpty() + ? item.getName() + : parentKey + ":" + item.getName(); + final String value = parentKey.isEmpty() + ? item.getName() + : parentKey.replaceAll(":", " -> ") + " -> " + item.getName(); + + subArrayKey.addItem(new ComboBoxItemData(key, value)); + + if (item.hasChildren()) { + populateSubArrayKeyCombobox(item.getChildren(), key); + } + } + } + } + + private void changeViewBySelectedArgumentType(final String itemValue) { + // make target value pane visible + objectValuePane.setVisible(itemValue.equals(DiArgumentType.OBJECT.getArgumentType())); + stringValuePane.setVisible(itemValue.equals(DiArgumentType.STRING.getArgumentType())); + booleanValuePane.setVisible(itemValue.equals(DiArgumentType.BOOLEAN.getArgumentType())); + numberValuePane.setVisible(itemValue.equals(DiArgumentType.NUMBER.getArgumentType())); + initParameterValuePane.setVisible( + itemValue.equals(DiArgumentType.INIT_PARAMETER.getArgumentType()) + ); + constantValuePane.setVisible(itemValue.equals(DiArgumentType.CONST.getArgumentType())); + arrayValuePane.setVisible(itemValue.equals(DiArgumentType.ARRAY.getArgumentType())); + + if (itemValue.equals(DiArgumentType.OBJECT.getArgumentType())) { + final String targetType = targetClass.getPresentableFQN(); + + if (noneRB.isSelected()) { + if (customObjectValue != null) { + objectValue.setText(customObjectValue); + } + objectValue.setEnabled(true); + } else if (proxyRB.isSelected()) { + objectValue.setEnabled(false); + objectValue.setText(targetType.concat("\\Proxy")); + } else if (factoryRB.isSelected()) { + objectValue.setEnabled(false); + objectValue.setText(targetType.concat("Factory")); + } + } + } + + private @NotNull String getArgumentValue() { + final ComboBoxItemData item = (ComboBoxItemData) argumentType.getSelectedItem(); + + if (item == null) { + return ""; + } + + if (item.getKey().equals(DiArgumentType.OBJECT.getArgumentType())) { + return objectValue.getText().trim(); + } else if (item.getKey().equals(DiArgumentType.STRING.getArgumentType())) { + return stringValue.getText().trim(); + } else if (item.getKey().equals(DiArgumentType.BOOLEAN.getArgumentType())) { + final ComboBoxItemData booleanValueItem = + (ComboBoxItemData) booleanValue.getSelectedItem(); + + if (booleanValueItem == null) { + return ""; + } + return booleanValueItem.getKey(); + } else if (item.getKey().equals(DiArgumentType.NUMBER.getArgumentType())) { + return numberValue.getText().trim(); + } else if (item.getKey().equals(DiArgumentType.INIT_PARAMETER.getArgumentType())) { + final ComboBoxItemData initParamValueItem = + (ComboBoxItemData) initParameterConstValue.getSelectedItem(); + + if (initParamValueItem == null) { + return ""; + } + final String initParamType = initParameterTypeValue.getText().trim(); + + return initParamType.concat("::").concat(initParamValueItem.getKey()); + } else if (item.getKey().equals(DiArgumentType.CONST.getArgumentType())) { + final ComboBoxItemData constValueItem = + (ComboBoxItemData) constantValue.getSelectedItem(); + + if (constValueItem == null) { + return ""; + } + final String constType = constantTypeValue.getText().trim(); + + return constType.concat("::").concat(constValueItem.getKey()); + } else if (item.getKey().equals(DiArgumentType.NULL.getArgumentType())) { + return ""; + } else if (item.getKey().equals(DiArgumentType.ARRAY.getArgumentType())) { + return arrayValues.convertToXml(arrayValues); + } + + return ""; + } + + private DiArgumentData getDialogDataObject() { + if (targetArea.getSelectedItem() == null) { + showErrorMessage(new ValidatorBundle().message(NotEmptyRule.MESSAGE, TARGET_AREA)); + return null; + } + + if (argumentType.getSelectedItem() == null) { + showErrorMessage(new ValidatorBundle().message(NotEmptyRule.MESSAGE, ARGUMENT_TYPE)); + return null; + } + final String argumentTypeValue = ((ComboBoxItemData) argumentType + .getSelectedItem()).getKey().trim(); + + if (argumentTypeValue.isEmpty()) { + showErrorMessage(new ValidatorBundle().message(NotEmptyRule.MESSAGE, ARGUMENT_TYPE)); + return null; + } + + final String argValue = getArgumentValue(); + + if (argValue.isEmpty() + && !argumentTypeValue.equals(DiArgumentType.NULL.getArgumentType())) { + showErrorMessage(new ValidatorBundle().message(NotEmptyRule.MESSAGE, ARGUMENT_VALUE)); + return null; + } + + return new DiArgumentData( + targetModule.getSelectedItem().toString().trim(), + targetClassField.getText().trim(), + targetArgument.getText().trim(), + Areas.getAreaByString(targetArea.getSelectedItem().toString().trim()), + DiArgumentType.getByValue(argumentTypeValue), + argValue + ); + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java index a9a626fdc..057126732 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java @@ -15,6 +15,7 @@ import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.ConfigPathRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.CronScheduleRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.DirectoryRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.ExtendedNumericRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierWithColonRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierWithForwardSlash; @@ -31,6 +32,7 @@ import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.TableNameLength; public enum RuleRegistry { + NOT_EMPTY(NotEmptyRule.class), BOX_NOT_EMPTY(BoxNotEmptyRule.class), PHP_CLASS(PhpClassRule.class), @@ -53,6 +55,7 @@ public enum RuleRegistry { CONFIG_PATH(ConfigPathRule.class), CLI_COMMAND(CliCommandRule.class), NUMERIC(NumericRule.class), + EXTENDED_NUMERIC(ExtendedNumericRule.class), TABLE_NAME_LENGTH(TableNameLength.class), MENU_IDENTIFIER(MenuIdentifierRule.class); diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/ExtendedNumericRule.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/ExtendedNumericRule.java new file mode 100644 index 000000000..2668cd4a2 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/ExtendedNumericRule.java @@ -0,0 +1,24 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule; + +import com.magento.idea.magento2plugin.util.RegExUtil; +import org.jetbrains.annotations.NotNull; + +public class ExtendedNumericRule implements ValidationRule { + + public static final String MESSAGE = "validator.onlyIntegerOrFloatNumbers"; + private static final ValidationRule INSTANCE = new ExtendedNumericRule(); + + @Override + public boolean check(final @NotNull String value) { + return value.matches(RegExUtil.EXTENDED_NUMERIC); + } + + public static ValidationRule getInstance() { + return INSTANCE; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/code/ArgumentInjectionGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/ArgumentInjectionGenerator.java new file mode 100644 index 000000000..8aae86fb6 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/ArgumentInjectionGenerator.java @@ -0,0 +1,219 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.generator.code; + +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArgumentData; +import com.magento.idea.magento2plugin.actions.generation.generator.FileGenerator; +import com.magento.idea.magento2plugin.actions.generation.generator.code.util.DiXmlTagManipulatorUtil; +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.GetCodeTemplateUtil; +import com.magento.idea.magento2plugin.actions.generation.generator.util.XmlFilePositionUtil; +import com.magento.idea.magento2plugin.bundles.CommonBundle; +import com.magento.idea.magento2plugin.bundles.ValidatorBundle; +import com.magento.idea.magento2plugin.indexes.ModuleIndex; +import com.magento.idea.magento2plugin.magento.files.ModuleDiXml; +import com.magento.idea.magento2plugin.magento.packages.Areas; +import com.magento.idea.magento2plugin.magento.packages.Package; +import com.magento.idea.magento2plugin.util.magento.FileBasedIndexUtil; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; +import org.jetbrains.annotations.NotNull; + +public final class ArgumentInjectionGenerator extends FileGenerator { + + private final DiArgumentData data; + private final ModuleDiXml file; + private final DirectoryGenerator directoryGenerator; + private final FileFromTemplateGenerator fileFromTemplateGenerator; + private final CommonBundle commonBundle; + private final ValidatorBundle validatorBundle; + private String generationErrorMessage; + + /** + * Argument injection generator constructor. + * + * @param data DiArgumentData + * @param project Project + */ + public ArgumentInjectionGenerator( + final @NotNull DiArgumentData data, + final @NotNull Project project + ) { + super(project); + this.data = data; + file = new ModuleDiXml(); + directoryGenerator = DirectoryGenerator.getInstance(); + fileFromTemplateGenerator = new FileFromTemplateGenerator(project); + commonBundle = new CommonBundle(); + validatorBundle = new ValidatorBundle(); + } + + /** + * Generate Web API XML declaration. + * + * @param actionName String + * + * @return PsiFile + */ + @Override + public PsiFile generate(final @NotNull String actionName) { + final PsiDirectory moduleDirectory = new ModuleIndex(project) + .getModuleDirectoryByModuleName(data.getModuleName()); + + if (moduleDirectory == null) { + generationErrorMessage = "Could not find the target module directory"; + return null; + } + + final XmlFile diXmlFile = getDiXmlFile(actionName, moduleDirectory); + + if (diXmlFile == null) { + if (generationErrorMessage == null) { + generationErrorMessage = "Could not generate the target di.xml file"; + } + return null; + } + + try { + final XmlTag rootTag = diXmlFile.getRootTag(); + + if (rootTag == null) { + generationErrorMessage = "Could not read the target di.xml file"; + return null; + } + final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project); + final Document document = psiDocumentManager.getDocument(diXmlFile); + + if (document == null) { + generationErrorMessage = "Could not get the document for the target di.xml file"; + return null; + } + XmlTag targetTag = getTargetTag(rootTag); + + if (targetTag == null) { + final List> attributes = new ArrayList<>(); + attributes.add(new Pair<>("name", data.getClazz())); + + targetTag = DiXmlTagManipulatorUtil.insertTag( + rootTag, + "type", + attributes + ); + } + + if (targetTag == null) { + return null; + } + DiXmlTagManipulatorUtil.insertArgumentInTypeTag( + targetTag, + data.getParameter(), + data.getValueType(), + data.getValue() + ); + } catch (Exception exception) { + generationErrorMessage = exception.getMessage(); + } + final PsiFile diXmlFileToReformat = diXmlFile; + + WriteCommandAction.runWriteCommandAction(project, () -> { + CodeStyleManager.getInstance(project).reformat(diXmlFileToReformat); + }); + + return diXmlFileToReformat; + } + + /** + * Get generation error message. + * + * @return String + */ + public String getGenerationErrorMessage() { + return generationErrorMessage; + } + + /** + * Fill argument injection values. + * + * @param attributes Properties + */ + @Override + protected void fillAttributes(final @NotNull Properties attributes) { + attributes.put("TYPE", data.getClazz()); + } + + private XmlTag getTargetTag(final @NotNull XmlTag rootTag) { + final Collection tags = PsiTreeUtil.findChildrenOfType(rootTag, XmlTag.class); + final List result = tags.stream() + .filter( + xmlTag -> xmlTag.getName().equals("type") + && xmlTag.getAttributeValue("name") != null + && xmlTag.getAttributeValue("name").equals(data.getClazz()) + ).collect(Collectors.toList()); + + return result.isEmpty() ? null : result.get(0); + } + + private XmlFile getDiXmlFile( + final @NotNull String actionName, + final @NotNull PsiDirectory moduleDirectory + ) { + PsiFile diXmlFile = FileBasedIndexUtil.findModuleConfigFile( + file.getFileName(), + data.getArea(), + data.getModuleName(), + project + ); + + if (diXmlFile == null) { + PsiDirectory diXmlFileDir = null; + + if (data.getArea().equals(Areas.base)) { + diXmlFileDir = directoryGenerator.findOrCreateSubdirectory( + moduleDirectory, + Package.moduleBaseAreaDir + ); + } else { + diXmlFileDir = directoryGenerator.findOrCreateSubdirectories( + moduleDirectory, + String.format( + "%s/%s", + Package.moduleBaseAreaDir, + this.data.getArea().toString() + ) + ); + } + + if (diXmlFileDir == null) { + generationErrorMessage = "Could not locate/generate the target scope directory"; + return null; + } + + diXmlFile = fileFromTemplateGenerator.generate( + file, + new Properties(), + diXmlFileDir, + actionName + ); + } + + return diXmlFile instanceof XmlFile ? (XmlFile) diXmlFile : null; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/code/util/DiXmlTagManipulatorUtil.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/util/DiXmlTagManipulatorUtil.java new file mode 100644 index 000000000..4f81b2373 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/util/DiXmlTagManipulatorUtil.java @@ -0,0 +1,187 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.generator.code.util; + +import com.intellij.openapi.util.Pair; +import com.intellij.psi.XmlElementFactory; +import com.intellij.psi.impl.source.xml.XmlTagImpl; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.psi.xml.XmlTagChild; +import com.intellij.psi.xml.XmlTagValue; +import com.intellij.util.xml.DomElement; +import com.intellij.xml.util.XmlPsiUtil; +import com.intellij.xml.util.XmlStringUtil; +import com.intellij.xml.util.XmlTagUtil; +import com.intellij.xml.util.XmlUtil; +import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArrayValueData; +import com.magento.idea.magento2plugin.actions.generation.generator.util.CommitXmlFileUtil; +import com.magento.idea.magento2plugin.magento.files.ModuleDiXml; +import com.magento.idea.magento2plugin.magento.packages.DiArgumentType; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.magento.idea.magento2plugin.util.xml.XmlPsiTreeUtil; +import org.jetbrains.annotations.NotNull; + +public final class DiXmlTagManipulatorUtil { + + /** + * Insert new tag. + * + * @param parentTag XmlTag + * @param tagName String + * @param attributes List[Pair[String, String]] + * + * @return XmlTag + */ + public static XmlTag insertTag( + final @NotNull XmlTag parentTag, + final @NotNull String tagName, + final List> attributes + ) { + XmlTag tag = parentTag.createChildTag( + tagName, + null, + "", + false + ); + + for (final Pair attributeData : attributes) { + tag.setAttribute(attributeData.getFirst(), attributeData.getSecond()); + } + final Map childParentRelationMap = new HashMap<>(); + childParentRelationMap.put(tag, parentTag); + + CommitXmlFileUtil.execute( + (XmlFile) parentTag.getContainingFile(), + List.of(tag), + childParentRelationMap + ); + + for (final XmlTag childTag : PsiTreeUtil.findChildrenOfType(parentTag, XmlTag.class)) { + if (childTag.getText().equals(tag.getText())) { + tag = childTag; + } + } + + return tag; + } + + /** + * Wrap Type/VirtualType argument value into corresponding XML. + * + * @param typeTag XmlTag + * @param name String + * @param type DiArgumentType + * @param value String + */ + public static void insertArgumentInTypeTag( + final @NotNull XmlTag typeTag, + final @NotNull String name, + final @NotNull DiArgumentType type, + final @NotNull String value + ) { + final List addSubTagsQueue = new ArrayList<>(); + final Map childParentRelationMap = new HashMap<>(); + final XmlTag argumentsTag = getOrCreateArgumentsTag( + typeTag, + addSubTagsQueue, + childParentRelationMap + ); + boolean isExists = false; + + for (final XmlTag argTag : PsiTreeUtil.findChildrenOfType(argumentsTag, XmlTag.class)) { + final String argName = argTag.getAttributeValue(ModuleDiXml.NAME_ATTR); + + if (name.equals(argName)) { + CommitXmlFileUtil.execute( + (XmlFile) typeTag.getContainingFile(), + () -> { + argTag.setAttribute(ModuleDiXml.XSI_TYPE_ATTR, type.getArgumentType()); + + if (type.equals(DiArgumentType.ARRAY)) { + argTag.getValue().setEscapedText(""); + String arrayValue = value; + boolean isNotChanged = false; + + while (!arrayValue.isEmpty() && !isNotChanged) { + final XmlTag xmlValueTag = XmlElementFactory.getInstance( + argTag.getProject() + ).createTagFromText(arrayValue); + argTag.addSubTag(xmlValueTag, false); + + final String newArrayValue = arrayValue.replace( + xmlValueTag.getText(), + "" + ); + + if (newArrayValue.equals(arrayValue)) { + isNotChanged = true; + } + arrayValue = newArrayValue; + } + } else { + argTag.getValue().setText(value); + } + + if (value.isEmpty()) { + argTag.collapseIfEmpty(); + } + } + ); + isExists = true; + break; + } + } + + if (!isExists) { + final XmlTag argTag = argumentsTag.createChildTag( + ModuleDiXml.ARGUMENT_TAG, + null, + value.isEmpty() ? null : value, + false + ); + addSubTagsQueue.add(argTag); + childParentRelationMap.put(argTag, argumentsTag); + argTag.setAttribute(ModuleDiXml.NAME_ATTR, name); + argTag.setAttribute(ModuleDiXml.XSI_TYPE_ATTR, type.getArgumentType()); + } + + if (!addSubTagsQueue.isEmpty()) { + CommitXmlFileUtil.execute( + (XmlFile) typeTag.getContainingFile(), + addSubTagsQueue, + childParentRelationMap + ); + } + } + + private static XmlTag getOrCreateArgumentsTag( + final @NotNull XmlTag typeTag, + final List addSubTagsQueue, + final Map childParentRelationMap + ) { + for (final XmlTag tag : PsiTreeUtil.findChildrenOfType(typeTag, XmlTag.class)) { + if (ModuleDiXml.ARGUMENTS_TAG.equals(tag.getName())) { + return tag; + } + } + final XmlTag argumentsTag = typeTag.createChildTag( + ModuleDiXml.ARGUMENTS_TAG, + null, + "", + false + ); + addSubTagsQueue.add(argumentsTag); + childParentRelationMap.put(argumentsTag, typeTag); + + return argumentsTag; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/CommitXmlFileUtil.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/CommitXmlFileUtil.java index e450cec31..1b1958532 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/CommitXmlFileUtil.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/CommitXmlFileUtil.java @@ -29,8 +29,7 @@ private CommitXmlFileUtil() {} public static XmlFile execute( final XmlFile xmlFile, final List subTags, - final Map childParentRelationMap + final Map childParentRelationMap ) { WriteCommandAction.runWriteCommandAction(xmlFile.getProject(), () -> { for (final XmlTag tag : Lists.reverse(subTags)) { @@ -50,4 +49,26 @@ public static XmlFile execute( } return xmlFile; } + + /** + * Make some XML editing operation in the safe env. + * + * @param xmlFile XmlFile + * @param runnable Runnable + */ + public static void execute( + final XmlFile xmlFile, + final Runnable runnable + ) { + WriteCommandAction.runWriteCommandAction(xmlFile.getProject(), runnable); + + final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance( + xmlFile.getProject() + ); + final Document document = psiDocumentManager.getDocument(xmlFile); + + if (document != null) { + psiDocumentManager.commitDocument(document); + } + } } diff --git a/src/com/magento/idea/magento2plugin/magento/packages/DiArgumentType.java b/src/com/magento/idea/magento2plugin/magento/packages/DiArgumentType.java new file mode 100644 index 000000000..e0da3bcfc --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/packages/DiArgumentType.java @@ -0,0 +1,133 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.magento.packages; + +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.ExtendedNumericRule; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.InputMismatchException; +import java.util.List; +import org.jetbrains.annotations.NotNull; + +public enum DiArgumentType { + + OBJECT("object"), + STRING("string"), + BOOLEAN("boolean"), + NUMBER("number"), + INIT_PARAMETER("init_parameter"), + CONST("const"), + NULL("null"), + ARRAY("array"); + + private final String argumentType; + + /** + * Dependency Injection argument types ENUM constructor. + * + * @param argumentType String + */ + DiArgumentType(final String argumentType) { + this.argumentType = argumentType; + } + + /** + * Get argument type. + * + * @return String + */ + public String getArgumentType() { + return argumentType; + } + + /** + * Check if provided value is valid for the current type. + * + * @param value String + * + * @return boolean + */ + public boolean isValid(final @NotNull String value) { + if (getArgumentType().equals(DiArgumentType.STRING.getArgumentType())) { + return validateString(value); + } else if (getArgumentType().equals(DiArgumentType.BOOLEAN.getArgumentType())) { + return validateBoolean(value); + } else if (getArgumentType().equals(DiArgumentType.NUMBER.getArgumentType())) { + return validateNumber(value); + } else if (getArgumentType().equals(DiArgumentType.NULL.getArgumentType())) { + return validateNull(value); + } else if (getArgumentType().equals(DiArgumentType.ARRAY.getArgumentType())) { + return validateArray(value); + } + + return true; + } + + /** + * Get ENUM by its string representation. + * + * @param value String + * + * @return PropertiesTypes + */ + public static DiArgumentType getByValue(final @NotNull String value) { + for (final DiArgumentType type : DiArgumentType.values()) { + if (type.getArgumentType().equals(value)) { + return type; + } + } + + throw new InputMismatchException( + "Invalid argument type value provided. Should be compatible with " + + DiArgumentType.class + ); + } + + /** + * Get argument value list. + * + * @return List[String] + */ + public static List getValueList() { + final List valueList = new ArrayList<>(); + final List simpleTypes = new ArrayList<>(); + + simpleTypes.add(DiArgumentType.STRING); + simpleTypes.add(DiArgumentType.BOOLEAN); + simpleTypes.add(DiArgumentType.NUMBER); + simpleTypes.add(DiArgumentType.NULL); + simpleTypes.add(DiArgumentType.ARRAY); + + for (final DiArgumentType type : DiArgumentType.values()) { + if (!simpleTypes.contains(type)) { + continue; + } + valueList.add(type.getArgumentType()); + } + + return valueList; + } + + private boolean validateString(final @NotNull String value) { + return true; + } + + private boolean validateBoolean(final @NotNull String value) { + return Arrays.asList("true", "false", "1", "0").contains(value); + } + + private boolean validateNumber(final @NotNull String value) { + return ExtendedNumericRule.getInstance().check(value); + } + + private boolean validateNull(final @NotNull String value) { + return true; + } + + private boolean validateArray(final @NotNull String value) { + return true; + } +} diff --git a/src/com/magento/idea/magento2plugin/util/RegExUtil.java b/src/com/magento/idea/magento2plugin/util/RegExUtil.java index 83ce45ed9..8a8794ba7 100644 --- a/src/com/magento/idea/magento2plugin/util/RegExUtil.java +++ b/src/com/magento/idea/magento2plugin/util/RegExUtil.java @@ -25,6 +25,9 @@ public class RegExUtil { public static final String NUMERIC = "[0-9]*"; + public static final String EXTENDED_NUMERIC + = "-?\\d+(\\.\\d+)?"; + public static final String IDENTIFIER = "[a-zA-Z0-9_\\-]*"; diff --git a/src/com/magento/idea/magento2plugin/util/php/PhpPsiElementsUtil.java b/src/com/magento/idea/magento2plugin/util/php/PhpPsiElementsUtil.java index 49dd6b8ba..a2df66c80 100644 --- a/src/com/magento/idea/magento2plugin/util/php/PhpPsiElementsUtil.java +++ b/src/com/magento/idea/magento2plugin/util/php/PhpPsiElementsUtil.java @@ -13,6 +13,7 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.jetbrains.php.lang.psi.PhpFile; import com.jetbrains.php.lang.psi.elements.Method; +import com.jetbrains.php.lang.psi.elements.Parameter; import com.jetbrains.php.lang.psi.elements.PhpClass; import com.magento.idea.magento2plugin.util.GetFirstClassOfFile; import org.jetbrains.annotations.NotNull; @@ -51,6 +52,23 @@ public static Method getPhpMethod(final @NotNull AnActionEvent event) { return element instanceof Method ? (Method) element : null; } + /** + * Get method argument from event. + * + * @param event AnActionEvent + * + * @return Method + */ + public static Parameter getMethodArgument(final @NotNull AnActionEvent event) { + PsiElement element = getElementUnderCursor(event); + + if (element instanceof LeafPsiElement && element.getParent() instanceof Parameter) { + element = element.getParent(); + } + + return element instanceof Parameter ? (Parameter) element : null; + } + /** * Get php file for event. * From 1ea194e65c56f0b50f870bd394088152a866df9e Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Mon, 7 Mar 2022 10:47:40 +0200 Subject: [PATCH 05/20] 409: Code refactoring --- .../InjectConstructorArgumentAction.java | 9 +---- .../generation/data/xml/DiArrayValueData.java | 26 ++++++------ .../dialog/GatherArrayValuesDialog.java | 30 ++++++-------- .../dialog/NewArgumentInjectionDialog.java | 40 ++++++++++--------- .../code/ArgumentInjectionGenerator.java | 12 +----- .../code/util/DiXmlTagManipulatorUtil.java | 14 ++----- 6 files changed, 56 insertions(+), 75 deletions(-) diff --git a/src/com/magento/idea/magento2plugin/actions/generation/InjectConstructorArgumentAction.java b/src/com/magento/idea/magento2plugin/actions/generation/InjectConstructorArgumentAction.java index 2ec70c4d1..8802b51b2 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/InjectConstructorArgumentAction.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/InjectConstructorArgumentAction.java @@ -8,7 +8,6 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDirectory; import com.jetbrains.php.lang.psi.elements.Method; import com.jetbrains.php.lang.psi.elements.Parameter; import com.jetbrains.php.lang.psi.elements.PhpClass; @@ -36,6 +35,7 @@ public InjectConstructorArgumentAction() { } @Override + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void update(final @NotNull AnActionEvent event) { setIsAvailableForEvent(event, false); final Project project = event.getProject(); @@ -69,7 +69,7 @@ public void update(final @NotNull AnActionEvent event) { } if (!method.getAccess().isPublic() - || !method.getName().equals(MagentoPhpClass.CONSTRUCT_METHOD_NAME)) { + || !MagentoPhpClass.CONSTRUCT_METHOD_NAME.equals(method.getName())) { return; } currentPhpClass = phpClass; @@ -79,19 +79,14 @@ public void update(final @NotNull AnActionEvent event) { @Override public void actionPerformed(final @NotNull AnActionEvent event) { - final PsiDirectory directory = - currentPhpClass.getContainingFile().getContainingDirectory(); - if (event.getProject() == null || currentPhpClass == null - || directory == null || currentParameter == null) { return; } NewArgumentInjectionDialog.open( event.getProject(), - directory, currentPhpClass, currentParameter ); diff --git a/src/com/magento/idea/magento2plugin/actions/generation/data/xml/DiArrayValueData.java b/src/com/magento/idea/magento2plugin/actions/generation/data/xml/DiArrayValueData.java index ced64aa79..4affc15cd 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/data/xml/DiArrayValueData.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/data/xml/DiArrayValueData.java @@ -58,7 +58,7 @@ public DiArrayItemData getItemByPath(final String path) { if (left.length > 0) { final DiArrayValueData childrenHolder = item.getChildren(); - if (childrenHolder == null) { + if (childrenHolder == null) { // NOPMD break; } target = childrenHolder.getItemByPath(String.join(":", left)); @@ -108,12 +108,12 @@ public String convertToXml(final DiArrayValueData data) { return stringBuilder.toString(); } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) private String buildArrayTree(final DiArrayValueData data, final int indentSize) { final StringBuilder stringBuilder = new StringBuilder(); - - stringBuilder.append(indent(0)); - stringBuilder.append("["); - stringBuilder.append("\n"); + stringBuilder + .append(indent(0)) + .append("[\n"); int currentItem = 0; final int itemsCount = data.getItems().size(); @@ -122,7 +122,7 @@ private String buildArrayTree(final DiArrayValueData data, final int indentSize) String value = item.getValue(); if (item.getType().equals(DiArgumentType.STRING)) { - value = "'" + value + "'"; + value = "'" + value + "'";// NOPMD } else if (item.getType().equals(DiArgumentType.ARRAY) && item.hasChildren()) { value = buildArrayTree(item.getChildren(), indentSize + 1); } else if (item.getType().equals(DiArgumentType.ARRAY) && !item.hasChildren()) { @@ -134,18 +134,20 @@ private String buildArrayTree(final DiArrayValueData data, final int indentSize) } stringBuilder - .append("'" + item.getName() + "'") - .append(" => ") + .append('\'') + .append(item.getName()) + .append("' => ") .append(value); if (currentItem != itemsCount - 1) { - stringBuilder.append(","); + stringBuilder.append(','); } - stringBuilder.append("\n"); + stringBuilder.append('\n'); currentItem++; } - stringBuilder.append(indent(indentSize)); - stringBuilder.append("]"); + stringBuilder + .append(indent(indentSize)) + .append(']'); return stringBuilder.toString(); } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.java index 04052a95a..b27a371be 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.java @@ -9,7 +9,10 @@ import com.intellij.openapi.util.Pair; import com.intellij.util.ui.UIUtil; import com.magento.idea.magento2plugin.actions.generation.InjectConstructorArgumentAction; - +import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArrayValueData; +import com.magento.idea.magento2plugin.bundles.ValidatorBundle; +import com.magento.idea.magento2plugin.magento.packages.DiArgumentType; +import com.magento.idea.magento2plugin.ui.table.TableGroupWrapper; import java.awt.Color; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; @@ -28,12 +31,6 @@ import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.table.DefaultTableModel; - -import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArrayValueData; -import com.magento.idea.magento2plugin.bundles.ValidatorBundle; -import com.magento.idea.magento2plugin.magento.packages.DiArgumentType; -import com.magento.idea.magento2plugin.magento.packages.PropertiesTypes; -import com.magento.idea.magento2plugin.ui.table.TableGroupWrapper; import org.jetbrains.annotations.NotNull; public class GatherArrayValuesDialog extends AbstractDialog { @@ -42,16 +39,14 @@ public class GatherArrayValuesDialog extends AbstractDialog { private static final String ITEM_TYPE = "Type"; private static final String ITEM_VALUE = "Value"; - private final @NotNull Project project; - private DiArrayValueData arrayValueData; - - private TableGroupWrapper tableGroupWrapper; + private final @NotNull Project project;// NOPMD + private final DiArrayValueData arrayValueData; private JPanel contentPane; private JButton buttonCancel; private JButton buttonOK; - private JPanel itemsPane; - private JScrollPane itemsScrollPane; + private JPanel itemsPane;// NOPMD + private JScrollPane itemsScrollPane;// NOPMD private JTable itemsTable; private JButton buttonAdd; private JLabel itemsTableErrorMessage; @@ -151,7 +146,7 @@ private void initTable() { final Map> sources = new HashMap<>(); sources.put(ITEM_TYPE, DiArgumentType.getValueList()); - tableGroupWrapper = new TableGroupWrapper( + final TableGroupWrapper tableGroupWrapper = new TableGroupWrapper( itemsTable, buttonAdd, columns, @@ -168,8 +163,6 @@ private Pair validateItems( final List itemsNames = new ArrayList<>(); for (final DiArrayValueData.DiArrayItemData item : items) { - final DiArgumentType type = item.getType(); - final String value = item.getValue().trim(); final String name = item.getName().trim(); if (name.isEmpty()) { @@ -179,6 +172,8 @@ private Pair validateItems( ); } itemsNames.add(name); + final DiArgumentType type = item.getType(); + final String value = item.getValue().trim(); final boolean isValid = type.isValid(value); @@ -206,13 +201,14 @@ private Pair validateItems( return new Pair<>(Boolean.TRUE, ""); } + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") private List extractItems( final DefaultTableModel tableModel ) { final List items = new ArrayList<>(); for (int rowNumber = 0; rowNumber < tableModel.getRowCount(); rowNumber++) { - DiArrayValueData.DiArrayItemData item = new DiArrayValueData.DiArrayItemData( + final DiArrayValueData.DiArrayItemData item = new DiArrayValueData.DiArrayItemData( tableModel.getValueAt(rowNumber, 0).toString(), DiArgumentType.getByValue(tableModel.getValueAt(rowNumber, 1).toString()), tableModel.getValueAt(rowNumber, 2).toString().trim() diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java index 86a4c2092..7432b4076 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java @@ -11,7 +11,6 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBox; -import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.ui.EditorTextField; import com.jetbrains.php.PhpIndex; @@ -34,7 +33,6 @@ import com.magento.idea.magento2plugin.magento.packages.Areas; import com.magento.idea.magento2plugin.magento.packages.DiArgumentType; import com.magento.idea.magento2plugin.ui.FilteredComboBox; -import com.magento.idea.magento2plugin.util.magento.GetModuleNameByDirectoryUtil; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; @@ -54,6 +52,12 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +@SuppressWarnings({ + "PMD.TooManyFields", + "PMD.UnusedPrivateField", + "PMD.ExcessiveImports", + "PMD.AvoidInstantiatingObjectsInLoops" +}) public class NewArgumentInjectionDialog extends AbstractDialog { private static final String TARGET_AREA = "Target Area"; @@ -64,9 +68,7 @@ public class NewArgumentInjectionDialog extends AbstractDialog { private static final String CONST_VALUE = "Target Constant"; private final @NotNull Project project; - private final String moduleName; private final PhpClass targetClass; - private final Parameter targetParameter; private JPanel contentPane; private JButton buttonCancel; @@ -130,7 +132,7 @@ public class NewArgumentInjectionDialog extends AbstractDialog { private JButton addArrayValueBtn; private JTextArea arrayView; - final DiArrayValueData arrayValues; + private final DiArrayValueData arrayValues; // labels private JLabel argumentTypeLabel;//NOPMD @@ -152,13 +154,17 @@ public class NewArgumentInjectionDialog extends AbstractDialog { * New argument injection dialog constructor. * * @param project Project - * @param directory PsiDirectory * @param targetClass PhpClass * @param parameter Parameter */ + @SuppressWarnings({ + "PMD.AccessorMethodGeneration", + "PMD.ExcessiveMethodLength", + "PMD.CognitiveComplexity", + "PMD.CyclomaticComplexity", + }) public NewArgumentInjectionDialog( final @NotNull Project project, - final @NotNull PsiDirectory directory, final @NotNull PhpClass targetClass, final @NotNull Parameter parameter ) { @@ -166,8 +172,6 @@ public NewArgumentInjectionDialog( this.project = project; this.targetClass = targetClass; - this.targetParameter = parameter; - this.moduleName = GetModuleNameByDirectoryUtil.execute(directory, project); arrayValues = new DiArrayValueData(); setContentPane(contentPane); @@ -197,7 +201,7 @@ public void windowClosing(final WindowEvent event) { addComponentListener(new FocusOnAFieldListener(() -> targetModule.requestFocusInWindow())); targetClassField.setText(targetClass.getPresentableFQN()); - targetArgument.setText(targetParameter.getName()); + targetArgument.setText(parameter.getName()); // make all value panes invisible objectValuePane.setVisible(false); @@ -335,18 +339,16 @@ public void documentChanged(final @NotNull DocumentEvent event) { * Open a new argument injection dialog. * * @param project Project - * @param directory PsiDirectory * @param targetClass PhpClass * @param parameter Parameter */ public static void open( final @NotNull Project project, - final @NotNull PsiDirectory directory, final @NotNull PhpClass targetClass, final @NotNull Parameter parameter ) { final NewArgumentInjectionDialog dialog = - new NewArgumentInjectionDialog(project, directory, targetClass, parameter); + new NewArgumentInjectionDialog(project, targetClass, parameter); dialog.pack(); dialog.centerDialog(dialog); dialog.setVisible(true); @@ -397,7 +399,7 @@ private void onOK() { /** * Create custom components and fill their entries. */ - @SuppressWarnings({"PMD.UnusedPrivateMethod", "PMD.AvoidInstantiatingObjectsInLoops"}) + @SuppressWarnings({"PMD.UnusedPrivateMethod"}) private void createUIComponents() { targetModule = new FilteredComboBox(new ModuleIndex(project).getEditableModuleNames()); targetArea = new ComboBox<>(); @@ -425,9 +427,10 @@ private void createUIComponents() { booleanValue.addItem(new ComboBoxItemData("", " --- Select Value --- ")); booleanValue.addItem(new ComboBoxItemData("false", "False")); booleanValue.addItem(new ComboBoxItemData("true", "True")); + final String selectConstantText = " --- Select Constant --- "; - initParameterConstValue.addItem(new ComboBoxItemData("", " --- Select Constant --- ")); - constantValue.addItem(new ComboBoxItemData("", " --- Select Constant --- ")); + initParameterConstValue.addItem(new ComboBoxItemData("", selectConstantText)); + constantValue.addItem(new ComboBoxItemData("", selectConstantText)); initParameterTypeValue = new EditorTextField("", project, FileTypes.PLAIN_TEXT); constantTypeValue = new EditorTextField("", project, FileTypes.PLAIN_TEXT); @@ -479,7 +482,7 @@ private List getConstantsNames(final @NotNull String fqn) { final Collection classes = phpIndex.getClassesByFQN(fqn); PhpClass clazz = null; - if (!interfaces.isEmpty()) { + if (!interfaces.isEmpty()) { // NOPMD clazz = interfaces.iterator().next(); } else if (!classes.isEmpty()) { clazz = classes.iterator().next(); @@ -509,7 +512,7 @@ private void populateSubArrayKeyCombobox() { subArrayKey.addItem(new ComboBoxItemData("", " --- Top Array --- ")); populateSubArrayKeyCombobox(arrayValues, ""); - if (subArrayKey.getItemCount() > 1) { + if (subArrayKey.getItemCount() > 1) { // NOPMD subArrayKeyLabel.setVisible(true); subArrayKey.setVisible(true); } @@ -564,6 +567,7 @@ private void changeViewBySelectedArgumentType(final String itemValue) { } } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) private @NotNull String getArgumentValue() { final ComboBoxItemData item = (ComboBoxItemData) argumentType.getSelectedItem(); diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/code/ArgumentInjectionGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/ArgumentInjectionGenerator.java index 8aae86fb6..91e048614 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/code/ArgumentInjectionGenerator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/ArgumentInjectionGenerator.java @@ -21,10 +21,6 @@ import com.magento.idea.magento2plugin.actions.generation.generator.code.util.DiXmlTagManipulatorUtil; 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.GetCodeTemplateUtil; -import com.magento.idea.magento2plugin.actions.generation.generator.util.XmlFilePositionUtil; -import com.magento.idea.magento2plugin.bundles.CommonBundle; -import com.magento.idea.magento2plugin.bundles.ValidatorBundle; import com.magento.idea.magento2plugin.indexes.ModuleIndex; import com.magento.idea.magento2plugin.magento.files.ModuleDiXml; import com.magento.idea.magento2plugin.magento.packages.Areas; @@ -43,8 +39,6 @@ public final class ArgumentInjectionGenerator extends FileGenerator { private final ModuleDiXml file; private final DirectoryGenerator directoryGenerator; private final FileFromTemplateGenerator fileFromTemplateGenerator; - private final CommonBundle commonBundle; - private final ValidatorBundle validatorBundle; private String generationErrorMessage; /** @@ -62,8 +56,6 @@ public ArgumentInjectionGenerator( file = new ModuleDiXml(); directoryGenerator = DirectoryGenerator.getInstance(); fileFromTemplateGenerator = new FileFromTemplateGenerator(project); - commonBundle = new CommonBundle(); - validatorBundle = new ValidatorBundle(); } /** @@ -128,7 +120,7 @@ public PsiFile generate(final @NotNull String actionName) { data.getValueType(), data.getValue() ); - } catch (Exception exception) { + } catch (Exception exception) { // NOPMD generationErrorMessage = exception.getMessage(); } final PsiFile diXmlFileToReformat = diXmlFile; @@ -183,7 +175,7 @@ private XmlFile getDiXmlFile( ); if (diXmlFile == null) { - PsiDirectory diXmlFileDir = null; + PsiDirectory diXmlFileDir; if (data.getArea().equals(Areas.base)) { diXmlFileDir = directoryGenerator.findOrCreateSubdirectory( diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/code/util/DiXmlTagManipulatorUtil.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/util/DiXmlTagManipulatorUtil.java index 4f81b2373..c0a83e044 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/code/util/DiXmlTagManipulatorUtil.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/util/DiXmlTagManipulatorUtil.java @@ -7,18 +7,9 @@ import com.intellij.openapi.util.Pair; import com.intellij.psi.XmlElementFactory; -import com.intellij.psi.impl.source.xml.XmlTagImpl; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; -import com.intellij.psi.xml.XmlTagChild; -import com.intellij.psi.xml.XmlTagValue; -import com.intellij.util.xml.DomElement; -import com.intellij.xml.util.XmlPsiUtil; -import com.intellij.xml.util.XmlStringUtil; -import com.intellij.xml.util.XmlTagUtil; -import com.intellij.xml.util.XmlUtil; -import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArrayValueData; import com.magento.idea.magento2plugin.actions.generation.generator.util.CommitXmlFileUtil; import com.magento.idea.magento2plugin.magento.files.ModuleDiXml; import com.magento.idea.magento2plugin.magento.packages.DiArgumentType; @@ -26,12 +17,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - -import com.magento.idea.magento2plugin.util.xml.XmlPsiTreeUtil; import org.jetbrains.annotations.NotNull; public final class DiXmlTagManipulatorUtil { + private DiXmlTagManipulatorUtil() {} + /** * Insert new tag. * @@ -82,6 +73,7 @@ public static XmlTag insertTag( * @param type DiArgumentType * @param value String */ + @SuppressWarnings("PMD.CognitiveComplexity") public static void insertArgumentInTypeTag( final @NotNull XmlTag typeTag, final @NotNull String name, From d93801f840fcd45262e5b2e07270f71c8e31d1ff Mon Sep 17 00:00:00 2001 From: silinmykola Date: Mon, 28 Feb 2022 19:48:16 +0200 Subject: [PATCH 06/20] 966 add context action to create layout xml file --- resources/META-INF/plugin.xml | 11 +- resources/magento2/common.properties | 1 + resources/magento2/validation.properties | 2 + .../context/xml/NewLayoutXmlAction.java | 118 ++++++++ .../generation/data/LayoutXmlData.java | 24 ++ .../dialog/NewLayoutTemplateDialog.form | 113 ++++++++ .../dialog/NewLayoutTemplateDialog.java | 271 ++++++++++++++++++ .../dialog/util/DialogFieldErrorUtil.java | 35 +++ .../validator/annotation/RuleRegistry.java | 4 +- .../dialog/validator/rule/LayoutNameRule.java | 24 ++ .../generator/LayoutXmlTemplateGenerator.java | 73 +++++ .../generator/util/FindOrCreateLayoutXml.java | 6 +- .../magento/files/LayoutXml.java | 35 ++- .../idea/magento2plugin/util/RegExUtil.java | 3 + .../util/magento/GetMagentoModuleUtil.java | 17 +- 15 files changed, 709 insertions(+), 28 deletions(-) create mode 100644 src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.form create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/LayoutNameRule.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index a1fbfdee1..859e091f3 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -75,6 +75,7 @@ + @@ -578,16 +579,6 @@ - - - - - - - - - - diff --git a/resources/magento2/common.properties b/resources/magento2/common.properties index 7270fbea4..01ad830e0 100644 --- a/resources/magento2/common.properties +++ b/resources/magento2/common.properties @@ -72,4 +72,5 @@ common.template.type=Email Type common.diagnostic.reportButtonText=Report Me common.diagnostic.reportSubmittedTitle=The report is successfully submitted! common.diagnostic.reportSubmittedMessage=Thank you for submitting your report! We will check it as soon as possible. +common.layout.filename=Layout File Name common.targetMethod=Target Method diff --git a/resources/magento2/validation.properties b/resources/magento2/validation.properties index b868b58fb..6248dfe1e 100644 --- a/resources/magento2/validation.properties +++ b/resources/magento2/validation.properties @@ -41,3 +41,5 @@ validator.lowerSnakeCase=The {0} field must be of the lower snake case format validator.menuIdentifierInvalid=The menu identifier is invalid validator.someFieldsHaveErrors=Please, check the dialog. Some fields have errors validator.dbSchema.invalidColumnType=Invalid ''{0}'' column type specified +validator.layoutNameRuleInvalid=The layout name is invalid +validator.layoutNameUnderscoreQtyInvalid=Wrong layout name, please check diff --git a/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java b/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java new file mode 100644 index 000000000..c01378302 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java @@ -0,0 +1,118 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.context.xml; + +import com.intellij.ide.fileTemplates.actions.AttributesDefaults; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.magento.idea.magento2plugin.MagentoIcons; +import com.magento.idea.magento2plugin.actions.generation.dialog.NewLayoutTemplateDialog; +import com.magento.idea.magento2plugin.magento.packages.Areas; +import com.magento.idea.magento2plugin.magento.packages.ComponentType; +import com.magento.idea.magento2plugin.magento.packages.Package; +import com.magento.idea.magento2plugin.project.Settings; +import com.magento.idea.magento2plugin.util.magento.GetMagentoModuleUtil; +import java.util.Arrays; +import java.util.List; +import org.jetbrains.annotations.NotNull; + +public class NewLayoutXmlAction extends AnAction { + + public static final String ACTION_NAME = "Magento 2 Layout File"; + public static final String ACTION_DESCRIPTION = "Create a new Magento 2 layout.xml file"; + private PsiDirectory targetDirectory; + + /** + * New layout.xml file generation action constructor. + */ + public NewLayoutXmlAction() { + super(ACTION_NAME, ACTION_DESCRIPTION, MagentoIcons.MODULE); + } + + @Override + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public void update(final @NotNull AnActionEvent event) { + setIsAvailableForEvent(event, false); + final Project project = event.getProject(); + + if (project == null || !Settings.isEnabled(project)) { + return; + } + final DataContext context = event.getDataContext(); + final PsiElement targetElement = LangDataKeys.PSI_ELEMENT.getData(context); + + if (!(targetElement instanceof PsiDirectory)) { + return; + } + final PsiDirectory targetDirectoryCandidate = (PsiDirectory) targetElement; + final GetMagentoModuleUtil.MagentoModuleData moduleData = GetMagentoModuleUtil + .getByContext(targetDirectoryCandidate, project); + + if (moduleData == null) { + return; + } + final PsiDirectory viewDir = moduleData.getViewDir(); + + if (viewDir == null) { + return; + } + final List allowedDirectories = Arrays.asList( + Package.moduleViewDir, + Areas.adminhtml.toString(), + Areas.frontend.toString() + ); + if (!allowedDirectories.contains(targetDirectoryCandidate.getName()) + || !moduleData.getType().equals(ComponentType.module)) { + return; + } + final PsiDirectory parentDir = targetDirectoryCandidate.getParentDirectory(); + + if (parentDir == null + || !targetDirectoryCandidate.equals(viewDir) && !parentDir.equals(viewDir)) { + return; + } + targetDirectory = targetDirectoryCandidate; + setIsAvailableForEvent(event, true); + } + + @Override + public void actionPerformed(final @NotNull AnActionEvent event) { + if (event.getProject() == null || targetDirectory == null) { + return; + } + + NewLayoutTemplateDialog.open(event.getProject(), targetDirectory); + } + + /** + * Set is action available for event. + * + * @param event AnActionEvent + * @param isAvailable boolean + */ + private void setIsAvailableForEvent( + final @NotNull AnActionEvent event, + final boolean isAvailable + ) { + event.getPresentation().setVisible(isAvailable); + event.getPresentation().setEnabled(isAvailable); + } + + protected AttributesDefaults getProperties( + final @NotNull AttributesDefaults defaults, + final @NotNull GetMagentoModuleUtil.MagentoModuleData moduleData, + final PsiDirectory targetDirectory, + final PsiFile targetFile + ) { + return null; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/data/LayoutXmlData.java b/src/com/magento/idea/magento2plugin/actions/generation/data/LayoutXmlData.java index 3be8921b5..c9727dbb1 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/data/LayoutXmlData.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/data/LayoutXmlData.java @@ -39,6 +39,30 @@ public LayoutXmlData( this.uiComponentName = uiComponentName; } + /** + * Layout XML data. + * + * @param area String + * @param route String + * @param moduleName String + * @param controllerName String + * @param actionName String + */ + public LayoutXmlData( + final String area, + final String route, + final String moduleName, + final String controllerName, + final String actionName + ) { + this.area = area; + this.route = route; + this.moduleName = moduleName; + this.controllerName = controllerName; + this.actionName = actionName; + this.uiComponentName = ""; + } + public String getArea() { return area; } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.form b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.form new file mode 100644 index 000000000..f5c0221d5 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.form @@ -0,0 +1,113 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java new file mode 100644 index 000000000..f819d49e5 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java @@ -0,0 +1,271 @@ +/* + * 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.intellij.openapi.ui.ComboBox; +import com.intellij.psi.PsiDirectory; +import com.magento.idea.magento2plugin.actions.context.xml.NewLayoutXmlAction; +import com.magento.idea.magento2plugin.actions.generation.data.LayoutXmlData; +import com.magento.idea.magento2plugin.actions.generation.data.ui.ComboBoxItemData; +import com.magento.idea.magento2plugin.actions.generation.dialog.util.DialogFieldErrorUtil; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.annotation.FieldValidation; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.annotation.RuleRegistry; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.NotEmptyRule; +import com.magento.idea.magento2plugin.actions.generation.generator.LayoutXmlTemplateGenerator; +import com.magento.idea.magento2plugin.bundles.ValidatorBundle; +import com.magento.idea.magento2plugin.magento.packages.Areas; +import com.magento.idea.magento2plugin.util.magento.GetModuleNameByDirectoryUtil; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.HashMap; +import java.util.Map; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.KeyStroke; +import org.jetbrains.annotations.NotNull; + +public class NewLayoutTemplateDialog extends AbstractDialog { + + private static final String LAYOUT_NAME = "Layout Name"; + + private final @NotNull Project project; + private final String moduleName; + private final PsiDirectory directory; + + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, message = {NotEmptyRule.MESSAGE, LAYOUT_NAME}) + @FieldValidation(rule = RuleRegistry.LAYOUT_NAME, + message = {IdentifierRule.MESSAGE, LAYOUT_NAME}) + private JTextField layoutName; + + private JComboBox area; + + // labels + private JLabel layoutNameLabel; // NOPMD + private JLabel areaLabel; // NOPMD + private JLabel layoutNameErrorMessage; // NOPMD + + /** + * NewLayoutTemplateDialog constructor. + * + * @param project Project + * @param directory PsiDirectory + */ + public NewLayoutTemplateDialog( + final @NotNull Project project, + final @NotNull PsiDirectory directory + ) { + super(); + + this.project = project; + this.moduleName = GetModuleNameByDirectoryUtil.execute(directory, project); + this.directory = directory; + + setContentPane(contentPane); + setModal(true); + setTitle(NewLayoutXmlAction.ACTION_DESCRIPTION); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(event -> onOK()); + buttonCancel.addActionListener(event -> onCancel()); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(final WindowEvent event) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction( + event -> onCancel(), + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + ); + + addComponentListener(new FocusOnAFieldListener(() -> area.requestFocusInWindow())); + autoSelectCurrentArea(); + } + + /** + * Open a new layout template dialog. + * + * @param project Project + * @param directory Directory + */ + public static void open( + final @NotNull Project project, + final @NotNull PsiDirectory directory + ) { + final NewLayoutTemplateDialog dialog = new NewLayoutTemplateDialog(project, directory); + dialog.pack(); + dialog.centerDialog(dialog); + dialog.setVisible(true); + } + + /** + * Fire generation process if all fields are valid. + */ + private void onOK() { + if (validateFormFields() && isUnderscoreCorrect()) { + new LayoutXmlTemplateGenerator( + new LayoutXmlData( + getArea(), + getRouteName(), + moduleName, + getControllerName(), + getActionName() + ), + project + ).generate(NewLayoutXmlAction.ACTION_NAME, true); + exit(); + } + } + + /** + * Create custom components and fill their entries. + */ + @SuppressWarnings({"PMD.UnusedPrivateMethod", "PMD.AvoidInstantiatingObjectsInLoops"}) + private void createUIComponents() { + area = new ComboBox<>(); + + for (final Areas areaEntry : Areas.values()) { + if (!areaEntry.equals(Areas.adminhtml) && !areaEntry.equals(Areas.frontend)) { + continue; + } + area.addItem(new ComboBoxItemData(areaEntry.toString(), areaEntry.toString())); + } + } + + private void autoSelectCurrentArea() { + final String selectedDirName = directory.getName(); + final Map areaIndexMap = new HashMap<>(); + + for (int i = 0; i < area.getItemCount(); i++) { + final ComboBoxItemData item = area.getItemAt(i); + areaIndexMap.put(item.getKey(), i); + } + + if (areaIndexMap.containsKey(selectedDirName)) { + area.setSelectedIndex(areaIndexMap.get(selectedDirName)); + } + } + + /** + * Check is count of underscore is correct in layout name. + * + * @return boolean + */ + private boolean isUnderscoreCorrect() { + final String name = layoutName.getText().trim(); + + if (name.contains("_")) { + final int count = countUnderscore(name); + + if (count != 0 && count != 2) { + DialogFieldErrorUtil.showErrorMessageForField( + layoutName, + layoutNameErrorMessage, + new ValidatorBundle() + .message("validator.layoutNameUnderscoreQtyInvalid") + ); + + return false; + } + } + + return true; + } + + /** + * Count underscore symbols in string. + * + * @param name String + * @return int + */ + private int countUnderscore(final String name) { + int count = 0; + + for (int i = 0; i < name.length(); i++) { + if (name.charAt(i) == '_') { //NOPMD + count++; + } + } + + return count; + } + + /** + * Get action name. + * + * @return String + */ + private String getActionName() { + if (layoutName.getText().trim().contains("_")) { + final int position = layoutName.getText().trim().lastIndexOf("_") + 1; + return layoutName.getText().trim().substring(position); + } + + return ""; + } + + /** + * Get area. + * + * @return String + */ + private String getArea() { + return area.getSelectedItem().toString(); + } + + /** + * Get controller name. + * + * @return String + */ + private String getControllerName() { + final String newLayoutName = layoutName.getText().trim(); + if (newLayoutName.contains("_")) { + final int start = newLayoutName.indexOf('_') + 1; + int end = newLayoutName.lastIndexOf('_'); + + if (start == end) { + end = newLayoutName.length() - 1; + } + return newLayoutName.substring(start, end); + } + + return ""; + } + + /** + * Get route name. + * + * @return String + */ + private String getRouteName() { + final String newLayoutName = layoutName.getText().trim(); + int position = newLayoutName.length(); + + if (newLayoutName.contains("_")) { + position = newLayoutName.indexOf('_'); + } + + return newLayoutName.substring(0, position); + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/util/DialogFieldErrorUtil.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/util/DialogFieldErrorUtil.java index 80c12d54a..385fc1566 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/util/DialogFieldErrorUtil.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/util/DialogFieldErrorUtil.java @@ -19,6 +19,7 @@ import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.border.Border; +import javax.swing.text.JTextComponent; import org.jetbrains.annotations.NotNull; public final class DialogFieldErrorUtil { @@ -165,6 +166,40 @@ public void focusLost(final FocusEvent event) { return true; } + /** + * Show error message for field for component. + * + * @param fieldComponent JTextComponent + * @param messageHolder JLabel + * @param message String + */ + public static void showErrorMessageForField( + final @NotNull JTextComponent fieldComponent, + final @NotNull JLabel messageHolder, + final @NotNull String message + ) { + highlightField(fieldComponent); + + messageHolder.setVisible(true); + messageHolder.setFont(UIUtil.getLabelFont(UIUtil.FontSize.MINI)); + messageHolder.setForeground(ERROR_COLOR); + messageHolder.setText(message); + + fieldComponent.addFocusListener(new FocusListener() { + @Override + public void focusGained(final FocusEvent event) { + messageHolder.setVisible(false); + messageHolder.setText(""); + } + + @Override + public void focusLost(final FocusEvent event) { + messageHolder.setVisible(false); + messageHolder.setText(""); + } + }); + } + /** * Get message holder component for field. * diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java index a9a626fdc..9a2e750fc 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java @@ -18,6 +18,7 @@ import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierWithColonRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierWithForwardSlash; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.LayoutNameRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.Lowercase; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.MenuIdentifierRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.NotEmptyRule; @@ -54,7 +55,8 @@ public enum RuleRegistry { CLI_COMMAND(CliCommandRule.class), NUMERIC(NumericRule.class), TABLE_NAME_LENGTH(TableNameLength.class), - MENU_IDENTIFIER(MenuIdentifierRule.class); + MENU_IDENTIFIER(MenuIdentifierRule.class), + LAYOUT_NAME(LayoutNameRule.class); private Class rule; diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/LayoutNameRule.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/LayoutNameRule.java new file mode 100644 index 000000000..9af322458 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/LayoutNameRule.java @@ -0,0 +1,24 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule; + +import com.magento.idea.magento2plugin.util.RegExUtil; +import org.jetbrains.annotations.NotNull; + +public class LayoutNameRule implements ValidationRule { + + public static final String MESSAGE = "validator.layoutNameRuleInvalid"; + public static final ValidationRule INSTANCE = new LayoutNameRule(); + + @Override + public boolean check(final @NotNull String value) { + return value.matches(RegExUtil.LAYOUT_NAME); + } + + public static ValidationRule getInstance() { + return INSTANCE; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java new file mode 100644 index 000000000..777c8c51a --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java @@ -0,0 +1,73 @@ +/* + * 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.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.magento.idea.magento2plugin.actions.generation.data.LayoutXmlData; +import com.magento.idea.magento2plugin.actions.generation.generator.util.FindOrCreateLayoutXml; +import java.util.Properties; +import org.jetbrains.annotations.NotNull; + +public class LayoutXmlTemplateGenerator extends FileGenerator { + private final LayoutXmlData layoutXmlData; + private final Project project; + private final FindOrCreateLayoutXml findOrCreateLayoutXml; + + /** + * Constructor. + * + * @param layoutXmlData LayoutXmlData + * @param project Project + */ + public LayoutXmlTemplateGenerator( + final @NotNull LayoutXmlData layoutXmlData, + final Project project + ) { + super(project); + this.layoutXmlData = layoutXmlData; + this.project = project; + this.findOrCreateLayoutXml = new FindOrCreateLayoutXml(project); + } + + /** + * Creates a module layout file. + * + * @param actionName String + * @return PsiFile + */ + @Override + public PsiFile generate(final String actionName) { + final XmlFile layoutXml = (XmlFile) findOrCreateLayoutXml.execute( + actionName, + layoutXmlData.getRoute(), + layoutXmlData.getControllerName(), + layoutXmlData.getActionName(), + layoutXmlData.getModuleName(), + layoutXmlData.getArea() + ); + final PsiDocumentManager psiDocumentManager = + PsiDocumentManager.getInstance(project); + final Document document = psiDocumentManager.getDocument(layoutXml); + WriteCommandAction.runWriteCommandAction(project, () -> { + final XmlTag rootTag = layoutXml.getRootTag(); + if (rootTag == null) { + return; + } + + psiDocumentManager.commitDocument(document); + }); + return layoutXml; + } + + @Override + protected void fillAttributes(final Properties attributes) {} //NOPMD +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java index 177059235..9dbe39698 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java @@ -60,7 +60,11 @@ public PsiFile execute( parentDirectory = directoryGenerator .findOrCreateSubdirectory(parentDirectory, fileDirectory); } - final LayoutXml layoutXml = new LayoutXml(routeId, controllerName, controllerActionName); + + LayoutXml layoutXml = new LayoutXml(routeId, controllerName, controllerActionName); + if ("".equals(controllerName)) { + layoutXml = new LayoutXml(routeId); + } PsiFile layoutXmlFile = FileBasedIndexUtil.findModuleViewFile( layoutXml.getFileName(), getArea(area), diff --git a/src/com/magento/idea/magento2plugin/magento/files/LayoutXml.java b/src/com/magento/idea/magento2plugin/magento/files/LayoutXml.java index 37faf3f34..cfe0910a8 100644 --- a/src/com/magento/idea/magento2plugin/magento/files/LayoutXml.java +++ b/src/com/magento/idea/magento2plugin/magento/files/LayoutXml.java @@ -11,19 +11,19 @@ @SuppressWarnings({"PMD.FieldNamingConventions", "PMD.ClassNamingConventions"}) public class LayoutXml implements ModuleFileInterface { - public static String DEFAULT_FILENAME = "default.xml"; - public static String CACHEABLE_ATTRIBUTE_NAME = "cacheable"; - public static String CACHEABLE_ATTRIBUTE_VALUE_FALSE = "false"; - public static String BLOCK_ATTRIBUTE_TAG_NAME = "block"; - public static String REFERENCE_BLOCK_ATTRIBUTE_TAG_NAME = "referenceBlock"; - public static String ROOT_TAG_NAME = "body"; - public static String REFERENCE_CONTAINER_TAG_NAME = "referenceContainer"; - public static String UI_COMPONENT_TAG_NAME = "uiComponent"; - public static String XML_ATTRIBUTE_TEMPLATE = "template"; - public static String ARGUMENTS_TEMPLATE = "Magento Module Class Arguments In Xml"; - public static String PARENT_DIR = "layout"; - public static String NAME_ATTRIBUTE = "name"; - public static String CONTENT_CONTAINER_NAME = "content"; + public static final String DEFAULT_FILENAME = "default.xml"; + public static final String CACHEABLE_ATTRIBUTE_NAME = "cacheable"; + public static final String CACHEABLE_ATTRIBUTE_VALUE_FALSE = "false"; + public static final String BLOCK_ATTRIBUTE_TAG_NAME = "block"; + public static final String REFERENCE_BLOCK_ATTRIBUTE_TAG_NAME = "referenceBlock"; + public static final String ROOT_TAG_NAME = "body"; + public static final String REFERENCE_CONTAINER_TAG_NAME = "referenceContainer"; + public static final String UI_COMPONENT_TAG_NAME = "uiComponent"; + public static final String XML_ATTRIBUTE_TEMPLATE = "template"; + public static final String ARGUMENTS_TEMPLATE = "Magento Module Class Arguments In Xml"; + public static final String PARENT_DIR = "layout"; + public static final String NAME_ATTRIBUTE = "name"; + public static final String CONTENT_CONTAINER_NAME = "content"; public static String TEMPLATE = "Magento Layout XML"; private String fileName; @@ -46,6 +46,15 @@ public LayoutXml(final String routeId, final String controllerName, final String ); } + /** + * Layout XML file. + * + * @param routeId String + */ + public LayoutXml(final String routeId) { + this.setFileName(routeId + ".xml"); + } + /** * Get name of file. * diff --git a/src/com/magento/idea/magento2plugin/util/RegExUtil.java b/src/com/magento/idea/magento2plugin/util/RegExUtil.java index 83ce45ed9..73a3b816c 100644 --- a/src/com/magento/idea/magento2plugin/util/RegExUtil.java +++ b/src/com/magento/idea/magento2plugin/util/RegExUtil.java @@ -46,6 +46,9 @@ public class RegExUtil { public static final String MAGENTO_VERSION = "(\\d+)\\.(\\d+)\\.(\\d+)[a-zA-Z0-9_\\-]*"; + public static final String LAYOUT_NAME + = "^([a-zA-Z0-9]+){1,}(_[a-zA-Z0-9]+){0,2}"; + public static class Magento { public static final String PHP_CLASS diff --git a/src/com/magento/idea/magento2plugin/util/magento/GetMagentoModuleUtil.java b/src/com/magento/idea/magento2plugin/util/magento/GetMagentoModuleUtil.java index 207b7eaf4..503844a89 100644 --- a/src/com/magento/idea/magento2plugin/util/magento/GetMagentoModuleUtil.java +++ b/src/com/magento/idea/magento2plugin/util/magento/GetMagentoModuleUtil.java @@ -51,6 +51,9 @@ public static MagentoModuleData getByContext( final PsiDirectory configDir = registrationFile .getContainingDirectory() .findSubdirectory(Package.moduleBaseAreaDir); + final PsiDirectory viewDir = registrationFile + .getContainingDirectory() + .findSubdirectory(Package.moduleViewDir); final Collection methodReferences = PsiTreeUtil.findChildrenOfType( registrationFile, MethodReference.class @@ -76,7 +79,7 @@ public static MagentoModuleData getByContext( return null; } - return new MagentoModuleData(name, resolvedType, configDir); + return new MagentoModuleData(name, resolvedType, configDir, viewDir); } return null; @@ -130,6 +133,7 @@ public static class MagentoModuleData { private final String name; private final ComponentType type; private final PsiDirectory configDir; + private final PsiDirectory viewDir; /** * Default constructor. @@ -141,7 +145,7 @@ public MagentoModuleData( final @NotNull String name, final @NotNull ComponentType type ) { - this(name, type, null); + this(name, type, null, null); } /** @@ -150,15 +154,18 @@ public MagentoModuleData( * @param name String * @param type ComponentType * @param configDir PsiDirectory + * @param viewDir PsiDirectory */ public MagentoModuleData( final @NotNull String name, final @NotNull ComponentType type, - final @Nullable PsiDirectory configDir + final @Nullable PsiDirectory configDir, + final @Nullable PsiDirectory viewDir ) { this.name = name; this.type = type; this.configDir = configDir; + this.viewDir = viewDir; } public String getName() { @@ -172,5 +179,9 @@ public ComponentType getType() { public @Nullable PsiDirectory getConfigDir() { return configDir; } + + public @Nullable PsiDirectory getViewDir() { + return viewDir; + } } } From 2cf2f80a07e5fad9f6fd429c4ce03376179580ca Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Mon, 7 Mar 2022 18:02:14 +0200 Subject: [PATCH 07/20] 967: Code refactoring --- .../actions/context/xml/NewLayoutXmlAction.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java b/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java index c01378302..ac934a78b 100644 --- a/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java +++ b/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java @@ -5,7 +5,6 @@ package com.magento.idea.magento2plugin.actions.context.xml; -import com.intellij.ide.fileTemplates.actions.AttributesDefaults; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; @@ -13,7 +12,6 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; import com.magento.idea.magento2plugin.MagentoIcons; import com.magento.idea.magento2plugin.actions.generation.dialog.NewLayoutTemplateDialog; import com.magento.idea.magento2plugin.magento.packages.Areas; @@ -106,13 +104,4 @@ private void setIsAvailableForEvent( event.getPresentation().setVisible(isAvailable); event.getPresentation().setEnabled(isAvailable); } - - protected AttributesDefaults getProperties( - final @NotNull AttributesDefaults defaults, - final @NotNull GetMagentoModuleUtil.MagentoModuleData moduleData, - final PsiDirectory targetDirectory, - final PsiFile targetFile - ) { - return null; - } } From 134472de39f7f68b432d60a531d1664a01485da5 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Mon, 7 Mar 2022 18:10:22 +0200 Subject: [PATCH 08/20] 967: Code refactoring --- .../generator/LayoutXmlTemplateGenerator.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java index 777c8c51a..0dc3c7ec6 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java @@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull; public class LayoutXmlTemplateGenerator extends FileGenerator { + private final LayoutXmlData layoutXmlData; private final Project project; private final FindOrCreateLayoutXml findOrCreateLayoutXml; @@ -42,10 +43,11 @@ public LayoutXmlTemplateGenerator( * Creates a module layout file. * * @param actionName String + * * @return PsiFile */ @Override - public PsiFile generate(final String actionName) { + public PsiFile generate(final @NotNull String actionName) { final XmlFile layoutXml = (XmlFile) findOrCreateLayoutXml.execute( actionName, layoutXmlData.getRoute(), @@ -54,17 +56,26 @@ public PsiFile generate(final String actionName) { layoutXmlData.getModuleName(), layoutXmlData.getArea() ); + + if (layoutXml == null) { + return null; + } final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project); final Document document = psiDocumentManager.getDocument(layoutXml); + + if (document == null) { + return null; + } WriteCommandAction.runWriteCommandAction(project, () -> { final XmlTag rootTag = layoutXml.getRootTag(); + if (rootTag == null) { return; } - psiDocumentManager.commitDocument(document); }); + return layoutXml; } From 42ca0e0f27a5f1dae7b3aed6a22366229ae44200 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Mon, 7 Mar 2022 18:12:11 +0200 Subject: [PATCH 09/20] 967: Code refactoring --- .../generation/generator/util/FindOrCreateLayoutXml.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java index 9dbe39698..2a5415391 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java @@ -17,6 +17,7 @@ import java.util.Properties; public final class FindOrCreateLayoutXml { + private final Project project; public FindOrCreateLayoutXml(final Project project) { @@ -61,9 +62,10 @@ public PsiFile execute( .findOrCreateSubdirectory(parentDirectory, fileDirectory); } - LayoutXml layoutXml = new LayoutXml(routeId, controllerName, controllerActionName); - if ("".equals(controllerName)) { - layoutXml = new LayoutXml(routeId); + LayoutXml layoutXml = new LayoutXml(routeId, controllerName, controllerActionName); + + if (controllerName.isEmpty()) { + layoutXml = new LayoutXml(routeId); } PsiFile layoutXmlFile = FileBasedIndexUtil.findModuleViewFile( layoutXml.getFileName(), From 5d661e6062434aa4c64fb6ef8e0fc09494665220 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Wed, 9 Mar 2022 11:09:18 +0200 Subject: [PATCH 10/20] 409: Added argument injection/replacement test cases --- .../injectArrayValue/di.xml | 15 + .../injectBooleanValue/di.xml | 9 + .../injectConstValue/di.xml | 9 + .../injectInitParameterValue/di.xml | 9 + .../injectNestedArrayValue/di.xml | 19 + .../injectNullValue/di.xml | 9 + .../injectNumberValue/di.xml | 9 + .../injectObjectValue/di.xml | 9 + .../injectStringValue/di.xml | 9 + .../replaceObjectValueWithFactoryValue/di.xml | 11 + .../replaceObjectValueWithNullValue/di.xml | 11 + .../replaceObjectValueWithProxyValue/di.xml | 11 + .../app/code/Foo/Bar/etc/crontab/di.xml | 11 + .../ArgumentInjectionGeneratorTest.java | 337 ++++++++++++++++++ 14 files changed, 478 insertions(+) create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/injectArrayValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/injectBooleanValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/injectConstValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/injectInitParameterValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/injectNestedArrayValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/injectNullValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/injectNumberValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/injectObjectValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/injectStringValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithFactoryValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithNullValue/di.xml create mode 100644 testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithProxyValue/di.xml create mode 100644 testData/project/magento2/app/code/Foo/Bar/etc/crontab/di.xml create mode 100644 tests/com/magento/idea/magento2plugin/actions/generation/generator/ArgumentInjectionGeneratorTest.java diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/injectArrayValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectArrayValue/di.xml new file mode 100644 index 000000000..0b8341ed4 --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectArrayValue/di.xml @@ -0,0 +1,15 @@ + + + + + + QW1 + QW2 + QW3 + QW4 + QW5 + + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/injectBooleanValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectBooleanValue/di.xml new file mode 100644 index 000000000..731759df9 --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectBooleanValue/di.xml @@ -0,0 +1,9 @@ + + + + + false + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/injectConstValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectConstValue/di.xml new file mode 100644 index 000000000..f26db45d3 --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectConstValue/di.xml @@ -0,0 +1,9 @@ + + + + + Foo\Bar\Model\ServiceTest::DEFAULT_SERVICE + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/injectInitParameterValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectInitParameterValue/di.xml new file mode 100644 index 000000000..f25afb7cb --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectInitParameterValue/di.xml @@ -0,0 +1,9 @@ + + + + + Foo\Bar\Model\AreaTest::DEFAULT_AREA + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/injectNestedArrayValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectNestedArrayValue/di.xml new file mode 100644 index 000000000..fda440cbd --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectNestedArrayValue/di.xml @@ -0,0 +1,19 @@ + + + + + + QW1 + QW2 + QW3 + QW4 + + NT1 + true + + + + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/injectNullValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectNullValue/di.xml new file mode 100644 index 000000000..28e6599cd --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectNullValue/di.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/injectNumberValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectNumberValue/di.xml new file mode 100644 index 000000000..1e1cfe5f7 --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectNumberValue/di.xml @@ -0,0 +1,9 @@ + + + + + 12 + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/injectObjectValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectObjectValue/di.xml new file mode 100644 index 000000000..7c85bc54c --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectObjectValue/di.xml @@ -0,0 +1,9 @@ + + + + + Foo\Bar\Model\Service + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/injectStringValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectStringValue/di.xml new file mode 100644 index 000000000..b8f8d9d30 --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/injectStringValue/di.xml @@ -0,0 +1,9 @@ + + + + + test + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithFactoryValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithFactoryValue/di.xml new file mode 100644 index 000000000..645bbe721 --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithFactoryValue/di.xml @@ -0,0 +1,11 @@ + + + + + 1111 + Foo\Bar\Model\ServiceFactory + Just another argument + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithNullValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithNullValue/di.xml new file mode 100644 index 000000000..206074d73 --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithNullValue/di.xml @@ -0,0 +1,11 @@ + + + + + 1111 + + Just another argument + + + diff --git a/testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithProxyValue/di.xml b/testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithProxyValue/di.xml new file mode 100644 index 000000000..1e708e60a --- /dev/null +++ b/testData/actions/generation/generator/ArgumentInjectionGenerator/replaceObjectValueWithProxyValue/di.xml @@ -0,0 +1,11 @@ + + + + + 1111 + Foo\Bar\Model\Service\Proxy + Just another argument + + + diff --git a/testData/project/magento2/app/code/Foo/Bar/etc/crontab/di.xml b/testData/project/magento2/app/code/Foo/Bar/etc/crontab/di.xml new file mode 100644 index 000000000..55c772245 --- /dev/null +++ b/testData/project/magento2/app/code/Foo/Bar/etc/crontab/di.xml @@ -0,0 +1,11 @@ + + + + + 1111 + Foo\Bar\Model\Service + Just another argument + + + diff --git a/tests/com/magento/idea/magento2plugin/actions/generation/generator/ArgumentInjectionGeneratorTest.java b/tests/com/magento/idea/magento2plugin/actions/generation/generator/ArgumentInjectionGeneratorTest.java new file mode 100644 index 000000000..5f5aec003 --- /dev/null +++ b/tests/com/magento/idea/magento2plugin/actions/generation/generator/ArgumentInjectionGeneratorTest.java @@ -0,0 +1,337 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.generator; + +import com.intellij.psi.PsiFile; +import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArgumentData; +import com.magento.idea.magento2plugin.actions.generation.data.xml.DiArrayValueData; +import com.magento.idea.magento2plugin.actions.generation.generator.code.ArgumentInjectionGenerator; +import com.magento.idea.magento2plugin.magento.files.ModuleDiXml; +import com.magento.idea.magento2plugin.magento.packages.Areas; +import com.magento.idea.magento2plugin.magento.packages.DiArgumentType; +import java.util.ArrayList; +import java.util.List; + +public class ArgumentInjectionGeneratorTest extends BaseGeneratorTestCase { + + private static final String EXPECTED_DIRECTORY = "src/app/code/Foo/Bar/etc/frontend"; + private static final String EXPECTED_DIR_FOR_REPLACING = "src/app/code/Foo/Bar/etc/crontab"; + private static final String MODULE_NAME = "Foo_Bar"; + private static final String TARGET_CLASS = "Foo\\Bar\\Model\\Test"; + private static final String STRING_PARAMETER = "name"; + private static final String STRING_VALUE = "test"; + private static final String BOOL_PARAMETER = "isEmpty"; + private static final String BOOL_VALUE = "false"; + private static final String NUMBER_PARAMETER = "age"; + private static final String NUMBER_VALUE = "12"; + private static final String INIT_PARAM_PARAMETER = "defaultArea"; + private static final String INIT_PARAM_VALUE = "Foo\\Bar\\Model\\AreaTest::DEFAULT_AREA"; + private static final String CONST_PARAMETER = "defaultService"; + private static final String CONST_VALUE = "Foo\\Bar\\Model\\ServiceTest::DEFAULT_SERVICE"; + private static final String NULL_PARAMETER = "object"; + private static final String NULL_VALUE = ""; + private static final String OBJECT_PARAMETER = "object"; + private static final String OBJECT_VALUE = "Foo\\Bar\\Model\\Service"; + private static final String ARRAY_PARAMETER = "methods"; + private static final Areas TEST_AREA = Areas.frontend; + + /** + * Tested string value injection. + */ + public void testInjectStringValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIRECTORY, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + STRING_PARAMETER, + TEST_AREA, + DiArgumentType.STRING, + STRING_VALUE + ) + ) + ); + } + + /** + * Tested boolean value injection. + */ + public void testInjectBooleanValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIRECTORY, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + BOOL_PARAMETER, + TEST_AREA, + DiArgumentType.BOOLEAN, + BOOL_VALUE + ) + ) + ); + } + + /** + * Tested number value injection. + */ + public void testInjectNumberValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIRECTORY, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + NUMBER_PARAMETER, + TEST_AREA, + DiArgumentType.NUMBER, + NUMBER_VALUE + ) + ) + ); + } + + /** + * Tested init_parameter value injection. + */ + public void testInjectInitParameterValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIRECTORY, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + INIT_PARAM_PARAMETER, + TEST_AREA, + DiArgumentType.INIT_PARAMETER, + INIT_PARAM_VALUE + ) + ) + ); + } + + /** + * Tested constant value injection. + */ + public void testInjectConstValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIRECTORY, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + CONST_PARAMETER, + TEST_AREA, + DiArgumentType.CONST, + CONST_VALUE + ) + ) + ); + } + + /** + * Tested null value injection. + */ + public void testInjectNullValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIRECTORY, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + NULL_PARAMETER, + TEST_AREA, + DiArgumentType.NULL, + NULL_VALUE + ) + ) + ); + } + + /** + * Tested object value injection. + */ + public void testInjectObjectValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIRECTORY, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + OBJECT_PARAMETER, + TEST_AREA, + DiArgumentType.OBJECT, + OBJECT_VALUE + ) + ) + ); + } + + /** + * Tested array value injection. + */ + public void testInjectArrayValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIRECTORY, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + ARRAY_PARAMETER, + TEST_AREA, + DiArgumentType.ARRAY, + getArrayValue() + ) + ) + ); + } + + /** + * Tested nested array value injection. + */ + public void testInjectNestedArrayValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIRECTORY, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + ARRAY_PARAMETER, + TEST_AREA, + DiArgumentType.ARRAY, + getNestedArrayValue() + ) + ) + ); + } + + /** + * Tested object value replacing with the null value injection. + */ + public void testReplaceObjectValueWithNullValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIR_FOR_REPLACING, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + OBJECT_PARAMETER, + Areas.crontab, + DiArgumentType.NULL, + NULL_VALUE + ) + ) + ); + } + + /** + * Tested object value replacing with the object proxy value injection. + */ + public void testReplaceObjectValueWithProxyValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIR_FOR_REPLACING, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + OBJECT_PARAMETER, + Areas.crontab, + DiArgumentType.OBJECT, + OBJECT_VALUE + "\\Proxy" + ) + ) + ); + } + + /** + * Tested object value replacing with the object factory value injection. + */ + public void testReplaceObjectValueWithFactoryValue() { + assertGeneratedFileIsCorrect( + myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME)), + EXPECTED_DIR_FOR_REPLACING, + injectConstructorArgument( + new DiArgumentData( + MODULE_NAME, + TARGET_CLASS, + OBJECT_PARAMETER, + Areas.crontab, + DiArgumentType.OBJECT, + OBJECT_VALUE + "Factory" + ) + ) + ); + } + + private PsiFile injectConstructorArgument( + final DiArgumentData data + ) { + final ArgumentInjectionGenerator generator = new ArgumentInjectionGenerator( + data, + myFixture.getProject() + ); + + return generator.generate("test"); + } + + private String getArrayValue() { + final List items = new ArrayList<>(); + items.add(new DiArrayValueData.DiArrayItemData("method1", DiArgumentType.STRING, "QW1")); + items.add(new DiArrayValueData.DiArrayItemData("method2", DiArgumentType.STRING, "QW2")); + items.add(new DiArrayValueData.DiArrayItemData("method3", DiArgumentType.STRING, "QW3")); + items.add(new DiArrayValueData.DiArrayItemData("method4", DiArgumentType.STRING, "QW4")); + items.add(new DiArrayValueData.DiArrayItemData("method5", DiArgumentType.STRING, "QW5")); + final DiArrayValueData arrayValueData = new DiArrayValueData(); + arrayValueData.setItems(items); + + return arrayValueData.convertToXml(arrayValueData); + } + + private String getNestedArrayValue() { + final List items = new ArrayList<>(); + items.add(new DiArrayValueData.DiArrayItemData("method1", DiArgumentType.STRING, "QW1")); + items.add(new DiArrayValueData.DiArrayItemData("method2", DiArgumentType.STRING, "QW2")); + items.add(new DiArrayValueData.DiArrayItemData("method3", DiArgumentType.STRING, "QW3")); + items.add(new DiArrayValueData.DiArrayItemData("method4", DiArgumentType.STRING, "QW4")); + final DiArrayValueData.DiArrayItemData nestedItem = new DiArrayValueData.DiArrayItemData( + "nested", + DiArgumentType.ARRAY, + "" + ); + + final DiArrayValueData nestedItemsHolder = new DiArrayValueData(); + final List nestedItems = new ArrayList<>(); + nestedItems.add( + new DiArrayValueData.DiArrayItemData("nested1", DiArgumentType.STRING, "NT1") + ); + nestedItems.add( + new DiArrayValueData.DiArrayItemData("nested2", DiArgumentType.BOOLEAN, "true") + ); + nestedItems.add( + new DiArrayValueData.DiArrayItemData("nested3", DiArgumentType.NULL, "") + ); + nestedItemsHolder.setItems(nestedItems); + nestedItem.setChildren(nestedItemsHolder); + items.add(nestedItem); + + final DiArrayValueData arrayValueData = new DiArrayValueData(); + arrayValueData.setItems(items); + + return arrayValueData.convertToXml(arrayValueData); + } +} From aeffd6fde50a1e8425d5741320a9fa20fa441bf7 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Wed, 9 Mar 2022 11:16:20 +0200 Subject: [PATCH 11/20] 409: Suppressed warning --- .../generation/generator/ArgumentInjectionGeneratorTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/com/magento/idea/magento2plugin/actions/generation/generator/ArgumentInjectionGeneratorTest.java b/tests/com/magento/idea/magento2plugin/actions/generation/generator/ArgumentInjectionGeneratorTest.java index 5f5aec003..496a86f5d 100644 --- a/tests/com/magento/idea/magento2plugin/actions/generation/generator/ArgumentInjectionGeneratorTest.java +++ b/tests/com/magento/idea/magento2plugin/actions/generation/generator/ArgumentInjectionGeneratorTest.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.List; +@SuppressWarnings("PMD.TooManyMethods") public class ArgumentInjectionGeneratorTest extends BaseGeneratorTestCase { private static final String EXPECTED_DIRECTORY = "src/app/code/Foo/Bar/etc/frontend"; From 3293ea116cd8485746cc8825feff763ccc43c81e Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Wed, 9 Mar 2022 11:55:59 +0200 Subject: [PATCH 12/20] 409: Added target type suggestion --- .../dialog/NewArgumentInjectionDialog.java | 39 +++++++++++++++++++ .../util/php/PhpTypeMetadataParserUtil.java | 31 ++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java index 7432b4076..16dab90f7 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java @@ -15,6 +15,7 @@ import com.intellij.ui.EditorTextField; import com.jetbrains.php.PhpIndex; import com.jetbrains.php.completion.PhpCompletionUtil; +import com.jetbrains.php.lang.PhpLangUtil; import com.jetbrains.php.lang.psi.elements.Field; import com.jetbrains.php.lang.psi.elements.Parameter; import com.jetbrains.php.lang.psi.elements.PhpClass; @@ -33,11 +34,13 @@ import com.magento.idea.magento2plugin.magento.packages.Areas; import com.magento.idea.magento2plugin.magento.packages.DiArgumentType; import com.magento.idea.magento2plugin.ui.FilteredComboBox; +import com.magento.idea.magento2plugin.util.php.PhpTypeMetadataParserUtil; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import javax.swing.JButton; @@ -69,6 +72,7 @@ public class NewArgumentInjectionDialog extends AbstractDialog { private final @NotNull Project project; private final PhpClass targetClass; + private final Parameter targetParameter; private JPanel contentPane; private JButton buttonCancel; @@ -172,6 +176,7 @@ public NewArgumentInjectionDialog( this.project = project; this.targetClass = targetClass; + targetParameter = parameter; arrayValues = new DiArrayValueData(); setContentPane(contentPane); @@ -333,6 +338,7 @@ public void documentChanged(final @NotNull DocumentEvent event) { } } }); + guessTargetType(); } /** @@ -618,6 +624,39 @@ private void changeViewBySelectedArgumentType(final String itemValue) { return ""; } + @SuppressWarnings("PMD.CyclomaticComplexity") + private void guessTargetType() { + final String mainType = PhpTypeMetadataParserUtil.getMainType(targetParameter); + + if (mainType == null) { + return; + } + String targetDiType = ""; + + if (Arrays.asList("int", "float").contains(mainType)) { + targetDiType = DiArgumentType.NUMBER.getArgumentType(); + } else if (DiArgumentType.STRING.getArgumentType().equals(mainType)) { + targetDiType = DiArgumentType.STRING.getArgumentType(); + } else if ("bool".equals(mainType)) { + targetDiType = DiArgumentType.BOOLEAN.getArgumentType(); + } else if (PhpLangUtil.isFqn(mainType)) { + targetDiType = DiArgumentType.OBJECT.getArgumentType(); + } else if ("array".equals(mainType)) { + targetDiType = DiArgumentType.ARRAY.getArgumentType(); + } + + if (targetDiType.isEmpty()) { + return; + } + + for (int i = 0; i < argumentType.getItemCount(); i++) { + if (targetDiType.equals(argumentType.getItemAt(i).getKey())) { + argumentType.setSelectedIndex(i); + break; + } + } + } + private DiArgumentData getDialogDataObject() { if (targetArea.getSelectedItem() == null) { showErrorMessage(new ValidatorBundle().message(NotEmptyRule.MESSAGE, TARGET_AREA)); diff --git a/src/com/magento/idea/magento2plugin/util/php/PhpTypeMetadataParserUtil.java b/src/com/magento/idea/magento2plugin/util/php/PhpTypeMetadataParserUtil.java index 6f8cec22f..9ea2c4941 100644 --- a/src/com/magento/idea/magento2plugin/util/php/PhpTypeMetadataParserUtil.java +++ b/src/com/magento/idea/magento2plugin/util/php/PhpTypeMetadataParserUtil.java @@ -135,7 +135,12 @@ public static List getMethodsByNames( * * @return String */ - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.ConfusingTernary"}) + @SuppressWarnings({ + "PMD.CyclomaticComplexity", + "PMD.CognitiveComplexity", + "PMD.NPathComplexity", + "PMD.ConfusingTernary" + }) public static String getMethodDefinitionForInterface( final @NotNull Method method, final String defaultMethodDescription @@ -269,6 +274,29 @@ public static List getMethodParametersTypes(final @NotNull Method method return types; } + /** + * Get main type for the specified parameter (?int -> main type is int). + * + * @param parameter Parameter + * + * @return String + */ + public static String getMainType(final @NotNull Parameter parameter) { + final List types = extractMultipleTypesFromString( + parameter.getDeclaredType().toString() + ); + + for (final String type : types) { + if (PhpLangUtil.isFqn(type)) { + return type; + } else if (PhpLangUtil.isParameterTypeHint(type, parameter.getProject())) { + return type; + } + } + + return null; + } + /** * Get method return type. * @@ -309,6 +337,7 @@ public static String getMethodReturnType(final @NotNull Method method) { * * @return List[String] */ + @SuppressWarnings("PMD.CognitiveComplexity") public static List getMethodExceptionsTypes(final @NotNull Method method) { final List types = new ArrayList<>(); From 2a0ec5fe6e824f13f69499839252e2860bcf97e6 Mon Sep 17 00:00:00 2001 From: silinmykola Date: Thu, 10 Mar 2022 14:45:26 +0200 Subject: [PATCH 13/20] 967 fixes after CR --- .../internal/Magento Layout XML.xml.ft | 3 +- .../dialog/NewLayoutTemplateDialog.java | 80 +++++++------------ .../generator/LayoutXmlTemplateGenerator.java | 13 ++- .../generator/util/FindOrCreateLayoutXml.java | 9 ++- 4 files changed, 48 insertions(+), 57 deletions(-) diff --git a/resources/fileTemplates/internal/Magento Layout XML.xml.ft b/resources/fileTemplates/internal/Magento Layout XML.xml.ft index 46efc847d..76d8eebda 100644 --- a/resources/fileTemplates/internal/Magento Layout XML.xml.ft +++ b/resources/fileTemplates/internal/Magento Layout XML.xml.ft @@ -1,4 +1,5 @@ #parse("XML File Header.xml") - + diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java index f819d49e5..2cd330235 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java @@ -123,13 +123,14 @@ public static void open( */ private void onOK() { if (validateFormFields() && isUnderscoreCorrect()) { + final String[] layoutNameParts = getLayoutNameParts(); new LayoutXmlTemplateGenerator( new LayoutXmlData( getArea(), - getRouteName(), + layoutNameParts[0], moduleName, - getControllerName(), - getActionName() + layoutNameParts[1], + layoutNameParts[2] ), project ).generate(NewLayoutXmlAction.ACTION_NAME, true); @@ -166,6 +167,29 @@ private void autoSelectCurrentArea() { } } + /** + * Get parts of inserted layout name + * + * @return String[] + */ + private String[] getLayoutNameParts() { + + final String[] layoutNameParts = layoutName.getText().trim().split("_"); + String routeName = ""; + String controllerName = ""; + String actionName = ""; + + if (layoutNameParts.length >= 1) { // NOPMD + routeName = layoutNameParts[0]; + } + + if (layoutNameParts.length == 3) { // NOPMD + controllerName = layoutNameParts[1]; + actionName = layoutNameParts[2]; + } + return new String[]{routeName, controllerName, actionName}; + } + /** * Check is count of underscore is correct in layout name. * @@ -210,20 +234,6 @@ private int countUnderscore(final String name) { return count; } - /** - * Get action name. - * - * @return String - */ - private String getActionName() { - if (layoutName.getText().trim().contains("_")) { - final int position = layoutName.getText().trim().lastIndexOf("_") + 1; - return layoutName.getText().trim().substring(position); - } - - return ""; - } - /** * Get area. * @@ -232,40 +242,4 @@ private String getActionName() { private String getArea() { return area.getSelectedItem().toString(); } - - /** - * Get controller name. - * - * @return String - */ - private String getControllerName() { - final String newLayoutName = layoutName.getText().trim(); - if (newLayoutName.contains("_")) { - final int start = newLayoutName.indexOf('_') + 1; - int end = newLayoutName.lastIndexOf('_'); - - if (start == end) { - end = newLayoutName.length() - 1; - } - return newLayoutName.substring(start, end); - } - - return ""; - } - - /** - * Get route name. - * - * @return String - */ - private String getRouteName() { - final String newLayoutName = layoutName.getText().trim(); - int position = newLayoutName.length(); - - if (newLayoutName.contains("_")) { - position = newLayoutName.indexOf('_'); - } - - return newLayoutName.substring(0, position); - } } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java index 0dc3c7ec6..a8e29784e 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java @@ -14,6 +14,8 @@ import com.intellij.psi.xml.XmlTag; import com.magento.idea.magento2plugin.actions.generation.data.LayoutXmlData; import com.magento.idea.magento2plugin.actions.generation.generator.util.FindOrCreateLayoutXml; +import com.magento.idea.magento2plugin.magento.packages.Areas; +import java.util.Objects; import java.util.Properties; import org.jetbrains.annotations.NotNull; @@ -36,7 +38,8 @@ public LayoutXmlTemplateGenerator( super(project); this.layoutXmlData = layoutXmlData; this.project = project; - this.findOrCreateLayoutXml = new FindOrCreateLayoutXml(project); + final Properties attributes = getAttributes(); + this.findOrCreateLayoutXml = new FindOrCreateLayoutXml(project, attributes); } /** @@ -80,5 +83,11 @@ public PsiFile generate(final @NotNull String actionName) { } @Override - protected void fillAttributes(final Properties attributes) {} //NOPMD + protected void fillAttributes(final Properties attributes) { + if (Objects.equals(layoutXmlData.getArea(), Areas.adminhtml.toString())) { + attributes.setProperty("IS_ADMIN", Boolean.TRUE.toString()); + } else { + attributes.setProperty("IS_ADMIN", Boolean.FALSE.toString()); + } + } } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java index 2a5415391..fb815c554 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java @@ -19,9 +19,16 @@ public final class FindOrCreateLayoutXml { private final Project project; + private final Properties properties; public FindOrCreateLayoutXml(final Project project) { this.project = project; + this.properties = new Properties(); + } + + public FindOrCreateLayoutXml(final Project project, Properties properties) { + this.project = project; + this.properties = properties; } /** @@ -77,7 +84,7 @@ public PsiFile execute( if (layoutXmlFile == null) { layoutXmlFile = fileFromTemplateGenerator.generate( layoutXml, - new Properties(), + this.properties, parentDirectory, actionName ); From 66394a6129390687cb8f80d75c7354797e0df95a Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Thu, 10 Mar 2022 16:49:09 +0200 Subject: [PATCH 14/20] 967: Code refactoring after code review --- .../internal/Magento Layout XML.xml.ft | 7 +++- .../context/xml/NewLayoutXmlAction.java | 34 +++++++++++++++++-- .../dialog/NewLayoutTemplateDialog.java | 3 +- .../generator/LayoutXmlTemplateGenerator.java | 14 ++------ .../generator/util/FindOrCreateLayoutXml.java | 22 ++++++++---- 5 files changed, 58 insertions(+), 22 deletions(-) diff --git a/resources/fileTemplates/internal/Magento Layout XML.xml.ft b/resources/fileTemplates/internal/Magento Layout XML.xml.ft index 76d8eebda..76f98fb5e 100644 --- a/resources/fileTemplates/internal/Magento Layout XML.xml.ft +++ b/resources/fileTemplates/internal/Magento Layout XML.xml.ft @@ -1,5 +1,10 @@ #parse("XML File Header.xml") - diff --git a/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java b/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java index ac934a78b..04e3cc15b 100644 --- a/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java +++ b/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java @@ -12,8 +12,10 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.magento.idea.magento2plugin.MagentoIcons; import com.magento.idea.magento2plugin.actions.generation.dialog.NewLayoutTemplateDialog; +import com.magento.idea.magento2plugin.magento.files.LayoutXml; import com.magento.idea.magento2plugin.magento.packages.Areas; import com.magento.idea.magento2plugin.magento.packages.ComponentType; import com.magento.idea.magento2plugin.magento.packages.Package; @@ -22,6 +24,7 @@ import java.util.Arrays; import java.util.List; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class NewLayoutXmlAction extends AnAction { @@ -47,11 +50,11 @@ public void update(final @NotNull AnActionEvent event) { } final DataContext context = event.getDataContext(); final PsiElement targetElement = LangDataKeys.PSI_ELEMENT.getData(context); + final PsiDirectory targetDirectoryCandidate = resolveTargetDirectory(targetElement); - if (!(targetElement instanceof PsiDirectory)) { + if (targetDirectoryCandidate == null) { return; } - final PsiDirectory targetDirectoryCandidate = (PsiDirectory) targetElement; final GetMagentoModuleUtil.MagentoModuleData moduleData = GetMagentoModuleUtil .getByContext(targetDirectoryCandidate, project); @@ -104,4 +107,31 @@ private void setIsAvailableForEvent( event.getPresentation().setVisible(isAvailable); event.getPresentation().setEnabled(isAvailable); } + + /** + * Resolve target directory. + * + * @param targetElement PsiElement + * + * @return PsiDirectory + */ + private @Nullable PsiDirectory resolveTargetDirectory(final PsiElement targetElement) { + PsiDirectory target = null; + + if (targetElement instanceof PsiDirectory) { + target = (PsiDirectory) targetElement; + } else if (targetElement instanceof PsiFile) { + target = ((PsiFile) targetElement).getContainingDirectory(); + } + + if (target == null) { + return null; + } + + if (LayoutXml.PARENT_DIR.equals(target.getName())) { + target = target.getParentDirectory(); + } + + return target; + } } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java index 2cd330235..9dc5507af 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java @@ -168,7 +168,7 @@ private void autoSelectCurrentArea() { } /** - * Get parts of inserted layout name + * Get parts of inserted layout name. * * @return String[] */ @@ -187,6 +187,7 @@ private String[] getLayoutNameParts() { controllerName = layoutNameParts[1]; actionName = layoutNameParts[2]; } + return new String[]{routeName, controllerName, actionName}; } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java index a8e29784e..dc95aa570 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java @@ -14,8 +14,6 @@ import com.intellij.psi.xml.XmlTag; import com.magento.idea.magento2plugin.actions.generation.data.LayoutXmlData; import com.magento.idea.magento2plugin.actions.generation.generator.util.FindOrCreateLayoutXml; -import com.magento.idea.magento2plugin.magento.packages.Areas; -import java.util.Objects; import java.util.Properties; import org.jetbrains.annotations.NotNull; @@ -38,8 +36,7 @@ public LayoutXmlTemplateGenerator( super(project); this.layoutXmlData = layoutXmlData; this.project = project; - final Properties attributes = getAttributes(); - this.findOrCreateLayoutXml = new FindOrCreateLayoutXml(project, attributes); + this.findOrCreateLayoutXml = new FindOrCreateLayoutXml(project); } /** @@ -83,11 +80,6 @@ public PsiFile generate(final @NotNull String actionName) { } @Override - protected void fillAttributes(final Properties attributes) { - if (Objects.equals(layoutXmlData.getArea(), Areas.adminhtml.toString())) { - attributes.setProperty("IS_ADMIN", Boolean.TRUE.toString()); - } else { - attributes.setProperty("IS_ADMIN", Boolean.FALSE.toString()); - } - } + @SuppressWarnings("PMD.UncommentedEmptyMethodBody") + protected void fillAttributes(final Properties attributes) {} } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java index fb815c554..d6b2e8055 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java @@ -15,6 +15,7 @@ import com.magento.idea.magento2plugin.util.magento.FileBasedIndexUtil; import java.util.ArrayList; import java.util.Properties; +import org.jetbrains.annotations.NotNull; public final class FindOrCreateLayoutXml { @@ -23,12 +24,7 @@ public final class FindOrCreateLayoutXml { public FindOrCreateLayoutXml(final Project project) { this.project = project; - this.properties = new Properties(); - } - - public FindOrCreateLayoutXml(final Project project, Properties properties) { - this.project = project; - this.properties = properties; + properties = new Properties(); } /** @@ -82,9 +78,10 @@ public PsiFile execute( LayoutXml.PARENT_DIR ); if (layoutXmlFile == null) { + fillDefaultAttributes(area, properties); layoutXmlFile = fileFromTemplateGenerator.generate( layoutXml, - this.properties, + properties, parentDirectory, actionName ); @@ -95,4 +92,15 @@ public PsiFile execute( private Areas getArea(final String area) { return Areas.getAreaByString(area); } + + private void fillDefaultAttributes( + final @NotNull String area, + final @NotNull Properties properties + ) { + if (Areas.adminhtml.toString().equals(area)) { + properties.setProperty("IS_ADMIN", Boolean.TRUE.toString()); + } else { + properties.setProperty("IS_ADMIN", Boolean.FALSE.toString()); + } + } } From 103b417ec6444f3ae07413718d0dea7aca7b7ea5 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Fri, 11 Mar 2022 11:15:01 +0200 Subject: [PATCH 15/20] 828: Code refactoring --- .../CallingDeprecatedMethod.html | 2 +- .../ExtendingDeprecatedClass.html | 2 +- .../ImplementedDeprecatedInterface.html | 2 +- .../ImportingDeprecatedClass.html | 2 +- .../ImportingDeprecatedInterface.html | 4 +- .../InheritedDeprecatedInterface.html | 2 +- .../OverridingDeprecatedConstant.html | 2 +- .../OverridingDeprecatedProperty.html | 2 +- .../UsingDeprecatedClass.html | 2 +- .../UsingDeprecatedConstant.html | 2 +- .../UsingDeprecatedInterface.html | 2 +- .../UsingDeprecatedProperty.html | 2 +- resources/uct/bundle/inspection.properties | 44 +++++++++---------- 13 files changed, 35 insertions(+), 35 deletions(-) diff --git a/resources/inspectionDescriptions/CallingDeprecatedMethod.html b/resources/inspectionDescriptions/CallingDeprecatedMethod.html index 7b011cc34..78867f210 100644 --- a/resources/inspectionDescriptions/CallingDeprecatedMethod.html +++ b/resources/inspectionDescriptions/CallingDeprecatedMethod.html @@ -1,6 +1,6 @@ -

[1439] Call Magento Open Source|Adobe Commerce @deprecated method: The deprecated method will be removed in upcoming versions. Consider relying on methods declared in API interfaces instead.

+

[1439] Call Magento 2 @deprecated method: The deprecated method will be removed in upcoming versions. Consider relying on methods declared in API interfaces instead.

diff --git a/resources/inspectionDescriptions/ExtendingDeprecatedClass.html b/resources/inspectionDescriptions/ExtendingDeprecatedClass.html index fd21d55a4..1b7f9a55e 100644 --- a/resources/inspectionDescriptions/ExtendingDeprecatedClass.html +++ b/resources/inspectionDescriptions/ExtendingDeprecatedClass.html @@ -1,6 +1,6 @@ -

[1131] Extending from Magento Open Source|Adobe Commerce @deprecated class: The extended class will be removed in upcoming versions. Inheritance is not recommended way of extending Magento Open Source|Adobe Commerce functionality. Update code to use a class marked as @api.

+

[1131] Extending from Magento 2 @deprecated class: The extended class will be removed in upcoming versions. Inheritance is not recommended way of extending Magento Open Source|Adobe Commerce functionality. Update code to use a class marked as @api.

diff --git a/resources/inspectionDescriptions/ImplementedDeprecatedInterface.html b/resources/inspectionDescriptions/ImplementedDeprecatedInterface.html index c92dc7dfe..fda1b33ef 100644 --- a/resources/inspectionDescriptions/ImplementedDeprecatedInterface.html +++ b/resources/inspectionDescriptions/ImplementedDeprecatedInterface.html @@ -1,6 +1,6 @@ -

[1338] Implemented Magento Open Source|Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider removing the interface inheritance, using an interface marked as @api or an interface introduced within your implementation instead.

+

[1338] Implemented Magento 2 @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider removing the interface inheritance, using an interface marked as @api or an interface introduced within your implementation instead.

diff --git a/resources/inspectionDescriptions/ImportingDeprecatedClass.html b/resources/inspectionDescriptions/ImportingDeprecatedClass.html index 2b5c78e8d..505ee62a1 100644 --- a/resources/inspectionDescriptions/ImportingDeprecatedClass.html +++ b/resources/inspectionDescriptions/ImportingDeprecatedClass.html @@ -1,6 +1,6 @@ -

[1132] Importing Magento Open Source|Adobe Commerce @deprecated class: The extended class will be removed in upcoming versions. Consider using Magento Open Source|Adobe Commerce class marked as @api instead.

+

[1132] Importing Magento 2 @deprecated class: The extended class will be removed in upcoming versions. Consider using Magento Open Source|Adobe Commerce class marked as @api instead.

diff --git a/resources/inspectionDescriptions/ImportingDeprecatedInterface.html b/resources/inspectionDescriptions/ImportingDeprecatedInterface.html index b87bf748e..f7945974f 100644 --- a/resources/inspectionDescriptions/ImportingDeprecatedInterface.html +++ b/resources/inspectionDescriptions/ImportingDeprecatedInterface.html @@ -1,6 +1,6 @@ -

[1332] Imported Magento Open Source|Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider using an interface or class marked as @api instead.

+

[1332] Imported Magento 2 @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider using an interface or class marked as @api instead.

- \ No newline at end of file + diff --git a/resources/inspectionDescriptions/InheritedDeprecatedInterface.html b/resources/inspectionDescriptions/InheritedDeprecatedInterface.html index 83732ecdb..954ee5a97 100644 --- a/resources/inspectionDescriptions/InheritedDeprecatedInterface.html +++ b/resources/inspectionDescriptions/InheritedDeprecatedInterface.html @@ -1,6 +1,6 @@ -

[1337] Inherited from Magento Open Source|Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider removing the interface inheritance, using an interface marked as @api or an interface introduced within your implementation instead.

+

[1337] Inherited from Magento 2 @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider removing the interface inheritance, using an interface marked as @api or an interface introduced within your implementation instead.

diff --git a/resources/inspectionDescriptions/OverridingDeprecatedConstant.html b/resources/inspectionDescriptions/OverridingDeprecatedConstant.html index 3e6de44e7..680aed0a7 100644 --- a/resources/inspectionDescriptions/OverridingDeprecatedConstant.html +++ b/resources/inspectionDescriptions/OverridingDeprecatedConstant.html @@ -1,6 +1,6 @@ -

[1235] Overriding Magento Open Source|Adobe Commerce @deprecated constant: The deprecated constant will be removed in upcoming versions. Consider using a constant marked as @api or a private constant within your implementation instead.

+

[1235] Overriding Magento 2 @deprecated constant: The deprecated constant will be removed in upcoming versions. Consider using a constant marked as @api or a private constant within your implementation instead.

diff --git a/resources/inspectionDescriptions/OverridingDeprecatedProperty.html b/resources/inspectionDescriptions/OverridingDeprecatedProperty.html index 5fc9bd27f..57af0fab7 100644 --- a/resources/inspectionDescriptions/OverridingDeprecatedProperty.html +++ b/resources/inspectionDescriptions/OverridingDeprecatedProperty.html @@ -1,6 +1,6 @@ -

[1535] Overriding Magento Open Source|Adobe Commerce @deprecated property: The deprecated property will be removed in upcoming versions. Consider relying on methods declared in API interfaces or using a private property within your implementation instead.

+

[1535] Overriding Magento 2 @deprecated property: The deprecated property will be removed in upcoming versions. Consider relying on methods declared in API interfaces or using a private property within your implementation instead.

diff --git a/resources/inspectionDescriptions/UsingDeprecatedClass.html b/resources/inspectionDescriptions/UsingDeprecatedClass.html index 26951b290..02c294146 100644 --- a/resources/inspectionDescriptions/UsingDeprecatedClass.html +++ b/resources/inspectionDescriptions/UsingDeprecatedClass.html @@ -1,6 +1,6 @@ -

[1134] Using Magento Open Source|Adobe Commerce @deprecated class: The extended class will be removed in upcoming versions. Consider using Magento Open Source|Adobe Commerce class marked as @api instead.

+

[1134] Using Magento 2 @deprecated class: The extended class will be removed in upcoming versions. Consider using Magento Open Source|Adobe Commerce class marked as @api instead.

diff --git a/resources/inspectionDescriptions/UsingDeprecatedConstant.html b/resources/inspectionDescriptions/UsingDeprecatedConstant.html index fe0cd280f..fcae69895 100644 --- a/resources/inspectionDescriptions/UsingDeprecatedConstant.html +++ b/resources/inspectionDescriptions/UsingDeprecatedConstant.html @@ -1,6 +1,6 @@ -

[1234] Using Magento Open Source|Adobe Commerce @deprecated constant: The deprecated constant will be removed in upcoming versions. Consider using a constant marked as @api or a private constant within your implementation instead.

+

[1234] Using Magento 2 @deprecated constant: The deprecated constant will be removed in upcoming versions. Consider using a constant marked as @api or a private constant within your implementation instead.

diff --git a/resources/inspectionDescriptions/UsingDeprecatedInterface.html b/resources/inspectionDescriptions/UsingDeprecatedInterface.html index 6dd322c66..a4e906cfe 100644 --- a/resources/inspectionDescriptions/UsingDeprecatedInterface.html +++ b/resources/inspectionDescriptions/UsingDeprecatedInterface.html @@ -1,6 +1,6 @@ -

[1334] Used Magento Open Source|Adobe Commerce @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider using an interface or class marked as @api instead.

+

[1334] Used Magento 2 @deprecated interface: The deprecated interface will be removed in upcoming versions. Consider using an interface or class marked as @api instead.

diff --git a/resources/inspectionDescriptions/UsingDeprecatedProperty.html b/resources/inspectionDescriptions/UsingDeprecatedProperty.html index e06e87bb6..27f849a61 100644 --- a/resources/inspectionDescriptions/UsingDeprecatedProperty.html +++ b/resources/inspectionDescriptions/UsingDeprecatedProperty.html @@ -1,6 +1,6 @@ -

[1534] Using Magento Open Source|Adobe Commerce @deprecated property: The deprecated method will be removed in upcoming versions. Consider relying on methods declared in API interfaces instead.

+

[1534] Using Magento 2 @deprecated property: The deprecated method will be removed in upcoming versions. Consider relying on methods declared in API interfaces instead.

diff --git a/resources/uct/bundle/inspection.properties b/resources/uct/bundle/inspection.properties index acb6cbfe6..14dd91065 100644 --- a/resources/uct/bundle/inspection.properties +++ b/resources/uct/bundle/inspection.properties @@ -14,28 +14,28 @@ inspection.displayName.InheritedDeprecatedInterface=Inherited from @deprecated i inspection.displayName.ImplementedDeprecatedInterface=Implemented @deprecated interface inspection.displayName.CallingDeprecatedMethod=Call @deprecated method inspection.displayName.UsingDeprecatedProperty=Using @deprecated property -inspection.displayName.ImportingNonExistentClass=Importing non-existent Magento Open Source|Adobe Commerce class -inspection.displayName.ImportingNonExistentInterface=Importing non-existent Magento Open Source|Adobe Commerce interface -inspection.displayName.InheritedNonExistentInterface=Inherited non-existent Magento Open Source|Adobe Commerce interface -inspection.displayName.ImplementedNonExistentInterface=Implemented non-existent Magento Open Source|Adobe Commerce interface -inspection.displayName.ExtendedNonExistentClass=Extended non-existent Magento Open Source|Adobe Commerce class -inspection.displayName.OverriddenNonExistentConstant=Overridden non-existent Magento Open Source|Adobe Commerce constant -inspection.displayName.OverriddenNonExistentProperty=Overridden non-existent Magento Open Source|Adobe Commerce property -inspection.displayName.CalledNonExistentMethod=Call non-existent Magento Open Source|Adobe Commerce method -inspection.displayName.UsedNonExistentType=Used non-existent Magento Open Source|Adobe Commerce type -inspection.displayName.UsedNonExistentConstant=Used non-existent Magento Open Source|Adobe Commerce constant -inspection.displayName.UsedNonExistentProperty=Used non-existent Magento Open Source|Adobe Commerce property -inspection.displayName.ImportedNonApiClass=Imported non Magento Open Source|Adobe Commerce API class -inspection.displayName.ImportedNonApiInterface=Imported non Magento Open Source|Adobe Commerce API interface -inspection.displayName.CalledNonApiMethod=Called non Magento Open Source|Adobe Commerce API method -inspection.displayName.OverriddenNonApiConstant=Overridden non Magento Open Source|Adobe Commerce API constant -inspection.displayName.OverriddenNonApiProperty=Overridden non Magento Open Source|Adobe Commerce API property -inspection.displayName.UsedNonApiConstant=Used non Magento Open Source|Adobe Commerce API constant -inspection.displayName.UsedNonApiProperty=Used non Magento Open Source|Adobe Commerce API property -inspection.displayName.UsedNonApiType=Used non Magento Open Source|Adobe Commerce API type -inspection.displayName.ImplementedNonApiInterface=Implemented non Magento Open Source|Adobe Commerce API interface -inspection.displayName.ExtendedNonApiClass=Extended non Magento Open Source|Adobe Commerce API class -inspection.displayName.InheritedNonApiInterface=Inherited non Magento Open Source|Adobe Commerce API interface +inspection.displayName.ImportingNonExistentClass=Importing non-existent Magento 2 class +inspection.displayName.ImportingNonExistentInterface=Importing non-existent Magento 2 interface +inspection.displayName.InheritedNonExistentInterface=Inherited non-existent Magento 2 interface +inspection.displayName.ImplementedNonExistentInterface=Implemented non-existent Magento 2 interface +inspection.displayName.ExtendedNonExistentClass=Extended non-existent Magento 2 class +inspection.displayName.OverriddenNonExistentConstant=Overridden non-existent Magento 2 constant +inspection.displayName.OverriddenNonExistentProperty=Overridden non-existent Magento 2 property +inspection.displayName.CalledNonExistentMethod=Call non-existent Magento 2 method +inspection.displayName.UsedNonExistentType=Used non-existent Magento 2 type +inspection.displayName.UsedNonExistentConstant=Used non-existent Magento 2 constant +inspection.displayName.UsedNonExistentProperty=Used non-existent Magento 2 property +inspection.displayName.ImportedNonApiClass=Imported non Magento 2 API class +inspection.displayName.ImportedNonApiInterface=Imported non Magento 2 API interface +inspection.displayName.CalledNonApiMethod=Called non Magento 2 API method +inspection.displayName.OverriddenNonApiConstant=Overridden non Magento 2 API constant +inspection.displayName.OverriddenNonApiProperty=Overridden non Magento 2 API property +inspection.displayName.UsedNonApiConstant=Used non Magento 2 API constant +inspection.displayName.UsedNonApiProperty=Used non Magento 2 API property +inspection.displayName.UsedNonApiType=Used non Magento 2 API type +inspection.displayName.ImplementedNonApiInterface=Implemented non Magento 2 API interface +inspection.displayName.ExtendedNonApiClass=Extended non Magento 2 API class +inspection.displayName.InheritedNonApiInterface=Inherited non Magento 2 API interface inspection.displayName.PossibleDependencyOnImplDetails=Possible dependency on implementation details inspection.displayName.CalledNonInterfaceMethod=Called non-interface method customCode.warnings.deprecated.1131=[1131] Extended class ''{0}'' that is @deprecated in the ''{1}'' From 9e799accf92cd6bf4f4e3e4464dfa55c8363fd5c Mon Sep 17 00:00:00 2001 From: Mykola Donin Date: Mon, 14 Mar 2022 15:37:15 +0200 Subject: [PATCH 16/20] 1023: added functional for addtional scanning files --- .../magento/files/ThemeXml.java | 38 ++++ .../execution/GenerateUctReportCommand.java | 78 +++++++ .../execution/scanner/ThemeFilesScanner.java | 66 ++++++ .../execution/scanner/ThemeScanner.java | 198 ++++++++++++++++++ 4 files changed, 380 insertions(+) create mode 100644 src/com/magento/idea/magento2plugin/magento/files/ThemeXml.java create mode 100644 src/com/magento/idea/magento2uct/execution/scanner/ThemeFilesScanner.java create mode 100644 src/com/magento/idea/magento2uct/execution/scanner/ThemeScanner.java diff --git a/src/com/magento/idea/magento2plugin/magento/files/ThemeXml.java b/src/com/magento/idea/magento2plugin/magento/files/ThemeXml.java new file mode 100644 index 000000000..d02a88b10 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/files/ThemeXml.java @@ -0,0 +1,38 @@ +/* + * 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 ThemeXml implements ModuleFileInterface { + public static final String FILE_NAME = "theme.xml"; + public static final String TITLE_ELEMENT_NAME = "title"; + public static final String TEMPLATE = "Magento Theme XML"; + private static final ThemeXml INSTANCE = new ThemeXml(); + + /** + * Getter for singleton instance of class. + */ + public static ThemeXml getInstance() { + 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/magento2uct/execution/GenerateUctReportCommand.java b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java index 2418a8ad9..ad2cd03f4 100644 --- a/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java +++ b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java @@ -26,6 +26,8 @@ import com.magento.idea.magento2uct.execution.process.OutputWrapper; import com.magento.idea.magento2uct.execution.scanner.ModuleFilesScanner; import com.magento.idea.magento2uct.execution.scanner.ModuleScanner; +import com.magento.idea.magento2uct.execution.scanner.ThemeFilesScanner; +import com.magento.idea.magento2uct.execution.scanner.ThemeScanner; import com.magento.idea.magento2uct.execution.scanner.data.ComponentData; import com.magento.idea.magento2uct.execution.scanner.filter.ExcludeMagentoBundledFilter; import com.magento.idea.magento2uct.inspections.UctInspectionManager; @@ -81,6 +83,7 @@ public void processTerminated(final @NotNull ProcessEvent event) { public void execute() { output.write("Upgrade compatibility tool\n"); final PsiDirectory rootDirectory = getTargetPsiDirectory(); + final PsiDirectory additionalDirectory = getAdditionalTargetPsiDirectory(); if (rootDirectory == null) { output.print( @@ -99,6 +102,10 @@ public void execute() { ); final ReportBuilder reportBuilder = new ReportBuilder(project); final UctReportOutputUtil outputUtil = new UctReportOutputUtil(output); + final ThemeScanner themeScanner = new ThemeScanner( + additionalDirectory, + new ExcludeMagentoBundledFilter() + ); ApplicationManager.getApplication().executeOnPooledThread(() -> { ApplicationManager.getApplication().runReadAction(() -> { @@ -152,6 +159,56 @@ public void execute() { } } } + for (final ComponentData themeComponentData: themeScanner) { + if (process.isProcessTerminated()) { + return; + } + boolean isThemeHeaderPrinted = false; + + for (final PsiFile psiFile : new ThemeFilesScanner(themeComponentData)) { + if (!(psiFile instanceof PhpFile)) { + continue; + } + + final String filename = psiFile.getVirtualFile().getPath(); + final UctInspectionManager inspectionManager = new UctInspectionManager( + project + ); + final UctProblemsHolder fileProblemsHolder = inspectionManager.run(psiFile); + + if (fileProblemsHolder == null) { + continue; + } + + if (fileProblemsHolder.hasResults()) { + if (!isThemeHeaderPrinted) { + outputUtil.printModuleName(themeComponentData.getName()); + isThemeHeaderPrinted = true; + } + outputUtil.printProblemFile(filename); + } + final List problems = SortDescriptorResultsUtil.sort( + FilterDescriptorResultsUtil.filter(fileProblemsHolder) + ); + + for (final ProblemDescriptor descriptor : problems) { + final SupportedIssue issue = fileProblemsHolder.getIssue(descriptor); + + final String errorMessage = descriptor + .getDescriptionTemplate() + .substring(6) + .trim(); + summary.addToSummary(issue.getLevel()); + reportBuilder.addIssue( + descriptor.getLineNumber() + 1, + filename, + errorMessage, + issue + ); + outputUtil.printIssue(descriptor, issue.getCode()); + } + } + } summary.trackProcessFinished(); summary.setProcessedModules(scanner.getModuleCount()); outputUtil.printSummary(summary); @@ -201,4 +258,25 @@ public void execute() { return PsiManager.getInstance(project).findDirectory(targetDirVirtualFile); } + + /** + * Get additional target psi directory. + * + * @return PsiDirectory + */ + private @Nullable PsiDirectory getAdditionalTargetPsiDirectory() { + final String additionalTargetDirPath = settingsService.getAdditionalPath(); + + if (additionalTargetDirPath == null) { + return null; + } + final VirtualFile targetDirVirtualFile + = VfsUtil.findFile(Paths.get(additionalTargetDirPath), false); + + if (targetDirVirtualFile == null) { + return null; + } + + return PsiManager.getInstance(project).findDirectory(targetDirVirtualFile); + } } diff --git a/src/com/magento/idea/magento2uct/execution/scanner/ThemeFilesScanner.java b/src/com/magento/idea/magento2uct/execution/scanner/ThemeFilesScanner.java new file mode 100644 index 000000000..cce12ec54 --- /dev/null +++ b/src/com/magento/idea/magento2uct/execution/scanner/ThemeFilesScanner.java @@ -0,0 +1,66 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2uct.execution.scanner; + +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.jetbrains.php.lang.psi.PhpFile; +import com.magento.idea.magento2uct.execution.scanner.data.ComponentData; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ThemeFilesScanner implements Iterable { + + private final ComponentData componentData; + private final List files; + + /** + * Module files scanner constructor. + * + * @param componentData ComponentData + */ + public ThemeFilesScanner(final @NotNull ComponentData componentData) { + this.componentData = componentData; + files = new ArrayList<>(); + } + + @Override + public @NotNull Iterator iterator() { + return run().iterator(); + } + + /** + * Collect module files. + * + * @return List[PsiFile] + */ + private List run() { + files.clear(); + collectFilesInDirectoryRecursively(componentData.getDirectory()); + + return files; + } + + /** + * Collect all files in directory recursively. + * + * @param directory PsiDirectory + */ + private void collectFilesInDirectoryRecursively(final @NotNull PsiDirectory directory) { + for (final PsiFile file : directory.getFiles()) { + if (!(file instanceof PhpFile)) { + files.add(file); + } + } + + for (final PsiDirectory subDirectory : directory.getSubdirectories()) { + collectFilesInDirectoryRecursively(subDirectory); + } + } +} diff --git a/src/com/magento/idea/magento2uct/execution/scanner/ThemeScanner.java b/src/com/magento/idea/magento2uct/execution/scanner/ThemeScanner.java new file mode 100644 index 000000000..9b17f61ed --- /dev/null +++ b/src/com/magento/idea/magento2uct/execution/scanner/ThemeScanner.java @@ -0,0 +1,198 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2uct.execution.scanner; + +import com.intellij.json.psi.JsonFile; +import com.intellij.json.psi.JsonObject; +import com.intellij.json.psi.JsonProperty; +import com.intellij.json.psi.JsonValue; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.magento.idea.magento2plugin.magento.files.ComposerJson; +import com.magento.idea.magento2plugin.magento.files.ThemeXml; +import com.magento.idea.magento2plugin.magento.packages.Package; +import com.magento.idea.magento2uct.execution.scanner.data.ComponentData; +import com.magento.idea.magento2uct.execution.scanner.filter.ModuleScannerFilter; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +public final class ThemeScanner implements Iterable { + + private static final String FRAMEWORK_LIBRARY_NAME = "magento/framework"; + + private final PsiDirectory rootDirectory; + private final List componentDataList; + private final List filters; + + /** + * Magento 2 module components scanner constructor. + * + * @param rootDirectory PsiDirectory + * @param filters ModuleScannerFilter[] + */ + public ThemeScanner( + final @NotNull PsiDirectory rootDirectory, + final @NotNull ModuleScannerFilter... filters + + ) { + this.rootDirectory = rootDirectory; + this.filters = Arrays.asList(filters); + componentDataList = new ArrayList<>(); + } + + @Override + public @NotNull Iterator iterator() { + return run().iterator(); + } + + /** + * Get found modules qty. + * + * @return int + */ + public int getThemeCount() { + return componentDataList.size(); + } + + /** + * Run scanner. + * + * @return List[ComponentData] + */ + private List run() { + componentDataList.clear(); + findThemeComponent(rootDirectory); + + return componentDataList; + } + + /** + * Look up magento 2 module components. + * + * @param directory PsiDirectory + */ + @SuppressWarnings({ + "PMD.NPathComplexity", + "PMD.CyclomaticComplexity", + "PMD.CognitiveComplexity", + "PMD.AvoidDeeplyNestedIfStmts" + }) + private void findThemeComponent(final @NotNull PsiDirectory directory) { + String name = null; + String composerBasedName = null; + String composerType; + String type = "magento2-theme"; + + for (final PsiFile file : directory.getFiles()) { + if (file instanceof XmlFile && ThemeXml.FILE_NAME.equals(file.getName())) { + final XmlTag rootTag = ((XmlFile) file).getRootTag(); + + if (rootTag != null && rootTag.getSubTags().length > 0) { + final XmlTag themeTag = rootTag.getSubTags()[0]; + name = themeTag.getValue().getText(); + } + break; + } + } + + for (final PsiFile file : directory.getFiles()) { + if (file instanceof JsonFile && ComposerJson.FILE_NAME.equals(file.getName())) { + final Pair meta = scanModuleComposerMeta((JsonFile) file); + composerBasedName = meta.getFirst(); + composerType = meta.getSecond(); + + if (composerBasedName == null || composerType == null) { + return; + } + + if (name == null && FRAMEWORK_LIBRARY_NAME.equals(composerBasedName)) { + name = meta.getFirst(); + type = composerType; + } + + if (!type.equals(composerType) && !"project".equals(composerType)) { + return; + } + break; + } + } + + if (name != null && composerBasedName != null) { + final ComponentData component = new ComponentData( + name, + composerBasedName, + type, + directory + ); + boolean isExcluded = false; + + for (final ModuleScannerFilter filter : filters) { + if (filter.isExcluded(component)) { + isExcluded = true; + break; + } + } + + if (!isExcluded) { + componentDataList.add(component); + } + return; + } + + for (final PsiDirectory subDirectory : directory.getSubdirectories()) { + findThemeComponent(subDirectory); + } + } + + /** + * Scan module metadata from the composer.json file. + * + * @param composerFile JsonFile + * + * @return Pair[String, String] + */ + @SuppressWarnings({ + "PMD.NPathComplexity", + "PMD.CyclomaticComplexity", + "PMD.CognitiveComplexity" + }) + private Pair scanModuleComposerMeta(final JsonFile composerFile) { + final JsonValue topNode = composerFile.getTopLevelValue(); + String name = null; + String type = null; + + if (topNode instanceof JsonObject) { + for (final JsonProperty property : ((JsonObject) topNode).getPropertyList()) { + switch (property.getName()) { + case "name": + if (property.getValue() != null) { + name = property.getValue().getText().replace("\"", ""); + } + break; + case "type": + if (property.getValue() != null) { + type = property.getValue().getText().replace("\"", ""); + } + break; + default: + break; + } + if (name != null && type != null) { + break; + } + } + } + + return new Pair<>(name, type); + } +} From 667f86b8db5523a58c5e82a80976e99a69294a8f Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Mon, 14 Mar 2022 22:25:11 +0200 Subject: [PATCH 17/20] 1023: Removed unnecessary files --- .../magento/files/ThemeXml.java | 38 ---- .../execution/scanner/ThemeFilesScanner.java | 66 ------ .../execution/scanner/ThemeScanner.java | 198 ------------------ 3 files changed, 302 deletions(-) delete mode 100644 src/com/magento/idea/magento2plugin/magento/files/ThemeXml.java delete mode 100644 src/com/magento/idea/magento2uct/execution/scanner/ThemeFilesScanner.java delete mode 100644 src/com/magento/idea/magento2uct/execution/scanner/ThemeScanner.java diff --git a/src/com/magento/idea/magento2plugin/magento/files/ThemeXml.java b/src/com/magento/idea/magento2plugin/magento/files/ThemeXml.java deleted file mode 100644 index d02a88b10..000000000 --- a/src/com/magento/idea/magento2plugin/magento/files/ThemeXml.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 ThemeXml implements ModuleFileInterface { - public static final String FILE_NAME = "theme.xml"; - public static final String TITLE_ELEMENT_NAME = "title"; - public static final String TEMPLATE = "Magento Theme XML"; - private static final ThemeXml INSTANCE = new ThemeXml(); - - /** - * Getter for singleton instance of class. - */ - public static ThemeXml getInstance() { - 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/magento2uct/execution/scanner/ThemeFilesScanner.java b/src/com/magento/idea/magento2uct/execution/scanner/ThemeFilesScanner.java deleted file mode 100644 index cce12ec54..000000000 --- a/src/com/magento/idea/magento2uct/execution/scanner/ThemeFilesScanner.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -package com.magento.idea.magento2uct.execution.scanner; - -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiFile; -import com.jetbrains.php.lang.psi.PhpFile; -import com.magento.idea.magento2uct.execution.scanner.data.ComponentData; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public class ThemeFilesScanner implements Iterable { - - private final ComponentData componentData; - private final List files; - - /** - * Module files scanner constructor. - * - * @param componentData ComponentData - */ - public ThemeFilesScanner(final @NotNull ComponentData componentData) { - this.componentData = componentData; - files = new ArrayList<>(); - } - - @Override - public @NotNull Iterator iterator() { - return run().iterator(); - } - - /** - * Collect module files. - * - * @return List[PsiFile] - */ - private List run() { - files.clear(); - collectFilesInDirectoryRecursively(componentData.getDirectory()); - - return files; - } - - /** - * Collect all files in directory recursively. - * - * @param directory PsiDirectory - */ - private void collectFilesInDirectoryRecursively(final @NotNull PsiDirectory directory) { - for (final PsiFile file : directory.getFiles()) { - if (!(file instanceof PhpFile)) { - files.add(file); - } - } - - for (final PsiDirectory subDirectory : directory.getSubdirectories()) { - collectFilesInDirectoryRecursively(subDirectory); - } - } -} diff --git a/src/com/magento/idea/magento2uct/execution/scanner/ThemeScanner.java b/src/com/magento/idea/magento2uct/execution/scanner/ThemeScanner.java deleted file mode 100644 index 9b17f61ed..000000000 --- a/src/com/magento/idea/magento2uct/execution/scanner/ThemeScanner.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -package com.magento.idea.magento2uct.execution.scanner; - -import com.intellij.json.psi.JsonFile; -import com.intellij.json.psi.JsonObject; -import com.intellij.json.psi.JsonProperty; -import com.intellij.json.psi.JsonValue; -import com.intellij.openapi.util.Pair; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiFile; -import com.intellij.psi.xml.XmlFile; -import com.intellij.psi.xml.XmlTag; -import com.magento.idea.magento2plugin.magento.files.ComposerJson; -import com.magento.idea.magento2plugin.magento.files.ThemeXml; -import com.magento.idea.magento2plugin.magento.packages.Package; -import com.magento.idea.magento2uct.execution.scanner.data.ComponentData; -import com.magento.idea.magento2uct.execution.scanner.filter.ModuleScannerFilter; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -public final class ThemeScanner implements Iterable { - - private static final String FRAMEWORK_LIBRARY_NAME = "magento/framework"; - - private final PsiDirectory rootDirectory; - private final List componentDataList; - private final List filters; - - /** - * Magento 2 module components scanner constructor. - * - * @param rootDirectory PsiDirectory - * @param filters ModuleScannerFilter[] - */ - public ThemeScanner( - final @NotNull PsiDirectory rootDirectory, - final @NotNull ModuleScannerFilter... filters - - ) { - this.rootDirectory = rootDirectory; - this.filters = Arrays.asList(filters); - componentDataList = new ArrayList<>(); - } - - @Override - public @NotNull Iterator iterator() { - return run().iterator(); - } - - /** - * Get found modules qty. - * - * @return int - */ - public int getThemeCount() { - return componentDataList.size(); - } - - /** - * Run scanner. - * - * @return List[ComponentData] - */ - private List run() { - componentDataList.clear(); - findThemeComponent(rootDirectory); - - return componentDataList; - } - - /** - * Look up magento 2 module components. - * - * @param directory PsiDirectory - */ - @SuppressWarnings({ - "PMD.NPathComplexity", - "PMD.CyclomaticComplexity", - "PMD.CognitiveComplexity", - "PMD.AvoidDeeplyNestedIfStmts" - }) - private void findThemeComponent(final @NotNull PsiDirectory directory) { - String name = null; - String composerBasedName = null; - String composerType; - String type = "magento2-theme"; - - for (final PsiFile file : directory.getFiles()) { - if (file instanceof XmlFile && ThemeXml.FILE_NAME.equals(file.getName())) { - final XmlTag rootTag = ((XmlFile) file).getRootTag(); - - if (rootTag != null && rootTag.getSubTags().length > 0) { - final XmlTag themeTag = rootTag.getSubTags()[0]; - name = themeTag.getValue().getText(); - } - break; - } - } - - for (final PsiFile file : directory.getFiles()) { - if (file instanceof JsonFile && ComposerJson.FILE_NAME.equals(file.getName())) { - final Pair meta = scanModuleComposerMeta((JsonFile) file); - composerBasedName = meta.getFirst(); - composerType = meta.getSecond(); - - if (composerBasedName == null || composerType == null) { - return; - } - - if (name == null && FRAMEWORK_LIBRARY_NAME.equals(composerBasedName)) { - name = meta.getFirst(); - type = composerType; - } - - if (!type.equals(composerType) && !"project".equals(composerType)) { - return; - } - break; - } - } - - if (name != null && composerBasedName != null) { - final ComponentData component = new ComponentData( - name, - composerBasedName, - type, - directory - ); - boolean isExcluded = false; - - for (final ModuleScannerFilter filter : filters) { - if (filter.isExcluded(component)) { - isExcluded = true; - break; - } - } - - if (!isExcluded) { - componentDataList.add(component); - } - return; - } - - for (final PsiDirectory subDirectory : directory.getSubdirectories()) { - findThemeComponent(subDirectory); - } - } - - /** - * Scan module metadata from the composer.json file. - * - * @param composerFile JsonFile - * - * @return Pair[String, String] - */ - @SuppressWarnings({ - "PMD.NPathComplexity", - "PMD.CyclomaticComplexity", - "PMD.CognitiveComplexity" - }) - private Pair scanModuleComposerMeta(final JsonFile composerFile) { - final JsonValue topNode = composerFile.getTopLevelValue(); - String name = null; - String type = null; - - if (topNode instanceof JsonObject) { - for (final JsonProperty property : ((JsonObject) topNode).getPropertyList()) { - switch (property.getName()) { - case "name": - if (property.getValue() != null) { - name = property.getValue().getText().replace("\"", ""); - } - break; - case "type": - if (property.getValue() != null) { - type = property.getValue().getText().replace("\"", ""); - } - break; - default: - break; - } - if (name != null && type != null) { - break; - } - } - } - - return new Pair<>(name, type); - } -} From 6228b9044b63d212215dc9a41fdd18dd75712c0b Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Tue, 15 Mar 2022 12:10:25 +0200 Subject: [PATCH 18/20] 1023: Added support of the theme component --- .../magento/packages/ComponentType.java | 3 +- .../execution/GenerateUctReportCommand.java | 103 ++------ .../magento2uct/execution/output/Summary.java | 19 ++ .../execution/output/UctReportOutputUtil.java | 1 + .../execution/scanner/ModuleScanner.java | 228 +++++++++++------- .../execution/scanner/data/ComponentData.java | 11 +- .../settings/UctSettingsService.java | 8 +- 7 files changed, 192 insertions(+), 181 deletions(-) diff --git a/src/com/magento/idea/magento2plugin/magento/packages/ComponentType.java b/src/com/magento/idea/magento2plugin/magento/packages/ComponentType.java index edcfa91bd..9d9d9faf7 100644 --- a/src/com/magento/idea/magento2plugin/magento/packages/ComponentType.java +++ b/src/com/magento/idea/magento2plugin/magento/packages/ComponentType.java @@ -10,7 +10,8 @@ @SuppressWarnings({"PMD.FieldNamingConventions"}) public enum ComponentType { module, - theme; + theme, + library; /** * Get component type by value. diff --git a/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java index ad2cd03f4..61082ec91 100644 --- a/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java +++ b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java @@ -26,8 +26,6 @@ import com.magento.idea.magento2uct.execution.process.OutputWrapper; import com.magento.idea.magento2uct.execution.scanner.ModuleFilesScanner; import com.magento.idea.magento2uct.execution.scanner.ModuleScanner; -import com.magento.idea.magento2uct.execution.scanner.ThemeFilesScanner; -import com.magento.idea.magento2uct.execution.scanner.ThemeScanner; import com.magento.idea.magento2uct.execution.scanner.data.ComponentData; import com.magento.idea.magento2uct.execution.scanner.filter.ExcludeMagentoBundledFilter; import com.magento.idea.magento2uct.inspections.UctInspectionManager; @@ -37,6 +35,7 @@ import com.magento.idea.magento2uct.util.inspection.FilterDescriptorResultsUtil; import com.magento.idea.magento2uct.util.inspection.SortDescriptorResultsUtil; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.List; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -82,8 +81,7 @@ public void processTerminated(final @NotNull ProcessEvent event) { @SuppressWarnings({"PMD.ExcessiveMethodLength", "PMD.AvoidInstantiatingObjectsInLoops"}) public void execute() { output.write("Upgrade compatibility tool\n"); - final PsiDirectory rootDirectory = getTargetPsiDirectory(); - final PsiDirectory additionalDirectory = getAdditionalTargetPsiDirectory(); + final PsiDirectory rootDirectory = getTargetPsiDirectory(settingsService.getModulePath()); if (rootDirectory == null) { output.print( @@ -92,8 +90,21 @@ public void execute() { process.destroyProcess(); return; } + final List directoriesToScan = new ArrayList<>(); + directoriesToScan.add(rootDirectory); + + if (settingsService.getHasAdditionalPath()) { + final PsiDirectory additionalDirectory = getTargetPsiDirectory( + settingsService.getAdditionalPath() + ); + + if (additionalDirectory != null) { + directoriesToScan.add(additionalDirectory); + } + } + final ModuleScanner scanner = new ModuleScanner( - rootDirectory, + directoriesToScan, new ExcludeMagentoBundledFilter() ); final Summary summary = new Summary( @@ -102,10 +113,6 @@ public void execute() { ); final ReportBuilder reportBuilder = new ReportBuilder(project); final UctReportOutputUtil outputUtil = new UctReportOutputUtil(output); - final ThemeScanner themeScanner = new ThemeScanner( - additionalDirectory, - new ExcludeMagentoBundledFilter() - ); ApplicationManager.getApplication().executeOnPooledThread(() -> { ApplicationManager.getApplication().runReadAction(() -> { @@ -159,58 +166,9 @@ public void execute() { } } } - for (final ComponentData themeComponentData: themeScanner) { - if (process.isProcessTerminated()) { - return; - } - boolean isThemeHeaderPrinted = false; - - for (final PsiFile psiFile : new ThemeFilesScanner(themeComponentData)) { - if (!(psiFile instanceof PhpFile)) { - continue; - } - - final String filename = psiFile.getVirtualFile().getPath(); - final UctInspectionManager inspectionManager = new UctInspectionManager( - project - ); - final UctProblemsHolder fileProblemsHolder = inspectionManager.run(psiFile); - - if (fileProblemsHolder == null) { - continue; - } - - if (fileProblemsHolder.hasResults()) { - if (!isThemeHeaderPrinted) { - outputUtil.printModuleName(themeComponentData.getName()); - isThemeHeaderPrinted = true; - } - outputUtil.printProblemFile(filename); - } - final List problems = SortDescriptorResultsUtil.sort( - FilterDescriptorResultsUtil.filter(fileProblemsHolder) - ); - - for (final ProblemDescriptor descriptor : problems) { - final SupportedIssue issue = fileProblemsHolder.getIssue(descriptor); - - final String errorMessage = descriptor - .getDescriptionTemplate() - .substring(6) - .trim(); - summary.addToSummary(issue.getLevel()); - reportBuilder.addIssue( - descriptor.getLineNumber() + 1, - filename, - errorMessage, - issue - ); - outputUtil.printIssue(descriptor, issue.getCode()); - } - } - } summary.trackProcessFinished(); summary.setProcessedModules(scanner.getModuleCount()); + summary.setProcessedThemes(scanner.getThemeCount()); outputUtil.printSummary(summary); if (summary.getProcessedModules() == 0) { @@ -242,11 +200,11 @@ public void execute() { /** * Get target psi directory. * + * @param targetDirPath String + * * @return PsiDirectory */ - private @Nullable PsiDirectory getTargetPsiDirectory() { - final String targetDirPath = settingsService.getModulePath(); - + private @Nullable PsiDirectory getTargetPsiDirectory(final String targetDirPath) { if (targetDirPath == null) { return null; } @@ -258,25 +216,4 @@ public void execute() { return PsiManager.getInstance(project).findDirectory(targetDirVirtualFile); } - - /** - * Get additional target psi directory. - * - * @return PsiDirectory - */ - private @Nullable PsiDirectory getAdditionalTargetPsiDirectory() { - final String additionalTargetDirPath = settingsService.getAdditionalPath(); - - if (additionalTargetDirPath == null) { - return null; - } - final VirtualFile targetDirVirtualFile - = VfsUtil.findFile(Paths.get(additionalTargetDirPath), false); - - if (targetDirVirtualFile == null) { - return null; - } - - return PsiManager.getInstance(project).findDirectory(targetDirVirtualFile); - } } diff --git a/src/com/magento/idea/magento2uct/execution/output/Summary.java b/src/com/magento/idea/magento2uct/execution/output/Summary.java index 1c7f5b954..470fddf69 100644 --- a/src/com/magento/idea/magento2uct/execution/output/Summary.java +++ b/src/com/magento/idea/magento2uct/execution/output/Summary.java @@ -18,6 +18,7 @@ public class Summary { private final SupportedVersion installedVersion; private final SupportedVersion targetVersion; private int processedModules; + private int processedThemes; private long processStartedTime; private long processEndedTime; private int phpWarnings; @@ -74,6 +75,24 @@ public void setProcessedModules(final int processedModules) { this.processedModules = processedModules; } + /** + * Get processed theme qty. + * + * @return int + */ + public int getProcessedThemes() { + return processedThemes; + } + + /** + * Set processed theme qty. + * + * @param processedThemes int + */ + public void setProcessedThemes(final int processedThemes) { + this.processedThemes = processedThemes; + } + /** * Track time before process is started. */ diff --git a/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java b/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java index cd370f81f..a304e2440 100644 --- a/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java +++ b/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java @@ -95,6 +95,7 @@ public void printSummary(final Summary summary) { summaryMap.put("Adobe Commerce version", summary.getTargetVersion()); summaryMap.put("Running time", summary.getProcessRunningTime()); summaryMap.put("Checked modules", String.valueOf(summary.getProcessedModules())); + summaryMap.put("Checked themes", String.valueOf(summary.getProcessedThemes())); summaryMap.put("Total warnings found", String.valueOf(summary.getPhpWarnings())); summaryMap.put("Total errors found", String.valueOf(summary.getPhpErrors())); summaryMap.put("Total critical errors found", diff --git a/src/com/magento/idea/magento2uct/execution/scanner/ModuleScanner.java b/src/com/magento/idea/magento2uct/execution/scanner/ModuleScanner.java index 8ced9c569..9665b017e 100644 --- a/src/com/magento/idea/magento2uct/execution/scanner/ModuleScanner.java +++ b/src/com/magento/idea/magento2uct/execution/scanner/ModuleScanner.java @@ -11,12 +11,17 @@ import com.intellij.json.psi.JsonValue; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.xml.XmlFile; -import com.intellij.psi.xml.XmlTag; +import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.php.lang.psi.PhpFile; +import com.jetbrains.php.lang.psi.elements.ClassConstantReference; +import com.jetbrains.php.lang.psi.elements.MethodReference; +import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; +import com.jetbrains.php.lang.psi.elements.impl.ClassConstImpl; import com.magento.idea.magento2plugin.magento.files.ComposerJson; -import com.magento.idea.magento2plugin.magento.files.ModuleXml; -import com.magento.idea.magento2plugin.magento.packages.Package; +import com.magento.idea.magento2plugin.magento.files.RegistrationPhp; +import com.magento.idea.magento2plugin.magento.packages.ComponentType; import com.magento.idea.magento2uct.execution.scanner.data.ComponentData; import com.magento.idea.magento2uct.execution.scanner.filter.ModuleScannerFilter; import java.util.ArrayList; @@ -27,11 +32,11 @@ public final class ModuleScanner implements Iterable { - private static final String FRAMEWORK_LIBRARY_NAME = "magento/framework"; - - private final PsiDirectory rootDirectory; + private final List rootDirectories; private final List componentDataList; private final List filters; + private int modulesQty; + private int themesQty; /** * Magento 2 module components scanner constructor. @@ -44,9 +49,25 @@ public ModuleScanner( final @NotNull ModuleScannerFilter... filters ) { - this.rootDirectory = rootDirectory; + this(List.of(rootDirectory), filters); + } + + /** + * Magento 2 module components scanner constructor. + * + * @param directories List[PsiDirectory] + * @param filters ModuleScannerFilter[] + */ + public ModuleScanner( + final List directories, + final @NotNull ModuleScannerFilter... filters + + ) { + this.rootDirectories = new ArrayList<>(directories); this.filters = Arrays.asList(filters); componentDataList = new ArrayList<>(); + modulesQty = 0; + themesQty = 0; } @Override @@ -60,7 +81,16 @@ public ModuleScanner( * @return int */ public int getModuleCount() { - return componentDataList.size(); + return modulesQty; + } + + /** + * Get found themes qty. + * + * @return int + */ + public int getThemeCount() { + return themesQty; } /** @@ -70,7 +100,10 @@ public int getModuleCount() { */ private List run() { componentDataList.clear(); - findModuleComponent(rootDirectory); + + for (final PsiDirectory rootDirectory : rootDirectories) { + findModuleComponent(rootDirectory); + } return componentDataList; } @@ -89,68 +122,51 @@ private List run() { private void findModuleComponent(final @NotNull PsiDirectory directory) { String name = null; String composerBasedName = null; - String composerType; - String type = "magento2-module"; - - for (final PsiDirectory subDirectory : directory.getSubdirectories()) { - if (Package.moduleBaseAreaDir.equals(subDirectory.getName())) { - for (final PsiFile file : subDirectory.getFiles()) { - if (file instanceof XmlFile && ModuleXml.FILE_NAME.equals(file.getName())) { - final XmlTag rootTag = ((XmlFile) file).getRootTag(); - - if (rootTag != null && rootTag.getSubTags().length > 0) { - final XmlTag moduleTag = rootTag.getSubTags()[0]; - name = moduleTag.getAttributeValue("name"); - } - break; - } - } - break; - } - } + ComponentType type = null; - for (final PsiFile file : directory.getFiles()) { - if (file instanceof JsonFile && ComposerJson.FILE_NAME.equals(file.getName())) { - final Pair meta = scanModuleComposerMeta((JsonFile) file); - composerBasedName = meta.getFirst(); - composerType = meta.getSecond(); + final PsiFile registration = directory.findFile(RegistrationPhp.FILE_NAME); - if (composerBasedName == null || composerType == null) { - return; - } - - if (name == null && FRAMEWORK_LIBRARY_NAME.equals(composerBasedName)) { - name = meta.getFirst(); - type = composerType; - } + if (registration instanceof PhpFile) { + final Pair registrationMeta = scanRegistrationMeta( + (PhpFile) registration + ); - if (!type.equals(composerType) && !"project".equals(composerType)) { - return; - } - break; + if (registrationMeta != null) { + name = registrationMeta.getFirst(); + type = registrationMeta.getSecond(); } - } - if (name != null) { - final ComponentData component = new ComponentData( - name, - composerBasedName, - type, - directory - ); - boolean isExcluded = false; + if (name != null) { + final PsiFile composerFile = directory.findFile(ComposerJson.FILE_NAME); - for (final ModuleScannerFilter filter : filters) { - if (filter.isExcluded(component)) { - isExcluded = true; - break; + if (composerFile instanceof JsonFile) { + composerBasedName = getComposerComponentName((JsonFile) composerFile); + } + final ComponentData component = new ComponentData( + name, + composerBasedName, + type, + directory + ); + boolean isExcluded = false; + + for (final ModuleScannerFilter filter : filters) { + if (filter.isExcluded(component)) { + isExcluded = true; + break; + } } - } - if (!isExcluded) { - componentDataList.add(component); + if (!isExcluded) { + if (component.getType().equals(ComponentType.theme)) { + themesQty++; + } else { + modulesQty++; + } + componentDataList.add(component); + } + return; } - return; } for (final PsiDirectory subDirectory : directory.getSubdirectories()) { @@ -159,44 +175,80 @@ private void findModuleComponent(final @NotNull PsiDirectory directory) { } /** - * Scan module metadata from the composer.json file. + * Scan module name from the composer.json file. * * @param composerFile JsonFile * - * @return Pair[String, String] + * @return String */ - @SuppressWarnings({ - "PMD.NPathComplexity", - "PMD.CyclomaticComplexity", - "PMD.CognitiveComplexity" - }) - private Pair scanModuleComposerMeta(final JsonFile composerFile) { + private String getComposerComponentName(final JsonFile composerFile) { final JsonValue topNode = composerFile.getTopLevelValue(); String name = null; - String type = null; if (topNode instanceof JsonObject) { for (final JsonProperty property : ((JsonObject) topNode).getPropertyList()) { - switch (property.getName()) { - case "name": - if (property.getValue() != null) { - name = property.getValue().getText().replace("\"", ""); - } - break; - case "type": - if (property.getValue() != null) { - type = property.getValue().getText().replace("\"", ""); - } - break; - default: - break; - } - if (name != null && type != null) { + if ("name".equals(property.getName())) { + if (property.getValue() != null) { + name = property.getValue().getText().replace("\"", ""); + } break; } } } - return new Pair<>(name, type); + return name; + } + + private Pair scanRegistrationMeta(final PhpFile registrationFile) { + for (final MethodReference reference + : PsiTreeUtil.findChildrenOfType(registrationFile, MethodReference.class)) { + + if (!RegistrationPhp.REGISTER_METHOD_NAME.equals(reference.getName())) { + continue; + } + final PsiElement typeHolder = reference.getParameter(0); + final PsiElement nameHolder = reference.getParameter(1); + + if (typeHolder == null || nameHolder == null) { + return null; + } + final String type = unwrapParameterValue(typeHolder); + final String name = unwrapParameterValue(nameHolder); + + if (name == null || type == null) { + return null; + } + final ComponentType resolvedType = ComponentType.getByValue(type); + + if (resolvedType == null) { + return null; + } + + return new Pair<>(name, resolvedType); + } + + return null; + } + + private String unwrapParameterValue(final @NotNull PsiElement parameterValue) { + if (parameterValue instanceof ClassConstantReference) { + final PsiElement resolvedValue = ((ClassConstantReference) parameterValue).resolve(); + + if (!(resolvedValue instanceof ClassConstImpl)) { + return null; + } + final ClassConstImpl resolvedConst = (ClassConstImpl) resolvedValue; + final PsiElement value = resolvedConst.getDefaultValue(); + + if (value == null) { + return null; + } + + return unwrapParameterValue(value); + } else if (parameterValue instanceof StringLiteralExpression) { + return ((StringLiteralExpression) parameterValue).getContents(); + } + + return null; } } diff --git a/src/com/magento/idea/magento2uct/execution/scanner/data/ComponentData.java b/src/com/magento/idea/magento2uct/execution/scanner/data/ComponentData.java index 1c1980b38..9d6d7ffee 100644 --- a/src/com/magento/idea/magento2uct/execution/scanner/data/ComponentData.java +++ b/src/com/magento/idea/magento2uct/execution/scanner/data/ComponentData.java @@ -6,13 +6,14 @@ package com.magento.idea.magento2uct.execution.scanner.data; import com.intellij.psi.PsiDirectory; +import com.magento.idea.magento2plugin.magento.packages.ComponentType; import org.jetbrains.annotations.NotNull; public class ComponentData { private final String name; private final String composerName; - private final String type; + private final ComponentType type; private final PsiDirectory directory; /** @@ -20,13 +21,13 @@ public class ComponentData { * * @param name String * @param composerName String - * @param type String + * @param type ComponentType * @param directory PsiDirectory */ public ComponentData( final @NotNull String name, final String composerName, - final @NotNull String type, + final @NotNull ComponentType type, final @NotNull PsiDirectory directory ) { this.name = name; @@ -56,9 +57,9 @@ public String getComposerName() { /** * Get component type. * - * @return String + * @return ComponentType */ - public String getType() { + public ComponentType getType() { return type; } diff --git a/src/com/magento/idea/magento2uct/settings/UctSettingsService.java b/src/com/magento/idea/magento2uct/settings/UctSettingsService.java index 4b2e41528..dea0e0b5c 100644 --- a/src/com/magento/idea/magento2uct/settings/UctSettingsService.java +++ b/src/com/magento/idea/magento2uct/settings/UctSettingsService.java @@ -257,7 +257,7 @@ public void setIgnoreCurrentVersion(final boolean ignoreCurrentVersion) { } /** - * Set if show additional path + * Set if show additional path. * * @param hasAdditionalPath boolean */ @@ -266,12 +266,12 @@ public void setHasAdditionalPath(final boolean hasAdditionalPath) { } /** - * Check if show additional path + * Check if show additional path. * * @return boolean */ - public @Nullable Boolean getHasAdditionalPath() { - return hasAdditionalPath; + public @NotNull Boolean getHasAdditionalPath() { + return hasAdditionalPath != null && hasAdditionalPath; } /** From 6f24218d292930b1070ab1132dda42a624ec60ec Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Tue, 15 Mar 2022 12:38:01 +0200 Subject: [PATCH 19/20] 1023: Added phtml files support --- .../execution/GenerateUctReportCommand.java | 4 +- .../execution/output/UctReportOutputUtil.java | 19 +++++++-- .../inspections/UctInspectionManager.java | 40 +++++++++---------- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java index 61082ec91..ecec26ccb 100644 --- a/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java +++ b/src/com/magento/idea/magento2uct/execution/GenerateUctReportCommand.java @@ -139,7 +139,7 @@ public void execute() { if (fileProblemsHolder.hasResults()) { if (!isModuleHeaderPrinted) { - outputUtil.printModuleName(componentData.getName()); + outputUtil.printModuleName(componentData); isModuleHeaderPrinted = true; } outputUtil.printProblemFile(filename); @@ -171,7 +171,7 @@ public void execute() { summary.setProcessedThemes(scanner.getThemeCount()); outputUtil.printSummary(summary); - if (summary.getProcessedModules() == 0) { + if (summary.getProcessedModules() == 0 && summary.getProcessedThemes() == 0) { process.destroyProcess(); return; } diff --git a/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java b/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java index a304e2440..704aa2816 100644 --- a/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java +++ b/src/com/magento/idea/magento2uct/execution/output/UctReportOutputUtil.java @@ -8,8 +8,10 @@ import com.intellij.codeInspection.ProblemDescriptor; import com.magento.idea.magento2uct.bundles.UctInspectionBundle; import com.magento.idea.magento2uct.execution.process.OutputWrapper; +import com.magento.idea.magento2uct.execution.scanner.data.ComponentData; import com.magento.idea.magento2uct.packages.SupportedIssue; import java.util.LinkedHashMap; +import java.util.Locale; import java.util.Map; import org.jetbrains.annotations.NotNull; @@ -31,10 +33,19 @@ public UctReportOutputUtil(final @NotNull OutputWrapper output) { /** * Print module name header. * - * @param moduleName String + * @param componentData ComponentData */ - public void printModuleName(final @NotNull String moduleName) { - final String moduleNameLine = "Module Name: ".concat(moduleName); + public void printModuleName(final @NotNull ComponentData componentData) { + final String componentType = componentData.getType().toString(); + final String componentTypeFormatted = componentType + .substring(0, 1) + .toUpperCase(new Locale("en","EN")) + .concat(componentType.substring(1)); + + final String moduleNameLine = componentTypeFormatted + .concat(" Name: ") + .concat(componentData.getName()); + stdout.print("\n\n" + stdout.wrapInfo(moduleNameLine).concat("\n")); stdout.print(stdout.wrapInfo("-".repeat(moduleNameLine.length())).concat("\n")); } @@ -81,7 +92,7 @@ public void printIssue(final @NotNull ProblemDescriptor descriptor, final int co */ @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public void printSummary(final Summary summary) { - if (summary.getProcessedModules() == 0) { + if (summary.getProcessedModules() == 0 && summary.getProcessedThemes() == 0) { stdout.print(stdout.wrapInfo("Couldn't find modules to analyse").concat("\n")); return; } diff --git a/src/com/magento/idea/magento2uct/inspections/UctInspectionManager.java b/src/com/magento/idea/magento2uct/inspections/UctInspectionManager.java index df1f69ee1..093530835 100644 --- a/src/com/magento/idea/magento2uct/inspections/UctInspectionManager.java +++ b/src/com/magento/idea/magento2uct/inspections/UctInspectionManager.java @@ -52,11 +52,6 @@ public UctInspectionManager(final @NotNull Project project) { if (!(psiFile instanceof PhpFile)) { return null; } - final PhpClass phpClass = GetFirstClassOfFile.getInstance().execute((PhpFile) psiFile); - - if (phpClass == null) { - return null; - } final UctProblemsHolder problemsHolder = new UctProblemsHolder( InspectionManager.getInstance(project), psiFile, @@ -64,7 +59,7 @@ public UctInspectionManager(final @NotNull Project project) { ); final List visitors = SupportedIssue.getVisitors(problemsHolder); - for (final PsiElement element : collectElements(phpClass)) { + for (final PsiElement element : collectElements(psiFile)) { for (final PsiElementVisitor visitor : visitors) { element.accept(visitor); } @@ -76,26 +71,31 @@ public UctInspectionManager(final @NotNull Project project) { /** * Collect elements for PHP based inspections. * - * @param phpClass PhpClass + * @param psiFile PsiFile * * @return List[PsiElement] */ - private List collectElements(final @NotNull PhpClass phpClass) { + private List collectElements(final @NotNull PsiFile psiFile) { final List elements = new LinkedList<>(); - elements.add(phpClass); - final PhpPsiElement scopeForUseOperator = PhpCodeInsightUtil.findScopeForUseOperator( - phpClass - ); - if (scopeForUseOperator != null) { - elements.addAll(PhpCodeInsightUtil.collectImports(scopeForUseOperator)); + final PhpClass phpClass = GetFirstClassOfFile.getInstance().execute((PhpFile) psiFile); + + if (phpClass != null) { + elements.add(phpClass); + final PhpPsiElement scopeForUseOperator = PhpCodeInsightUtil.findScopeForUseOperator( + phpClass + ); + + if (scopeForUseOperator != null) { + elements.addAll(PhpCodeInsightUtil.collectImports(scopeForUseOperator)); + } + elements.addAll(Arrays.asList(phpClass.getOwnFields())); } - elements.addAll(PsiTreeUtil.findChildrenOfType(phpClass, ClassConstantReference.class)); - elements.addAll(Arrays.asList(phpClass.getOwnFields())); - elements.addAll(PsiTreeUtil.findChildrenOfType(phpClass, MethodReference.class)); - elements.addAll(PsiTreeUtil.findChildrenOfType(phpClass, AssignmentExpression.class)); - elements.addAll(PsiTreeUtil.findChildrenOfType(phpClass, ClassReference.class)); - elements.addAll(PsiTreeUtil.findChildrenOfType(phpClass, FieldReference.class)); + elements.addAll(PsiTreeUtil.findChildrenOfType(psiFile, ClassConstantReference.class)); + elements.addAll(PsiTreeUtil.findChildrenOfType(psiFile, MethodReference.class)); + elements.addAll(PsiTreeUtil.findChildrenOfType(psiFile, AssignmentExpression.class)); + elements.addAll(PsiTreeUtil.findChildrenOfType(psiFile, ClassReference.class)); + elements.addAll(PsiTreeUtil.findChildrenOfType(psiFile, FieldReference.class)); return elements; } From 47d4cdcff3c9e8a3457fa2ce4c72149a57409646 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Tue, 15 Mar 2022 12:47:06 +0200 Subject: [PATCH 20/20] 1023: Added themes count into the json report --- .../magento/idea/magento2uct/execution/output/ReportBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/magento/idea/magento2uct/execution/output/ReportBuilder.java b/src/com/magento/idea/magento2uct/execution/output/ReportBuilder.java index b48a0775d..fd6a0734e 100644 --- a/src/com/magento/idea/magento2uct/execution/output/ReportBuilder.java +++ b/src/com/magento/idea/magento2uct/execution/output/ReportBuilder.java @@ -163,6 +163,7 @@ public JsonFile build() { + "installedVersion\": \"" + summary.getInstalledVersion() + "\"," + "\"AdobeCommerceVersion\": \"" + summary.getTargetVersion() + "\"," + "\"checkedModules\": " + summary.getProcessedModules() + "," + + "\"checkedThemes\": " + summary.getProcessedThemes() + "," + "\"runningTime\": \"" + summary.getProcessRunningTime() + "\"," + "\"totalWarnings\": " + summary.getPhpWarnings() + "," + "\"totalErrors\": " + summary.getPhpErrors() + ","