1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace LaravelUi5\OData\Edm;
6:
7: use LaravelUi5\OData\Edm\Contracts\Annotation\AnnotationInterface;
8: use LaravelUi5\OData\Edm\Vocabularies\VocabularyRegistry;
9:
10: /**
11: * Shared implementation of AnnotatableInterface for readonly Edm classes.
12: *
13: * This trait serves as the canonical AnnotatableTrait described in the
14: * architectural specification. It provides both getAnnotations() and the
15: * alias-resolving getAnnotation() method so that callers may pass either
16: * a fully qualified term name ("Org.OData.Core.V1.Description") or an
17: * alias-qualified term name ("Core.Description") and receive the correct
18: * result.
19: *
20: * Alias resolution is performed via VocabularyRegistry::getInstance(), the
21: * static singleton built from VocabularyCatalog::default(). When the input
22: * term is already fully qualified the singleton returns it unchanged; when
23: * it carries an unknown alias the singleton returns null and the lookup
24: * falls through to null.
25: *
26: * Every class using this trait MUST assign $this->annotations in its
27: * constructor before the property is read.
28: */
29: trait HasAnnotations
30: {
31: /** @var list<AnnotationInterface> */
32: private readonly array $annotations;
33:
34: /** @return list<AnnotationInterface> */
35: public function getAnnotations(): array
36: {
37: return $this->annotations;
38: }
39:
40: public function getAnnotation(string $term, ?string $qualifier = null): ?AnnotationInterface
41: {
42: $resolved = VocabularyRegistry::getInstance()->fullyQualify($term) ?? $term;
43:
44: foreach ($this->annotations as $annotation) {
45: if ($annotation->getTerm() === $resolved && $annotation->getQualifier() === $qualifier) {
46: return $annotation;
47: }
48: }
49: return null;
50: }
51: }
52: