Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. DocParser.php

function DocParser::Annotation

Same name in this branch
  1. 11.1.x core/lib/Drupal/Component/Annotation/Doctrine/DocParser.php \Drupal\Component\Annotation\Doctrine\DocParser::Annotation()

Annotation ::= "@" AnnotationName MethodCall AnnotationName ::= QualifiedName | SimpleName QualifiedName ::= NameSpacePart "\" {NameSpacePart "\"}* SimpleName NameSpacePart ::= identifier | null | false | true SimpleName ::= identifier | null | false | true

Return value

object|false False if it is not a valid annotation.

Throws

AnnotationException

ReflectionException

2 calls to DocParser::Annotation()
DocParser::Annotations in vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php
Annotations ::= Annotation {[ "*" ]* [Annotation]}*
DocParser::PlainValue in vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php
PlainValue ::= integer | string | float | boolean | Array | Annotation

File

vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php, line 737

Class

DocParser
A parser for docblock annotations.

Namespace

Doctrine\Common\Annotations

Code

private function Annotation() {
    $this->match(DocLexer::T_AT);
    // check if we have an annotation
    $name = $this->Identifier();
    if ($this->lexer
        ->isNextToken(DocLexer::T_MINUS) && $this->lexer
        ->nextTokenIsAdjacent()) {
        // Annotations with dashes, such as "@foo-" or "@foo-bar", are to be discarded
        return false;
    }
    // only process names which are not fully qualified, yet
    // fully qualified names must start with a \
    $originalName = $name;
    if ($name[0] !== '\\') {
        $pos = strpos($name, '\\');
        $alias = $pos === false ? $name : substr($name, 0, $pos);
        $found = false;
        $loweredAlias = strtolower($alias);
        if ($this->namespaces) {
            foreach ($this->namespaces as $namespace) {
                if ($this->classExists($namespace . '\\' . $name)) {
                    $name = $namespace . '\\' . $name;
                    $found = true;
                    break;
                }
            }
        }
        elseif (isset($this->imports[$loweredAlias])) {
            $namespace = ltrim($this->imports[$loweredAlias], '\\');
            $name = $pos !== false ? $namespace . substr($name, $pos) : $namespace;
            $found = $this->classExists($name);
        }
        elseif (!isset($this->ignoredAnnotationNames[$name]) && isset($this->imports['__NAMESPACE__']) && $this->classExists($this->imports['__NAMESPACE__'] . '\\' . $name)) {
            $name = $this->imports['__NAMESPACE__'] . '\\' . $name;
            $found = true;
        }
        elseif (!isset($this->ignoredAnnotationNames[$name]) && $this->classExists($name)) {
            $found = true;
        }
        if (!$found) {
            if ($this->isIgnoredAnnotation($name)) {
                return false;
            }
            throw AnnotationException::semanticalError(sprintf(<<<'EXCEPTION'
The annotation "@%s" in %s was never imported. Did you maybe forget to add a "use" statement for this annotation?
EXCEPTION
, $name, $this->context));
        }
    }
    $name = ltrim($name, '\\');
    if (!$this->classExists($name)) {
        throw AnnotationException::semanticalError(sprintf('The annotation "@%s" in %s does not exist, or could not be auto-loaded.', $name, $this->context));
    }
    // at this point, $name contains the fully qualified class name of the
    // annotation, and it is also guaranteed that this class exists, and
    // that it is loaded
    // collects the metadata annotation only if there is not yet
    if (!isset(self::$annotationMetadata[$name])) {
        $this->collectAnnotationMetadata($name);
    }
    // verify that the class is really meant to be an annotation and not just any ordinary class
    if (self::$annotationMetadata[$name]['is_annotation'] === false) {
        if ($this->isIgnoredAnnotation($originalName) || $this->isIgnoredAnnotation($name)) {
            return false;
        }
        throw AnnotationException::semanticalError(sprintf(<<<'EXCEPTION'
The class "%s" is not annotated with @Annotation.
Are you sure this class can be used as annotation?
If so, then you need to add @Annotation to the _class_ doc comment of "%s".
If it is indeed no annotation, then you need to add @IgnoreAnnotation("%s") to the _class_ doc comment of %s.
EXCEPTION
, $name, $name, $originalName, $this->context));
    }
    
    //if target is nested annotation
    $target = $this->isNestedAnnotation ? Target::TARGET_ANNOTATION : $this->target;
    // Next will be nested
    $this->isNestedAnnotation = true;
    
    //if annotation does not support current target
    if ((self::$annotationMetadata[$name]['targets'] & $target) === 0 && $target) {
        throw AnnotationException::semanticalError(sprintf(<<<'EXCEPTION'
Annotation @%s is not allowed to be declared on %s. You may only use this annotation on these code elements: %s.
EXCEPTION
, $originalName, $this->context, self::$annotationMetadata[$name]['targets_literal']));
    }
    $arguments = $this->MethodCall();
    $values = $this->resolvePositionalValues($arguments, $name);
    if (isset(self::$annotationMetadata[$name]['enum'])) {
        // checks all declared attributes
        foreach (self::$annotationMetadata[$name]['enum'] as $property => $enum) {
            // checks if the attribute is a valid enumerator
            if (isset($values[$property]) && !in_array($values[$property], $enum['value'])) {
                throw AnnotationException::enumeratorError($property, $name, $this->context, $enum['literal'], $values[$property]);
            }
        }
    }
    // checks all declared attributes
    foreach (self::$annotationMetadata[$name]['attribute_types'] as $property => $type) {
        if ($property === self::$annotationMetadata[$name]['default_property'] && !isset($values[$property]) && isset($values['value'])) {
            $property = 'value';
        }
        // handle a not given attribute or null value
        if (!isset($values[$property])) {
            if ($type['required']) {
                throw AnnotationException::requiredError($property, $originalName, $this->context, 'a(n) ' . $type['value']);
            }
            continue;
        }
        if ($type['type'] === 'array') {
            // handle the case of a single value
            if (!is_array($values[$property])) {
                $values[$property] = [
                    $values[$property],
                ];
            }
            // checks if the attribute has array type declaration, such as "array<string>"
            if (isset($type['array_type'])) {
                foreach ($values[$property] as $item) {
                    if (gettype($item) !== $type['array_type'] && !$item instanceof $type['array_type']) {
                        throw AnnotationException::attributeTypeError($property, $originalName, $this->context, 'either a(n) ' . $type['array_type'] . ', or an array of ' . $type['array_type'] . 's', $item);
                    }
                }
            }
        }
        elseif (gettype($values[$property]) !== $type['type'] && !$values[$property] instanceof $type['type']) {
            throw AnnotationException::attributeTypeError($property, $originalName, $this->context, 'a(n) ' . $type['value'], $values[$property]);
        }
    }
    if (self::$annotationMetadata[$name]['has_named_argument_constructor']) {
        if (PHP_VERSION_ID >= 80000) {
            foreach ($values as $property => $value) {
                if (!isset(self::$annotationMetadata[$name]['constructor_args'][$property])) {
                    throw AnnotationException::creationError(sprintf(<<<'EXCEPTION'
The annotation @%s declared on %s does not have a property named "%s"
that can be set through its named arguments constructor.
Available named arguments: %s
EXCEPTION
, $originalName, $this->context, $property, implode(', ', array_keys(self::$annotationMetadata[$name]['constructor_args']))));
                }
            }
            return $this->instantiateAnnotiation($originalName, $this->context, $name, $values);
        }
        $positionalValues = [];
        foreach (self::$annotationMetadata[$name]['constructor_args'] as $property => $parameter) {
            $positionalValues[$parameter['position']] = $parameter['default'];
        }
        foreach ($values as $property => $value) {
            if (!isset(self::$annotationMetadata[$name]['constructor_args'][$property])) {
                throw AnnotationException::creationError(sprintf(<<<'EXCEPTION'
The annotation @%s declared on %s does not have a property named "%s"
that can be set through its named arguments constructor.
Available named arguments: %s
EXCEPTION
, $originalName, $this->context, $property, implode(', ', array_keys(self::$annotationMetadata[$name]['constructor_args']))));
            }
            $positionalValues[self::$annotationMetadata[$name]['constructor_args'][$property]['position']] = $value;
        }
        return $this->instantiateAnnotiation($originalName, $this->context, $name, $positionalValues);
    }
    // check if the annotation expects values via the constructor,
    // or directly injected into public properties
    if (self::$annotationMetadata[$name]['has_constructor'] === true) {
        return $this->instantiateAnnotiation($originalName, $this->context, $name, [
            $values,
        ]);
    }
    $instance = $this->instantiateAnnotiation($originalName, $this->context, $name, []);
    foreach ($values as $property => $value) {
        if (!isset(self::$annotationMetadata[$name]['properties'][$property])) {
            if ($property !== 'value') {
                throw AnnotationException::creationError(sprintf(<<<'EXCEPTION'
The annotation @%s declared on %s does not have a property named "%s".
Available properties: %s
EXCEPTION
, $originalName, $this->context, $property, implode(', ', self::$annotationMetadata[$name]['properties'])));
            }
            // handle the case if the property has no annotations
            $property = self::$annotationMetadata[$name]['default_property'];
            if (!$property) {
                throw AnnotationException::creationError(sprintf('The annotation @%s declared on %s does not accept any values, but got %s.', $originalName, $this->context, json_encode($values)));
            }
        }
        $instance->{$property} = $value;
    }
    return $instance;
}
RSS feed
Powered by Drupal