Passed
Push — master ( e0fdae...17ebc9 )
by Anton
01:48
created

ResolveInterfaces::run()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
namespace Cycle\Schema\Generator;
11
12
use Cycle\Schema\Definition\Entity;
13
use Cycle\Schema\Exception\BuilderException;
14
use Cycle\Schema\Exception\RelationException;
15
use Cycle\Schema\GeneratorInterface;
16
use Cycle\Schema\Registry;
17
18
class ResolveInterfaces implements GeneratorInterface
19
{
20
    // option to indicate that static link resolution is required
21
    public const STATIC_LINK = 'staticLink';
22
23
    /**
24
     * @param Registry $registry
25
     * @return Registry
26
     */
27
    public function run(Registry $registry): Registry
28
    {
29
        foreach ($registry as $entity) {
30
            $this->compute($registry, $entity);
31
        }
32
33
        return $registry;
34
    }
35
36
    /**
37
     * @param Registry $registry
38
     * @param Entity   $entity
39
     *
40
     * @throws RelationException
41
     */
42
    protected function compute(Registry $registry, Entity $entity)
43
    {
44
        foreach ($entity->getRelations() as $relation) {
45
            if (!$relation->getOptions()->has(self::STATIC_LINK)) {
46
                continue;
47
            }
48
49
            $target = $relation->getTarget();
50
            if ($registry->hasRole($target)) {
51
                // no need to resolve
52
                continue;
53
            }
54
55
            $relation->setTarget($this->resolve($registry, $target));
56
57
        }
58
    }
59
60
    /**
61
     * @param Registry $registry
62
     * @param string   $target
63
     * @return string
64
     */
65
    protected function resolve(Registry $registry, string $target): string
66
    {
67
        if (!class_exists($target)) {
68
            throw new RelationException("Unable to resolve static link to non interface target `{$target}`");
69
        }
70
71
        $found = null;
72
        foreach ($registry->getIterator() as $entity) {
73
            if ($entity->getClass() === null) {
74
                continue;
75
            }
76
77
            try {
78
                $candidate = new \ReflectionClass($entity->getClass());
79
            } catch (\ReflectionException $e) {
80
                throw new BuilderException($e->getMessage(), $e->getCode(), $e);
81
            }
82
83
            if ($candidate->isSubclassOf($target) || $candidate->implementsInterface($target)) {
84
                if ($found !== null) {
85
                    throw new RelationException("Ambiguous static link to `{$target}`");
86
                }
87
88
                $found = $entity->getClass();
89
            }
90
        }
91
92
        if ($found !== null) {
93
            return $found;
94
        }
95
96
        throw new RelationException("Unable to resolve static link to `{$target}`");
97
    }
98
}