Skip to content

Commit e858ef2

Browse files
committed
Implemented #93: Action/Code Generation. Observer Generation
- added logic to locate event name - added code generation for the Observer class
1 parent 0c3ff4f commit e858ef2

19 files changed

+1267
-17
lines changed

resources/META-INF/plugin.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939

4040
<actions>
4141
<group id="MagentoGenerateGroup">
42+
<action id="MagentoGenerateObserverMethodAction"
43+
class="com.magento.idea.magento2plugin.actions.generation.PluginGenerateBeforeMethodAction"
44+
text="Magento Before Plugin..."
45+
description="Create Magento before plugin method."/>
4246
<action id="MagentoGenerateBeforeMethodAction"
4347
class="com.magento.idea.magento2plugin.actions.generation.PluginGenerateBeforeMethodAction"
4448
text="Magento Before Plugin..."
@@ -57,6 +61,9 @@
5761
<action id="Magento2NewModule" class="com.magento.idea.magento2plugin.actions.generation.NewModuleAction"/>
5862
<add-to-group group-id="NewGroup" anchor="after" relative-to-action="NewDir"/>
5963
</group>
64+
<action id="MagentoCreateAnObserver.Menu" class="com.magento.idea.magento2plugin.actions.generation.CreateAnObserverAction">
65+
<add-to-group group-id="EditorPopupMenu"/>
66+
</action>
6067
<action id="MagentoCreateAPlugin.Menu" class="com.magento.idea.magento2plugin.actions.generation.CreateAPluginAction">
6168
<add-to-group group-id="EditorPopupMenu"/>
6269
</action>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
#parse("PHP File Header.php")
3+
4+
#if (${NAMESPACE})
5+
6+
namespace ${NAMESPACE};
7+
8+
#end
9+
use Magento\Framework\Event\ObserverInterface;
10+
use Magento\Framework\Event\Observer;
11+
12+
class ${NAME} implements ObserverInterface {
13+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!--
2+
/*
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
-->
7+
<html>
8+
<body>
9+
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse">
10+
<tr>
11+
<td><font face="verdana" size="-1">Magento runs all after methods following the completion of the observed method.
12+
Magento requires these methods have a return value and they must have the same name as the observed method with ‘after’ as the prefix.
13+
</font><br>
14+
</td>
15+
</tr>
16+
</table>
17+
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse">
18+
<tr>
19+
<td colspan="3"><font face="verdana" size="-1">Predefined variables will take the following values:</font></td>
20+
</tr>
21+
<tr>
22+
<td valign="top"><nobr><font face="verdana" size="-2"><b>${PARAM_DOC}</b></font></nobr></td>
23+
<td width="10">&nbsp;</td>
24+
<td width="100%" valign="top"><font face="verdana" size="-1">PHP DocBlock for plugin function</font></td>
25+
</tr>
26+
<tr>
27+
<td valign="top"><nobr><font face="verdana" size="-2"><b>${NAME}</b></font></nobr></td>
28+
<td width="10">&nbsp;</td>
29+
<td width="100%" valign="top"><font face="verdana" size="-1">Name of the plugin function</font></td>
30+
</tr>
31+
<tr>
32+
<td valign="top"><nobr><font face="verdana" size="-2"><b>${PARAM_LIST}</b></font></nobr></td>
33+
<td width="10">&nbsp;</td>
34+
<td width="100%" valign="top"><font face="verdana" size="-1">List of plugin function parameters</font></td>
35+
</tr>
36+
<tr>
37+
<td valign="top"><nobr><font face="verdana" size="-2"><b>${RETURN_VARIABLES}</b></font></nobr></td>
38+
<td width="10">&nbsp;</td>
39+
<td width="100%" valign="top"><font face="verdana" size="-1">Return value for plugin function</font></td>
40+
</tr>
41+
</table>
42+
</body>
43+
</html>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* Observer for ${EVENT_NAME}
3+
*
4+
* @param Observer $observer
5+
* @throws \Magento\Framework\Validator\Exception
6+
* @return void
7+
*/
8+
public function execute(Observer $observer)
9+
{
10+
$event = $observer->getEvent();
11+
// TODO: Implement observer method.
12+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!--
2+
/*
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
-->
7+
<html>
8+
<body>
9+
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse">
10+
<tr>
11+
<td><font face="verdana" size="-1">Magento runs all after methods following the completion of the observed method.
12+
Magento requires these methods have a return value and they must have the same name as the observed method with ‘after’ as the prefix.
13+
</font><br>
14+
</td>
15+
</tr>
16+
</table>
17+
<table width="100%" border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse">
18+
<tr>
19+
<td colspan="3"><font face="verdana" size="-1">Predefined variables will take the following values:</font></td>
20+
</tr>
21+
<tr>
22+
<td valign="top"><nobr><font face="verdana" size="-2"><b>${PARAM_DOC}</b></font></nobr></td>
23+
<td width="10">&nbsp;</td>
24+
<td width="100%" valign="top"><font face="verdana" size="-1">PHP DocBlock for plugin function</font></td>
25+
</tr>
26+
<tr>
27+
<td valign="top"><nobr><font face="verdana" size="-2"><b>${NAME}</b></font></nobr></td>
28+
<td width="10">&nbsp;</td>
29+
<td width="100%" valign="top"><font face="verdana" size="-1">Name of the plugin function</font></td>
30+
</tr>
31+
<tr>
32+
<td valign="top"><nobr><font face="verdana" size="-2"><b>${PARAM_LIST}</b></font></nobr></td>
33+
<td width="10">&nbsp;</td>
34+
<td width="100%" valign="top"><font face="verdana" size="-1">List of plugin function parameters</font></td>
35+
</tr>
36+
<tr>
37+
<td valign="top"><nobr><font face="verdana" size="-2"><b>${RETURN_VARIABLES}</b></font></nobr></td>
38+
<td width="10">&nbsp;</td>
39+
<td width="100%" valign="top"><font face="verdana" size="-1">Return value for plugin function</font></td>
40+
</tr>
41+
</table>
42+
</body>
43+
</html>
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
package com.magento.idea.magento2plugin.actions.generation;
6+
7+
import com.intellij.lang.ASTNode;
8+
import com.intellij.openapi.actionSystem.AnActionEvent;
9+
import com.intellij.openapi.actionSystem.PlatformDataKeys;
10+
import com.intellij.openapi.editor.Caret;
11+
import com.intellij.openapi.project.DumbAwareAction;
12+
import com.intellij.openapi.project.Project;
13+
import com.intellij.psi.PsiElement;
14+
import com.intellij.psi.PsiFile;
15+
import com.intellij.psi.tree.IElementType;
16+
import com.jetbrains.php.lang.lexer.PhpTokenTypes;
17+
import com.jetbrains.php.lang.psi.PhpFile;
18+
import com.jetbrains.php.lang.psi.elements.MethodReference;
19+
import com.jetbrains.php.lang.psi.elements.ParameterList;
20+
import com.magento.idea.magento2plugin.MagentoIcons;
21+
import com.magento.idea.magento2plugin.actions.generation.dialog.CreateAnObserverDialog;
22+
import com.magento.idea.magento2plugin.project.Settings;
23+
import org.jetbrains.annotations.NotNull;
24+
25+
public class CreateAnObserverAction extends DumbAwareAction {
26+
public static final String ACTION_NAME = "Create a Magento Observer...";
27+
static final String ACTION_DESCRIPTION = "Create a new Magento 2 Observer for the event";
28+
static final String SIGNATURE = "#M#C\\Magento\\Framework\\Event\\ManagerInterface.dispatch|#M#M#C\\Magento\\Framework\\App\\Action\\Context.getEventManager.dispatch";
29+
public String targetEvent;
30+
31+
public CreateAnObserverAction() {
32+
super(ACTION_NAME, ACTION_DESCRIPTION, MagentoIcons.MODULE);
33+
}
34+
35+
public void update(AnActionEvent event) {
36+
Project project = event.getData(PlatformDataKeys.PROJECT);
37+
if (!Settings.isEnabled(project)) {
38+
this.setStatus(event, false);
39+
return;
40+
}
41+
PsiFile psiFile = event.getData(PlatformDataKeys.PSI_FILE);
42+
if (!(psiFile instanceof PhpFile)) {
43+
this.setStatus(event, false);
44+
return;
45+
}
46+
47+
PsiElement element = getElement(event);
48+
if (element == null) {
49+
this.setStatus(event, false);
50+
return;
51+
}
52+
53+
if (isObserverEventNameClicked(element)) {
54+
this.setStatus(event, true);
55+
targetEvent = element.getText();
56+
return;
57+
}
58+
59+
if (isDispatchMethodClicked(element)) {
60+
//@TODO implement fetching from the dispatch method
61+
//this.setStatus(event, true);
62+
//targetEvent = fetchTargetEventName(element);
63+
//return;
64+
}
65+
66+
this.setStatus(event, false);
67+
}
68+
69+
private PsiElement getElement(@NotNull AnActionEvent event) {
70+
Caret caret = event.getData(PlatformDataKeys.CARET);
71+
PsiFile psiFile = event.getData(PlatformDataKeys.PSI_FILE);
72+
if (caret == null) {
73+
return null;
74+
}
75+
int offset = caret.getOffset();
76+
PsiElement element = psiFile.findElementAt(offset);
77+
if (element == null) {
78+
return null;
79+
}
80+
return element;
81+
}
82+
83+
private boolean isObserverEventNameClicked(@NotNull PsiElement element) {
84+
if (checkIsElementStringLiteral(element)) {
85+
//@TODO check if quotes are clicked
86+
87+
if (checkIsParametersList(element.getParent().getParent()) &&
88+
checkIsMethodReference(element.getParent().getParent().getParent()) &&
89+
checkIsEventDispatchMethod((MethodReference) element.getParent().getParent().getParent()))
90+
{
91+
return true;
92+
}
93+
}
94+
return false;
95+
}
96+
97+
private boolean checkIsParametersList(@NotNull PsiElement element) {
98+
if (element instanceof ParameterList) {
99+
return true;
100+
}
101+
return false;
102+
}
103+
104+
private boolean checkIsMethodReference(@NotNull PsiElement element) {
105+
if (element instanceof MethodReference) {
106+
return true;
107+
}
108+
return false;
109+
}
110+
111+
private boolean checkIsEventDispatchMethod(MethodReference element) {
112+
return element.getSignature().equals(SIGNATURE);
113+
}
114+
115+
private boolean checkIsElementStringLiteral(@NotNull PsiElement element) {
116+
ASTNode astNode = element.getNode();
117+
if (astNode == null) {
118+
return false;
119+
}
120+
IElementType elementType = astNode.getElementType();
121+
122+
if (elementType != PhpTokenTypes.STRING_LITERAL && elementType != PhpTokenTypes.STRING_LITERAL_SINGLE_QUOTE) {
123+
return false;
124+
}
125+
126+
return true;
127+
}
128+
129+
private boolean checkIsElementMethodReference(@NotNull PsiElement element) {
130+
ASTNode astNode = element.getNode();
131+
if (astNode == null) {
132+
return false;
133+
}
134+
IElementType elementType = astNode.getElementType();
135+
if (elementType != PhpTokenTypes.IDENTIFIER) {
136+
return false;
137+
}
138+
139+
return true;
140+
}
141+
142+
private boolean isDispatchMethodClicked(@NotNull PsiElement element) {
143+
if (checkIsElementMethodReference(element) &&
144+
checkIsMethodReference(element.getParent()) &&
145+
checkIsEventDispatchMethod((MethodReference) element.getParent())) {
146+
return true;
147+
}
148+
149+
return false;
150+
}
151+
152+
private String fetchTargetEventName(@NotNull PsiElement element) {
153+
//@TODO implement fetching event name from the dispatch method
154+
return null;
155+
}
156+
157+
private void setStatus(AnActionEvent event, boolean status) {
158+
event.getPresentation().setVisible(status);
159+
event.getPresentation().setEnabled(status);
160+
}
161+
162+
@Override
163+
public void actionPerformed(@NotNull AnActionEvent e) {
164+
CreateAnObserverDialog.open(e.getProject(), this.targetEvent);
165+
}
166+
167+
@Override
168+
public boolean isDumbAware() {
169+
return false;
170+
}
171+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
package com.magento.idea.magento2plugin.actions.generation;
6+
7+
import com.intellij.codeInsight.CodeInsightActionHandler;
8+
import com.intellij.codeInsight.actions.CodeInsightAction;
9+
import com.intellij.openapi.editor.Editor;
10+
import com.intellij.openapi.project.Project;
11+
import com.intellij.openapi.util.Key;
12+
import com.intellij.psi.PsiFile;
13+
import com.jetbrains.php.lang.psi.elements.Method;
14+
import com.jetbrains.php.lang.psi.elements.PhpClass;
15+
import com.magento.idea.magento2plugin.actions.generation.data.code.PluginMethodData;
16+
import com.magento.idea.magento2plugin.actions.generation.generator.code.PluginMethodsGenerator;
17+
import com.magento.idea.magento2plugin.magento.files.Plugin;
18+
import org.jetbrains.annotations.NotNull;
19+
20+
public class ObserverGenerateExecuteMethodAction extends CodeInsightAction {
21+
private final PluginGenerateMethodHandlerBase myHandler = new PluginGenerateMethodHandlerBase(Plugin.PluginType.before) {
22+
protected PluginMethodData[] createPluginMethods(PhpClass currentClass, Method method, Key<Object> targetClassKey) {
23+
return (new PluginMethodsGenerator(currentClass, method, targetClassKey)
24+
.createPluginMethods(Plugin.PluginType.before));
25+
}
26+
};
27+
28+
protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
29+
return this.myHandler.isValidFor(editor, file);
30+
}
31+
32+
@NotNull
33+
protected CodeInsightActionHandler getHandler() {
34+
return this.myHandler;
35+
}
36+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.magento.idea.magento2plugin.actions.generation.data;
2+
3+
import com.jetbrains.php.lang.psi.elements.PhpClass;
4+
5+
public class ObserverEventsXmlData {
6+
public ObserverEventsXmlData(String observerArea, String pluginModule, PhpClass targetClass, String observerSortOrder, String observerName, String pluginClassFqn) {
7+
//@TODO implement XML file generation
8+
}
9+
}

0 commit comments

Comments
 (0)