Passed
Push — master ( c12f94...3e1cf8 )
by Anton
03:42
created

GenerateRelations   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 71
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 37
dl 0
loc 71
rs 10
c 0
b 0
f 0
wmc 7

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 4
A compute() 0 18 3
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
class GenerateRelations implements GeneratorInterface
25
{
26
    // aliases between option names and their internal IDs
27
    // todo: throw an exception when no option found
28
    public const OPTION_MAP = [
29
        'cascade'         => Relation::CASCADE,
30
        'nullable'        => Relation::NULLABLE,
31
        'innerKey'        => Relation::INNER_KEY,
32
        'outerKey'        => Relation::OUTER_KEY,
33
        'morphKey'        => Relation::MORPH_KEY,
34
        'thought'         => Relation::THOUGHT_ENTITY,
35
        'thoughInnerKey'  => Relation::THOUGHT_INNER_KEY,
36
        'thoughOuterKey'  => Relation::THOUGHT_OUTER_KEY,
37
        'thoughtWhere'    => Relation::THOUGHT_WHERE,
38
        'thoughConstrain' => Relation::THOUGHT_CONSTRAIN,
39
        'constrain'       => Relation::CONSTRAIN,
40
        'where'           => Relation::WHERE,
41
        'fkCreate'        => RelationSchema::FK_CREATE,
42
        'fkAction'        => RelationSchema::FK_ACTION,
43
        'indexCreate'     => RelationSchema::INDEX_CREATE,
44
        'bindInterface'   => RelationSchema::BIND_INTERFACE
45
    ];
46
47
    /** @var OptionSchema */
48
    private $options;
49
50
    /** @var RelationInterface[] */
51
    private $relations = [];
52
53
    /**
54
     * @param array             $relations
55
     * @param OptionSchema|null $optionSchema
56
     */
57
    public function __construct(array $relations, OptionSchema $optionSchema = null)
58
    {
59
        $this->options = $optionSchema ?? new OptionSchema(self::OPTION_MAP);
60
61
        foreach ($relations as $id => $relation) {
62
            if (!$relation instanceof RelationInterface) {
63
                throw new \InvalidArgumentException(sprintf(
64
                    "Invalid relation type, RelationInterface excepted, `%s` given",
65
                    is_object($relation) ? get_class($relation) : gettype($relation)
66
                ));
67
            }
68
69
            $this->relations[$id] = $relation;
70
        }
71
    }
72
73
    /**
74
     * @param Registry $registry
75
     * @param Entity   $entity
76
     */
77
    public function compute(Registry $registry, Entity $entity)
78
    {
79
        foreach ($entity->getRelations() as $name => $r) {
80
            if (!isset($this->relations[$r->getType()])) {
81
                throw new BuilderException("Undefined relation type `{$r->getType()}`");
82
            }
83
84
            $schema = $this->relations[$r->getType()]->withContext(
85
                $name,
86
                $entity->getRole(),
87
                $r->getTarget(),
88
                $this->options->withOptions($r->getOptions())
89
            );
90
91
            // compute relation values (field names, related entities and etc)
92
            $schema->compute($registry);
93
94
            $registry->registerRelation($entity, $name, $schema);
95
        }
96
    }
97
}