Completed
Branch feature/pre-split (4f3c6e)
by Anton
03:29
created

MorphedTrait   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 95
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 0
loc 95
rs 10
c 0
b 0
f 0
wmc 11
lcom 1
cbo 6

5 Methods

Rating   Name   Duplication   Size   Complexity  
B findOuter() 0 23 4
B verifyOuter() 0 22 4
A findTargets() 0 10 3
getDefinition() 0 1 ?
option() 0 1 ?
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
8
namespace Spiral\ORM\Schemas\Relations\Traits;
9
10
use Spiral\Database\Schemas\Prototypes\AbstractColumn;
11
use Spiral\ORM\Exceptions\RelationSchemaException;
12
use Spiral\ORM\ORMInterface;
13
use Spiral\ORM\Record;
14
use Spiral\ORM\Schemas\Definitions\RelationDefinition;
15
use Spiral\ORM\Schemas\SchemaBuilder;
16
17
/**
18
 * Helps to locate all outer records matching given interface.
19
 */
20
trait MorphedTrait
21
{
22
    /**
23
     * Resolving outer key.
24
     *
25
     * @param \Spiral\ORM\Schemas\SchemaBuilder $builder
26
     *
27
     * @return \Spiral\Database\Schemas\Prototypes\AbstractColumn|null When no outer records found
28
     *                                                                 NULL will be returned.
29
     */
30
    protected function findOuter(SchemaBuilder $builder)
31
    {
32
        foreach ($this->findTargets($builder) as $schema) {
33
            $outerTable = $builder->requestTable($schema->getTable(), $schema->getDatabase());
34
            $outerKey = $this->option(Record::OUTER_KEY);
35
36
            if ($outerKey == ORMInterface::R_PRIMARY_KEY) {
37
                $outerKey = current($outerTable->getPrimaryKeys());
38
            }
39
40
            if (!$outerTable->hasColumn($outerKey)) {
41
                throw new RelationSchemaException(sprintf("Outer key '%s'.'%s' (%s) does not exists",
42
                    $outerTable->getName(),
43
                    $outerKey,
44
                    $this->getDefinition()->getName()
45
                ));
46
            }
47
48
            return $outerTable->column($outerKey);
49
        }
50
51
        return null;
52
    }
53
54
    /**
55
     * Make sure all tables have same outer key.
56
     *
57
     * @param \Spiral\ORM\Schemas\SchemaBuilder                  $builder
58
     * @param \Spiral\Database\Schemas\Prototypes\AbstractColumn $column
59
     *
60
     * @throws RelationSchemaException
61
     */
62
    protected function verifyOuter(SchemaBuilder $builder, AbstractColumn $column)
63
    {
64
        foreach ($this->findTargets($builder) as $schema) {
65
            $outerTable = $builder->requestTable($schema->getTable(), $schema->getDatabase());
66
67
            if (!$outerTable->hasColumn($column->getName())) {
68
                //Column is missing
69
                throw new RelationSchemaException(
70
                    "Unable to build morphed relation, outer key '{$column->getName()}' "
71
                    . "is missing in '{$outerTable->getName()}'"
72
                );
73
            }
74
75
            if ($outerTable->column($column->getName())->phpType() != $column->phpType()) {
76
                //Inconsistent type
77
                throw new RelationSchemaException(
78
                    "Unable to build morphed relation, outer key '{$column->getName()}' "
79
                    . "has different type in '{$outerTable->getName()}'"
80
                );
81
            }
82
        }
83
    }
84
85
    /**
86
     * Find all matched schemas.
87
     *
88
     * @param \Spiral\ORM\Schemas\SchemaBuilder $builder
89
     *
90
     * @return \Generator|\Spiral\ORM\Schemas\SchemaInterface[]
91
     */
92
    protected function findTargets(SchemaBuilder $builder): \Generator
93
    {
94
        foreach ($builder->getSchemas() as $schema) {
95
            if (!is_a($schema->getClass(), $this->getDefinition()->getTarget(), true)) {
96
                //Not our targets
97
                continue;
98
            }
99
            yield $schema;
100
        }
101
    }
102
103
    /**
104
     * @return \Spiral\ORM\Schemas\Definitions\RelationDefinition
105
     */
106
    abstract public function getDefinition(): RelationDefinition;
107
108
    /**
109
     * @param string $key
110
     *
111
     * @return mixed
112
     */
113
    abstract protected function option(string $key);
114
}