SupportsAnnotations   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 97
Duplicated Lines 0 %

Test Coverage

Coverage 60.38%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 22
eloc 48
c 1
b 0
f 0
dl 0
loc 97
ccs 32
cts 53
cp 0.6038
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A inferValidTypes() 0 5 1
A inferValueFactories() 0 17 5
B getClassAnnotations() 0 17 7
A flatMapTraits() 0 8 2
A inferTypeFactories() 0 19 5
A getInheritance() 0 14 2
1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the daikon-cqrs/interop project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Daikon\Interop;
10
11
use ReflectionClass;
12
13
trait SupportsAnnotations
14
{
15
    protected static function inferValidTypes(): array
16
    {
17
        return array_map(
18
            fn(array $annotation): string => explode('::', $annotation['value'])[0],
19
            static::getClassAnnotations('type')
20
        );
21
    }
22
23
    /** @return callable[] */
24
    protected static function inferTypeFactories(): array
25
    {
26
        $typeFactories = [];
27
        foreach (static::getClassAnnotations('type') as $annotation) {
28
            $callable = explode('::', $annotation['value']);
29
            if (interface_exists($callable[0], false)) {
30
                continue; //skip interfaces
31
            }
32
            if (!isset($callable[1]) && is_a($callable[0], FromNativeInterface::class, true)) {
33
                $callable[1] = 'fromNative';
34
            }
35
            Assertion::isCallable(
36
                $callable,
37
                sprintf("Type factory '%s' is not callable in '%s'.", $annotation['value'], static::class)
38
            );
39
            $typeFactories[$callable[0]] = $callable;
40
        }
41
42
        return $typeFactories;
43
    }
44
45
    /** @return callable[] */
46 7
    protected static function inferValueFactories(string ...$filter): array
47
    {
48 7
        $valueFactories = [];
49 7
        foreach (static::getClassAnnotations(...($filter ?: ['id', 'rev', 'map'])) as $annotation) {
50 4
            list($property, $factory) = array_map('trim', explode(',', $annotation['value']));
51 4
            $callable = explode('::', $factory);
52 4
            if (!isset($callable[1]) && is_a($callable[0], FromNativeInterface::class, true)) {
53 4
                $callable[1] = 'fromNative';
54
            }
55 4
            Assertion::isCallable(
56 4
                $callable,
57 4
                sprintf("Value factory '%s' is not callable in '%s'.", $factory, static::class)
58
            );
59 4
            $valueFactories[$property] = $callable;
60
        }
61
62 7
        return $valueFactories;
63
    }
64
65 7
    private static function getClassAnnotations(string ...$keys): array
66
    {
67 7
        $annotations = $matches = [];
68 7
        foreach (static::getInheritance() as $class) {
69 7
            if (!($docComment = $class->getDocComment())
70 7
                || !preg_match_all('/^[\s\*]+@(?<key>\w+)\((?<value>.+)\)$/m', $docComment, $matches, PREG_SET_ORDER)
71
            ) {
72 7
                continue;
73
            }
74 4
            foreach ($matches as $match) {
75 4
                if (empty($keys) || in_array($match['key'], $keys)) {
76 4
                    $annotations[] = ['key' => trim($match['key']), 'value' => trim($match['value'])];
77
                }
78
            }
79
        }
80
81 7
        return $annotations;
82
    }
83
84
    /** @return ReflectionClass[] */
85 7
    private static function getInheritance(): array
86
    {
87 7
        $currentReflection = new ReflectionClass(static::class);
88 7
        $reflectionClasses = array_merge([$currentReflection], static::flatMapTraits($currentReflection));
89
90 7
        while ($currentReflection = $currentReflection->getParentClass()) {
91
            $reflectionClasses = array_merge(
92
                $reflectionClasses,
93
                [$currentReflection],
94
                static::flatMapTraits($currentReflection)
95
            );
96
        }
97
98 7
        return $reflectionClasses;
99
    }
100
101
    /** @return ReflectionClass[] */
102 7
    private static function flatMapTraits(ReflectionClass $reflectionClass): array
103
    {
104 7
        $reflectionClasses = [];
105 7
        foreach ($reflectionClass->getTraits() as $trait) {
106 7
            $reflectionClasses = array_merge($reflectionClasses, [$trait], static::flatMapTraits($trait));
107
        }
108
109 7
        return $reflectionClasses;
110
    }
111
}
112