Completed
Push — master ( b3febe...348067 )
by Zach
04:06 queued 02:03
created

Migrator::getLog()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Yarak\Migrations;
4
5
use Yarak\Helpers\Str;
6
use Yarak\Config\Config;
7
use Yarak\Helpers\Loggable;
8
use Yarak\Helpers\Filesystem;
9
use Yarak\DB\ConnectionResolver;
10
11
class Migrator
12
{
13
    use Filesystem, Loggable;
14
15
    /**
16
     * Yarak config.
17
     *
18
     * @var Config
19
     */
20
    protected $config;
21
22
    /**
23
     * Database connection resolver.
24
     *
25
     * @var ConnectionResolver
26
     */
27
    protected $resolver;
28
29
    /**
30
     * Repository for logging migration activity.
31
     *
32
     * @var MigrationRepository
33
     */
34
    protected $repository;
35
36
    /**
37
     * The active database connection.
38
     *
39
     * @var Phalcon\Db\Adapter\Pdo
40
     */
41
    protected $connection = null;
42
43
    /**
44
     * Construct.
45
     *
46
     * @param Config                       $config
47
     * @param ConnectionResolver           $resolver
48
     * @param MigrationRepositoryInterface $repository
49
     */
50
    public function __construct(
51
        Config $config,
52
        ConnectionResolver $resolver,
53
        MigrationRepository $repository
54
    ) {
55
        $this->config = $config;
56
        $this->resolver = $resolver;
57
        $this->repository = $repository;
58
    }
59
60
    /**
61
     * Run migrations.
62
     *
63
     * @return array
64
     */
65
    public function run()
66
    {
67
        $this->setUp();
68
69
        $pendingMigrations = $this->getPendingMigrations();
70
71
        return $this->runPending($pendingMigrations);
72
    }
73
74
    /**
75
     * Get all migration filenames that have not been run.
76
     *
77
     * @return array
78
     */
79
    protected function getPendingMigrations()
80
    {
81
        return array_diff(
82
            $this->getMigrationFiles(),
83
            $this->repository->getRanMigrations()
84
        );
85
    }
86
87
    /**
88
     * Get array of migration file names from directory listed in config.
89
     *
90
     * @return array
91
     */
92
    protected function getMigrationFiles()
93
    {
94
        $files = scandir($this->config->getMigrationDirectory());
95
96
        $files = array_filter($files, function ($file) {
97
            return strpos($file, '.php') !== false;
98
        });
99
100
        $files = array_map(function ($file) {
101
            return str_replace('.php', '', $file);
102
        }, $files);
103
104
        return array_values($files);
105
    }
106
107
    /**
108
     * Run pending migrations.
109
     *
110
     * @param array $migrations
111
     *
112
     * @return array
113
     */
114
    protected function runPending(array $migrations)
115
    {
116
        if (count($migrations) === 0) {
117
            $this->log('<info>No pending migrations to run.</info>');
118
119
            return [];
120
        }
121
122
        $batch = $this->repository->getNextBatchNumber();
123
124
        $this->connection->begin();
125
126
        foreach ($migrations as $migration) {
127
            $this->runUp($migration, $batch);
128
        }
129
130
        $this->connection->commit();
131
132
        return $migrations;
133
    }
134
135
    /**
136
     * Run the migration.
137
     *
138
     * @param string $migration
139
     * @param int    $batch
140
     */
141 View Code Duplication
    protected function runUp($migration, $batch)
142
    {
143
        $migrationClass = $this->resolveMigrationClass($migration);
144
145
        try {
146
            $migrationClass->up($this->connection);
147
        } catch (\Exception $e) {
148
            return $this->log("<error>{$e->getMessage()}</error>");
149
        }
150
151
        $this->log("<info>Migrated {$migration}.</info>");
152
153
        $this->repository->insertRecord($migration, $batch);
154
    }
155
156
    /**
157
     * Resolve the migration class from the file name.
158
     *
159
     * @param string $migration
160
     *
161
     * @return Yarak\Migrations\Migration
162
     */
163
    public function resolveMigrationClass($migration)
164
    {
165
        require_once $this->config->getMigrationDirectory().$migration.'.php';
166
167
        $class = Str::studly(implode('_', array_slice(explode('_', $migration), 4)));
168
169
        return new $class();
170
    }
171
172
    /**
173
     * Rollback migrations.
174
     *
175
     * @param int $steps
176
     *
177
     * @return array
178
     */
179
    public function rollback($steps = 1)
180
    {
181
        $this->setUp();
182
183
        $toRollback = $this->repository->getRanMigrations(null, $steps);
184
185
        return $this->runRollback($toRollback);
186
    }
187
188
    /**
189
     * Rollback given migrations.
190
     *
191
     * @param array $migrations
192
     *
193
     * @return array
194
     */
195
    protected function runRollback(array $migrations)
196
    {
197
        if (count($migrations) === 0) {
198
            $this->log('<info>Nothing to rollback.</info>');
199
200
            return [];
201
        }
202
203
        $this->connection->begin();
204
205
        foreach (array_reverse($migrations) as $migration) {
206
            $this->runDown($migration);
207
        }
208
209
        $this->connection->commit();
210
211
        return $migrations;
212
    }
213
214
    /**
215
     * Rollback the migration.
216
     *
217
     * @param string $migration
218
     */
219 View Code Duplication
    protected function runDown($migration)
220
    {
221
        $migrationClass = $this->resolveMigrationClass($migration);
222
223
        try {
224
            $migrationClass->down($this->connection);
225
        } catch (\Exception $e) {
226
            return $this->log("<error>{$e->getMessage()}</error>");
227
        }
228
229
        $this->log("<info>Rolled back {$migration}.</info>");
230
231
        $this->repository->deleteRecord($migration);
232
    }
233
234
    /**
235
     * Reset the database by rolling back all migrations.
236
     *
237
     * @return array
238
     */
239
    public function reset()
240
    {
241
        $this->setUp();
242
243
        $toRollback = $this->repository->getRanMigrations();
244
245
        return $this->runRollback($toRollback);
246
    }
247
248
    /**
249
     * Reset the database and run all migrations.
250
     *
251
     * @return array
252
     */
253
    public function refresh()
254
    {
255
        $this->setUp();
256
257
        $toRollback = $this->repository->getRanMigrations();
258
259
        $this->runRollback($toRollback);
260
261
        $pendingMigrations = $this->getPendingMigrations();
262
263
        return $this->runPending($pendingMigrations);
264
    }
265
266
    /**
267
     * Perform setup procedures for migrations.
268
     */
269
    protected function setUp()
270
    {
271
        if (!$this->connection) {
272
            $this->setConnection();
273
        }
274
275
        $this->createMigrationsRepository();
276
277
        $this->makeDirectoryStructure($this->config->getAllDatabaseDirectories());
278
    }
279
280
    /**
281
     * Set connection to database on object.
282
     *
283
     * @return Pdo
284
     */
285
    public function setConnection()
286
    {
287
        $dbConfig = $this->config->get('database');
288
289
        $this->connection = $this->resolver->getConnection($dbConfig);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->resolver->getConnection($dbConfig) of type object<Yarak\DB\Phalcon\Db\Adapter\Pdo> is incompatible with the declared type object<Yarak\Migrations\Phalcon\Db\Adapter\Pdo> of property $connection.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
290
291
        $this->repository->setConnection($this->connection);
292
293
        return $this;
294
    }
295
296
    /**
297
     * Return the connection.
298
     *
299
     * @return Phalcon\Db\Adapter\Pdo
300
     */
301
    public function getConnection()
302
    {
303
        return $this->connection;
304
    }
305
306
    /**
307
     * Create the migrations table if it doesn't exist.
308
     */
309
    public function createMigrationsRepository()
310
    {
311
        if (!$this->repository->exists()) {
312
            $this->repository->create();
313
        }
314
315
        return $this;
316
    }
317
}
318