AbstractSchema::isConstrained()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
/**
3
 * Spiral, Core 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
        //Fetching all needed options
91
        $schema = $this->options->defineMultiple(static::PACK_OPTIONS);
92
93
        if (
94
            in_array(Record::RELATION_COLUMNS, static::PACK_OPTIONS)
95
            && empty($schema[Record::RELATION_COLUMNS])
96
            && !empty($this->definition->targetContext())
97
        ) {
98
            //Target table
99
            $table = $this->targetTable($builder);
100
101
            //Let's read list of columns
102
            foreach ($table->getColumns() as $column) {
103
                $schema[Record::RELATION_COLUMNS][] = $column->getName();
104
            }
105
        }
106
107
108
        $target = $this->getDefinition()->getTarget();
109
        if ($this->definition->isLateBinded()) {
110
            //Located while rendering
111
            $target = $this->definition->targetContext()->getClass();
112
        }
113
114
        return [
115
            ORMInterface::R_TYPE   => static::RELATION_TYPE,
116
            ORMInterface::R_CLASS  => $target,
117
            ORMInterface::R_SCHEMA => $schema
118
        ];
119
    }
120
121
    /**
122
     * Check if relation requests foreign key constraints to be created.
123
     *
124
     * @return bool
125
     */
126
    public function isConstrained()
127
    {
128
        $source = $this->definition->sourceContext();
129
        $target = $this->definition->targetContext();
130
        if (empty($target)) {
131
            return false;
132
        }
133
134
        if ($source->getDatabase() != $target->getDatabase()) {
135
            //Unable to create constrains for records in different databases
136
            return false;
137
        }
138
139
        return $this->option(Record::CREATE_CONSTRAINT);
140
    }
141
142
    /**
143
     * Define relation configuration option.
144
     *
145
     * @param string $option
146
     *
147
     * @return mixed
148
     *
149
     * @throws OptionsException
150
     */
151
    protected function option(string $option)
152
    {
153
        return $this->options->define($option);
154
    }
155
156
}