Skip to content

Commit

Permalink
Merge pull request #1188 from anzin/1139-add-setup-data-patch
Browse files Browse the repository at this point in the history
1139: Creating a new data patch template
  • Loading branch information
bohdan-harniuk authored Sep 20, 2022
2 parents fae3dc2 + 9985598 commit c8f351a
Show file tree
Hide file tree
Showing 12 changed files with 777 additions and 5 deletions.
3 changes: 2 additions & 1 deletion resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@
<action id="MagentoCreateWidgetFile" class="com.magento.idea.magento2plugin.actions.context.xml.NewWidgetXmlAction"/>
<action id="MagentoCreateLayoutFile" class="com.magento.idea.magento2plugin.actions.context.xml.NewLayoutXmlAction"/>
<action id="MagentoCreateReadmeFile" class="com.magento.idea.magento2plugin.actions.context.md.NewReadmeMdAction"/>
<action id="MagentoDataPatchFile" class="com.magento.idea.magento2plugin.actions.context.php.NewObserverAction"/>
<action id="MagentoNewObserverFile" class="com.magento.idea.magento2plugin.actions.context.php.NewObserverAction"/>
<action id="MagentoNewSetupDataPatchFile" class="com.magento.idea.magento2plugin.actions.context.php.NewSetupDataPatchAction"/>
<!-- Context dependent actions -->
<separator/>
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewXml"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php
#parse("PHP File Header.php")

namespace ${MODULE_NAME}\Setup\Patch\Data;

use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

