private static Collection<PhpClass> getPhpClassInsideNamespace(
      Project project, PhpIndex phpIndex, String namespaceName, int maxDeep) {

    final Collection<PhpClass> phpClasses = new ArrayList<PhpClass>();

    if (maxDeep-- <= 0) {
      return phpClasses;
    }

    StubIndex.getInstance()
        .process(
            PhpNamespaceIndex.KEY,
            namespaceName.toLowerCase(),
            project,
            phpIndex.getSearchScope(),
            new Processor<PhpNamespace>() {
              @Override
              public boolean process(PhpNamespace phpNamespace) {
                phpClasses.addAll(
                    PsiTreeUtil.getChildrenOfTypeAsList(
                        phpNamespace.getStatements(), PhpClass.class));
                return true;
              }
            });

    for (String ns : phpIndex.getChildNamespacesByParentName(namespaceName + "\\")) {
      phpClasses.addAll(
          getPhpClassInsideNamespace(project, phpIndex, namespaceName + "\\" + ns, maxDeep));
    }

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

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

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

    for (String typeName :
        PhpIndex.getInstance(project)
            .completeType(project, phpType, new HashSet<String>())
            .getTypes()) {
      if (typeName.startsWith("\\")) {

        // we clean array types \Foo[]
        if (typeName.endsWith("[]")) {
          typeName = typeName.substring(0, typeName.length() - 2);
        }

        PhpClass phpClass = PhpElementsUtil.getClassInterface(project, typeName);
        if (phpClass != null) {
          phpClasses.add(phpClass);
        }
      }
    }

    return phpClasses;
  }
  @NotNull
  @Override
  public Collection<PsiElement> getPsiTargets(
      @NotNull SourceContributorDeclarationHandlerParameter parameter) {
    String contents = parameter.getHandlerParameter().getContents();
    if (StringUtils.isBlank(contents)) {
      return Collections.emptyList();
    }

    String sourceParameter = parameter.getSourceParameter();
    if (sourceParameter == null) {
      return Collections.emptyList();
    }

    final Collection<PsiElement> psiElements = new ArrayList<PsiElement>();

    for (PhpClass phpClass :
        PhpIndex.getInstance(parameter.getProject()).getAllSubclasses(sourceParameter)) {
      if (StringUtils.stripStart(contents, "\\")
          .equalsIgnoreCase(StringUtils.stripStart(phpClass.getPresentableFQN(), "\\"))) {
        psiElements.add(phpClass);
      }
    }

    return psiElements;
  }
  @Nullable
  public static String getControllerMethodShortcut(Method method) {

    // indexAction
    String methodName = method.getName();
    if (!methodName.endsWith("Action")) {
      return null;
    }

    PhpClass phpClass = method.getContainingClass();
    if (null == phpClass) {
      return null;
    }

    // defaultController
    // default/Folder/FolderController
    String className = phpClass.getName();
    if (!className.endsWith("Controller")) {
      return null;
    }

    SymfonyBundleUtil symfonyBundleUtil =
        new SymfonyBundleUtil(PhpIndex.getInstance(method.getProject()));
    SymfonyBundle symfonyBundle = symfonyBundleUtil.getContainingBundle(phpClass);
    if (symfonyBundle == null) {
      return null;
    }

    // find the bundle name of file
    PhpClass BundleClass = symfonyBundle.getPhpClass();
    if (null == BundleClass) {
      return null;
    }

    // check if files is in <Bundle>/Controller/*
    if (!phpClass.getNamespaceName().startsWith(BundleClass.getNamespaceName() + "Controller\\")) {
      return null;
    }

    // strip the controller folder name
    String templateFolderName =
        phpClass.getNamespaceName().substring(BundleClass.getNamespaceName().length() + 11);

    // HomeBundle:default:indexes
    // HomeBundle:default/Test:indexes
    templateFolderName = templateFolderName.replace("\\", "/");
    String shortcutName =
        symfonyBundle.getName()
            + ":"
            + templateFolderName
            + className.substring(0, className.lastIndexOf("Controller"))
            + ":"
            + methodName.substring(0, methodName.lastIndexOf("Action"));

    // we should support types later on
    // HomeBundle:default:indexes.html.twig
    return shortcutName + ".html.twig";
  }
  public static Collection<PhpClass> getClassesInterface(
      Project project, @NotNull String className) {

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

    return PhpIndex.getInstance(project).getAnyByFQN(className);
  }
  @Override
  public Collection<? extends PhpNamedElement> getBySignature(String expression, Project project) {

    // get back our original call
    int endIndex = expression.lastIndexOf(TRIM_KEY);
    if (endIndex == -1) {
      return Collections.emptySet();
    }

    String originalSignature = expression.substring(0, endIndex);
    String parameter = expression.substring(endIndex + 1);

    // search for called method
    PhpIndex phpIndex = PhpIndex.getInstance(project);
    Collection<? extends PhpNamedElement> phpNamedElementCollections =
        phpIndex.getBySignature(originalSignature, null, 0);
    if (phpNamedElementCollections.size() == 0) {
      return Collections.emptySet();
    }

    PhpNamedElement phpNamedElement = phpNamedElementCollections.iterator().next();
    if (!(phpNamedElement instanceof Method)) {
      return Arrays.asList(phpNamedElement);
    }

    if (!new Symfony2InterfacesUtil()
        .isCallTo(
            (Method) phpNamedElement, "\\Doctrine\\Common\\Persistence\\ObjectManager", "find")) {
      return phpNamedElementCollections;
    }

    parameter = PhpTypeProviderUtil.getResolvedParameter(phpIndex, parameter);
    if (parameter == null) {
      return phpNamedElementCollections;
    }

    PhpClass phpClass = EntityHelper.resolveShortcutName(project, parameter);
    if (phpClass == null) {
      return phpNamedElementCollections;
    }

    return Arrays.asList(phpClass);
  }
  public static PsiElement[] getPsiElementsBySignature(
      Project project, @Nullable String signature) {

    if (signature == null) {
      return new PsiElement[0];
    }

    Collection<? extends PhpNamedElement> phpNamedElementCollections =
        PhpIndex.getInstance(project).getBySignature(signature, null, 0);
    return phpNamedElementCollections.toArray(new PsiElement[phpNamedElementCollections.size()]);
  }
  private void parseTypes2(
      Map<String, Collection<String>> map, Iterable<ArrayHashElement> elements, String parent) {
    Collection<String> types = map.get(parent);
    if (types == null) {
      types = new ArrayList<String>();
      map.put(parent, types);
    }

    for (ArrayHashElement element : elements) {
      PhpPsiElement key = element.getKey();
      if (key instanceof StringLiteralExpression) {
        // key
        String keyName = ((StringLiteralExpression) key).getContents();
        types.add(keyName);

        String fullKeyName = parent.length() > 0 ? (parent + "." + keyName) : keyName;

        // value
        PhpPsiElement val = element.getValue();
        if (val instanceof ArrayCreationExpression) { // recursive
          Iterable<ArrayHashElement> subElements =
              ((ArrayCreationExpression) val).getHashElements();
          parseTypes2(map, subElements, fullKeyName);

        } else if (val instanceof FieldReference) { // reference to a field, where it's defined
          String classFqn = ((ClassReference) ((FieldReference) val).getClassReference()).getFQN();
          for (PhpClass phpClass :
              PhpIndex.getInstance(element.getProject()).getClassesByFQN(classFqn)) {
            Field field = phpClass.findFieldByName(((FieldReference) val).getNameCS(), false);
            if (field.getDefaultValue() instanceof ArrayCreationExpression) {
              Iterable<ArrayHashElement> subElements =
                  ((ArrayCreationExpression) field.getDefaultValue()).getHashElements();
              parseTypes2(map, subElements, fullKeyName);
            }
          }

        } else { // get value type
          parseValueType(val);

          // try annotation
          PsiElement el2 = element;
          while (el2 != null
              && (el2 instanceof LeafPsiElement
                      && ((LeafPsiElement) el2).getElementType() == PhpTokenTypes.opCOMMA
                  || el2 instanceof PsiWhiteSpace)) {
            el2 = el2.getNextSibling();
          }
          if (el2 instanceof PsiComment) {
            System.out.println("Comment for " + fullKeyName + ": " + el2.getText());
          }
        }
      }
    }
  }
  @Nullable
  public static PhpClass getClassInterface(Project project, @NotNull String className) {

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

    Collection<PhpClass> phpClasses = PhpIndex.getInstance(project).getAnyByFQN(className);
    return phpClasses.size() == 0 ? null : phpClasses.iterator().next();
  }
  @Nullable
  public static PhpClass getInterface(PhpIndex phpIndex, String className) {

    // api workaround
    if (!className.startsWith("\\")) {
      className = "\\" + className;
    }

    Collection<PhpClass> classes = phpIndex.getInterfacesByFQN(className);
    return classes.isEmpty() ? null : classes.iterator().next();
  }
    @Override
    protected void addCompletions(
        @NotNull CompletionParameters parameters,
        ProcessingContext processingContext,
        @NotNull CompletionResultSet completionResultSet) {

      if (!Symfony2ProjectComponent.isEnabled(parameters.getPosition())) {
        return;
      }

      PhpIndex phpIndex = PhpIndex.getInstance(parameters.getOriginalFile().getProject());
      for (PhpClass phpClass : phpIndex.getAllSubclasses("\\Doctrine\\ORM\\EntityRepository")) {
        String presentableFQN = phpClass.getPresentableFQN();
        if (presentableFQN != null) {
          completionResultSet.addElement(
              LookupElementBuilder.create(phpClass.getName())
                  .withTypeText(phpClass.getPresentableFQN(), true)
                  .withIcon(phpClass.getIcon()));
        }
      }
    }
  @NotNull
  public static Collection<SymfonyCommand> getCommands(@NotNull Project project) {

    Collection<SymfonyCommand> symfonyCommands = new ArrayList<SymfonyCommand>();

    for (PhpClass phpClass :
        PhpIndex.getInstance(project)
            .getAllSubclasses("\\Symfony\\Component\\Console\\Command\\Command")) {

      if (PhpElementsUtil.isTestClass(phpClass)) {
        continue;
      }

      Method method = phpClass.findOwnMethodByName("configure");
      if (method == null) {
        continue;
      }

      PsiElement[] psiElements =
          PsiTreeUtil.collectElements(
              method,
              new PsiElementFilter() {
                @Override
                public boolean isAccepted(PsiElement psiElement) {
                  return psiElement instanceof MethodReference
                      && "setName".equals(((MethodReference) psiElement).getName());
                }
              });

      for (PsiElement psiElement : psiElements) {

        if (!(psiElement instanceof MethodReference)) {
          continue;
        }

        PsiElement psiMethodParameter =
            PsiElementUtils.getMethodParameterPsiElementAt((MethodReference) psiElement, 0);
        if (psiMethodParameter == null) {
          continue;
        }

        String stringValue = PhpElementsUtil.getStringValue(psiMethodParameter);
        if (stringValue == null) {
          continue;
        }

        symfonyCommands.add(new SymfonyCommand(stringValue, psiElement));
      }
    }

    return symfonyCommands;
  }
  @Nullable
  public static Method getClassMethod(Project project, String phpClassName, String methodName) {

    // we need here an each; because eg Command is non unique because phar file
    for (PhpClass phpClass : PhpIndex.getInstance(project).getClassesByFQN(phpClassName)) {
      Method method = getClassMethod(phpClass, methodName);
      if (method != null) {
        return method;
      }
    }

    return null;
  }
  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;
  }
  @NotNull
  @Override
  public Collection<LookupElement> getLookupElements(
      @NotNull SourceContributorParameter parameter) {
    String sourceParameter = parameter.getSourceParameter();
    if (sourceParameter == null) {
      return Collections.emptyList();
    }

    Collection<LookupElement> lookupElements = new ArrayList<LookupElement>();
    for (PhpClass phpClass :
        PhpIndex.getInstance(parameter.getProject()).getAllSubclasses(sourceParameter)) {
      lookupElements.add(
          LookupElementBuilder.create(phpClass.getPresentableFQN()).withIcon(phpClass.getIcon()));
    }

    return lookupElements;
  }
  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;
  }
  /**
   * we can also pipe php references signatures and resolve them here overwrite parameter to get
   * string value
   */
  @Nullable
  public static String getResolvedParameter(PhpIndex phpIndex, String parameter) {

    // PHP 5.5 class constant: "Class\Foo::class"
    if (parameter.startsWith("#K#C")) {
      // PhpStorm9: #K#C\Class\Foo.class
      if (parameter.endsWith(".class")) {
        return parameter.substring(4, parameter.length() - 6);
      }

      // PhpStorm8: #K#C\Class\Foo.
      // workaround since signature has empty type
      if (parameter.endsWith(".")) {
        return parameter.substring(4, parameter.length() - 1);
      }
    }

    // #K#C\Class\Foo.property
    // #K#C\Class\Foo.CONST
    if (parameter.startsWith("#")) {

      // get psi element from signature
      Collection<? extends PhpNamedElement> signTypes = phpIndex.getBySignature(parameter, null, 0);
      if (signTypes.size() == 0) {
        return null;
      }

      // get string value
      parameter = PhpElementsUtil.getStringValue(signTypes.iterator().next());
      if (parameter == null) {
        return null;
      }
    }

    return parameter;
  }
 private Collection<Variable> getVariables(Project project, String key) {
   return PhpIndex.getInstance(project).getVariablesByName(key);
 }
 /**
  * Collect PhpClass which are inside current namespace and in sub-namespaces
  *
  * @param project current project
  * @param namespaceName namespace name should start with \ and not end with "\"
  * @return classes inside namespace and sub-namespace
  */
 public static Collection<PhpClass> getPhpClassInsideNamespace(
     Project project, String namespaceName) {
   return getPhpClassInsideNamespace(project, PhpIndex.getInstance(project), namespaceName, 10);
 }
  private Map<String, String> findRootDefinition(Collection<MethodReference> methodReferences) {

    Map<String, String> roots = new HashMap<String, String>();

    if (methodReferences.size() == 0) {
      return roots;
    }

    String rootAlias = null;
    String repository = null;

    for (MethodReference methodReference : methodReferences) {
      String methodReferenceName = methodReference.getName();

      // get alias
      // ->createQueryBuilder('test');
      if ("createQueryBuilder".equals(methodReferenceName)) {
        String possibleAlias =
            PhpElementsUtil.getStringValue(
                PsiElementUtils.getMethodParameterPsiElementAt(methodReference, 0));
        if (possibleAlias != null) {
          rootAlias = possibleAlias;
        }
      }

      // find repository class
      // getRepository('Foo')->createQueryBuilder('test');
      if ("getRepository".equals(methodReferenceName)) {
        String possibleRepository =
            PhpElementsUtil.getStringValue(
                PsiElementUtils.getMethodParameterPsiElementAt(methodReference, 0));
        if (possibleRepository != null) {
          repository = possibleRepository;
          PhpClass phpClass = EntityHelper.resolveShortcutName(project, repository);
          if (phpClass != null) {
            repository = phpClass.getPresentableFQN();
          }
        }
      }

      // $qb->from('Foo\Class', 'article')
      if ("from".equals(methodReferenceName)) {
        String table =
            PhpElementsUtil.getStringValue(
                PsiElementUtils.getMethodParameterPsiElementAt(methodReference, 0));
        String alias =
            PhpElementsUtil.getStringValue(
                PsiElementUtils.getMethodParameterPsiElementAt(methodReference, 1));
        if (table != null && alias != null) {
          PhpClass phpClass = EntityHelper.resolveShortcutName(project, table);
          if (phpClass != null) {
            table = phpClass.getPresentableFQN();
          }

          roots.put(table, alias);
        }
      }
    }

    // we have a valid root so add it
    if (rootAlias != null && repository != null) {
      roots.put(repository, rootAlias);
    }

    // we found a alias but not a repository name, so try a scope search if we are inside repository
    // class
    // class implements \Doctrine\Common\Persistence\ObjectRepository, so search for model name of
    // "repositoryClass"
    if (rootAlias != null && repository == null) {
      MethodReference methodReference = methodReferences.iterator().next();
      PhpClass phpClass = PsiTreeUtil.getParentOfType(methodReference, PhpClass.class);
      if (new Symfony2InterfacesUtil()
          .isInstanceOf(phpClass, "\\Doctrine\\Common\\Persistence\\ObjectRepository")) {
        for (DoctrineModel model : EntityHelper.getModelClasses(project)) {
          String className = model.getPhpClass().getPresentableFQN();
          if (className != null) {
            PhpClass resolvedRepoName = EntityHelper.getEntityRepositoryClass(project, className);
            if (PhpElementsUtil.isEqualClassName(resolvedRepoName, phpClass.getPresentableFQN())) {
              roots.put(className, rootAlias);
              return roots;
            }
          }
        }
      }
    }

    // search on PhpTypeProvider
    // $er->createQueryBuilder()
    if (rootAlias != null && repository == null) {
      for (MethodReference methodReference : methodReferences) {
        if ("createQueryBuilder".equals(methodReference.getName())) {
          String signature = methodReference.getSignature();
          int endIndex = signature.lastIndexOf(ObjectRepositoryTypeProvider.TRIM_KEY);
          if (endIndex != -1) {
            String parameter = signature.substring(endIndex + 1);
            int point = parameter.indexOf(".");
            if (point > -1) {
              parameter = parameter.substring(0, point);
              parameter =
                  PhpTypeProviderUtil.getResolvedParameter(
                      PhpIndex.getInstance(project), parameter);
              if (parameter != null) {
                PhpClass phpClass = EntityHelper.resolveShortcutName(project, parameter);
                if (phpClass != null && phpClass.getPresentableFQN() != null) {
                  roots.put(phpClass.getPresentableFQN(), rootAlias);
                  return roots;
                }
              }
            }
          }
        }
      }
    }

    return roots;
  }
 @Nullable
 public static PhpClass getClass(Project project, String className) {
   return getClass(PhpIndex.getInstance(project), className);
 }
 @Nullable
 public static PhpClass getClass(PhpIndex phpIndex, String className) {
   Collection<PhpClass> classes = phpIndex.getClassesByFQN(className);
   return classes.isEmpty() ? null : classes.iterator().next();
 }