Test Setup Failed
Pull Request — master (#10)
by
unknown
01:32
created

src/Schema/Blueprint.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent\Schema;
4
5
use ArangoDBClient\CollectionHandler;
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 from one DB type to another
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,
29
        Tables,
30
        Columns,
31
        Indexes;
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 $collectionHandler;
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 _key (and thus proxy _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
     * @param string $collection
99
     * @param CollectionHandler $collectionHandler
100
     * @param Closure|null $callback
101
     * @param string $prefix
102
     */
103
    public function __construct($collection, $collectionHandler, Closure $callback = null, $prefix = '')
104
    {
105
        $this->table = $collection;
106
107
        $this->collectionHandler = $collectionHandler;
108
109
        $this->prefix = $prefix;
110
111
        if (! is_null($callback)) {
112
            $callback($this);
113
        }
114
    }
115
116
    /**
117
     * Execute the blueprint against the database.
118
     *
119
     * @param Connection $connection
120
     * @param Grammar $grammar
121
     * @return void
122
     */
123
    public function build(Connection $connection, Grammar $grammar)
124
    {
125
        $this->connection = $connection;
126
127
        if (! isset($grammar)) {
128
            $this->grammar = $connection->getSchemaGrammar();
129
        }
130
131
        foreach ($this->commands as $command) {
132
            if ($command->handler == 'aql') {
133
                $command = $this->compileAqlCommand($command);
134
            }
135
136
            $this->executeCommand($command);
137
        }
138
    }
139
140
    /**
141
     * Generate the compilation method name and call it if method exists in the Grammar object.
142
     *
143
     * @param Fluent $command
144
     * @return mixed
145
     */
146
    public function compileAqlCommand($command)
147
    {
148
        $compileMethod = 'compile'.ucfirst($command->name);
149
        if (method_exists($this->grammar, $compileMethod)) {
150
            return $this->grammar->$compileMethod($this->table, $command);
151
        }
152
    }
153
154
    /**
155
     * Generate the execution method name and call it if the method exists.
156
     *
157
     * @param $command
158
     */
159
    public function executeCommand($command)
160
    {
161
        $executeNamedMethod = 'execute'.ucfirst($command->name).'Command';
162
        $executeHandlerMethod = 'execute'.ucfirst($command->handler).'Command';
163
        if (method_exists($this, $executeNamedMethod)) {
164
            $this->$executeNamedMethod($command);
165
        } elseif (method_exists($this, $executeHandlerMethod)) {
166
            $this->$executeHandlerMethod($command);
167
        }
168
    }
169
170
    /**
171
     * Execute an AQL statement.
172
     *
173
     * @param $command
174
     */
175
    public function executeAqlCommand($command)
176
    {
177
        $this->connection->statement($command->aqb->query, $command->aqb->binds);
178
    }
179
180
    public function executeCollectionCommand($command)
181
    {
182
        if ($this->connection->pretending()) {
183
            $this->connection->logQuery('/* '.$command->explanation." */\n", []);
184
185
            return;
186
        }
187
188
        if (method_exists($this->collectionHandler, $command->method)) {
189
            $this->collectionHandler->{$command->method}($command->parameters);
190
        }
191
    }
192
193
    /**
194
     * Solely provides feedback to the developer in pretend mode.
195
     *
196
     * @param $command
197
     * @return null
198
     */
199
    public function executeIgnoreCommand($command)
200
    {
201
        if ($this->connection->pretending()) {
202
            $this->connection->logQuery('/* '.$command->explanation." */\n", []);
203
204
            return;
205
        }
206
    }
207
208
    /**
209
     * Add a new command to the blueprint.
210
     *
211
     * @param  string  $name
212
     * @param  array  $parameters
213
     * @return Fluent
214
     */
215
    protected function addCommand($name, array $parameters = [])
216
    {
217
        $this->commands[] = $command = $this->createCommand($name, $parameters);
218
219
        return $command;
220
    }
221
222
    /**
223
     * Create a new Fluent command.
224
     *
225
     * @param  string  $name
226
     * @param  array  $parameters
227
     * @return Fluent
228
     */
229
    protected function createCommand($name, array $parameters = [])
230
    {
231
        return new Fluent(array_merge(compact('name'), $parameters));
232
    }
233
234
    /**
235
     * Get the commands on the blueprint.
236
     *
237
     * @return Fluent[]
238
     */
239
    public function getCommands()
240
    {
241
        return $this->commands;
242
    }
243
244
    /**
245
     * Silently catch unsupported schema methods. Store columns for backwards compatible fluent index creation.
246
     *
247
     * @param $method
248
     * @param $args
249
     * @return Blueprint
250
     */
251
    public function __call($method, $args)
252
    {
253
        $columnMethods = [
254
            'bigIncrements', 'bigInteger', 'binary', 'boolean', 'char', 'date', 'dateTime', 'dateTimeTz', 'decimal',
255
            'double', 'enum', 'engine', 'float', 'geometry', 'geometryCollection', 'increments', 'integer', 'ipAddress', 'json',
256
            'jsonb', 'lineString', 'longText', 'macAddress', 'mediumIncrements', 'mediumInteger', 'mediumText',
257
            'morphs', 'uuidMorphs', 'multiLineString', 'multiPoint', 'multiPolygon',
258
            'nullableMorphs', 'nullableUuidMorphs', 'nullableTimestamps', 'point', 'polygon', 'rememberToken',
259
            'set', 'smallIncrements', 'smallInteger', 'softDeletes', 'softDeletesTz', 'string',
260
            'text', 'time', 'timeTz', 'timestamp', 'timestampTz', 'timestamps', 'tinyIncrements', 'tinyInteger',
261
            'unsignedBigInteger', 'unsignedDecimal', 'unsignedInteger', 'unsignedMediumInteger', 'unsignedSmallInteger',
262
            'unsignedTinyInteger', 'uuid', 'year',
263
        ];
264
265
        if (in_array($method, $columnMethods)) {
266
            if (isset($args)) {
267
                $this->columns[] = $args;
268
            }
269
        }
270
271
        $autoIncrementMethods = ['increments', 'autoIncrement'];
272
        if (in_array($method, $autoIncrementMethods)) {
273
            $this->autoIncrement = true;
274
        }
275
276
        $info['method'] = $method;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$info was never initialized. Although not strictly required by PHP, it is generally a good practice to add $info = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
277
        $info['explanation'] = "'$method' is ignored; Aranguent Schema Blueprint doesn't support it.";
278
        $this->addCommand('ignore', $info);
279
280
        return $this;
281
    }
282
}
283