public static ArrayList<String> getExtendedTypeClasses(Project project, String... formTypeNames) {

    List<String> formTypeNamesList = Arrays.asList(formTypeNames);

    ArrayList<String> extendedTypeClasses = new ArrayList<String>();

    FormExtensionServiceParser formExtensionServiceParser =
        ServiceXmlParserFactory.getInstance(project, FormExtensionServiceParser.class);
    for (String formClass : formExtensionServiceParser.getFormExtensions().keySet()) {

      PsiElement psiElements[] =
          PhpElementsUtil.getPsiElementsBySignature(
              project, "#M#C\\" + formClass + ".getExtendedType");
      for (PsiElement psiElement : psiElements) {
        PhpReturn phpReturn = PsiTreeUtil.findChildOfType(psiElement, PhpReturn.class);
        if (phpReturn != null) {
          PhpPsiElement returnValue = phpReturn.getFirstPsiChild();
          if (returnValue instanceof StringLiteralExpression
              && formTypeNamesList.contains(
                  ((StringLiteralExpression) returnValue).getContents())) {
            extendedTypeClasses.add(formClass);
          }
        }
      }
    }

    return extendedTypeClasses;
  }
  @Deprecated
  public static PsiElement[] getClassInterfacePsiElements(
      Project project, String FQNClassOrInterfaceName) {

    // convert ResolveResult to PsiElement
    List<PsiElement> results = new ArrayList<PsiElement>();
    for (ResolveResult result : getClassInterfaceResolveResult(project, FQNClassOrInterfaceName)) {
      results.add(result.getElement());
    }

    return results.toArray(new PsiElement[results.size()]);
  }
  public static List<QueryBuilderRelation> attachRelationFields(PhpClass phpClass) {

    List<QueryBuilderRelation> relations = new ArrayList<QueryBuilderRelation>();

    for (DoctrineModelField field : EntityHelper.getModelFields(phpClass)) {
      if (field.getRelation() != null && field.getRelationType() != null) {
        relations.add(new QueryBuilderRelation(field.getName(), field.getRelation()));
      }
    }

    return relations;
  }
  public static List<ResolveResult> getClassInterfaceResolveResult(
      Project project, String fqnClassOrInterfaceName) {

    // api workaround for at least interfaces
    if (!fqnClassOrInterfaceName.startsWith("\\")) {
      fqnClassOrInterfaceName = "\\" + fqnClassOrInterfaceName;
    }

    List<ResolveResult> results = new ArrayList<ResolveResult>();
    for (PhpClass phpClass : PhpIndex.getInstance(project).getAnyByFQN(fqnClassOrInterfaceName)) {
      results.add(new PsiElementResolveResult(phpClass));
    }

    return results;
  }
  public static Collection<PhpClass> getClassFromPhpTypeSet(Project project, Set<String> types) {

    PhpType phpType = new PhpType();
    phpType.add(types);

    List<PhpClass> phpClasses = new ArrayList<PhpClass>();

    for (String typeName :
        PhpIndex.getInstance(project)
            .completeType(project, phpType, new HashSet<String>())
            .getTypes()) {
      if (typeName.startsWith("\\")) {
        PhpClass phpClass = PhpElementsUtil.getClassInterface(project, typeName);
        if (phpClass != null) {
          phpClasses.add(phpClass);
        }
      }
    }

    return phpClasses;
  }
  public QueryBuilderScopeContext collect() {
    QueryBuilderScopeContext qb = new QueryBuilderScopeContext();

    // doctrine needs valid root with an alias, try to find one in method references or scope
    Map<String, String> map = this.findRootDefinition(methodReferences);
    if (map.size() > 0) {
      Map.Entry<String, String> entry = map.entrySet().iterator().next();
      qb.addTable(entry.getKey(), entry.getValue());
    }

    for (MethodReference methodReference : methodReferences) {

      String name = methodReference.getName();
      if (name != null) {
        collectParameter(qb, methodReference, name);
        collectJoins(qb, methodReference, name);
        collectSelects(qb, methodReference, name);
        collectSelectInForm(qb, methodReference, name);
      }
    }

    // first tableMap entry is root, we add several initial data
    if (qb.getTableMap().size() > 0) {
      Map.Entry<String, String> entry = qb.getTableMap().entrySet().iterator().next();
      String className = entry.getKey();
      PhpClass phpClass = PhpElementsUtil.getClassInterface(project, className);

      // add root select fields
      if (phpClass != null) {

        qb.addPropertyAlias(
            entry.getValue(),
            new QueryBuilderPropertyAlias(
                entry.getValue(),
                null,
                new DoctrineModelField(entry.getValue())
                    .addTarget(phpClass)
                    .setTypeName(phpClass.getPresentableFQN())));

        List<QueryBuilderRelation> relationList = new ArrayList<QueryBuilderRelation>();

        // qb.addRelation(entry.getValue(), attachRelationFields(phpClass));
        for (DoctrineModelField field : EntityHelper.getModelFields(phpClass)) {
          qb.addPropertyAlias(
              entry.getValue() + "." + field.getName(),
              new QueryBuilderPropertyAlias(entry.getValue(), field.getName(), field));
          if (field.getRelation() != null && field.getRelationType() != null) {
            relationList.add(new QueryBuilderRelation(field.getName(), field.getRelation()));
          }
        }

        qb.addRelation(entry.getValue(), relationList);
      }

      QueryBuilderRelationClassResolver resolver =
          new QueryBuilderRelationClassResolver(
              project, entry.getValue(), entry.getKey(), qb.getRelationMap(), qb.getJoinMap());
      resolver.collect();
    }

    // we have a querybuilder which complete known elements now
    // se we can builder a property (field) map table from it
    this.buildPropertyMap(qb);

    return qb;
  }