/**
* Patch is mechanism, that allows to do atomic upgrade data changes.
*/
class ${CLASS_NAME} implements DataPatchInterface
{
/**
* @var ModuleDataSetupInterface
*/
private $moduleDataSetup;

/**
* @param ModuleDataSetupInterface $moduleDataSetup
*/
public function __construct(
ModuleDataSetupInterface $moduleDataSetup
) {
$this->moduleDataSetup = $moduleDataSetup;
}

/**
* Do Upgrade.
*
* @return void
*/
public function apply()
{
$this->moduleDataSetup->getConnection()->startSetup();

// TODO: The code that you want apply in the patch

$this->moduleDataSetup->getConnection()->endSetup();
}

/**
* Get aliases (previous names) for the patch.
*
* @return string[]
*/
public function getAliases()
{
return [];
}

/**
* Get array of patches that have to be executed prior to this.
*
* Example of implementation:
*
* [
* \Vendor_Name\Module_Name\Setup\Patch\Patch1::class,
* \Vendor_Name\Module_Name\Setup\Patch\Patch2::class
* ]
*
* @return string[]
*/
public static function getDependencies()
{
return [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!--
/*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<html>
<body>
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse">
<tr>
<td><font face="verdana" size="-1">
A data patch is a class that contains data modification instructions.
</font><br>
</td>
</tr>
<tr>
<td><font face="verdana" size="-1">
Read more About the data and schema patches in the
<a href="https://devdocs.magento.com/guides/v2.4/extension-dev-guide/declarative-schema/data-patches.html">
DevDocs</a>.
</font><br>
</td>
</tr>
</table>
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse">
<tr>
<td colspan="3"><font face="verdana" size="-1">Predefined variables explanation:</font></td>
</tr>
<tr>
<td valign="top"><nobr><font face="verdana" size="-2"><b>${CLASS_NAME}</b></font></nobr></td>
<td width="10">&nbsp;</td>
<td width="100%" valign="top"><font face="verdana" size="-1">Specifies the name of your class
</font>
</td>
</tr>
</table>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

package com.magento.idea.magento2plugin.actions.context.php;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.magento.idea.magento2plugin.actions.context.CustomGeneratorContextAction;
import com.magento.idea.magento2plugin.actions.generation.dialog.NewSetupDataPatchDialog;
import com.magento.idea.magento2plugin.magento.packages.ComponentType;
import com.magento.idea.magento2plugin.magento.packages.Package;
import com.magento.idea.magento2plugin.util.magento.GetMagentoModuleUtil;
import org.jetbrains.annotations.NotNull;

public class NewSetupDataPatchAction extends CustomGeneratorContextAction {

public static final String ACTION_NAME = "Magento 2 Setup Data Patch";
public static final String ACTION_DESCRIPTION = "Create a new Magento 2 Setup Data Patch";
public static final String SETUP_DIRECTORY = "Setup";
public static final String PATCH_DIRECTORY = "Patch";
public static final String DATA_DIRECTORY = "Data";

public NewSetupDataPatchAction() {
super(ACTION_NAME, ACTION_DESCRIPTION);
}

@Override
public void actionPerformed(final @NotNull AnActionEvent event) {
final GetMagentoModuleUtil.MagentoModuleData moduleData = getModuleData();

if (event.getProject() == null || moduleData == null || getDirectory() == null) {
return;
}
final String[] module = moduleData.getName().split(Package.vendorModuleNameSeparator);

if (module.length != 2) { //NOPMD
return;
}
final PsiDirectory rootDirectory = moduleData.getModuleDir().findSubdirectory(
SETUP_DIRECTORY
);

if (rootDirectory == null) {
return;
}
NewSetupDataPatchDialog.open(event.getProject(), rootDirectory, module[0], module[1]);
}

@Override
protected boolean isVisible(
final @NotNull GetMagentoModuleUtil.MagentoModuleData moduleData,
final PsiDirectory targetDirectory,
final PsiFile targetFile
) {
if (!moduleData.getType().equals(ComponentType.module)) {
return false;
}

if (SETUP_DIRECTORY.equals(targetDirectory.getName())) {
return moduleData.getModuleDir().equals(targetDirectory.getParentDirectory());
}

if (PATCH_DIRECTORY.equals(targetDirectory.getName())) {
final PsiDirectory setupDirCandidate = targetDirectory.getParentDirectory();

return setupDirCandidate != null
&& SETUP_DIRECTORY.equals(setupDirCandidate.getName())
&& moduleData.getModuleDir().equals(setupDirCandidate.getParentDirectory());
}

if (DATA_DIRECTORY.equals(targetDirectory.getName())) {
final PsiDirectory patchDirCandidate = targetDirectory.getParentDirectory();

if (patchDirCandidate == null) {
return false;
}
final PsiDirectory setupDirCandidate = patchDirCandidate.getParentDirectory();

return setupDirCandidate != null
&& PATCH_DIRECTORY.equals(patchDirCandidate.getName())
&& SETUP_DIRECTORY.equals(setupDirCandidate.getName())
&& moduleData.getModuleDir().equals(setupDirCandidate.getParentDirectory());
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

package com.magento.idea.magento2plugin.actions.generation;

import com.intellij.psi.PsiDirectory;
import org.jetbrains.annotations.NotNull;

public class ModuleSetupDataPatchData {

private final String packageName;
private final String moduleName;
private final PsiDirectory baseDir;
private final String className;

/**
* Constructor.
*
* @param packageName String
* @param moduleName String
* @param baseDir PsiDirectory
*/
public ModuleSetupDataPatchData(
final @NotNull String packageName,
final @NotNull String moduleName,
final @NotNull PsiDirectory baseDir,
final @NotNull String className
) {
this.packageName = packageName;
this.moduleName = moduleName;
this.baseDir = baseDir;
this.className = className;
}

public @NotNull String getPackageName() {
return packageName;
}

public @NotNull String getModuleName() {
return moduleName;
}

public @NotNull PsiDirectory getBaseDir() {
return baseDir;
}

public @NotNull String getClassName() {
return className;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.magento.idea.magento2plugin.actions.generation.ModuleObserverData;
import com.magento.idea.magento2plugin.actions.generation.data.ObserverEventsXmlData;
import com.magento.idea.magento2plugin.actions.generation.data.ui.ComboBoxItemData;
import com.magento.idea.magento2plugin.actions.generation.dialog.reflection.GetReflectionFieldUtil;
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.DirectoryRule;
Expand All @@ -37,6 +38,7 @@
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -239,27 +241,34 @@ protected void onOK() {

private boolean validateFields() {
final PsiFile[] directoryFiles = getDirectoryFiles(baseDir);
final Field classNameField = GetReflectionFieldUtil.getByName("className", this.getClass());

if (directoryFiles != null) {
if (directoryFiles != null && classNameField != null) {
for (final PsiFile file : directoryFiles) {
final String className = ModuleObserverFile.resolveClassNameFromInput(
getClassName()
);

if (file.getName().equals(className + ModuleObserverFile.EXTENSION)) {
showErrorMessage(
fieldsValidationsList.get(1).getField(),
classNameField,
"Class name " + className + " already exist."
);

return false;
}
}
}
if (!getDirectoryStructure().isEmpty()
final Field directoryStructureField = GetReflectionFieldUtil.getByName(
"directoryStructure",
this.getClass()
);

if (!getDirectoryStructure().isEmpty() && directoryStructureField != null
&& !DirectoryRule.getInstance().check(getDirectoryStructure())
) {
showErrorMessage(
this.getClass().getDeclaredFields()[11],
directoryStructureField,
"The Directory Path field does not contain a valid directory."
);

Expand Down
Loading

0 comments on commit c8f351a

Please sign in to comment.