Skip to content

Commit 88d09cd

Browse files
authored
Merge pull request #1921 from Haehnchen/feature/global-twig-annotation
support global naming for twig method resolving
2 parents 56ae0a7 + 524d305 commit 88d09cd

File tree

3 files changed

+167
-51
lines changed

3 files changed

+167
-51
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/templating/util/TwigUtil.java

Lines changed: 79 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -144,65 +144,93 @@ public static String[] getControllerMethodShortcut(@NotNull Method method) {
144144
return new String[0];
145145
}
146146

147+
String shortcutName = null;
148+
String shortcutNameForOldNotation = null;
149+
147150
SymfonyBundleUtil symfonyBundleUtil = new SymfonyBundleUtil(method.getProject());
148151
SymfonyBundle symfonyBundle = symfonyBundleUtil.getContainingBundle(phpClass);
149-
if(symfonyBundle == null) {
150-
return new String[0];
151-
}
152-
153-
// check if files is in <Bundle>/Controller/*
154-
PhpClass bundleClass = symfonyBundle.getPhpClass();
155-
if(!phpClass.getNamespaceName().startsWith(bundleClass.getNamespaceName() + "Controller\\")) {
156-
return new String[0];
157-
}
158-
159-
// strip the controller folder name
160-
String templateFolderName = phpClass.getNamespaceName().substring(bundleClass.getNamespaceName().length() + 11);
152+
if(symfonyBundle != null) {
153+
// check if files is in <Bundle>/Controller/*
154+
PhpClass bundleClass = symfonyBundle.getPhpClass();
155+
if(!phpClass.getNamespaceName().startsWith(bundleClass.getNamespaceName() + "Controller\\")) {
156+
return new String[0];
157+
}
158+
159+
// strip the controller folder name
160+
String templateFolderName = phpClass.getNamespaceName().substring(bundleClass.getNamespaceName().length() + 11);
161+
162+
// HomeBundle:default:indexes
163+
// HomeBundle:default/Test:indexes
164+
templateFolderName = templateFolderName.replace("\\", "/");
165+
166+
// Foobar without (.html.twig)
167+
String templateName = className.substring(0, className.lastIndexOf("Controller"));
168+
169+
if(methodName.equals("__invoke")) {
170+
// AppBundle::foo_bar.html.twig
171+
shortcutName = String.format(
172+
"%s::%s%s",
173+
symfonyBundle.getName(),
174+
underscore(templateFolderName),
175+
underscore(templateName)
176+
);
161177

162-
// HomeBundle:default:indexes
163-
// HomeBundle:default/Test:indexes
164-
templateFolderName = templateFolderName.replace("\\", "/");
178+
// AppBundle::FooBar.html.twig
179+
shortcutNameForOldNotation = String.format(
180+
"%s::%s%s",
181+
symfonyBundle.getName(),
182+
templateFolderName,
183+
templateName
184+
);
185+
} else {
186+
// FooBundle:foo_bar:foo_bar.html.twig
187+
shortcutName = String.format(
188+
"%s:%s%s:%s",
189+
symfonyBundle.getName(),
190+
underscore(templateFolderName),
191+
underscore(templateName),
192+
underscore(StringUtils.removeEnd(methodName, "Action"))
193+
);
165194

166-
String shortcutName;
167-
String shortcutNameForOldNotation;
195+
// FooBundle:FooBar:fooBar.html.twig
196+
shortcutNameForOldNotation = String.format(
197+
"%s:%s%s:%s",
198+
symfonyBundle.getName(),
199+
templateFolderName,
200+
templateName,
201+
StringUtils.removeEnd(methodName, "Action")
202+
);
203+
}
204+
} else {
205+
// https://github.com/sensiolabs/SensioFrameworkExtraBundle/blob/master/src/Templating/TemplateGuesser.php
206+
String fqn = phpClass.getFQN();
207+
Matcher matcher = Pattern.compile("Controller\\\\(.+)Controller$").matcher(fqn);
208+
if(matcher.find()) {
209+
String domain = matcher.group(1);
210+
211+
String matchController = domain.replaceAll("\\\\", "/");
212+
213+
String matchAction = null;
214+
if (!"__invoke".equals(methodName)) {
215+
matchAction = methodName.replaceAll("Action$", "");
216+
matchAction = matchAction;
217+
}
168218

169-
// Foobar without (.html.twig)
170-
String templateName = className.substring(0, className.lastIndexOf("Controller"));
219+
List<String> parts = new ArrayList<>(
220+
Arrays.asList(matchController.split("/"))
221+
);
171222

172-
if(methodName.equals("__invoke")) {
173-
// AppBundle::foo_bar.html.twig
174-
shortcutName = String.format(
175-
"%s::%s%s",
176-
symfonyBundle.getName(),
177-
underscore(templateFolderName),
178-
underscore(templateName)
179-
);
223+
if (matchAction != null) {
224+
parts.add(matchAction);
225+
}
180226

181-
// AppBundle::FooBar.html.twig
182-
shortcutNameForOldNotation = String.format(
183-
"%s::%s%s",
184-
symfonyBundle.getName(),
185-
templateFolderName,
186-
templateName
187-
);
188-
} else {
189-
// FooBundle:foo_bar:foo_bar.html.twig
190-
shortcutName = String.format(
191-
"%s:%s%s:%s",
192-
symfonyBundle.getName(),
193-
underscore(templateFolderName),
194-
underscore(templateName),
195-
underscore(StringUtils.removeEnd(methodName, "Action"))
196-
);
227+
shortcutNameForOldNotation = String.join("/", parts);
228+
shortcutName = underscore(String.join("/", parts));
229+
}
230+
}
197231

198-
// FooBundle:FooBar:fooBar.html.twig
199-
shortcutNameForOldNotation = String.format(
200-
"%s:%s%s:%s",
201-
symfonyBundle.getName(),
202-
templateFolderName,
203-
templateName,
204-
StringUtils.removeEnd(methodName, "Action")
205-
);
232+
if (shortcutName == null || shortcutNameForOldNotation == null) {
233+
return new String[0];
206234
}
207235

208236
// @TODO: we should support types later on; but nicer

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/templating/inspection/TemplateExistsAnnotationPhpAttributeLocalInspectionTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
public class TemplateExistsAnnotationPhpAttributeLocalInspectionTest extends SymfonyLightCodeInsightFixtureTestCase {
1111
public void setUp() throws Exception {
1212
super.setUp();
13+
1314
myFixture.copyFileToProject("classes.php");
1415
}
1516

@@ -139,4 +140,23 @@ public void testThatTemplateCreationForInvokeMethodProvidesQuickfix() {
139140
"Twig: Missing Template"
140141
);
141142
}
143+
144+
public void testThatMissingTemplateForGlobalNamespaceWithoutBundleScopeForController() {
145+
assertLocalInspectionContains("foobar.php", "<?php\n" +
146+
"namespace FoobarApp\\Controller;\n" +
147+
"use Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Template;\n" +
148+
"\n" +
149+
"class FoobarController\n" +
150+
"{\n" +
151+
" /**\n" +
152+
" * @Temp<caret>late()\n" +
153+
" */\n" +
154+
" public function fooAction()\n" +
155+
" {\n" +
156+
" }\n" +
157+
"}\n" +
158+
"",
159+
"Twig: Missing Template"
160+
);
161+
}
142162
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/templating/util/TwigUtilTest.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,74 @@ public void testGetControllerMethodShortcutForInvokeWithSnakeCase() {
471471
assertContainsElements(strings, "FooBundle::FooBar.text.twig");
472472
}
473473

474+
public void testGetControllerMethodShortcutForInvokeForGlobalNamespace() {
475+
myFixture.configureByText(PhpFileType.INSTANCE, "<?php\n" +
476+
"namespace FoobarUnknownBundle\\Controller;\n" +
477+
"class FooBarController\n" +
478+
"{\n" +
479+
" public function foo<caret>Action() {}\n" +
480+
"" +
481+
"}\n"
482+
);
483+
484+
PsiElement psiElement = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
485+
486+
List<String> strings = Arrays.asList(TwigUtil.getControllerMethodShortcut((Method) psiElement.getParent()));
487+
488+
assertContainsElements(strings, "foo_bar/foo.html.twig");
489+
assertContainsElements(strings, "foo_bar/foo.json.twig");
490+
assertContainsElements(strings, "foo_bar/foo.xml.twig");
491+
assertContainsElements(strings, "foo_bar/foo.text.twig");
492+
493+
assertContainsElements(strings, "FooBar/foo.html.twig");
494+
assertContainsElements(strings, "FooBar/foo.json.twig");
495+
assertContainsElements(strings, "FooBar/foo.xml.twig");
496+
assertContainsElements(strings, "FooBar/foo.text.twig");
497+
}
498+
499+
public void testGetControllerMethodShortcutForInvokeForGlobalNamespaceInInvoke() {
500+
myFixture.configureByText(PhpFileType.INSTANCE, "<?php\n" +
501+
"namespace FoobarUnknownBundle\\Controller;\n" +
502+
"class FooBarController\n" +
503+
"{\n" +
504+
" public function __inv<caret>oke() {}\n" +
505+
"" +
506+
"}\n"
507+
);
508+
509+
PsiElement psiElement = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
510+
511+
List<String> strings = Arrays.asList(TwigUtil.getControllerMethodShortcut((Method) psiElement.getParent()));
512+
513+
assertContainsElements(strings, "foo_bar.html.twig");
514+
assertContainsElements(strings, "foo_bar.json.twig");
515+
assertContainsElements(strings, "foo_bar.xml.twig");
516+
assertContainsElements(strings, "foo_bar.text.twig");
517+
518+
assertContainsElements(strings, "FooBar.html.twig");
519+
assertContainsElements(strings, "FooBar.json.twig");
520+
assertContainsElements(strings, "FooBar.xml.twig");
521+
assertContainsElements(strings, "FooBar.text.twig");
522+
}
523+
524+
public void testGetControllerMethodShortcutForInvokeForGlobalNamespaceInInvokeWIthPath() {
525+
myFixture.configureByText(PhpFileType.INSTANCE, "<?php\n" +
526+
"namespace Fixture\\Controller\\MyAdmin;\n" +
527+
"class OutOfBundleController\n" +
528+
"{\n" +
529+
" public function index<caret>Action() {}\n" +
530+
"" +
531+
"}\n"
532+
);
533+
534+
PsiElement psiElement = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
535+
536+
List<String> strings = Arrays.asList(TwigUtil.getControllerMethodShortcut((Method) psiElement.getParent()));
537+
538+
assertContainsElements(strings, "my_admin/out_of_bundle/index.html.twig");
539+
assertContainsElements(strings, "MyAdmin/OutOfBundle/index.html.twig");
540+
}
541+
474542
public void testFindTwigFileController() {
475543
myFixture.copyFileToProject("bundle.php");
476544

0 commit comments

Comments
 (0)