Resolve the object type for given object instance when object use polymorphic definitions

@param Endpoint                       $endpoint
@param PolymorphicDefinitionInterface $definition
@param mixed                          $object

@return null|string
434209
public static function resolveConcreteType(Endpoint $endpoint, PolymorphicDefinitionInterface $definition, $object)
    {
        //if discriminator map is set is used to get the value type
        if ($map = $definition->getDiscriminatorMap()) {
            //get concrete type based on property
            if ($definition->getDiscriminatorProperty()) {
                $property = $definition->getDiscriminatorProperty();
                $accessor = new PropertyAccessor();
                $propValue = $accessor->getValue($object, $property);
                $resolvedType = $map[$propValue] ?? null;
            }

            //get concrete type based on class
            if (!$resolvedType) {
                $class = DoctrineClassUtils::getClass($object);
                $resolvedType = $map[$class] ?? null;
            }
        }

        //final solution in case of not mapping is guess type based on class
        if (!$resolvedType && $definition instanceof InterfaceDefinition) {
            foreach ($definition->getImplementors() as $implementor) {
                $implementorDef = $endpoint->getType($implementor);
                if ($implementorDef instanceof ClassAwareDefinitionInterface
                    && $implementorDef->getClass() === DoctrineClassUtils::getClass($object)) {
                    $resolvedType = $implementorDef->getName();
                }
            }
        }

        if ($endpoint->hasType($resolvedType)) {
            $resolvedTypeDefinition = $endpoint->getType($resolvedType);
            if ($resolvedTypeDefinition instanceof PolymorphicDefinitionInterface) {
                $resolvedType = self::resolveConcreteType($endpoint, $resolvedTypeDefinition, $object);
            }
        }

        return $resolvedType;
    }
964036
protected function configureAuthenticationEndpoint(EndpointInterface $Endpoint)
    {
        $data = $this->credentials;
        $data['grant_type'] = static::$_DEFAULT_GRANT_TYPE;
        return $Endpoint->setData($data);
    }
956849
private function getOrCreateEndpoint($endpoint)
    {
        if (!array_key_exists($endpoint, $this->endpoints)) {
            if (!array_key_exists($endpoint, self::$endpointClassMap)) {
                throw new \Exception(sprintf('Unknown endpoint "%s"', $endpoint));
            }

            $endpointClass = self::$endpointClassMap[$endpoint];
            $this->endpoints[$endpoint] = $this->createEndpoint($endpointClass);
        }

        return $this->endpoints[$endpoint];
    }
317608
protected function _injectMethodsAndProperties(
        DefinitionInterface $definition, $instance)
    {
        $classReflection = new ReflectionClass($instance);

        /** @var ObjectDefinition $definition */

        // Property injections
        foreach ($definition->getProperties() as $property)
        {
            $this->_propertyInjection($instance, $property, $classReflection);
        }

        // Method injections
        foreach ($definition->getMethods() as $method) {
            $this->_methodInjection($instance, $method, $classReflection);
        }
    }
126302
private function resolve($reflection, Type $type = null)
    {
        if ($type === null) {
            return null;
        }

        if (
            method_exists($reflection, 'getDeclaringClass') && (
                $type instanceof This ||
                $type instanceof Self_ ||
                $type instanceof Static_ ||
                $type instanceof Parent_
            )
        ) {
            $class = $reflection->getDeclaringClass()->getName();

            if ($type instanceof Parent_) {
                $class = get_parent_class($class) ?: $class;
            }

            return new Object_(new Fqsen('\\' . $class));
        }

        return $type;
    }
636182
public static function fromEndpoint(Endpoint $endpoint)
    {
        return static::generateKey(strtolower($endpoint->getRegion()->getDomain()).$endpoint->getUrl());
    }
