diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5eb5c53
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+out/
+*.jar
diff --git a/META-INF/plugin.xml b/META-INF/plugin.xml
new file mode 100644
index 0000000..b168ad4
--- /dev/null
+++ b/META-INF/plugin.xml
@@ -0,0 +1,44 @@
+
+ cz.matej21.intellij.kdyby.doctrine
+ Kdyby Doctrine support
+ 0.1.0
+ David Matejka
+
+ com.intellij.modules.lang
+ com.jetbrains.php
+
+ Kdyby Doctrine library
+ ]]>
+
+ 0.1.0
+
+ - First proof of concept
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/intellij-kdyby-doctrine.iml b/intellij-kdyby-doctrine.iml
new file mode 100644
index 0000000..b2f3591
--- /dev/null
+++ b/intellij-kdyby-doctrine.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/php-project/doctrine.php b/php-project/doctrine.php
new file mode 100644
index 0000000..421f337
--- /dev/null
+++ b/php-project/doctrine.php
@@ -0,0 +1,63 @@
+fooDao = $entityManager->getDao(FooEntity::class);
+ }
+
+ /**
+ * @return FooEntity|object
+ */
+ public function doSth()
+ {
+ return $this->fooDao->find();
+ }
+}
+
+
+
+/** @var \Kdyby\Doctrine\EntityManager $entityManager */
+$entityDao = $entityManager->getDao(FooEntity::class);
+$entityDao->find()->id;
+
+
+foreach($entityDao->findAll() as $entity) {
+ $entity->id;
+}
+
+$result = $entityDao->fetch();
+$result->applyPaginator();
+foreach($result as $entity) {
+ $entity->id;
+}
\ No newline at end of file
diff --git a/php-project/model.php b/php-project/model.php
new file mode 100644
index 0000000..59a3ec2
--- /dev/null
+++ b/php-project/model.php
@@ -0,0 +1,12 @@
+ getClasses(PhpTypedElement element, Project project) {
+ PhpIndex phpIndex = PhpIndex.getInstance(project);
+ Collection classes = new ArrayList();
+ for (String className : element.getType().getTypes()) {
+ classes.addAll(phpIndex.getClassesByFQN(className));
+ }
+
+ return classes;
+ }
+
+ private class UnresolvableValueException extends Exception {
+ }
+}
+
diff --git a/src/cz/matej21/intellij/kdyby/doctrine/ForeachEntityTypeProvider.java b/src/cz/matej21/intellij/kdyby/doctrine/ForeachEntityTypeProvider.java
new file mode 100644
index 0000000..4e8c53d
--- /dev/null
+++ b/src/cz/matej21/intellij/kdyby/doctrine/ForeachEntityTypeProvider.java
@@ -0,0 +1,68 @@
+package cz.matej21.intellij.kdyby.doctrine;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.php.PhpIndex;
+import com.jetbrains.php.lang.psi.elements.ForeachStatement;
+import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
+import com.jetbrains.php.lang.psi.elements.PhpTypedElement;
+import com.jetbrains.php.lang.psi.elements.Variable;
+import com.jetbrains.php.lang.psi.resolve.types.PhpType;
+import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider2;
+import com.jetbrains.php.lang.psi.resolve.types.PhpTypeSignatureKey;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+
+public class ForeachEntityTypeProvider implements PhpTypeProvider2 {
+
+ @Override
+ public char getKey() {
+ return '\u2102';
+ }
+
+ @Nullable
+ @Override
+ public String getType(PsiElement psiElement) {
+ if (!(psiElement instanceof Variable)) {
+ return null;
+ }
+ Variable variable = (Variable) psiElement;
+ PsiElement arrayAccessExpression = variable.getParent();
+ if (!(arrayAccessExpression instanceof ForeachStatement)) {
+ return null;
+ }
+ ForeachStatement arrayIndex = (ForeachStatement) arrayAccessExpression;
+ PsiElement operation = arrayIndex.getArray();
+ if (!(operation instanceof PhpTypedElement)) {
+ return null;
+ }
+ PhpType value = ((PhpTypedElement) operation).getType();
+ if (variable == arrayIndex.getKey()) {
+ return null;
+ }
+
+ if (variable != arrayIndex.getValue()) {
+ return null;
+ }
+ for (String strType : value.elementType().getTypes()) {
+ if (strType.length() < 2
+ || strType.charAt(0) != '#'
+ || strType.indexOf(RepositoryMethodTypeProvider.KEY) == -1
+ || !strType.contains("[]")) {
+ continue;
+ }
+ if (PhpTypeSignatureKey.ARRAY_ELEMENT.is(strType.charAt(1))) {
+ strType = strType.substring(2);
+ }
+ return strType.substring(strType.indexOf(RepositoryMethodTypeProvider.KEY) + 1, strType.indexOf("[]"));
+ }
+ return null;
+ }
+
+ @Override
+ public Collection extends PhpNamedElement> getBySignature(String s, Project project) {
+ return PhpIndex.getInstance(project).getAnyByFQN(s);
+ }
+}
diff --git a/src/cz/matej21/intellij/kdyby/doctrine/RepositoryMethodTypeProvider.java b/src/cz/matej21/intellij/kdyby/doctrine/RepositoryMethodTypeProvider.java
new file mode 100644
index 0000000..d2f48a9
--- /dev/null
+++ b/src/cz/matej21/intellij/kdyby/doctrine/RepositoryMethodTypeProvider.java
@@ -0,0 +1,87 @@
+package cz.matej21.intellij.kdyby.doctrine;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.php.PhpIndex;
+import com.jetbrains.php.lang.psi.elements.MethodReference;
+import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
+import com.jetbrains.php.lang.psi.elements.PhpTypedElement;
+import com.jetbrains.php.lang.psi.resolve.types.PhpType;
+import com.jetbrains.php.lang.psi.resolve.types.PhpTypeAnalyserVisitor;
+import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider2;
+import com.jetbrains.php.lang.psi.resolve.types.PhpTypeSignatureKey;
+import gnu.trove.THashSet;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+
+public class RepositoryMethodTypeProvider implements PhpTypeProvider2 {
+ public static final char KEY = '\u2101';
+ private static final HashSet singleEntityMethods = new HashSet(Arrays.asList("find", "findOneBy"));
+ private static final HashSet setEntityMethods = new HashSet(Arrays.asList("findAll", "findBy", "fetch"));
+
+
+ @Override
+ public char getKey() {
+ return KEY;
+ }
+
+
+ @Nullable
+ @Override
+ public String getType(PsiElement psiElement) {
+ if (!(psiElement instanceof MethodReference)) {
+ return null;
+ }
+ MethodReference ref = (MethodReference) psiElement;
+ if (!singleEntityMethods.contains(ref.getName()) && !setEntityMethods.contains(ref.getName())) {
+ return null;
+ }
+ if (psiElement.getChildren().length == 0) {
+ return null;
+ }
+ PhpType type = ((PhpTypedElement) psiElement.getChildren()[0]).getType();
+ PhpTypeAnalyserVisitor analyzer = new PhpTypeAnalyserVisitor(0);
+ psiElement.accept(analyzer);
+ for (String strType : type.getTypes()) {
+ if (strType.length() < 2 && strType.charAt(0) == '#' || strType.charAt(1) != RepositoryTypeProvider.KEY) {
+ continue;
+ }
+ String entityType = strType.substring(2, strType.indexOf("."));
+ if (setEntityMethods.contains(ref.getName())) {
+ entityType += "[]";
+ }
+ String originalType = strType.substring(strType.indexOf(".") + 1);
+ if (originalType.contains("|")) {
+ originalType = originalType.substring(0, originalType.indexOf("|"));
+ }
+ if (originalType.charAt(0) == '#') {
+ originalType = "." + PhpTypeSignatureKey.METHOD.sign(originalType + "." + ref.getName());
+ } else {
+ originalType = "";
+ }
+ return entityType + originalType;
+ }
+
+ return null;
+ }
+
+ @Override
+ public Collection extends PhpNamedElement> getBySignature(String s, Project project) {
+ Collection result = new THashSet();
+ PhpIndex phpIndex = PhpIndex.getInstance(project);
+ String entityName = s.substring(0, s.indexOf("."));
+ if (!entityName.endsWith("[]")) {
+ result.addAll(phpIndex.getAnyByFQN(entityName));
+ }
+ String signature = s.substring(s.indexOf(".") + 1);
+ if (signature.contains("|")) {
+ signature = signature.substring(0, signature.indexOf("|"));
+ }
+ result.addAll(phpIndex.getBySignature(signature));
+
+ return result;
+ }
+}
diff --git a/src/cz/matej21/intellij/kdyby/doctrine/RepositoryTypeProvider.java b/src/cz/matej21/intellij/kdyby/doctrine/RepositoryTypeProvider.java
new file mode 100644
index 0000000..29dd549
--- /dev/null
+++ b/src/cz/matej21/intellij/kdyby/doctrine/RepositoryTypeProvider.java
@@ -0,0 +1,70 @@
+package cz.matej21.intellij.kdyby.doctrine;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.php.PhpIndex;
+import com.jetbrains.php.lang.psi.elements.MethodReference;
+import com.jetbrains.php.lang.psi.elements.ParameterList;
+import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
+import com.jetbrains.php.lang.psi.elements.PhpTypedElement;
+import com.jetbrains.php.lang.psi.resolve.types.PhpType;
+import com.jetbrains.php.lang.psi.resolve.types.PhpTypeAnalyserVisitor;
+import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider2;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+
+public class RepositoryTypeProvider implements PhpTypeProvider2 {
+
+ public static final char KEY = '\u2100';
+ private static final PhpType entityManager = new PhpType().add("Kdyby\\Doctrine\\EntityManager").add("Doctrine\\ORM\\EntityManager");
+
+ @Override
+ public char getKey() {
+ return KEY;
+ }
+
+ @Nullable
+ @Override
+ public String getType(PsiElement psiElement) {
+ if (!(psiElement instanceof MethodReference)) {
+ return null;
+ }
+ MethodReference ref = (MethodReference) psiElement;
+ if (ref.getName() == null || (!ref.getName().equals("getDao") && !ref.getName().equals("getRepository"))) {
+ return null;
+ }
+ if (psiElement.getChildren().length == 0) {
+ return null;
+ }
+ PhpType type = ((PhpTypedElement) psiElement.getChildren()[0]).getType();
+ if (!type.isConvertibleFrom(entityManager, PhpIndex.getInstance(psiElement.getProject()))) {
+ return null;
+ }
+ ParameterList list = ref.getParameterList();
+ if (list == null || list.getChildren().length == 0) {
+ return null;
+ }
+ String className = ElementValueResolver.resolve(list.getFirstChild());
+ if (className == null) {
+ return null;
+ }
+
+ PhpTypeAnalyserVisitor analyzer = new PhpTypeAnalyserVisitor(0);
+ psiElement.accept(analyzer);
+ return className + "." + analyzer.getType().toString();
+ }
+
+ @Override
+ public Collection extends PhpNamedElement> getBySignature(String s, Project project) {
+ String signature = s.substring(s.indexOf(".") + 1);
+ if (signature.contains("|")) {
+ signature = signature.substring(0, signature.indexOf("|"));
+ }
+
+ return PhpIndex.getInstance(project).getBySignature(signature);
+ }
+
+
+}