Completed
Branch feature/pre-split (364e4e)
by Anton
03:31
created

AbstractSchema::packRelation()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 2
nop 1
dl 0
loc 24
rs 8.6845
c 0
b 0
f 0
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
8
namespace Spiral\ORM\Schemas\Relations;
9
10
use Spiral\ORM\Exceptions\OptionsException;
11
use Spiral\ORM\Helpers\RelationOptions;
12
use Spiral\ORM\ORMInterface;
13
use Spiral\ORM\Record;
14
use Spiral\ORM\Schemas\Definitions\RelationDefinition;
15
use Spiral\ORM\Schemas\RelationInterface;
16
use Spiral\ORM\Schemas\Relations\Traits\TablesTrait;
17
use Spiral\ORM\Schemas\SchemaBuilder;
18
19
/**
20
 * Basic class for SQL specific relations.
21
 */
22
abstract class AbstractSchema implements RelationInterface
23
{
24
    use TablesTrait;
25
26
    /**
27
     * Relation type to be stored in packed schema.
28
     */
29
    const RELATION_TYPE = null;
30
31
    /**
32
     * Options to be packed in schema (not all options are required in runtime).
33
     */
34
    const PACK_OPTIONS = [];
35
36
    /**
37
     * Most of relations provides ability to specify many different configuration options, such
38
     * as key names, pivot table schemas, foreign key request, ability to be nullabe and etc.
39
     *
40
     * To simple schema definition in real projects we can fill some of this values automatically
41
     * based on some "environment" values such as parent/outer record table, role name, primary key
42
     * and etc.
43
     *
44
     * Example:
45
     * Record::INNER_KEY => '{outer:role}_{outer:primaryKey}'
46
     *
47
     * Result:
48
     * Outer Record is User with primary key "id" => "user_id"
49
     *
50
     * @var array
51
     */
52
    const OPTIONS_TEMPLATE = [];
53
54
    /**
55
     * @var RelationDefinition
56
     */
57
    protected $definition;
58
59
    /**
60
     * Provides ability to define missing relation options based on template. Column names will be
61
     * added automatically if target presented.
62
     *
63
     * @see self::OPTIONS_TEMPLATE
64
     * @var RelationOptions
65
     */
66
    protected $options;
67
68
    /**
69
     * @param RelationDefinition $definition
70
     */
71
    public function __construct(RelationDefinition $definition)
72
    {
73
        $this->definition = $definition;
74
        $this->options = new RelationOptions($definition, static::OPTIONS_TEMPLATE);
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function getDefinition(): RelationDefinition
81
    {
82
        return $this->definition;
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    public function packRelation(SchemaBuilder $builder): array
89
    {
90
        //Target table
91
        $table = $this->targetTable($builder);
92
93
        //Fetching all needed options
94
        $schema = $this->options->defineMultiple(static::PACK_OPTIONS);
95
96
        if (
97
            in_array(Record::RELATION_COLUMNS, static::PACK_OPTIONS)
98
            && empty($schema[Record::RELATION_COLUMNS])
99
        ) {
100
            //Let's read list of columns
101
            foreach ($table->getColumns() as $column) {
102
                $schema[Record::RELATION_COLUMNS][] = $column->getName();
103
            }
104
        }
105
106
        return [
107
            ORMInterface::R_TYPE   => static::RELATION_TYPE,
108
            ORMInterface::R_CLASS  => $this->getDefinition()->getTarget(),
109
            ORMInterface::R_SCHEMA => $schema
110
        ];
111
    }
112
113
    /**
114
     * Check if relation requests foreign key constraints to be created.
115
     *
116
     * @return bool
117
     */
118
    public function isConstrained()
119
    {
120
        $source = $this->definition->sourceContext();
121
        $target = $this->definition->targetContext();
122
        if (empty($target)) {
123
            return false;
124
        }
125
126
        if ($source->getDatabase() != $target->getDatabase()) {
127
            //Unable to create constrains for records in different databases
128
            return false;
129
        }
130
131
        return $this->option(Record::CREATE_CONSTRAINT);
132
    }
133
134
    /**
135
     * Define relation configuration option.
136
     *
137
     * @param string $option
138
     *
139
     * @return mixed
140
     *
141
     * @throws OptionsException
142
     */
143
    protected function option(string $option)
144
    {
145
        return $this->options->define($option);
146
    }
147
148
}