Completed
Branch feature/pre-split (4c50c1)
by Anton
03:17
created

RelationBuilder::inverseRelations()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 4
nop 0
dl 0
loc 25
rs 8.5806
c 0
b 0
f 0
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\ORM\Schemas;
8
9
use Spiral\Core\FactoryInterface;
10
use Spiral\ORM\Configs\RelationsConfig;
11
use Spiral\ORM\Exceptions\DefinitionException;
12
use Spiral\ORM\Schemas\Definitions\RelationDefinition;
13
14
/**
15
 * Subsection of SchemaBuilder used to configure tables and columns defined by model to model
16
 * relations.
17
 */
18
class RelationBuilder
19
{
20
    /**
21
     * @invisible
22
     * @var RelationsConfig
23
     */
24
    protected $config;
25
26
    /**
27
     * @invisible
28
     * @var FactoryInterface
29
     */
30
    protected $factory;
31
32
    /**
33
     * Set of relation definitions.
34
     *
35
     * @var RelationInterface[]
36
     */
37
    private $relations = [];
38
39
    /**
40
     * @param RelationsConfig  $config
41
     * @param FactoryInterface $factory
42
     */
43
    public function __construct(RelationsConfig $config, FactoryInterface $factory)
44
    {
45
        $this->config = $config;
46
        $this->factory = $factory;
47
    }
48
49
    /**
50
     * Registering new relation definition.
51
     *
52
     * @param RelationDefinition $definition Relation options (definition).
53
     *
54
     * @throws DefinitionException
55
     */
56
    public function registerRelation(RelationDefinition $definition)
57
    {
58
        if (!$this->config->hasRelation($definition->getType())) {
59
            throw new DefinitionException(sprintf(
60
                "Undefined relation type '%s' in '%s'.'%s'",
61
                $definition->getType(),
62
                $definition->sourceContext()->getClass(),
63
                $definition->getName()
64
            ));
65
        }
66
67
        $class = $this->config->relationClass(
68
            $definition->getType(),
69
            RelationsConfig::SCHEMA_CLASS
70
        );
71
72
        //Creating relation schema
73
        $relation = $this->factory->make($class, compact('definition'));
74
75
        //Equavalent (low)?
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
76
77
        //todo: morphed relations are a bit special
78
        //todo: make sure no dubs
79
80
        $this->relations[] = $relation;
81
    }
82
83
    /**
84
     * Create inverse relations where needed.
85
     *
86
     * @throws DefinitionException
87
     */
88
    public function inverseRelations()
89
    {
90
        /**
91
         * Inverse process is relation specific.
92
         */
93
        foreach ($this->relations as $relation) {
94
            $definition = $relation->getDefinition();
95
96
            if ($definition->needInversion()) {
97
                if (!$relation instanceof InversableRelationInterface) {
98
                    throw new DefinitionException(sprintf(
99
                        "Unable to inverse relation '%s'.'%s', relation schema '%s' is non inversable",
100
                        $definition->sourceContext()->getClass(),
101
                        $definition->getName(),
102
                        get_class($relation)
103
                    ));
104
                }
105
106
                //todo: make sure no dubs
107
108
                //Let's perform inversion
109
                $this->registerRelation($relation->inverseDefinition($definition->getInverse()));
110
            }
111
        }
112
    }
113
114
    //todo: normalize relations?
115
116
    /**
117
     * Declare set of tables for each relation. Method must return Generator of AbstractTable
118
     * sequentially (attention, non sequential processing will cause collision issues between
119
     * tables).
120
     *
121
     * @param SchemaBuilder $builder
122
     *
123
     * @return \Generator
124
     */
125
    public function declareTables(SchemaBuilder $builder): \Generator
126
    {
127
        foreach ($this->relations as $relation) {
128
            foreach ($relation->declareTables($builder) as $table) {
129
                yield $table;
130
            }
131
        }
132
    }
133
134
    /**
135
     * Pack relation schemas for specific model class in order to be saved in memory.
136
     *
137
     * @param string        $class
138
     * @param SchemaBuilder $builder
139
     *
140
     * @return array
141
     */
142
    public function packRelations(string $class, SchemaBuilder $builder): array
143
    {
144
        $result = [];
145
        foreach ($this->relations as $relation) {
146
            $definition = $relation->getDefinition();
147
148
            if ($definition->sourceContext()->getClass() == $class) {
149
                //Packing relation, relation schema are given with associated table
150
                $result[$definition->getName()] = $relation->packRelation($builder->requestTable(
151
                    $definition->targetContext()->getTable(),
152
                    $definition->targetContext()->getDatabase()
153
                ));
154
            }
155
        }
156
157
        return $result;
158
    }
159
}