diff --git a/META-INF/plugin.xml b/META-INF/plugin.xml index 40027f0ca..dd608ba88 100644 --- a/META-INF/plugin.xml +++ b/META-INF/plugin.xml @@ -94,6 +94,7 @@ + diff --git a/src/fr/adrienbrault/idea/symfony2plugin/SymfonyInterfacesHelper.java b/src/fr/adrienbrault/idea/symfony2plugin/SymfonyInterfacesHelper.java index 92bf9d223..89e518895 100644 --- a/src/fr/adrienbrault/idea/symfony2plugin/SymfonyInterfacesHelper.java +++ b/src/fr/adrienbrault/idea/symfony2plugin/SymfonyInterfacesHelper.java @@ -26,6 +26,14 @@ public static boolean isTemplatingRenderCall(PsiElement e) { }); } + public static boolean isRepositoryCall(PsiElement e) { + // EntityManager is needed for symfony 2.0? + return isCallTo(e, new String[] { + "\\Doctrine\\ORM\\EntityManager.getRepository", + "\\Doctrine\\Common\\Persistence\\ObjectManager.getRepository" + }); + } + private static boolean isCallTo(PsiElement e, String expectedMethodFQN) { return isCallTo(e, new String[] { expectedMethodFQN }, 1); } diff --git a/src/fr/adrienbrault/idea/symfony2plugin/doctrine/DoctrineEntityReferenceContributor.java b/src/fr/adrienbrault/idea/symfony2plugin/doctrine/DoctrineEntityReferenceContributor.java new file mode 100644 index 000000000..a69c56d3c --- /dev/null +++ b/src/fr/adrienbrault/idea/symfony2plugin/doctrine/DoctrineEntityReferenceContributor.java @@ -0,0 +1,45 @@ +package fr.adrienbrault.idea.symfony2plugin.doctrine; + +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.*; +import com.intellij.util.ProcessingContext; +import com.jetbrains.php.lang.psi.elements.MethodReference; +import com.jetbrains.php.lang.psi.elements.ParameterList; +import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; +import fr.adrienbrault.idea.symfony2plugin.SymfonyInterfacesHelper; +import org.jetbrains.annotations.NotNull; + +/** + * @author Daniel Espendiller + */ +public class DoctrineEntityReferenceContributor extends PsiReferenceContributor { + + @Override + public void registerReferenceProviders(PsiReferenceRegistrar psiReferenceRegistrar) { + psiReferenceRegistrar.registerReferenceProvider( + PlatformPatterns.psiElement(StringLiteralExpression.class), + new PsiReferenceProvider() { + @NotNull + @Override + public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) { + if (!(psiElement.getContext() instanceof ParameterList)) { + return new PsiReference[0]; + } + ParameterList parameterList = (ParameterList) psiElement.getContext(); + + if (!(parameterList.getContext() instanceof MethodReference)) { + return new PsiReference[0]; + } + MethodReference method = (MethodReference) parameterList.getContext(); + + if (!SymfonyInterfacesHelper.isRepositoryCall(method)) { + return new PsiReference[0]; + } + + return new PsiReference[]{ new EntityReference((StringLiteralExpression) psiElement) }; + } + } + ); + } + +} diff --git a/src/fr/adrienbrault/idea/symfony2plugin/doctrine/EntityHelper.java b/src/fr/adrienbrault/idea/symfony2plugin/doctrine/EntityHelper.java new file mode 100644 index 000000000..388db0ac4 --- /dev/null +++ b/src/fr/adrienbrault/idea/symfony2plugin/doctrine/EntityHelper.java @@ -0,0 +1,65 @@ +package fr.adrienbrault.idea.symfony2plugin.doctrine; + +import com.intellij.openapi.project.Project; +import com.jetbrains.php.PhpIndex; +import com.jetbrains.php.lang.psi.elements.PhpClass; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Daniel Espendiller + */ +public class EntityHelper { + + /** + * + * @param project PHPStorm projects + * @param shortcutName name as MyBundle\Entity\Model or MyBundle:Model + * @return null|PhpClass + */ + public static PhpClass resolveShortcutName(Project project, String shortcutName) { + + PhpIndex phpIndex = PhpIndex.getInstance(project); + Collection phpClasses = phpIndex.getAllSubclasses("\\Symfony\\Component\\HttpKernel\\Bundle\\Bundle"); + + Map bundlesDirectories = new HashMap(); + for (PhpClass phpClass : phpClasses) { + bundlesDirectories.put(phpClass.getName(), phpClass.getNamespaceName()); + } + + String entity_name = null; + + // resolve: + // MyBundle:Model -> MyBundle\Entity\Model + // MyBundle:Folder\Model -> MyBundle\Entity\Folder\Model + if (shortcutName.contains(":")) { + + int firstDirectorySeparatorIndex = shortcutName.indexOf(":"); + + String bundlename = shortcutName.substring(0, firstDirectorySeparatorIndex); + String entityName = shortcutName.substring(firstDirectorySeparatorIndex + 1); + + String namespace = bundlesDirectories.get(bundlename); + + if(namespace == null) { + return null; + } + + entity_name = namespace + "Entity\\" + entityName; + + } else { + entity_name = shortcutName; + } + + // dont we have any unique class getting method here? + Collection entity_classes = phpIndex.getClassesByFQN(entity_name); + if(!entity_classes.isEmpty()){ + return entity_classes.iterator().next(); + } + + return null; + } + +} diff --git a/src/fr/adrienbrault/idea/symfony2plugin/doctrine/EntityReference.java b/src/fr/adrienbrault/idea/symfony2plugin/doctrine/EntityReference.java new file mode 100644 index 000000000..09870f95d --- /dev/null +++ b/src/fr/adrienbrault/idea/symfony2plugin/doctrine/EntityReference.java @@ -0,0 +1,78 @@ +package fr.adrienbrault.idea.symfony2plugin.doctrine; + +import com.intellij.psi.*; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.psi.PsiElement; +import com.jetbrains.php.PhpIndex; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import com.jetbrains.php.lang.psi.elements.PhpNamespace; +import com.jetbrains.php.lang.psi.elements.StringLiteralExpression; +import fr.adrienbrault.idea.symfony2plugin.doctrine.dict.DoctrineEntityLookupElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Daniel Espendiller + */ +public class EntityReference extends PsiReferenceBase implements PsiReference { + private String entityName; + + public EntityReference(@NotNull StringLiteralExpression element) { + super(element); + + entityName = element.getText().substring( + element.getValueRange().getStartOffset(), + element.getValueRange().getEndOffset() + ); + } + + @Nullable + @Override + public PsiElement resolve() { + + PhpClass entity = EntityHelper.resolveShortcutName(getElement().getProject(), this.entityName); + if(entity != null) { + return new PsiElementResolveResult(entity).getElement(); + } + + return null; + } + + @NotNull + @Override + public Object[] getVariants() { + + PhpIndex phpIndex = PhpIndex.getInstance(getElement().getProject()); + Collection phpClasses = phpIndex.getAllSubclasses("\\Symfony\\Component\\HttpKernel\\Bundle\\Bundle"); + + List results = new ArrayList(); + for (PhpClass phpClass : phpClasses) { + + // search for classes that match the symfony2 namings + String ns = phpClass.getNamespaceName() + "Entity"; + Collection entities = phpIndex.getNamespacesByName(ns); + + // @TODO: it looks like PhpIndex cant search for classes like \ns\Path\*\... + // temporary only use flat entities and dont support "MyBundle:Folder\Entity" + for (PhpNamespace entity_files : entities) { + + // build our symfony2 shortcut + System.out.println(entity_files.getContainingFile().getContainingDirectory()); + String filename = entity_files.getContainingFile().getName(); + String className = filename.substring(0, filename.lastIndexOf('.')); + String repoName = phpClass.getName() + ':' + className; + + for (PhpClass entity_phpclass : phpIndex.getClassesByFQN(ns + "\\" + className)) { + results.add(new DoctrineEntityLookupElement(repoName, entity_phpclass)); + } + + } + + } + + return results.toArray(); + } + +} diff --git a/src/fr/adrienbrault/idea/symfony2plugin/doctrine/dict/DoctrineEntityLookupElement.java b/src/fr/adrienbrault/idea/symfony2plugin/doctrine/dict/DoctrineEntityLookupElement.java new file mode 100644 index 000000000..9f5e2278e --- /dev/null +++ b/src/fr/adrienbrault/idea/symfony2plugin/doctrine/dict/DoctrineEntityLookupElement.java @@ -0,0 +1,36 @@ +package fr.adrienbrault.idea.symfony2plugin.doctrine.dict; + +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementPresentation; +import com.jetbrains.php.PhpIcons; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import org.jetbrains.annotations.NotNull; + +/** + * @author Daniel Espendiller + */ +public class DoctrineEntityLookupElement extends LookupElement { + + private String entityName; + private PhpClass className; + + public DoctrineEntityLookupElement(String entityName, PhpClass className) { + this.entityName = entityName; + this.className = className; + } + + @NotNull + @Override + public String getLookupString() { + return entityName; + } + + public void renderElement(LookupElementPresentation presentation) { + presentation.setItemText(getLookupString()); + presentation.setTypeText(className.getPresentableFQN()); + presentation.setTypeGrayed(true); + presentation.setIcon(PhpIcons.CLASS); + } + +} + diff --git a/src/fr/adrienbrault/idea/symfony2plugin/templating/TemplateHelper.java b/src/fr/adrienbrault/idea/symfony2plugin/templating/TemplateHelper.java index 412dedc4f..d220edd0b 100644 --- a/src/fr/adrienbrault/idea/symfony2plugin/templating/TemplateHelper.java +++ b/src/fr/adrienbrault/idea/symfony2plugin/templating/TemplateHelper.java @@ -53,9 +53,13 @@ public static Map getTwigFilesByName(Project project) { String templateDirectory = null; // xxx:XXX:xxx String templateFile = null; // xxx:xxx:XXX if (templatePath.contains("/")) { - int lastDirectorySeparatorIndex = templatePath.lastIndexOf("/"); - templateDirectory = templatePath.substring(0, lastDirectorySeparatorIndex); - templateFile = templatePath.substring(lastDirectorySeparatorIndex + 1); + + // remap twig folder shortcut: + // Folder/Subfolder/file.html.twig -> BundleName:Folder/Subfolder:file.html.twig + + int firstDirectorySeparatorIndex = templatePath.indexOf("/"); + templateDirectory = templatePath.substring(0, firstDirectorySeparatorIndex); + templateFile = templatePath.substring(firstDirectorySeparatorIndex + 1); } else { templateDirectory = ""; templateFile = templatePath;