Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend methods in PYZ #10

Merged
merged 1 commit into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ jobs:

# Upload plugin artifact to make it available in the next jobs
- name: Upload artifact
uses: actions/upload-artifact@v2.2.3
uses: actions/upload-artifact@v3
with:
name: plugin-artifact
path: ./build/distributions/${{ steps.properties.outputs.artifact }}
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<!-- Keep a Changelog guide -> https://keepachangelog.com -->
# PYZ Plugin Changelog

## [0.9.0] - 2024-09-06
### Added
- Extend methods in PYZ

## [0.8.0] - 2024-09-05
### Added
- Added codeception helper navigation
- Codeception helper navigation

## [0.7.8] - 2024-04-25
### Fixed
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ A collection of little helpers that improve your daily work with Spryker.

## Features
- Extend Spryker core classes, interfaces and xml files on project level (right-click -> Extend in PYZ / CTRL-ALT-E)
- Extend Spryker core class methods on project level (right-click on method name inside Spryker core class -> Extend in PYZ / CTRL-ALT-E)
- Open Spryker files on github.com (right-click -> View on GitHub / CTRL-ALT-G)
- Goto-handling for Zed stub calls and their gateway controller actions (URLs are clickable)
- Resolve usages of gateway controller actions in Zed stub calls
- Navigate from OMS XML files to included sub-processes and the definitions of commands/conditions
- Navigate from Twig files to included, embedded and extended files and widgets
- Navigate from transfer object classes and instantiations to XML definitions (and vice versa)
- Navigate from codeception.yml to helper classes

## How to use
- To extend files on project level, use the context menu item "Extend in PYZ". It will appear for files located in one of the Spryker vendor directories only.
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

pluginGroup = com.github.senordingdong.sprykerideaplugin
pluginName = PYZ
pluginVersion = 0.8.0
pluginVersion = 0.9.0

# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
# for insight into build numbers and IntelliJ Platform versions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,27 @@
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileTypes.UnknownFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.file.PsiDirectoryFactory;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.php.lang.PhpFileType;
import com.jetbrains.php.lang.psi.PhpPsiElementFactory;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.jetbrains.php.lang.psi.elements.impl.MethodImpl;
import com.turbinekreuzberg.plugins.settings.AppSettingsState;
import com.turbinekreuzberg.plugins.utils.SprykerRelativeClassPathCreator;
import com.turbinekreuzberg.plugins.utils.PhpContentCreator;
import com.turbinekreuzberg.plugins.utils.GenericContentCreator;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
Expand All @@ -37,24 +46,29 @@ public ExtendInPyzAction() {
public void actionPerformed(@NotNull AnActionEvent actionEvent) {
Project project = actionEvent.getProject();

String selectedMethod = "";
if (actionEvent.getData(PlatformDataKeys.PSI_ELEMENT) instanceof MethodImpl) {
selectedMethod = actionEvent.getData(PlatformDataKeys.PSI_ELEMENT).getText();
}

VirtualFile[] selectedVirtualFiles = actionEvent.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);

assert selectedVirtualFiles != null;

for (VirtualFile selectedVirtualFile : selectedVirtualFiles) {
processFile(project, selectedVirtualFile);
processFile(project, selectedVirtualFile, selectedMethod);
}
}