599875
public static function fromRequest(RequestInterface $request)
    {
        if ($request->hasHeader('X-Endpoint')) {
            $name = $request->getHeaderLine('X-Endpoint');
            
            if (! isset(BaseApi::$endpointDefinitions[$name])) {
                throw new \InvalidArgumentException('Could not resolve Endpoint from the request: \n'.$request->getRequestTarget());
            }
            
            /** @var BaseEndpoint $endpointClass */
            $endpointClass = BaseApi::$endpointDefinitions[$name]['class'];

            return new $endpointClass(Region::create($request->getHeaderLine('X-Region')));
        }
        
        $matchingScore = -1;
        /** @var Endpoint $endpointInstance */
        $endpointInstance = null;

        foreach (BaseApi::$endpointDefinitions as $urlTemplate => $definition) {
            $score = levenshtein($request->getRequestTarget(), $urlTemplate);
            if ($score > $matchingScore) {
                $matchingScore = $score;
                $endpointInstance = $definition['instance'];
            }
        }
        
        return $endpointInstance;
    }
664380
public function getEndpointSchema($endpoint, $forceReload = false)
    {
        $this->loadApiDefinition($forceReload);

        return $this->definition->getSchema($endpoint);
    }
767626
public function requestEndpoint(AbstractEndpoint $endpoint)
    {
        return $this->request(
            \ltrim($endpoint->getURI(), '/'),
            $endpoint->getMethod(),
            null === $endpoint->getBody() ? [] : $endpoint->getBody(),
            $endpoint->getParams()
        );
    }
625037
public function setDefinition(ExecutableDefinitionInterface $definition): ContextBuilder
    {
        $this->definition = $definition;

        $type = null;
        if ($definition instanceof NodeAwareDefinitionInterface && $definition->getNode()) {
            $type = $definition->getNode();
        }

        if (!$type) {
            $type = $definition->getType();
        }

        if ($this->endpoint->hasType($type)
            && ($nodeDefinition = $this->endpoint->getType($type))
            && ($nodeDefinition instanceof ObjectDefinition || $nodeDefinition instanceof InterfaceDefinition)) {
            $this->node = $nodeDefinition;
        }

        return $this;
    }
295194
public function parse($annotation, \ReflectionClass $refClass, Endpoint $endpoint)
    {
        $query = new QueryDefinition();

        if ($annotation->name) {
            $query->setName($annotation->name);
        } else {
            $query->setName(lcfirst(ClassUtils::getDefaultName($refClass->getName())));
        }

        $endpoint->addQuery($query);

        if ($annotation->type) {
            $type = TypeUtil::normalize($annotation->type);
            if (class_exists($annotation->type)) {
                $type = $endpoint->getTypeForClass($annotation->type);
            }
            if ($endpoint->hasType($type)) {
                $query->setNode($type);
            }
            $query->setType($type);
        }

        $query->setList(TypeUtil::isTypeList($annotation->type));
        $query->setNonNull(TypeUtil::isTypeNonNull($annotation->type));
        $query->setNonNullList(TypeUtil::isTypeNonNullList($annotation->type));

        if (!$query->getType()) {
            $nodeType = ClassUtils::getNodeFromClass($refClass->getName());
            $objectDefinition = null;
            if ($nodeType && $endpoint->hasType($nodeType)) {
                $objectDefinition = $endpoint->getType($nodeType);
            }
            if ($objectDefinition) {
                $query->setType($objectDefinition->getName());
                $query->setNode($objectDefinition->getName());
            } else {
                //avoid throw Exception when the schema is empty
                //when the schema is empty the NodeInterface has not been loaded
                //then the node(id) and nodes(ids) queries fails
                if ('Node' === $nodeType) {
                    $endpoint->removeQuery($query->getName());

                    return;
                }

                $error = sprintf('Does not exist any valid type for class "%s"', $refClass->getName());
                throw new \RuntimeException($error);
            }
        }

        if ($annotation->arguments) {
            foreach ($annotation->arguments as $argAnnotation) {
                if ($argAnnotation instanceof Annotation\Argument) {
                    $this->resolveArgument($query, $argAnnotation);
                }
            }
        } else {
            $argAnnotations = $this->reader->getClassAnnotations($refClass);
            foreach ($argAnnotations as $argAnnotation) {
                if ($argAnnotation instanceof Annotation\Argument) {
                    $this->resolveArgument($query, $argAnnotation);
                }
            }
        }

        $query->setResolver($annotation->resolver ?? $refClass->getName());
        $query->setDeprecationReason($annotation->deprecationReason);
        $query->setDescription($annotation->description);

        foreach ($annotation->options as $option => $value) {
            $query->setMeta($option, $value);
        }
    }
