package com.cedricziel.idea.typo3.psi;

import com.intellij.patterns.PlatformPatterns;
import com.intellij.patterns.PsiElementPattern;
import com.intellij.psi.PsiElement;
import com.jetbrains.php.PhpIndex;
import com.jetbrains.php.lang.parser.PhpElementTypes;
import com.jetbrains.php.lang.patterns.PhpPatterns;
import com.jetbrains.php.lang.psi.elements.ClassReference;
import com.jetbrains.php.lang.psi.elements.MethodReference;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class PhpElementsUtil {
    public static boolean isMethodWithFirstStringOrFieldReference(PsiElement psiElement, String... methodName) {
        if (!PlatformPatterns
                .psiElement(PhpElementTypes.METHOD_REFERENCE)
                .withChild(PlatformPatterns
                        .psiElement(PhpElementTypes.PARAMETER_LIST)
                        .withFirstChild(PlatformPatterns.or(
                                PlatformPatterns.psiElement(PhpElementTypes.STRING),
                                PlatformPatterns.psiElement(PhpElementTypes.FIELD_REFERENCE),
                                PlatformPatterns.psiElement(PhpElementTypes.CLASS_CONSTANT_REFERENCE)
                        ))
                ).accepts(psiElement)) {

            return false;
        }

        // cant we move it up to PlatformPatterns? withName condition dont looks working
        String methodRefName = ((MethodReference) psiElement).getName();

        return null != methodRefName && Arrays.asList(methodName).contains(methodRefName);
    }

    public static boolean extendsClass(PhpClass subject, PhpClass extendedClass) {

        List<ClassReference> classReferences = allExtendedClasses(subject)
                .stream()
                .map(e -> (ClassReference) e.getReference())
                .collect(Collectors.toList());

        return classReferences.contains((ClassReference) extendedClass.getReference());
    }

    public static List<PhpClass> allExtendedClasses(PhpClass phpClass) {
        List<PhpClass> classReferences = new ArrayList<>();
        PhpIndex index = PhpIndex.getInstance(phpClass.getProject());

        List<ClassReference> referenceElements = phpClass.getExtendsList().getReferenceElements();
        for (ClassReference reference : referenceElements) {
            Collection<PhpClass> classesByFQN = index.getClassesByFQN(reference.getFQN());
            for (PhpClass phpClass1 : classesByFQN) {
                classReferences.add(phpClass);
                classReferences.addAll(allExtendedClasses(phpClass1));
            }
        }

        return classReferences;
    }

    public static PsiElementPattern.Capture<PsiElement> isStringArrayValue() {

        return PhpPatterns.psiElement()
                .withParent(
                        PlatformPatterns.psiElement(StringLiteralExpression.class)
                                .withParent(PlatformPatterns.psiElement(PhpElementTypes.ARRAY_VALUE))
                );
    }
}

@@ -348,30 +348,17 @@
 lements.
-ClassReference
+*
 ;%0Aimport
@@ -350,35 +350,35 @@
 ments.*;%0Aimport 
-com
+org
 .jetbrains.php.l
@@ -376,166 +376,28 @@
 ins.
-php.lang.psi.elements.MethodReference;%0Aimport com.jetbrains.php.lang.psi.elements.PhpClass;%0Aimport com.jetbrains.php.lang.psi.elements.StringLiteralExpression
+annotations.Nullable
 ;%0A%0Ai
@@ -3032,11 +3032,585 @@
 );%0A    %7D
+%0A%0A    @Nullable%0A    public static String extractArrayIndexFromValue(PsiElement element) %7B%0A        PsiElement arrayElement = element.getParent().getParent().getParent();%0A        if (arrayElement instanceof ArrayHashElement) %7B%0A            ArrayHashElement arrayHashElement = (ArrayHashElement) arrayElement;%0A            PhpPsiElement keyPsiElement = arrayHashElement.getKey();%0A            if (keyPsiElement instanceof StringLiteralExpression) %7B%0A                return ((StringLiteralExpression) keyPsiElement).getContents();%0A            %7D%0A        %7D%0A%0A        return null;%0A    %7D
 %0A%7D%0A

Add extractArrayIndexFromValue to PhpElementsUtil