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) { // NOPMD
+ 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();
+ }
+
+ @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"})
+ private String buildArrayTree(final DiArrayValueData data, final int indentSize) {
+ final StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder
+ .append(indent(0))
+ .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 + "'";// 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()) {
+ 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('\'')
+ .append(item.getName())
+ .append("' => ")
+ .append(value);
+
+ if (currentItem != itemsCount - 1) {
+ stringBuilder.append(',');
+ }
+ stringBuilder.append('\n');
+ currentItem++;
+ }
+ stringBuilder
+ .append(indent(indentSize))
+ .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..b27a371be
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/GatherArrayValuesDialog.java
@@ -0,0 +1,231 @@
+/*
+ * 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 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;
+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 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;// NOPMD
+ private final DiArrayValueData arrayValueData;
+
+ private JPanel contentPane;
+ private JButton buttonCancel;
+ private JButton buttonOK;
+ private JPanel itemsPane;// NOPMD
+ private JScrollPane itemsScrollPane;// NOPMD
+ 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());
+
+ final TableGroupWrapper 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 String name = item.getName().trim();
+
+ if (name.isEmpty()) {
+ return new Pair<>(
+ Boolean.FALSE,
+ validatorBundle.message("validator.arrayValuesDialog.nameMustNotBeEmpty")
+ );
+ }
+ itemsNames.add(name);
+ final DiArgumentType type = item.getType();
+ final String value = item.getValue().trim();
+
+ 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, "");
+ }
+
+ @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
+ private List extractItems(
+ final DefaultTableModel tableModel
+ ) {
+ final List items = new ArrayList<>();
+
+ for (int rowNumber = 0; rowNumber < tableModel.getRowCount(); rowNumber++) {
+ 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()
+ );
+
+ 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..16dab90f7
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewArgumentInjectionDialog.java
@@ -0,0 +1,695 @@
+/*
+ * 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.PsiFile;
+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;
+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.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;
+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;
+
+@SuppressWarnings({
+ "PMD.TooManyFields",
+ "PMD.UnusedPrivateField",
+ "PMD.ExcessiveImports",
+ "PMD.AvoidInstantiatingObjectsInLoops"
+})
+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 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;
+
+ private 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 targetClass PhpClass
+ * @param parameter Parameter
+ */
+ @SuppressWarnings({
+ "PMD.AccessorMethodGeneration",
+ "PMD.ExcessiveMethodLength",
+ "PMD.CognitiveComplexity",
+ "PMD.CyclomaticComplexity",
+ })
+ public NewArgumentInjectionDialog(
+ final @NotNull Project project,
+ final @NotNull PhpClass targetClass,
+ final @NotNull Parameter parameter
+ ) {
+ super();
+
+ this.project = project;
+ this.targetClass = targetClass;
+ targetParameter = parameter;
+ 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(parameter.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);
+ }
+ }
+ });
+ guessTargetType();
+ }
+
+ /**
+ * Open a new argument injection dialog.
+ *
+ * @param project Project
+ * @param targetClass PhpClass
+ * @param parameter Parameter
+ */
+ public static void open(
+ final @NotNull Project project,
+ final @NotNull PhpClass targetClass,
+ final @NotNull Parameter parameter
+ ) {
+ final NewArgumentInjectionDialog dialog =
+ new NewArgumentInjectionDialog(project, 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"})
+ 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"));
+ final String selectConstantText = " --- 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);
+ }
+
+ 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()) { // NOPMD
+ 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) { // NOPMD
+ 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"));
+ }
+ }
+ }
+
+ @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"})
+ 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 "";
+ }
+
+ @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));
+ 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..91e048614
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/ArgumentInjectionGenerator.java
@@ -0,0 +1,211 @@
+/*
+ * 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.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 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);
+ }
+
+ /**
+ * 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) { // NOPMD
+ 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;
+
+ 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..c0a83e044
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/code/util/DiXmlTagManipulatorUtil.java
@@ -0,0 +1,179 @@
+/*
+ * 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.util.PsiTreeUtil;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.psi.xml.XmlTag;
+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 org.jetbrains.annotations.NotNull;
+
+public final class DiXmlTagManipulatorUtil {
+
+ private 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
+ */
+ @SuppressWarnings("PMD.CognitiveComplexity")
+ 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.
*
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<>();
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..496a86f5d
--- /dev/null
+++ b/tests/com/magento/idea/magento2plugin/actions/generation/generator/ArgumentInjectionGeneratorTest.java
@@ -0,0 +1,338 @@
+/*
+ * 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;
+
+@SuppressWarnings("PMD.TooManyMethods")
+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);
+ }
+}