private void processFile(Project project, VirtualFile selectedVirtualFile) {
private void processFile(Project project, VirtualFile selectedVirtualFile, String method) {
String relativeClassPath = sprykerRelativeClassPathCreator.getRelativeClassPath(selectedVirtualFile);
String targetPath = project.getBasePath() + AppSettingsState.getInstance().pyzDirectory + relativeClassPath;

PsiManager psiManager = PsiManager.getInstance(project);
PsiFile selectedFile = psiManager.findFile(selectedVirtualFile);

String renderedContent = getRenderedContent(selectedFile, relativeClassPath);
PsiFile pyzFile = createFile(selectedVirtualFile, project, renderedContent);
String renderedContent = getRenderedContent(selectedFile, relativeClassPath, method);
PsiFile pyzFile = createFile(selectedVirtualFile.getName(), project, renderedContent);

ApplicationManager.getApplication().runWriteAction(() -> {
VirtualFile virtualPyzDirectory = null;
Expand All @@ -66,17 +80,39 @@ private void processFile(Project project, VirtualFile selectedVirtualFile) {

if (virtualPyzDirectory != null) {
PsiDirectory pyzDirectory = PsiDirectoryFactory.getInstance(project).createDirectory(virtualPyzDirectory);
if (pyzDirectory.findFile(pyzFile.getName()) == null) {
PsiFile existingFile = pyzDirectory.findFile(pyzFile.getName());
if (existingFile == null) {
pyzDirectory.add(pyzFile);
} else if (!method.isEmpty()) {
addToFile(project, method, existingFile, pyzDirectory);
}

findFileInDirectoryAndOpenInEditor(project, pyzDirectory, pyzFile.getName());
}
});
}

private void addToFile(Project project, String method, PsiFile existingFile, PsiDirectory pyzDirectory) {
Method phpmethod = PhpPsiElementFactory.createMethod(project, method);
if (existingFile.getText().contains("function " + phpmethod.getName())) {
return;
}

WriteCommandAction.runWriteCommandAction(project, () -> {
Document document = PsiDocumentManager.getInstance(project).getDocument(existingFile);
if (document != null) {
int offset = StringUtils.substringBeforeLast(existingFile.getText(), "}").length();
document.insertString(offset, method);
PsiDocumentManager.getInstance(project).commitDocument(document);
}

CodeStyleManager.getInstance(project).reformat(existingFile);
});
}

private void findFileInDirectoryAndOpenInEditor(Project project, PsiDirectory pyzDirectory, String fileName) {
PsiFile foundFile = pyzDirectory.findFile(fileName);
new OpenFileDescriptor(project, foundFile.getVirtualFile()).navigate(true);
new OpenFileDescriptor(project, foundFile.getVirtualFile(), foundFile.getFileDocument().getLineCount(), 0).navigate(true);
}

@Override
Expand Down Expand Up @@ -105,16 +141,16 @@ private boolean isNotFileInSprykerVendor(@NotNull VirtualFile vFile) {
}

@NotNull
private PsiFile createFile(@NotNull VirtualFile sourceFile, Project project, String renderedContent) {
private PsiFile createFile(@NotNull String fileName, Project project, String renderedContent) {
final PsiFileFactory factory = PsiFileFactory.getInstance(project);

return factory.createFileFromText(sourceFile.getName(), PhpFileType.INSTANCE, renderedContent);
return factory.createFileFromText(fileName, PhpFileType.INSTANCE, renderedContent);
}

@NotNull
private String getRenderedContent(@NotNull PsiFile file, String relativePath) {
private String getRenderedContent(@NotNull PsiFile file, String relativePath, String method) {
if (file.getFileType() == PhpFileType.INSTANCE) {
return new PhpContentCreator().create(file, relativePath);
return new PhpContentCreator().create(file, relativePath, method);
}

return new GenericContentCreator().create(file);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import java.io.InputStream;

public class PhpContentCreator {
public String create(PsiFile file, String relativePath) {
public String create(PsiFile file, String relativePath, String method) {
InputStream inputStream = ResourceUtil.getResourceAsStream(getClass().getClassLoader(), "templates", "phpClass.txt");
String content = null;
try {
Expand All @@ -25,6 +25,7 @@ public String create(PsiFile file, String relativePath) {

contentWithClassName = contentWithClassName.replace("{{type}}", getType(file));
contentWithClassName = contentWithClassName.replace("{{sprykerNamespace}}", sprykerNamespace);
contentWithClassName = contentWithClassName.replace("{{method}}", method);

return contentWithClassName.replace("{{namespace}}", AppSettingsState.getInstance().pyzNamespace + "\\" + namespace);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public void testCreatePhpClass(){
String expectedFileContent = getFileContent("ExpectedExtendedExampleFacade.php");

// Act
String createdFileContent = new PhpContentCreator().create(baseClass, "Zed/Example");
String createdFileContent = new PhpContentCreator().create(baseClass, "Zed/Example", "");

// Assert
assertEquals(expectedFileContent, createdFileContent);
Expand All @@ -27,7 +27,7 @@ public void testCreatePhpInterface(){
String expectedFileContent = getFileContent("ExpectedExtendedExampleFacadeInterface.php");

// Act
String createdFileContent = new PhpContentCreator().create(baseClass, "Zed/Example");
String createdFileContent = new PhpContentCreator().create(baseClass, "Zed/Example", "");

// Assert
assertEquals(expectedFileContent, createdFileContent);
Expand All @@ -39,7 +39,7 @@ public void testCreatePhpTrait(){
String expectedFileContent = getFileContent("ExpectedExtendedExampleTrait.php");

// Act
String createdFileContent = new PhpContentCreator().create(baseClass, "Zed/Example");
String createdFileContent = new PhpContentCreator().create(baseClass, "Zed/Example", "");

// Assert
assertEquals(expectedFileContent, createdFileContent);
Expand All @@ -51,7 +51,7 @@ public void testCreatePhpAbstractClass(){
String expectedFileContent = getFileContent("ExpectedExtendedAbstractExample.php");

// Act
String createdFileContent = new PhpContentCreator().create(baseClass, "Zed/Example");
String createdFileContent = new PhpContentCreator().create(baseClass, "Zed/Example", "");

// Assert
assertEquals(expectedFileContent, createdFileContent);
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/META-INF/change-notes.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<html>
<ul>
<li>Added Navigation to Helper classes in codeception.yml files</li>
<li>Navigation to Helper classes in codeception.yml files</li>
<li>Extend Spryker methods in PYZ by right-clicking its name</li>
</ul>
</html>
2 changes: 1 addition & 1 deletion src/main/resources/templates/phpClass.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ use {{sprykerNamespace}}\{{className}} as Spryker{{className}};

{{type}} {{className}} extends Spryker{{className}}
{

{{method}}
}
Loading