Passed
Push — next ( a87628...835774 )
by Bas
02:38
created

Blueprint::getCommands()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent\Schema;
4
5
use ArangoClient\Schema\SchemaManager;
6
use Closure;
7
use Illuminate\Database\Connection;
8
use Illuminate\Support\Fluent;
9
use Illuminate\Support\Traits\Macroable;
10
use LaravelFreelancerNL\Aranguent\Schema\Concerns\Columns;
11
use LaravelFreelancerNL\Aranguent\Schema\Concerns\Indexes;
12
use LaravelFreelancerNL\Aranguent\Schema\Concerns\Tables;
13
14
/**
15
 * Class Blueprint.
16
 *
17
 * The Schema blueprint works differently from the standard Illuminate version:
18
 * 1) ArangoDB is schemaless: we don't need to (and can't) create columns
19
 * 2) ArangoDB doesn't allow DB schema actions within AQL nor within a transaction.
20
 *
21
 * This means that:
22
 * 1) We catch column related methods silently for backwards compatibility and ease of migrating between DB types
23
 * 2) We don't need to compile AQL for transactions within the accompanying schema grammar. (for now)
24
 * 3) We can just execute each command on order. We will gather them first for possible future optimisations.
25
 */
26
class Blueprint
27
{
28
    use Macroable;
0 ignored issues
show
Bug introduced by
The trait Illuminate\Support\Traits\Macroable requires the property $name which is not provided by LaravelFreelancerNL\Aranguent\Schema\Blueprint.
Loading history...
29
    use Tables;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...\Schema\Concerns\Tables requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Schema\Blueprint: $name, $options, $explanation
Loading history...
30
    use Columns;
31
    use Indexes;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...Schema\Concerns\Indexes requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Schema\Blueprint: $indexOptions, $id, $explanation, $type, $unique, $index
Loading history...
32
33
    /**
34
     * The connection that is used by the blueprint.
35
     *
36
     * @var Connection
37
     */
38
    protected $connection;
39
40
    /**
41
     * The grammar that is used by the blueprint.
42
     *
43
     * @var Grammar
44
     */
45
    protected $grammar;
46
47
    /**
48
     * The table the blueprint describes.
49
     *
50
     * @var string
51
     */
52
    protected $table;
53
54
    /**
55
     * The handler for table manipulation.
56
     */
57
    protected SchemaManager $schemaManager;
58
59
    /**
60
     * The prefix of the table.
61
     *
62
     * @var string
63
     */
64
    protected $prefix;
65
66
    /**
67
     * The commands that should be run for the table.
68
     *
69
     * @var Fluent[]
70
     */
71
    protected $commands = [];
72
73
    /**
74
     * Catching columns to be able to add fluent indexes.
75
     *
76
     * @var array
77
     */
78
    protected $columns = [];
79
80
    /**
81
     * Whether to make the table temporary.
82
     *
83
     * @var bool
84
     */
85
    public $temporary = false;
86
87
    /**
88
     * Detect if _id should autoincrement.
89
     *
90
     * @var bool
91
     */
92
    protected $autoIncrement = false;
93
94
    /**
95
     * Create a new schema blueprint.
96
     *
97
     * Blueprint constructor.
98
     *
99
     * @param string            $table
100
     * @param SchemaManager     $schemaManager
101
     * @param Closure|null      $callback
102
     * @param string            $prefix
103
     */
104 139
    public function __construct($table, $schemaManager, Closure $callback = null, $prefix = '')
105
    {
106 139
        $this->table = $table;
107
108 139
        $this->schemaManager = $schemaManager;
109
110 139
        $this->prefix = $prefix;
111
112 139
        if (!is_null($callback)) {
113 9
            $callback($this);
114
        }
115 139
    }
116
117
    /**
118
     * Execute the blueprint against the database.
119
     *
120
     * @param Connection $connection
121
     * @param Grammar    $grammar
122
     *
123
     * @return void
124
     */
125 139
    public function build(Connection $connection, Grammar $grammar = null)
126
    {
127 139
        $this->connection = $connection;
128
129 139
        if (!isset($grammar)) {
130
            $this->grammar = $connection->getSchemaGrammar();
131
        }
132
133 139
        foreach ($this->commands as $command) {
134 139
            if ($command->handler == 'aql') {
135
                $command = $this->compileAqlCommand($command);
136
            }
137
138 139
            $this->executeCommand($command);
139
        }
140 139
    }
141
142
    /**
143
     * Generate the compilation method name and call it if method exists in the Grammar object.
144
     */
145
    public function compileAqlCommand(Fluent $command): Fluent
146
    {
147
        $compileMethod = 'compile' . ucfirst($command->name);
0 ignored issues
show
Bug introduced by
It seems like $command->name can also be of type null; however, parameter $string of ucfirst() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

147
        $compileMethod = 'compile' . ucfirst(/** @scrutinizer ignore-type */ $command->name);
Loading history...
148
        if (method_exists($this->grammar, $compileMethod)) {
149
            return $this->grammar->$compileMethod($this->table, $command);
150
        }
151
152
        return $command;
153
    }
154
155
    /**
156
     * Generate the execution method name and call it if the method exists.
157
     */
158 139
    public function executeCommand(Fluent $command)
159
    {
160 139
        $executeNamedMethod = 'execute' . ucfirst($command->name) . 'Command';
0 ignored issues
show
Bug introduced by
It seems like $command->name can also be of type null; however, parameter $string of ucfirst() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

160
        $executeNamedMethod = 'execute' . ucfirst(/** @scrutinizer ignore-type */ $command->name) . 'Command';
Loading history...
161 139
        $executeHandlerMethod = 'execute' . ucfirst($command->handler) . 'Command';
162 139
        if (method_exists($this, $executeNamedMethod)) {
163 139
            $this->$executeNamedMethod($command);
164
        } elseif (method_exists($this, $executeHandlerMethod)) {
165
            $this->$executeHandlerMethod($command);
166
        }
167 139
    }
168
169
    /**
170
     * Execute an AQL statement.
171
     */
172
    public function executeAqlCommand(Fluent $command)
173
    {
174
        $this->connection->statement($command->aqb->query, $command->aqb->binds);
175
    }
176
177
    public function executeCollectionCommand(Fluent $command): void
178
    {
179
        if ($this->connection->pretending()) {
180
            $this->connection->logQuery('/* ' . $command->explanation . " */\n", []);
181
182
            return;
183
        }
184
185
        if (method_exists($this->schemaManager, $command->method)) {
0 ignored issues
show
Bug introduced by
It seems like $command->method can also be of type null; however, parameter $method of method_exists() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

185
        if (method_exists($this->schemaManager, /** @scrutinizer ignore-type */ $command->method)) {
Loading history...
186
            $this->schemaManager->{$command->method}($command->parameters);
187
        }
188
    }
189
190
    /**
191
     * Solely provides feedback to the developer in pretend mode.
192
     *
193
     * @return null
194
     */
195 138
    public function executeIgnoreCommand(Fluent $command)
196
    {
197 138
        if ($this->connection->pretending()) {
198
            $this->connection->logQuery('/* ' . $command->explanation . " */\n", []);
199
200
            return;
201
        }
202 138
    }
203
204
    /**
205
     * Add a new command to the blueprint.
206
     *
207
     * @param string $name
208
     * @param array  $parameters
209
     *
210
     * @return Fluent
211
     */
212 139
    protected function addCommand($name, array $parameters = [])
213
    {
214 139
        $this->commands[] = $command = $this->createCommand($name, $parameters);
215
216 139
        return $command;
217
    }
218
219
    /**
220
     * Create a new Fluent command.
221
     *
222
     * @param string $name
223
     * @param array  $parameters
224
     *
225
     * @return Fluent
226
     */
227 139
    protected function createCommand($name, array $parameters = [])
228
    {
229 139
        return new Fluent(array_merge(compact('name'), $parameters));
230
    }
231
232
    /**
233
     * Get the commands on the blueprint.
234
     *
235
     * @return Fluent[]
236
     */
237 3
    public function getCommands()
238
    {
239 3
        return $this->commands;
240
    }
241
242
    /**
243
     * Silently catch unsupported schema methods. Store columns for backwards compatible fluent index creation.
244
     *
245
     * @param string $method
246
     * @param array<mixed> $args
247
     *
248
     * @return Blueprint
249
     */
250 138
    public function __call(string $method, array $args = [])
251
    {
252 138
        $columnMethods = [
253
            'bigIncrements', 'bigInteger', 'binary', 'boolean', 'char', 'date', 'dateTime', 'dateTimeTz', 'decimal',
254
            'double', 'enum', 'engine', 'float', 'foreignId', 'geometry', 'geometryCollection', 'increments', 'integer',
255
            'ipAddress', 'json', 'jsonb', 'lineString', 'longText', 'macAddress', 'mediumIncrements', 'mediumInteger',
256
            'mediumText', 'morphs', 'uuidMorphs', 'multiLineString', 'multiPoint', 'multiPolygon',
257
            'nullableMorphs', 'nullableUuidMorphs', 'nullableTimestamps', 'point', 'polygon', 'rememberToken',
258
            'set', 'smallIncrements', 'smallInteger', 'softDeletes', 'softDeletesTz', 'string',
259
            'text', 'time', 'timeTz', 'timestamp', 'timestampTz', 'timestamps', 'tinyIncrements', 'tinyInteger',
260
            'unsignedBigInteger', 'unsignedDecimal', 'unsignedInteger', 'unsignedMediumInteger', 'unsignedSmallInteger',
261
            'unsignedTinyInteger', 'uuid', 'year',
262
        ];
263
264 138
        if (in_array($method, $columnMethods)) {
265 138
            if (isset($args[0]) && is_string($args[0])) {
266 138
                $this->columns[] = $args[0];
267
            }
268
        }
269
270 138
        $autoIncrementMethods = ['increments', 'autoIncrement'];
271 138
        if (in_array($method, $autoIncrementMethods)) {
272
            $this->autoIncrement = true;
273
        }
274
275 138
        $info = [];
276 138
        $info['method'] = $method;
277 138
        $info['explanation'] = "'$method' is ignored; Aranguent Schema Blueprint doesn't support it.";
278 138
        $this->addCommand('ignore', $info);
279
280 138
        return $this;
281
    }
282
}
283