package fr.adrienbrault.idea.symfony2plugin.util;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.FileBasedIndex;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import fr.adrienbrault.idea.symfony2plugin.config.EventDispatcherSubscriberUtil;
import fr.adrienbrault.idea.symfony2plugin.config.dic.EventDispatcherSubscribedEvent;
import fr.adrienbrault.idea.symfony2plugin.dic.tags.ServiceTagFactory;
import fr.adrienbrault.idea.symfony2plugin.dic.tags.ServiceTagInterface;
import fr.adrienbrault.idea.symfony2plugin.dic.tags.ServiceTagVisitorInterface;
import fr.adrienbrault.idea.symfony2plugin.stubs.ServiceIndexUtil;
import fr.adrienbrault.idea.symfony2plugin.stubs.dict.DispatcherEvent;
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.EventAnnotationStubIndex;
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class EventSubscriberUtil {
public static void visitNamedTag(@NotNull Project project, @NotNull String tagName, @NotNull ServiceTagVisitorInterface visitor) {
for (String service : ServiceUtil.getTaggedServices(project, tagName)) {
for (PsiElement psiElement : ServiceIndexUtil.findServiceDefinitions(project, service)) {
Collection<ServiceTagInterface> serviceTagVisitorArguments = ServiceTagFactory.create(service, psiElement);
if(serviceTagVisitorArguments == null) {
continue;
}
for (ServiceTagInterface tagVisitorArgument : serviceTagVisitorArguments) {
if(tagName.equals(tagVisitorArgument.getName())) {
visitor.visit(tagVisitorArgument);
}
}
}
}
}
/**
* @TODO: implement collection with prio
*/
@Nullable
public static String getTaggedEventMethodParameter(@NotNull Project project, @NotNull String eventName) {
// Static list
if(ServiceUtil.TAGS.containsKey(eventName)) {
return ServiceUtil.TAGS.get(eventName);
}
// @Event annotation
DispatcherEvent dispatcherEvent = ContainerUtil.getFirstItem(FileBasedIndex.getInstance().getValues(
EventAnnotationStubIndex.KEY,
eventName,
GlobalSearchScope.allScope(project))
);
if(dispatcherEvent != null && StringUtils.isNotBlank(dispatcherEvent.getInstance())) {
return dispatcherEvent.getInstance();
}
// Extract from directly from EventSubscriberInterface
for (EventDispatcherSubscribedEvent event : EventDispatcherSubscriberUtil.getSubscribedEvent(project, eventName)) {
String methodName = event.getMethodName();
if(methodName == null) {
continue;
}
Method method = PhpElementsUtil.getClassMethod(project, event.getFqnClassName(), methodName);
if(method != null) {
String methodParameterClassHint = PhpElementsUtil.getMethodParameterTypeHint(method);
if(methodParameterClassHint != null) {
return methodParameterClassHint;
}
}
}
// Visit all services tagged with "kernel.event_listener"
for (String service : ServiceUtil.getTaggedServices(project, "kernel.event_listener")) {
for (PsiElement psiElement : ServiceIndexUtil.findServiceDefinitions(project, service)) {
Collection<ServiceTagInterface> serviceTagVisitorArguments = ServiceTagFactory.create(service, psiElement);
if(serviceTagVisitorArguments == null) {
continue;
}
for (ServiceTagInterface tag : serviceTagVisitorArguments) {
if(!eventName.equals(tag.getAttribute("event"))) {
continue;
}
String methodName = tag.getAttribute("method");
if(StringUtils.isBlank(methodName)) {
continue;
}
// @TODO: collect
PhpClass phpClass = ServiceUtil.getServiceClass(project, tag.getServiceId());
if(phpClass != null) {
Method method = phpClass.findMethodByName(methodName);
if(method != null) {
String methodParameterTypeHint = PhpElementsUtil.getMethodParameterTypeHint(method);
if(methodParameterTypeHint != null) {
return methodParameterTypeHint;
}
}
}
}
}
}
return null;
}
}