Passed
Push — master ( 578537...871390 )
by Anton
08:44 queued 02:16
created

GenerateRelations::compute()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 3
nop 2
dl 0
loc 18
rs 9.9332
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\ORM\Relation;
13
use Cycle\Schema\Definition\Entity;
14
use Cycle\Schema\Exception\BuilderException;
15
use Cycle\Schema\GeneratorInterface;
16
use Cycle\Schema\Registry;
17
use Cycle\Schema\Relation\OptionSchema;
18
use Cycle\Schema\Relation\RelationSchema;
19
use Cycle\Schema\RelationInterface;
20
21
/**
22
 * Generate relations based on their schematic definitions.
23
 */
24
final class GenerateRelations implements GeneratorInterface
25
{
26
    // aliases between option names and their internal IDs
27
    public const OPTION_MAP = [
28
        'cascade'         => Relation::CASCADE,
29
        'nullable'        => Relation::NULLABLE,
30
        'innerKey'        => Relation::INNER_KEY,
31
        'outerKey'        => Relation::OUTER_KEY,
32
        'morphKey'        => Relation::MORPH_KEY,
33
        'thought'         => Relation::THOUGHT_ENTITY,
34
        'thoughInnerKey'  => Relation::THOUGHT_INNER_KEY,
35
        'thoughOuterKey'  => Relation::THOUGHT_OUTER_KEY,
36
        'thoughtWhere'    => Relation::THOUGHT_WHERE,
37
        'thoughConstrain' => Relation::THOUGHT_CONSTRAIN,
38
        'constrain'       => Relation::CONSTRAIN,
39
        'where'           => Relation::WHERE,
40
        'fkCreate'        => RelationSchema::FK_CREATE,
41
        'fkAction'        => RelationSchema::FK_ACTION,
42
        'indexCreate'     => RelationSchema::INDEX_CREATE,
43
        'bindInterface'   => RelationSchema::BIND_INTERFACE
44
    ];
45
46
    /** @var OptionSchema */
47
    private $options;
48
49
    /** @var RelationInterface[] */
50
    private $relations = [];
51
52
    /**
53
     * @param array             $relations
54
     * @param OptionSchema|null $optionSchema
55
     */
56
    public function __construct(array $relations, OptionSchema $optionSchema = null)
57
    {
58
        $this->options = $optionSchema ?? new OptionSchema(self::OPTION_MAP);
59
60
        foreach ($relations as $id => $relation) {
61
            if (!$relation instanceof RelationInterface) {
62
                throw new \InvalidArgumentException(sprintf(
63
                    "Invalid relation type, RelationInterface excepted, `%s` given",
64
                    is_object($relation) ? get_class($relation) : gettype($relation)
65
                ));
66
            }
67
68
            $this->relations[$id] = $relation;
69
        }
70
    }
71
72
    /**
73
     * @param Registry $registry
74
     * @return Registry
75
     */
76
    public function run(Registry $registry): Registry
77
    {
78
        foreach ($registry as $entity) {
79
            $this->compute($registry, $entity);
80
        }
81
82
        return $registry;
83
    }
84
85
    /**
86
     * @param Registry $registry
87
     * @param Entity   $entity
88
     */
89
    protected function compute(Registry $registry, Entity $entity)
90
    {
91
        foreach ($entity->getRelations() as $name => $r) {
92
            if (!isset($this->relations[$r->getType()])) {
93
                throw new BuilderException("Undefined relation type `{$r->getType()}`");
94
            }
95
96
            $schema = $this->relations[$r->getType()]->withContext(
97
                $name,
98
                $entity->getRole(),
99
                $r->getTarget(),
100
                $this->options->withOptions($r->getOptions())
101
            );
102
103
            // compute relation values (field names, related entities and etc)
104
            $schema->compute($registry);
105
106
            $registry->registerRelation($entity, $name, $schema);
107
        }
108
    }
109
}