Skip to content

Commit c17ffbf

Browse files
committed
optimize service name generator and provide custom javascript strategy for it #362
1 parent 3752191 commit c17ffbf

File tree

10 files changed

+328
-5
lines changed

10 files changed

+328
-5
lines changed

src/fr/adrienbrault/idea/symfony2plugin/Settings.java

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class Settings implements PersistentStateComponent<Settings> {
3232
public String pathToTranslation = DEFAULT_TRANSLATION_PATH;
3333
public String directoryToWeb = DEFAULT_WEB_DIRECTORY;
3434
public String directoryToApp = DEFAULT_APP_DIRECTORY;
35+
public String serviceJsNameStrategy = null;
3536

3637
public boolean pluginEnabled = false;
3738

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package fr.adrienbrault.idea.symfony2plugin.action.generator.naming;
2+
3+
import org.apache.commons.lang.StringUtils;
4+
import org.jetbrains.annotations.NotNull;
5+
import org.jetbrains.annotations.Nullable;
6+
7+
import java.util.ArrayList;
8+
import java.util.Arrays;
9+
import java.util.Collection;
10+
11+
/**
12+
* @author Daniel Espendiller <daniel@espendiller.net>
13+
*/
14+
public class DefaultServiceNameStrategy implements ServiceNameStrategyInterface {
15+
16+
@Nullable
17+
@Override
18+
public String getServiceName(@NotNull ServiceNameStrategyParameter parameter) {
19+
20+
String className = parameter.getClassName();
21+
if(className.startsWith("\\")) {
22+
className = className.substring(1);
23+
}
24+
25+
String[] split = className.split("\\\\");
26+
27+
if (className.contains("Bundle")) {
28+
29+
int x = -1;
30+
for (int i = 0; i < split.length; i++) {
31+
if (split[i].endsWith("Bundle")) {
32+
split[i] = split[i].substring(0, split[i].length() - "Bundle".length());
33+
x = i + 1;
34+
}
35+
}
36+
37+
Collection<String> parts = new ArrayList<String>();
38+
parts.add(StringUtils.join(Arrays.copyOfRange(split, 0, x), "_"));
39+
40+
String[] bundleAfter = Arrays.copyOfRange(split, x, split.length);
41+
if (bundleAfter.length > 1) {
42+
parts.add(StringUtils.join(Arrays.copyOfRange(bundleAfter, 0, bundleAfter.length - 1), "_"));
43+
parts.add(bundleAfter[bundleAfter.length - 1]);
44+
return formatParts(parts);
45+
} else if (bundleAfter.length == 1) {
46+
parts.add(bundleAfter[0]);
47+
return formatParts(parts);
48+
}
49+
50+
}
51+
52+
return formatParts(Arrays.asList(split));
53+
}
54+
55+
private String formatParts(Collection<String> parts) {
56+
57+
Collection<String> partString = new ArrayList<String>();
58+
for (String s : parts) {
59+
partString.add(fr.adrienbrault.idea.symfony2plugin.util.StringUtils.underscore(s));
60+
}
61+
62+
return StringUtils.join(partString, ".");
63+
}
64+
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package fr.adrienbrault.idea.symfony2plugin.action.generator.naming;
2+
3+
import com.google.gson.JsonObject;
4+
import com.intellij.openapi.project.Project;
5+
import com.intellij.openapi.vfs.VfsUtil;
6+
import com.jetbrains.php.lang.psi.elements.PhpClass;
7+
import fr.adrienbrault.idea.symfony2plugin.Settings;
8+
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
9+
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
10+
import org.apache.commons.lang.StringUtils;
11+
import org.jetbrains.annotations.NotNull;
12+
import org.jetbrains.annotations.Nullable;
13+
14+
import javax.script.ScriptEngine;
15+
import javax.script.ScriptEngineManager;
16+
import javax.script.ScriptException;
17+
18+
/**
19+
* @author Daniel Espendiller <daniel@espendiller.net>
20+
*/
21+
public class JavascriptServiceNameStrategy implements ServiceNameStrategyInterface {
22+
23+
@Nullable
24+
@Override
25+
public String getServiceName(@NotNull ServiceNameStrategyParameter parameter) {
26+
27+
String serviceJsNameStrategy = Settings.getInstance(parameter.getProject()).serviceJsNameStrategy;
28+
if(serviceJsNameStrategy == null || StringUtils.isBlank(serviceJsNameStrategy)) {
29+
return null;
30+
}
31+
32+
try {
33+
Object eval = run(parameter.getProject(), parameter.getClassName(), serviceJsNameStrategy);
34+
if(!(eval instanceof String)) {
35+
return null;
36+
}
37+
return StringUtils.isNotBlank((String) eval) ? (String) eval : null;
38+
} catch (ScriptException e) {
39+
Symfony2ProjectComponent.getLogger().error(String.format("ScriptException: '%s' - Script: '%s'", e.getMessage(), serviceJsNameStrategy));
40+
}
41+
42+
return null;
43+
}
44+
45+
@Nullable
46+
public static Object run(@NotNull Project project, @NotNull String className, @NotNull String serviceJsNameStrategy) throws ScriptException {
47+
48+
JsonObject jsonObject = new JsonObject();
49+
50+
jsonObject.addProperty("className", className);
51+
jsonObject.addProperty("projectName", project.getName());
52+
jsonObject.addProperty("projectBasePath", project.getBasePath());
53+
54+
PhpClass aClass = PhpElementsUtil.getClass(project, className);
55+
if(aClass != null) {
56+
String relativePath = VfsUtil.getRelativePath(aClass.getContainingFile().getVirtualFile(), project.getBaseDir(), '/');
57+
if(relativePath != null) {
58+
jsonObject.addProperty("relativePath", relativePath);
59+
}
60+
jsonObject.addProperty("absolutePath", aClass.getContainingFile().getVirtualFile().toString());
61+
}
62+
63+
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
64+
if(engine == null) {
65+
return null;
66+
}
67+
68+
return engine.eval("var __p = eval(" + jsonObject.toString() + "); result = function(args) { " + serviceJsNameStrategy + " }(__p)");
69+
}
70+
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package fr.adrienbrault.idea.symfony2plugin.action.generator.naming;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
import org.jetbrains.annotations.Nullable;
5+
6+
/**
7+
* @author Daniel Espendiller <daniel@espendiller.net>
8+
*/
9+
public interface ServiceNameStrategyInterface {
10+
@Nullable
11+
public String getServiceName(@NotNull ServiceNameStrategyParameter parameter);
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package fr.adrienbrault.idea.symfony2plugin.action.generator.naming;
2+
3+
import com.intellij.openapi.project.Project;
4+
import org.jetbrains.annotations.NotNull;
5+
6+
/**
7+
* @author Daniel Espendiller <daniel@espendiller.net>
8+
*/
9+
public class ServiceNameStrategyParameter {
10+
11+
@NotNull
12+
private final Project project;
13+
14+
@NotNull
15+
private final String className;
16+
17+
public ServiceNameStrategyParameter(@NotNull Project project, @NotNull String className) {
18+
this.project = project;
19+
this.className = className;
20+
}
21+
22+
@NotNull
23+
public String getClassName() {
24+
return className;
25+
}
26+
27+
@NotNull
28+
public Project getProject() {
29+
return project;
30+
}
31+
32+
}

src/fr/adrienbrault/idea/symfony2plugin/action/ui/SymfonyCreateService.java

+23-5
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@
1010
import com.intellij.util.ui.ListTableModel;
1111
import com.jetbrains.php.lang.psi.elements.*;
1212
import fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil;
13+
import fr.adrienbrault.idea.symfony2plugin.action.generator.naming.DefaultServiceNameStrategy;
14+
import fr.adrienbrault.idea.symfony2plugin.action.generator.naming.JavascriptServiceNameStrategy;
15+
import fr.adrienbrault.idea.symfony2plugin.action.generator.naming.ServiceNameStrategyInterface;
16+
import fr.adrienbrault.idea.symfony2plugin.action.generator.naming.ServiceNameStrategyParameter;
1317
import fr.adrienbrault.idea.symfony2plugin.dic.ContainerService;
1418
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
1519
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1620
import org.apache.commons.lang.StringUtils;
21+
import org.jetbrains.annotations.NotNull;
1722
import org.jetbrains.annotations.Nullable;
1823
import org.jetbrains.yaml.psi.YAMLFile;
1924

@@ -65,6 +70,11 @@ public SymfonyCreateService(Project project, @Nullable PsiFile psiFile) {
6570
this.psiFile = psiFile;
6671
}
6772

73+
private static ServiceNameStrategyInterface[] NAME_STRATEGIES = new ServiceNameStrategyInterface[] {
74+
new JavascriptServiceNameStrategy(),
75+
new DefaultServiceNameStrategy(),
76+
};
77+
6878
public void init() {
6979

7080
setContentPane(panel1);
@@ -489,12 +499,20 @@ public int compare(ContainerService o1, ContainerService o2) {
489499
}
490500
}
491501

492-
private String generateServiceName(String className) {
502+
@NotNull
503+
private String generateServiceName(@NotNull String className) {
504+
505+
// normalize
506+
if(className.startsWith("\\")) {
507+
className = className.substring(1);
508+
}
493509

494-
if(className.contains("Bundle")) {
495-
String formattedName = className.substring(0, className.indexOf("Bundle") + 6).toLowerCase().replace("\\", "_");
496-
formattedName += className.substring(className.indexOf("Bundle") + 6).toLowerCase().replace("\\", ".");
497-
return formattedName;
510+
ServiceNameStrategyParameter parameter = new ServiceNameStrategyParameter(project, className);
511+
for (ServiceNameStrategyInterface nameStrategy : NAME_STRATEGIES) {
512+
String serviceName = nameStrategy.getServiceName(parameter);
513+
if(serviceName != null && StringUtils.isNotBlank(serviceName)) {
514+
return serviceName;
515+
}
498516
}
499517

500518
return className.toLowerCase().replace("\\", "_");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package fr.adrienbrault.idea.symfony2plugin.doctrine.querybuilder.detector;
2+
3+
import com.intellij.psi.PsiElement;
4+
import com.intellij.psi.util.PsiTreeUtil;
5+
import com.jetbrains.php.lang.psi.elements.MethodReference;
6+
import com.jetbrains.php.lang.psi.elements.PhpClass;
7+
import org.jetbrains.annotations.NotNull;
8+
import org.jetbrains.annotations.Nullable;
9+
10+
/**
11+
* @author Daniel Espendiller <daniel@espendiller.net>
12+
*/
13+
public class RepositoryQueryBuilderRepositoryDetector implements QueryBuilderRepositoryDetector {
14+
15+
@Nullable
16+
@Override
17+
public String getRepository(@NotNull QueryBuilderRepositoryDetectorParameter parameter) {
18+
19+
MethodReference qbMethodRef = parameter.getMethodReferenceByName("createQueryBuilder");
20+
if(qbMethodRef == null) {
21+
return null;
22+
}
23+
24+
PhpClass parentOfType = PsiTreeUtil.getParentOfType(qbMethodRef, PhpClass.class);
25+
if(parentOfType == null) {
26+
return null;
27+
}
28+
29+
30+
31+
return null;
32+
}
33+
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package fr.adrienbrault.idea.symfony2plugin.tests.actions.generator.naming;
2+
3+
import fr.adrienbrault.idea.symfony2plugin.action.generator.naming.DefaultServiceNameStrategy;
4+
import fr.adrienbrault.idea.symfony2plugin.action.generator.naming.ServiceNameStrategyParameter;
5+
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
6+
import org.junit.Assert;
7+
import org.junit.Test;
8+
9+
/**
10+
* @author Daniel Espendiller <daniel@espendiller.net>
11+
*/
12+
13+
public class DefaultServiceNameStrategyTest extends SymfonyLightCodeInsightFixtureTestCase {
14+
15+
public void testGetServiceName() {
16+
17+
DefaultServiceNameStrategy defaultNaming = new DefaultServiceNameStrategy();
18+
19+
assertEquals("foo.foo_name.class_name", defaultNaming.getServiceName(getParameter("FooBundle\\FooName\\ClassName")));
20+
assertEquals("foo.form_bar.class_name_form", defaultNaming.getServiceName(getParameter("FooBundle\\Form\\Bar\\ClassNameForm")));
21+
assertEquals("foo.form.bar.class_name_form", defaultNaming.getServiceName(getParameter("Foo\\Form\\Bar\\ClassNameForm")));
22+
23+
assertEquals("foo_form_bar.class_name_form", defaultNaming.getServiceName(getParameter("Foo\\Form\\BarBundle\\ClassNameForm")));
24+
assertEquals("foo.form.bar.class_name_form", defaultNaming.getServiceName(getParameter("Foo\\Form\\Bar\\ClassNameForm")));
25+
26+
assertEquals("foo", defaultNaming.getServiceName(getParameter("\\Foo")));
27+
assertEquals("foo", defaultNaming.getServiceName(getParameter("\\FooBundle")));
28+
assertEquals("foo.foo", defaultNaming.getServiceName(getParameter("\\FooBundle\\Foo")));
29+
assertEquals("foo", defaultNaming.getServiceName(getParameter("\\FooBundle\\")));
30+
}
31+
32+
private ServiceNameStrategyParameter getParameter(String className) {
33+
return new ServiceNameStrategyParameter(getProject(), className);
34+
}
35+
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package fr.adrienbrault.idea.symfony2plugin.tests.actions.generator.naming;
2+
3+
import fr.adrienbrault.idea.symfony2plugin.Settings;
4+
import fr.adrienbrault.idea.symfony2plugin.action.generator.naming.DefaultServiceNameStrategy;
5+
import fr.adrienbrault.idea.symfony2plugin.action.generator.naming.JavascriptServiceNameStrategy;
6+
import fr.adrienbrault.idea.symfony2plugin.action.generator.naming.ServiceNameStrategyParameter;
7+
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
8+
import org.junit.Assert;
9+
import org.junit.Test;
10+
11+
import java.io.File;
12+
13+
/**
14+
* @author Daniel Espendiller <daniel@espendiller.net>
15+
*/
16+
17+
public class JavascriptServiceNameStrategyTest extends SymfonyLightCodeInsightFixtureTestCase {
18+
19+
public void setUp() throws Exception {
20+
super.setUp();
21+
myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject("classes.php"));
22+
}
23+
24+
protected String getTestDataPath() {
25+
return new File(this.getClass().getResource("fixtures").getFile()).getAbsolutePath();
26+
}
27+
28+
public void testGetServiceName() {
29+
30+
JavascriptServiceNameStrategy defaultNaming = new JavascriptServiceNameStrategy();
31+
32+
Settings.getInstance(getProject()).serviceJsNameStrategy = "return args.projectName;";
33+
assertTrue(defaultNaming.getServiceName(new ServiceNameStrategyParameter(getProject(), "asas")).contains("light"));
34+
35+
Settings.getInstance(getProject()).serviceJsNameStrategy = "return args.className.replace(\"Foo\", \"Bar\");";
36+
assertEquals("Bar\\Class", defaultNaming.getServiceName(getParameter("Foo\\Class")));
37+
38+
Settings.getInstance(getProject()).serviceJsNameStrategy = "return args.absolutePath;";
39+
assertTrue("Bar\\Class", defaultNaming.getServiceName(getParameter("MyClass\\Is\\Nice\\Nicer")).endsWith("classes.php"));
40+
41+
Settings.getInstance(getProject()).serviceJsNameStrategy = "return null";
42+
assertNull(defaultNaming.getServiceName(getParameter("MyClass\\Is\\Nice\\Nicer")));
43+
}
44+
45+
private ServiceNameStrategyParameter getParameter(String className) {
46+
return new ServiceNameStrategyParameter(getProject(), className);
47+
}
48+
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace MyClass\Is\Nice {
4+
class Nicer{}
5+
}

0 commit comments

Comments
 (0)