package fr.adrienbrault.idea.symfony2plugin.doctrine.metadata; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.psi.PsiElement; import com.jetbrains.php.lang.psi.elements.MethodReference; import com.jetbrains.php.lang.psi.elements.PhpClass; import com.jetbrains.php.lang.psi.elements.PhpExpression; import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; import com.jetbrains.php.lang.psi.resolve.types.PhpType; 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.doctrine.EntityHelper; import fr.adrienbrault.idea.symfony2plugin.doctrine.dict.DoctrineModelField; import fr.adrienbrault.idea.symfony2plugin.doctrine.dict.DoctrineModelFieldLookupElement; import fr.adrienbrault.idea.symfony2plugin.doctrine.dict.DoctrineModelInterface; import fr.adrienbrault.idea.symfony2plugin.doctrine.metadata.util.DoctrineMetadataUtil; import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher; import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil; import org.jetbrains.annotations.NotNull; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; /** * @author Daniel Espendiller <daniel@espendiller.net> */ public class ObjectRepositoryFindGotoCompletionRegistrar implements GotoCompletionRegistrar { public void register(GotoCompletionRegistrarParameter registrar) { // "@var $om \Doctrine\Common\Persistence\ObjectManager" // "$om->getRepository('Foo\Bar')->" + s + "(['foo' => 'foo', '<caret>' => 'foo'])" registrar.register(PhpElementsUtil.getParameterListArrayValuePattern(), psiElement -> { PsiElement context = psiElement.getContext(); if (!(context instanceof StringLiteralExpression)) { return null; } MethodMatcher.MethodMatchParameter methodMatchParameter = new MethodMatcher.ArrayParameterMatcher(context, 0) .withSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "findOneBy") .withSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "findBy") .match(); if(methodMatchParameter != null) { MethodReference methodReference = methodMatchParameter.getMethodReference(); // extract from type provide on completion: // $foo->getRepository('MODEL')->findBy() Collection<PhpClass> phpClasses = PhpElementsUtil.getClassFromPhpTypeSetArrayClean(psiElement.getProject(), methodReference.getType().getTypes()); // resolve every direct repository instance $this->findBy() // or direct repository instance $repository->findBy() if(phpClasses.size() == 0) { PhpExpression classReference = methodReference.getClassReference(); if(classReference != null) { PhpType type = classReference.getType(); for (String s : type.getTypes()) { // dont visit type providers if(PhpType.isUnresolved(s)) { continue; } for (DoctrineModelInterface doctrineModel : DoctrineMetadataUtil.findMetadataModelForRepositoryClass(psiElement.getProject(), s)) { phpClasses.addAll(PhpElementsUtil.getClassesInterface(psiElement.getProject(), doctrineModel.getClassName())); } } } } if(phpClasses.size() == 0) { return null; } return new MyArrayFieldMetadataGotoCompletionRegistrar(psiElement, phpClasses); } return null; }); } private static class MyArrayFieldMetadataGotoCompletionRegistrar extends GotoCompletionProvider { @NotNull private final Collection<PhpClass> phpClasses; MyArrayFieldMetadataGotoCompletionRegistrar(@NotNull PsiElement element, @NotNull Collection<PhpClass> phpClasses) { super(element); this.phpClasses = phpClasses; } @NotNull @Override public Collection<LookupElement> getLookupElements() { List<LookupElement> results = new ArrayList<>(); phpClasses.forEach(phpClass -> results.addAll(EntityHelper.getModelFields(phpClass).stream() .map((Function<DoctrineModelField, LookupElement>) DoctrineModelFieldLookupElement::new) .collect(Collectors.toList()) ) ); return results; } @NotNull @Override public Collection<PsiElement> getPsiTargets(PsiElement element) { String content = GotoCompletionUtil.getTextValueForElement(element); if(content == null) { return Collections.emptyList(); } Collection<PsiElement> results = new ArrayList<>(); phpClasses.forEach(phpClass -> results.addAll(Arrays.asList(EntityHelper.getModelFieldTargets(phpClass, content))) ); return results; } } }