Completed
Branch feature/pre-split (ca29cf)
by Anton
03:23
created

SchemaBuilder::packSchema()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 3
nop 0
dl 0
loc 23
rs 8.7972
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 Psr\Log\LoggerInterface;
10
use Spiral\Database\DatabaseManager;
11
use Spiral\Database\Exceptions\DBALException;
12
use Spiral\Database\Exceptions\DriverException;
13
use Spiral\Database\Exceptions\QueryException;
14
use Spiral\Database\Helpers\SynchronizationBus;
15
use Spiral\Database\Schemas\Prototypes\AbstractTable;
16
use Spiral\ORM\Exceptions\SchemaException;
17
use Spiral\ORM\ORMInterface;
18
19
class SchemaBuilder
20
{
21
    /**
22
     * @var DatabaseManager
23
     */
24
    private $manager;
25
26
    /**
27
     * @var AbstractTable[]
28
     */
29
    private $tables = [];
30
31
    /**
32
     * @var SchemaInterface[]
33
     */
34
    private $schemas = [];
35
36
    /**
37
     * Class names of sources associated with specific class.
38
     *
39
     * @var array
40
     */
41
    private $sources = [];
42
43
    /**
44
     * @param DatabaseManager $manager
45
     */
46
    public function __construct(DatabaseManager $manager)
47
    {
48
        $this->manager = $manager;
49
    }
50
51
    /**
52
     * Add new model schema into pool.
53
     *
54
     * @param SchemaInterface $schema
55
     *
56
     * @return self|$this
57
     */
58
    public function addSchema(SchemaInterface $schema): SchemaBuilder
59
    {
60
        $this->schemas[$schema->getClass()] = $schema;
61
62
        return $this;
63
    }
64
65
    /**
66
     * @param string $class
67
     *
68
     * @return bool
69
     */
70
    public function hasSchema(string $class): bool
71
    {
72
        return isset($this->schemas[$class]);
73
    }
74
75
    /**
76
     * @param string $class
77
     *
78
     * @return SchemaInterface
79
     *
80
     * @throws SchemaException
81
     */
82
    public function getSchema(string $class): SchemaInterface
83
    {
84
        if (!$this->hasSchema($class)) {
85
            throw new SchemaException("Unable to find schema for class '{$class}'");
86
        }
87
88
        return $this->schemas[$class];
89
    }
90
91
    /**
92
     * All available document schemas.
93
     *
94
     * @return SchemaInterface[]
95
     */
96
    public function getSchemas(): array
97
    {
98
        return $this->schemas;
99
    }
100
101
    /**
102
     * Associate source class with entity class. Source will be automatically associated with given
103
     * class and all classes from the same collection which extends it.
104
     *
105
     * @param string $class
106
     * @param string $source
107
     *
108
     * @return SchemaBuilder
109
     *
110
     * @throws SchemaException
111
     */
112
    public function addSource(string $class, string $source): SchemaBuilder
113
    {
114
        if (!$this->hasSchema($class)) {
115
            throw new SchemaException("Unable to add source to '{$class}', class is unknown to ORM");
116
        }
117
118
        $this->sources[$class] = $source;
119
120
        return $this;
121
    }
122
123
    /**
124
     * Check if given entity has associated source.
125
     *
126
     * @param string $class
127
     *
128
     * @return bool
129
     */
130
    public function hasSource(string $class): bool
131
    {
132
        return array_key_exists($class, $this->sources);
133
    }
134
135
    /**
136
     * Get source associated with specific class, if any.
137
     *
138
     * @param string $class
139
     *
140
     * @return string|null
141
     */
142
    public function getSource(string $class)
143
    {
144
        if (!$this->hasSource($class)) {
145
            return null;
146
        }
147
148
        return $this->sources[$class];
149
    }
150
151
    /**
152
     * Process all added schemas and relations in order to created needed tables, indexes and etc.
153
     * Attention, this method will return new instance of SchemaBuilder without affecting original
154
     * object. You MUST call this method before calling packSchema() method.
155
     *
156
     * Attention, this methods DOES NOT write anything into database, use pushSchema() to push
157
     * changes into database using automatic diff generation. You can also access list of
158
     * generated/changed tables via getTables() to create your own migrations.
159
     *
160
     * @see packSchema()
161
     * @see pushSchema()
162
     * @see getTables()
163
     *
164
     * @return SchemaBuilder
165
     */
166
    public function renderSchema(): SchemaBuilder
167
    {
168
        //bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla!
169
170
        //START YOUR WORK HERE!
171
172
        return $this;
173
    }
174
175
    /**
176
     * Get all defined tables, make sure to call renderSchema() first. Attention, all given tables
177
     * will be returned in detached state.
178
     *
179
     * @return AbstractTable[]
180
     *
181
     * @throws SchemaException
182
     */
183
    public function getTables(): array
184
    {
185
        if (empty($this->tables) && !empty($this->schemas)) {
186
            throw new SchemaException(
187
                "Unable to get tables, no defined tables were found, call defineTables() first"
188
            );
189
        }
190
191
        $result = [];
192
        foreach ($this->tables as $table) {
193
            //Detaching
194
            $result[] = clone $table;
195
        }
196
197
        return $result;
198
    }
199
200
    /**
201
     * Save every change made to generated tables. Method utilizes default DBAL diff mechanism,
202
     * use getTables() method in order to generate your own migrations.
203
     *
204
     * @param LoggerInterface|null $logger
205
     *
206
     * @throws SchemaException
207
     * @throws DBALException
208
     * @throws QueryException
209
     * @throws DriverException
210
     */
211
    public function pushSchema(LoggerInterface $logger = null)
212
    {
213
        $bus = new SynchronizationBus($this->getTables());
214
        $bus->run($logger);
215
    }
216
217
    /**
218
     * Pack declared schemas in a normalized form, make sure to call renderSchema() first.
219
     *
220
     * @return array
221
     *
222
     * @throws SchemaException
223
     */
224
    public function packSchema(): array
225
    {
226
        if (empty($this->tables) && !empty($this->schemas)) {
227
            throw new SchemaException(
228
                "Unable to pack schema, no defined tables were found, call defineTables() first"
229
            );
230
        }
231
232
        $result = [];
233
        foreach ($this->schemas as $class => $schema) {
234
            $result[$class][] = [
235
                ORMInterface::R_INSTANTIATOR => $schema->getInstantiator(),
236
                ORMInterface::R_SCHEMA       => $schema->packSchema($this, null),
237
                ORMInterface::R_SOURCE_CLASS => $this->getSource($class),
238
                ORMInterface::R_DATABASE     => $schema->getDatabase(),
239
                ORMInterface::R_TABLE        => $schema->getTable(),
240
                ORMInterface::R_RELATIONS    => [/*external manager*/]
241
                //relations???
242
            ];
243
        }
244
245
        return $result;
246
    }
247
}