Skip to content

Commit

Permalink
Merge pull request #2340 from Haehnchen/feature/route-invoke
Browse files Browse the repository at this point in the history
#2176 support route names on class level with __invoke method
  • Loading branch information
Haehnchen committed Apr 6, 2024
2 parents 107fede + 8144d2c commit 6e20613
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public DataIndexer<String, StubIndexedRoute, FileContent> getIndexer() {
}
}
} else if(psiFile instanceof PhpFile) {
// annotations: @Route()
// @Route(), #[Route]
if(!isValidForIndex(inputData, psiFile)) {
return map;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,19 @@ public void visitFile(@NotNull PhpClass phpClass) {

PhpAttributesList childOfType = PsiTreeUtil.getChildOfType(method, PhpAttributesList.class);
if (childOfType != null) {
visitPhpAttributesList(childOfType);
visitPhpAttributesList(childOfType, method, phpClass, false);
}
}

Method invoke = phpClass.findOwnMethodByName("__invoke");
if (invoke != null) {
PhpAttributesList childOfType = PsiTreeUtil.getChildOfType(phpClass, PhpAttributesList.class);
if (childOfType != null) {
visitPhpAttributesList(childOfType, invoke, phpClass, true);
}
}
}

private void visitPhpDocTag(@NotNull PhpDocTag phpDocTag) {

// "@var" and user non-related tags don't need an action
Expand Down Expand Up @@ -132,32 +141,33 @@ private void visitPhpDocTag(@NotNull PhpDocTag phpDocTag) {
}
}

private void visitPhpAttributesList(@NotNull PhpAttributesList phpAttributesList) {
private void visitPhpAttributesList(@NotNull PhpAttributesList phpAttributesList, @NotNull Method method, @NotNull PhpClass phpClass, boolean classLevel) {
PsiElement parent = phpAttributesList.getParent();

// prefix on class scope
String routeNamePrefix = "";
String routePathPrefix = "";
if (parent instanceof Method) {
PhpClass containingClass = ((Method) parent).getContainingClass();
if (containingClass != null) {
for (PhpAttribute attribute : containingClass.getAttributes()) {
String fqn = attribute.getFQN();
if(fqn == null || !RouteHelper.isRouteClassAnnotation(fqn)) {
continue;
}

String nameAttribute = PhpPsiAttributesUtil.getAttributeValueByNameAsString(attribute, 1, "name");
if (nameAttribute != null) {
routeNamePrefix = nameAttribute;
}
for (PhpAttribute attribute : phpClass.getAttributes()) {
String fqn = attribute.getFQN();
if(fqn == null || !RouteHelper.isRouteClassAnnotation(fqn)) {
continue;
}

String pathAttribute = PhpPsiAttributesUtil.getAttributeValueByNameAsStringWithDefaultParameterFallback(attribute, "path");;
if (pathAttribute != null) {
routePathPrefix = pathAttribute;
}
}
String nameAttribute = PhpPsiAttributesUtil.getAttributeValueByNameAsString(attribute, 1, "name");
if (nameAttribute != null) {
routeNamePrefix = nameAttribute;
}

String pathAttribute = PhpPsiAttributesUtil.getAttributeValueByNameAsStringWithDefaultParameterFallback(attribute, "path");;
if (pathAttribute != null) {
routePathPrefix = pathAttribute;
}
}

if (classLevel) {
routePathPrefix = "";
routeNamePrefix = "";
}

for (PhpAttribute attribute : phpAttributesList.getAttributes()) {
Expand All @@ -168,13 +178,11 @@ private void visitPhpAttributesList(@NotNull PhpAttributesList phpAttributesList

String nameAttribute = PhpPsiAttributesUtil.getAttributeValueByNameAsString(attribute, 1, "name");

String routeName = null;
String routeName;
if (nameAttribute != null) {
routeName = nameAttribute;
} else {
if (parent instanceof Method) {
routeName = AnnotationBackportUtil.getRouteByMethod((Method) parent);
}
routeName = AnnotationBackportUtil.getRouteByMethod(method);
}

if (routeName == null) {
Expand All @@ -183,8 +191,10 @@ private void visitPhpAttributesList(@NotNull PhpAttributesList phpAttributesList

StubIndexedRoute route = new StubIndexedRoute(routeNamePrefix + routeName);

if (parent instanceof Method) {
route.setController(getController((Method) parent));
if (classLevel) {
route.setController(getController(phpClass));
} else {
route.setController(getController(method));
}

// find path "#[Route('/attributesWithoutName')]" or "#[Route(path: '/attributesWithoutName')]"
Expand Down Expand Up @@ -304,6 +314,18 @@ private String getController(@NotNull Method method) {
);
}

private String getController(@NotNull PhpClass phpClass) {
if(phpClass.findOwnMethodByName("__invoke") == null) {
return null;
}

return String.format(
"%s::%s",
StringUtils.stripStart(phpClass.getFQN(), "\\"),
"__invoke"
);
}

@Nullable
private String getClassRoutePattern(@NotNull PhpDocTag phpDocTag) {
PhpClass phpClass = PsiTreeUtil.getParentOfType(phpDocTag, PhpClass.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,16 @@ public void testThatPhp8AttributesMethodsAreInIndex() {
assertEquals("/foo-attributes/edit-not-named/{id}", route9.getPath());
}

public void testThatPhp8AttributesViaClassInvokeMethodsAreInIndex() {
RouteInterface route = getFirstValue("invoke_route_attribute");
assertEquals("/foo-attributes", route.getPath());
assertEquals("AttributeInvoke\\MyController::__invoke", route.getController());

RouteInterface route2 = getFirstValue("attributeinvoke_noname__invoke");
assertEquals("/foo-attributes/no-name", route2.getPath());
assertEquals("AttributeInvoke\\NoNameController::__invoke", route2.getController());
}

@NotNull
private RouteInterface getFirstValue(@NotNull String key) {
return FileBasedIndex.getInstance().getValues(RoutesStubIndex.KEY, key, GlobalSearchScope.allScope(getProject())).get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,28 @@ public function emptyAttribute()
}
}


namespace AttributeInvoke
{
use Symfony\Component\Routing\Annotation\Route;

#[Route(path: '/foo-attributes', name: 'invoke_route_attribute')]
class MyController
{
public function __invoke()
{
}
}

#[Route(path: '/foo-attributes/no-name')]
class NoNameController
{
public function __invoke()
{
}
}
}

namespace Symfony\Component\Routing\Annotation
{
class Route
Expand Down

0 comments on commit 6e20613

Please sign in to comment.