package fr.adrienbrault.idea.symfony2plugin.form;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementResolveResult;
import com.intellij.psi.PsiPolyVariantReferenceBase;
import com.intellij.psi.ResolveResult;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import fr.adrienbrault.idea.symfony2plugin.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class FormUnderscoreMethodReference extends PsiPolyVariantReferenceBase<StringLiteralExpression> {
@NotNull
private PhpClass phpClass;
public FormUnderscoreMethodReference(@NotNull StringLiteralExpression element, @NotNull PhpClass phpClass) {
super(element);
this.phpClass = phpClass;
}
@NotNull
@Override
public ResolveResult[] multiResolve(boolean incompleteCode) {
String contents = getElement().getContents();
if(org.apache.commons.lang.StringUtils.isBlank(contents)) {
return new ResolveResult[0];
}
Collection<PsiElement> psiElements = new ArrayList<>();
Set<String> methods = getCamelizeAndUnderscoreString(contents);
// provide setter fallback for non model class or or unknown methods
for (String value : methods) {
Method method = phpClass.findMethodByName("set" + value);
if (method != null) {
psiElements.add(method);
}
}
// property path
psiElements.addAll(this.phpClass.getFields().stream()
.filter(field -> !field.isConstant() && field.getModifier().isPublic() && methods.contains(field.getName()))
.collect(Collectors.toList())
);
return PsiElementResolveResult.createResults(psiElements);
}
@NotNull
@Override
public Object[] getVariants() {
Collection<LookupElement> lookupElements = new ArrayList<>();
// provide setter fallback for non model class or unknown methods
for(Method method: this.phpClass.getMethods()) {
String name = method.getName();
if(name.length() > 3 && name.startsWith("set")) {
lookupElements.add(new PhpFormPropertyMethodLookupElement(method, StringUtils.lcfirst(name.substring(3))));
}
}
// Symfony\Component\PropertyAccess\PropertyAccessor::getWriteAccessInfo
// property: public $foobar
lookupElements.addAll(this.phpClass.getFields().stream()
.filter(field -> !field.isConstant() && field.getModifier().isPublic())
.map(field -> new PhpFormPropertyMethodLookupElement(field, field.getName()))
.collect(Collectors.toList())
);
return lookupElements.toArray();
}
@NotNull
private Set<String> getCamelizeAndUnderscoreString(@NotNull String string) {
TreeSet<String> strings = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
string = StringUtils.lcfirst(string);
strings.addAll(Arrays.asList(
StringUtils.underscore(string),
StringUtils.camelize(string),
string
));
return strings;
}
}