I wrote a PHPStorm plugin

kristijankanalas

Kristijan Kanalaš

Posted on July 26, 2019

I wrote a PHPStorm plugin

There is a high chance you were once so upset at your IDE for not having a feature you need, that you thought of writing a plugin for it. Most of us end up never doing it and finishing the job without the said plugin. The same happened to me.
I had an idea for a PHPStorm plugin for months but never finding time to write it. Until I had to do the same boring routine one too many times.
So I wrote a PHPStorm plugin.

The problem

When you have a class that has getters and setters in some (rare) cases you will need to write something like this:



$car = new Car();
$car->setMake('Audi');
$car->setModel('A6');


Enter fullscreen mode Exit fullscreen mode

With some auto-complete features that InteliJ platform provides I can finish this pretty quickly. But what if a class has a dozen of getters or setters you need to call?
Idea

The idea

The idea was simple a developer places the caret on the $car variable and by pressing a shortcut, generate all the getters or setters (depending on the shortcut) for the given object.

Writing the plugin

I was really nervous cause I haven't touched java since my school days but I made a decision to just do it.
Just do it!

Prerequisites

  • PHPStorm - contains php-openapi.jar and php.jar
  • InteliJ IDEA Community Edition

Setup

I've followed a setup written by the people at Jetbrains, Setting-up environment for PhpStorm plugin development. If you are going to follow this setup make sure that when you are configuring the SDK you add php-openapi.jar and php.jar like so
don't make the same mistake as me by not seeing the warning to not set those in Libraries.

Debugger setup

By default InteliJ will setup and run another instance of InteliJ when you click on the debug button. It works really good, but I was developing a plugin for PHPStorm, not for InteliJ. I've searched far and wide for a debugger setup if you are developing a PHPStorm plugin and I couldn't find any. So I had to discover how to do it on my own.
You can go to the edit debug configurations like so Debug configuration in the JRE field navigate to the path of your PHPStorm and voila, now it works. Easier than I thought it would be.

Coding

I must say I found it hard to do anything, documentation is pretty scarce and I forgot a lot of java rules and syntax.
Unfortunately I couldn't find a way to tap in the power of PHPStorm and to ask it; what it knows about a certain variable. The only choice I had left is to use PSI and try to figure out where is the declaration of the variable and what type it is. After a few hours of trial and error I have succeeded in that.



    static void generateMethods(AnActionEvent event, String typeOfMethod) {
        final Project project = event.getData(PlatformDataKeys.PROJECT);
        final Editor editor = event.getData(PlatformDataKeys.EDITOR);
        if (editor != null) {
            final CaretModel caret = editor.getCaretModel();
            PsiFile file = event.getData(LangDataKeys.PSI_FILE);
            if (file != null) {
                PsiElement selectedElement = file.findElementAt(caret.getOffset());
                if (selectedElement != null && selectedElement.getParent().getReference() != null) {
                    PsiElement variableDeclaration = selectedElement.getParent().getReference().resolve();                        
                    if (variableDeclaration != null) {
                        PsiElement assignmentExpression = variableDeclaration.getContext();
                        if (assignmentExpression != null) {
                            final Collection<PsiElement> selectedElementClass = new SmartList<>();
                            assignmentExpression.accept(new PsiRecursiveElementVisitor() {
                                @Override
                                public void visitElement(PsiElement element) {
                                    if (element instanceof ClassReferenceImpl) {
                                        if (element.getReference() != null) {
                                            selectedElementClass.add(element.getReference().resolve());
                                        }
                                    }
                                    super.visitElement(element);
                                }
                            });
                        }
                    }
                }
            }
        }
    }


Enter fullscreen mode Exit fullscreen mode

Believe me, I'm not proud of this code and I am looking forward to rewriting it soon.

Now the only thing left was to get the getters and setters of the instantiated class and add the calls to the editor. I managed to get the methods of a class without any issues. I expected the writing to the editor to be the easiest task of them all and boy was I wrong. Again I had to spend a few hours to figure out how to do it and this is the best I could come up with



Document document = editor.getDocument();
boolean firstMethodGeneration = true;
for(PsiElement initClass:selectedElementClass) {
    PhpClassImpl phpClass=(PhpClassImpl)initClass;
    for(Method method:phpClass.getMethods()) {
        String methodName=method.getName();

        // If method name has "set" on position 0 add it to editor
        if(methodName.indexOf(typeOfMethod)==0) {
            boolean FirstSetter=firstMethodGeneration;
            WriteCommandAction.runWriteCommandAction(project,()->{
                if(FirstSetter){
                    caret.moveToOffset(caret.getVisualLineEnd());
                    document.insertString(caret.getOffset(),"\n");
                }
                caret.moveToOffset(caret.getVisualLineEnd());
                document.insertString(caret.getOffset(),selectedElement.getText()
                +"->"+methodName+"();\n");
            });
        }
        firstMethodGeneration=false;
    }
}


Enter fullscreen mode Exit fullscreen mode

Final result

In the end I got a very limited plugin that can generate setters or getters only for the variables instantiated in the same file. It can't determine variable type from a function return or more advanced stuff like that. Having said that I'm still very happy how it turned out and I'm planning to make it more powerful in the future and add more features to the plugin.

If you want to see more of the plugin feel free to visit the GitHub repository.

GitHub logo KristijanKanalas / PHPCodeGeneratorPlus

PhpStorm plugin that let's you generate even more PHP code

PHP code generator + JetBrains IntelliJ plugins License: MIT

PhpStorm plugin that lets you generate even more PHP code.

Plugin provides the following features:

  • Generates calls for the setters of the declared variable (Shift +Ctrl + NUMPAD1)
  • Generates calls for the getters of the declared variable (Shift +Ctrl + NUMPAD2)
Key Value
Plugin Url https://plugins.jetbrains.com/plugin/12590-php-code-generator-
ID PHPCodeGenerator+

Install

  • Install the plugin by going to Settings -> Plugins -> Marketplace and then search for PHP code generator

Usage

By placing your caret at an initialized variable and pressing ALT + Insert a PhpStorm code generator menu will popup you can then choose Get getters or Get setters option. Actions also have shortcuts Shift + Ctrl + NUMPAD1 and Shift + Ctrl + NUMPAD2.

Authors




💖 💪 🙅 🚩
kristijankanalas
Kristijan Kanalaš

Posted on July 26, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

I wrote a PHPStorm plugin
php I wrote a PHPStorm plugin

July 26, 2019