314075
private function resolve(Definition $definition)
    {
        if(!$this->container->isFrozen()) {
            throw new \LogicException("cannot use create method on factory without freezing/compiling container");
        }
        $subContainer = new ContainerBuilder();
        $subContainer->merge($this->container);
        $subContainer->setDefinition("__tmp__", $definition);
        $subContainer->compile();
        $obj = $subContainer->get("__tmp__");
        return $obj;
    }
241553
public function parse($annotation, \ReflectionClass $refClass, Endpoint $endpoint)
    {
        /** @var Annotation\Subscription $annotation */

        if (!preg_match('/\\Subscription\\\\/', $refClass->getName())) {
            $error = sprintf(
                'Annotation "@Subscription" in the class "%s" is not valid, 
            mutations can only be applied to classes inside "...Bundle\Subscription\..."',
                $refClass->getName()
            );
            throw new \RuntimeException($error);
        }

        if (!$annotation->resolver && !$refClass->hasMethod('__invoke')) {
            $error = sprintf(
                'The class "%s" should have a method "__invoke" to process the subscription.',
                $refClass->getName()
            );
            throw new \RuntimeException($error);
        }

        $subscription = new SubscriptionDefinition();
        $subscription->setType(TypeUtil::normalize($annotation->payload));

        if ($annotation->name) {
            $subscription->setName($annotation->name);
        } else {
            $subscription->setName(lcfirst(ClassUtils::getDefaultName($refClass->getName())));
        }

        if (!$subscription->getType()) {
            $nodeType = ClassUtils::getNodeFromClass($refClass->getName());
            $objectDefinition = null;
            if ($nodeType && $endpoint->hasType($nodeType)) {
                $objectDefinition = $endpoint->getType($nodeType);
            }
            if ($objectDefinition) {
                $subscription->setType($objectDefinition->getName());
                $subscription->setNode($objectDefinition->getName());
            } else {
                $error = sprintf('Does not exist any valid type for class "%s"', $refClass->getName());
                throw new \RuntimeException($error);
            }
        }

        $endpoint->addSubscription($subscription);

        if (!$annotation->payload) {
            if (class_exists($refClass->getName().'Payload')) {
                $annotation->payload = $refClass->getName().'Payload';
                if (!$endpoint->hasTypeForClass($annotation->payload)) {
                    $error = sprintf(
                        'The payload "%s" exist but does not exist a valid GraphQL type, is missing ObjectType annotation?',
                        $annotation->payload
                    );
                    throw new \RuntimeException($error);
                }
            }
        }

        // create subscription event
        $subscriptionEvent = new ObjectDefinition();
        $subscriptionEvent->setName(ucfirst($subscription->getName()).'Event');
        $field = new FieldDefinition();
        $field->setName($annotation->fieldName ?? 'data');
        $field->setDescription($annotation->fieldDescription ?? null);
        $field->setType($subscription->getType());
        $field->setNode($subscription->getNode());
        $field->setNonNull(TypeUtil::isTypeNonNull($annotation->payload));
        $field->setList(TypeUtil::isTypeList($annotation->payload));
        $field->setNonNullList(TypeUtil::isTypeNonNullList($annotation->payload));
        $subscriptionEvent->addField($field);
        $endpoint->addType($subscriptionEvent);

        // subscription response is a union between SubscriptionLink object and specific Subscription Event
        $subscriptionResponse = new UnionDefinition();
        $subscriptionResponse->setName(ucfirst($subscription->getName()).'Subscription');
        $subscriptionResponse->addType(new UnionTypeDefinition($subscriptionEvent->getName()));
        $subscriptionResponse->addType(new UnionTypeDefinition($endpoint->getTypeForClass(SubscriptionLink::class)));
        $endpoint->addType($subscriptionResponse);
        $subscription->setType(TypeUtil::normalize($subscriptionResponse->getName()));

        if (!$subscription->getType()) {
            $error = sprintf(
                'The subscription "%s" does not have a valid payload,
                 create a file called %sPayload or specify a payload.',
                $subscription->getName(),
                $refClass->getName()
            );
            throw new \RuntimeException($error);
        }

        $argAnnotations = $this->reader->getClassAnnotations($refClass);
        foreach ($argAnnotations as $argAnnotation) {
            if ($argAnnotation instanceof Annotation\Argument) {
                $this->resolveArgument($subscription, $argAnnotation);
            }
        }

        if ($annotation->node) {
            $subscription->setNode($annotation->node);
        } elseif (($node = ClassUtils::getNodeFromClass($refClass->getName())) && $endpoint->hasType($node)) {
            $subscription->setNode($node);
        }

        $subscription->setResolver($annotation->resolver ?? $refClass->getName());
        $subscription->setDeprecationReason($annotation->deprecationReason);
        $subscription->setDescription($annotation->description);

        foreach ($annotation->options as $option => $value) {
            $subscription->setMeta($option, $value);
        }
    }
