package fr.adrienbrault.idea.symfony2plugin.security;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.php.lang.PhpLanguage;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
import fr.adrienbrault.idea.symfony2plugin.TwigHelper;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProvider;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrar;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrarParameter;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.utils.GotoCompletionUtil;
import fr.adrienbrault.idea.symfony2plugin.security.utils.VoterUtil;
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.*;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class VoterGotoCompletionRegistrar implements GotoCompletionRegistrar {
@Override
public void register(GotoCompletionRegistrarParameter registrar) {
// {% is_granted('foobar') %}
// {% is_granted({'foobar'}) %}
// {% is_granted(['foobar']) %}
registrar.register(
PlatformPatterns.or(
TwigHelper.getPrintBlockOrTagFunctionPattern("is_granted"),
TwigHelper.getFunctionWithFirstParameterAsArrayPattern("is_granted"),
TwigHelper.getFunctionWithFirstParameterAsLiteralPattern("is_granted")
),
MyVisitorGotoCompletionProvider::new
);
// Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface::isGranted %}
registrar.register(PlatformPatterns.psiElement().withParent(StringLiteralExpression.class).withLanguage(PhpLanguage.INSTANCE), psiElement -> {
PsiElement context = psiElement.getContext();
if (!(context instanceof StringLiteralExpression)) {
return null;
}
MethodMatcher.MethodMatchParameter methodMatchParameter = new MethodMatcher.StringParameterRecursiveMatcher(context, 0)
.withSignature("Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "isGranted")
.withSignature("Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "denyAccessUnlessGranted")
.withSignature("Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationCheckerInterface", "isGranted")
.match();
if(methodMatchParameter != null) {
return new MyVisitorGotoCompletionProvider(psiElement);
}
// ['foobar']
MethodMatcher.MethodMatchParameter arrayMatchParameter = new MethodMatcher.ArrayParameterMatcher(context, 0)
.withSignature("Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "isGranted")
.withSignature("Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "denyAccessUnlessGranted")
.withSignature("Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationCheckerInterface", "isGranted")
.match();
if(arrayMatchParameter != null) {
return new MyVisitorGotoCompletionProvider(psiElement);
}
return null;
});
}
private static class MyVisitorGotoCompletionProvider extends GotoCompletionProvider {
MyVisitorGotoCompletionProvider(PsiElement psiElement) {
super(psiElement);
}
@NotNull
@Override
public Collection<LookupElement> getLookupElements() {
Collection<LookupElement> lookupElements = new ArrayList<>();
Set<String> elements = new HashSet<>();
VoterUtil.visitAttribute(getProject(), pair -> {
String name = pair.getFirst();
if(!elements.contains(name)) {
LookupElementBuilder lookupElement = LookupElementBuilder.create(name).withIcon(Symfony2Icons.SYMFONY);
PhpClass phpClass = PsiTreeUtil.getParentOfType(pair.getSecond(), PhpClass.class);
if(phpClass != null) {
lookupElement = lookupElement.withTypeText(phpClass.getName(), true);
}
lookupElements.add(lookupElement);
elements.add(name);
}
});
return lookupElements;
}
@NotNull
@Override
public Collection<PsiElement> getPsiTargets(PsiElement element) {
String text = GotoCompletionUtil.getTextValueForElement(element);
if(StringUtils.isBlank(text)) {
return Collections.emptyList();
}
VoterUtil.TargetPairConsumer foo = new VoterUtil.TargetPairConsumer(text);
VoterUtil.visitAttribute(getProject(), foo);
return foo.getValues();
}
}
}