private void collectSelects(
      QueryBuilderScopeContext qb, MethodReference methodReference, String name) {

    if (!Arrays.asList("select", "addSelect").contains(name)) {
      return;
    }

    // $qb->select('foo')
    PsiElement psiElement = PsiElementUtils.getMethodParameterPsiElementAt(methodReference, 0);
    String literalValue = PhpElementsUtil.getStringValue(psiElement);
    if (literalValue != null) {
      qb.addSelect(literalValue);
      return;
    }

    // $qb->select(array('foo', 'bar', 'accessoryDetail'))
    if (psiElement instanceof ArrayCreationExpression) {
      for (PsiElement arrayValue :
          PsiElementUtils.getChildrenOfTypeAsList(
              psiElement, PlatformPatterns.psiElement(PhpElementTypes.ARRAY_VALUE))) {
        if (arrayValue.getChildren().length == 1) {
          String arrayValueString = PhpElementsUtil.getStringValue(arrayValue.getChildren()[0]);
          if (arrayValueString != null) {
            qb.addSelect(arrayValueString);
          }
        }
      }
    }
  }
    @Override
    protected void addCompletions(
        @NotNull CompletionParameters parameters,
        ProcessingContext processingContext,
        @NotNull CompletionResultSet completionResultSet) {

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

      PsiElement prevSiblingOfType =
          PsiElementUtils.getPrevSiblingOfType(
              position, YamlElementPatternHelper.getPreviousCommaSibling());
      if (prevSiblingOfType == null) {
        return;
      }

      String service = PsiElementUtils.trimQuote(prevSiblingOfType.getText());
      if (StringUtils.isBlank(service)) {
        return;
      }

      PhpClass phpClass = ServiceUtil.getServiceClass(prevSiblingOfType.getProject(), service);
      if (phpClass == null) {
        return;
      }

      for (Method method : phpClass.getMethods()) {
        if (method.getAccess().isPublic() && !(method.getName().startsWith("__"))) {
          completionResultSet.addElement(new PhpLookupElement(method));
        }
      }
    }
  private void collectJoins(
      QueryBuilderScopeContext qb, MethodReference methodReference, String name) {

    if (!collectJoins
        || !Arrays.asList("join", "leftJoin", "rightJoin", "innerJoin").contains(name)) {
      return;
    }

    String join = PsiElementUtils.getMethodParameterAt(methodReference, 0);
    String alias = PsiElementUtils.getMethodParameterAt(methodReference, 1);
    if (join != null && alias != null) {
      qb.addJoin(alias, new QueryBuilderJoin(join, alias));
    }
  }
  @Nullable
  public static MethodReferenceBag getMethodParameterReferenceBag(
      PsiElement psiElement, int wantIndex) {

    PsiElement variableContext = psiElement.getContext();
    if (!(variableContext instanceof ParameterList)) {
      return null;
    }

    ParameterList parameterList = (ParameterList) variableContext;
    if (!(parameterList.getContext() instanceof MethodReference)) {
      return null;
    }

    ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);
    if (currentIndex == null) {
      return null;
    }

    if (wantIndex >= 0 && currentIndex.getIndex() != wantIndex) {
      return null;
    }

    return new MethodReferenceBag(
        parameterList, (MethodReference) parameterList.getContext(), currentIndex);
  }
  @Nullable
  public static String getArrayHashValue(
      ArrayCreationExpression arrayCreationExpression, String keyName) {
    ArrayHashElement translationArrayHashElement =
        PsiElementUtils.getChildrenOfType(
            arrayCreationExpression,
            PlatformPatterns.psiElement(ArrayHashElement.class)
                .withFirstChild(
                    PlatformPatterns.psiElement(PhpElementTypes.ARRAY_KEY)
                        .withText(
                            PlatformPatterns.string()
                                .oneOf("'" + keyName + "'", "\"" + keyName + "\""))));

    if (translationArrayHashElement == null) {
      return null;
    }

    if (!(translationArrayHashElement.getValue() instanceof StringLiteralExpression)) {
      return null;
    }

    StringLiteralExpression valueString =
        (StringLiteralExpression) translationArrayHashElement.getValue();
    if (valueString == null) {
      return null;
    }

    return valueString.getContents();
  }
 private static void getMethodVars(Set<String> stringSet, Method method) {
   Collection<FieldReference> fieldReferences =
       PsiTreeUtil.collectElementsOfType(method, FieldReference.class);
   for (FieldReference fieldReference : fieldReferences) {
     PsiElement psiVar =
         PsiElementUtils.getChildrenOfType(
             fieldReference, PlatformPatterns.psiElement().withText("vars"));
     if (psiVar != null) {
       getFormViewVarsAttachKeys(stringSet, fieldReference);
     }
   }
 }
  @Nullable
  @Override
  public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int i, Editor editor) {

    if (!Symfony2ProjectComponent.isEnabled(psiElement)) {
      return null;
    }

    // only string values like "foo", foo
    if (!PlatformPatterns.psiElement(YAMLTokenTypes.TEXT)
            .withLanguage(YAMLLanguage.INSTANCE)
            .accepts(psiElement)
        && !PlatformPatterns.psiElement(YAMLTokenTypes.SCALAR_DSTRING)
            .withLanguage(YAMLLanguage.INSTANCE)
            .accepts(psiElement)
        && !PlatformPatterns.psiElement(YAMLTokenTypes.SCALAR_STRING)
            .withLanguage(YAMLLanguage.INSTANCE)
            .accepts(psiElement)) {

      return new PsiElement[] {};
    }

    String psiText = PsiElementUtils.getText(psiElement);
    if (null == psiText || psiText.length() == 0) {
      return new PsiElement[] {};
    }

    List<PsiElement> psiElements = new ArrayList<PsiElement>();

    if (psiText.startsWith("@") && psiText.length() > 1) {
      psiElements.addAll(Arrays.asList((serviceGoToDeclaration(psiElement, psiText.substring(1)))));
    }

    // match: %annotations.reader.class%
    if (psiText.length() > 3 && psiText.startsWith("%") && psiText.endsWith("%")) {
      psiElements.addAll(Arrays.asList((parameterGoToDeclaration(psiElement, psiText))));
    }

    if (psiText.contains("\\")) {
      psiElements.addAll(classGoToDeclaration(psiElement, psiText));
    }

    if (psiText.endsWith(".twig") || psiText.endsWith(".php")) {
      psiElements.addAll(templateGoto(psiElement, psiText));
    }

    if (psiText.matches("^[\\w_.]+") && getGlobalServiceStringPattern().accepts(psiElement)) {
      psiElements.addAll(Arrays.asList((serviceGoToDeclaration(psiElement, psiText))));
    }

    return psiElements.toArray(new PsiElement[psiElements.size()]);
  }
  @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;
  }
  public static int getParameterIndexValue(@Nullable PsiElement parameterListChild) {

    if (parameterListChild == null) {
      return -1;
    }

    ParameterBag parameterBag = PsiElementUtils.getCurrentParameterIndex(parameterListChild);
    if (parameterBag == null) {
      return -1;
    }

    return parameterBag.getIndex();
  }
  private void collectSelectInForm(
      QueryBuilderScopeContext qb, MethodReference methodReference, String name) {

    // $qb->from('foo', 'select')
    if (!"from".equals(name)) {
      return;
    }

    PsiElement psiElement = PsiElementUtils.getMethodParameterPsiElementAt(methodReference, 1);
    String literalValue = PhpElementsUtil.getStringValue(psiElement);
    if (literalValue != null) {
      qb.addSelect(literalValue);
    }
  }
  private void collectParameter(
      QueryBuilderScopeContext qb, MethodReference methodReference, String name) {

    if (!collectParameter || !Arrays.asList("where", "andWhere").contains(name)) {
      return;
    }

    String value = PsiElementUtils.getMethodParameterAt(methodReference, 0);
    if (value != null) {
      Matcher matcher = Pattern.compile(":(\\w+)", Pattern.MULTILINE).matcher(value);
      while (matcher.find()) {
        qb.addParameter(matcher.group(1));
      }
    }
  }
  private static void addYamlClassMethods(
      @Nullable PsiElement psiElement, CompletionResultSet completionResultSet, String classTag) {

    if (psiElement == null) {
      return;
    }

    YAMLKeyValue classKeyValue =
        PsiElementUtils.getChildrenOfType(
            psiElement, PlatformPatterns.psiElement(YAMLKeyValue.class).withName(classTag));
    if (classKeyValue == null) {
      return;
    }

    PhpClass phpClass =
        ServiceUtil.getResolvedClassDefinition(
            psiElement.getProject(), classKeyValue.getValueText());
    if (phpClass != null) {
      PhpElementsUtil.addClassPublicMethodCompletion(completionResultSet, phpClass);
    }
  }
  public static boolean isCallToWithParameter(
      PsiElement psiElement, String className, String methodName, int parameterIndex) {
    if (!(psiElement.getContext() instanceof ParameterList)) {
      return false;
    }

    ParameterList parameterList = (ParameterList) psiElement.getContext();
    if (parameterList == null || !(parameterList.getContext() instanceof MethodReference)) {
      return false;
    }

    MethodReference method = (MethodReference) parameterList.getContext();
    Symfony2InterfacesUtil interfacesUtil = new Symfony2InterfacesUtil();
    if (!interfacesUtil.isCallTo(method, className, methodName)) {
      return false;
    }

    ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);
    if (currentIndex == null || currentIndex.getIndex() != parameterIndex) {
      return false;
    }

    return true;
  }
  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;
  }