777573
protected function _resolveDefinition(
        DefinitionInterface $definition, array $parameters = [])
    {
        $entryName = $definition->getName();
        $definitionResolver = $this->_getDefinitionResolver($definition);

        try {
            $value = $definitionResolver->resolve($definition, $parameters);
        } catch (\Exception $exception) {
            throw new DependencyException(
                "An error occurred while resolving " .
                "entry '{$entryName}': " . $exception->getMessage(),
                0,
                $exception
            );
        }

        return $value;
    }
863832
public function callEndpoint($endpoint, array $endpointParameters = [], $body = null, $method = HttpMethod::REQUEST_GET)
    {
        // Set the endpoint
        $this->setEndpoint($endpoint);
        // Set the parameters
        $this->setEndpointParameters($endpointParameters);
        // Set the body
        $this->setBody($body);
        // Set the HTTP method
        $this->setHttpMethod($method);
        // Call the endpoint
        $this->call();
        // return the result
        return $this->getResult();
    }
73902
protected function configureRefreshEndpoint(EndpointInterface $Endpoint)
    {
        $data = array();
        $data['client_id'] = $this->credentials['client_id'];
        $data['client_secret'] = $this->credentials['client_secret'];
        $data['grant_type'] = self::OAUTH_REFRESH_GRANT;
        $data['refresh_token'] = $this->token['refresh_token'];
        return $Endpoint->setData($data);
    }
566476
public function parseType(Object\TypeObjectInterface $type, $data)
    {
        if($type instanceof Object\ReferentialInterface && $type->hasRef()) {
            $objectType = $type->getRef();
            $type = $this->resolveReference($type);
        } else {
            try {
                $objectType = $type->getType();
            } catch(SwaggerException\MissingDocumentPropertyException $e) {
                $objectType = null;
            }
        }
        
        if($objectType == 'array') {
            $schemaObject = [];
            
            $arrayItemType = $type->getItems();
            
            foreach($data as $key => $value) {
                $schemaObject[$key] = $this->parseType($arrayItemType, $value);
            }
        } elseif($type instanceof Object\Schema) {
            $schemaObject = new SchemaObject($objectType);
        
            foreach(array_keys(get_object_vars($data)) as $propertyKey) {
                try {
                    $propertySchema = $this->findSchemaForProperty($type, $propertyKey);
                } catch(SwaggerException\MissingDocumentPropertyException $e) {
                    throw (new SwaggerException\UndefinedPropertySchemaException)
                        ->setPropertyName($name)
                        ->setSchema($type);
                }
            
                $propertyValue = $this->parseType(
                    $propertySchema,
                    $data->$propertyKey
                );
                
                $schemaObject->setProperty($propertyKey, $propertyValue);
            }
        } else {
            $schemaObject = $data;
        }
        
        return $schemaObject;
    }