Migration::endMigration()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 51
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 5.1777

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 26
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 51
ccs 21
cts 26
cp 0.8077
crap 5.1777
rs 9.1928

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\StorageHandler\Database;
4
5
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
6
use Doctrine\DBAL\Schema\Schema;
7
use eZ\Publish\Core\Persistence\Database\DatabaseHandler;
8
use eZ\Publish\Core\Persistence\Database\QueryException;
9
use eZ\Publish\Core\Persistence\Database\SelectQuery;
10
use Kaliop\eZMigrationBundle\API\StorageHandlerInterface;
11
use Kaliop\eZMigrationBundle\API\Collection\MigrationCollection;
12
use Kaliop\eZMigrationBundle\API\Exception\MigrationBundleException;
13
use Kaliop\eZMigrationBundle\API\Value\Migration as APIMigration;
14
use Kaliop\eZMigrationBundle\API\Value\MigrationDefinition;
15
16
use Kaliop\eZMigrationBundle\API\ConfigResolverInterface;
17
18
/**
19
 * Database-backed storage for info on executed migrations
20
 *
21
 * @todo replace all usage of the ezcdb api with the doctrine dbal one, so that we only depend on one
22
 */
23
class Migration extends TableStorage implements StorageHandlerInterface
24
{
25
    protected $fieldList = 'migration, md5, path, execution_date, status, execution_error';
26
27
    /**
28
     * @param DatabaseHandler $dbHandler
29
     * @param string $tableNameParameter
30
     * @param ConfigResolverInterface $configResolver
31
     * @param array $tableCreationOptions
32
     * @throws \Exception
33
     */
34 149
    public function __construct(DatabaseHandler $dbHandler, $tableNameParameter = 'kaliop_migrations', ConfigResolverInterface $configResolver = null, $tableCreationOptions = array())
35
    {
36 149
        parent::__construct($dbHandler, $tableNameParameter, $configResolver, $tableCreationOptions);
37 149
    }
38
39
    /**
40
     * @param int $limit
41
     * @param int $offset
42
     * @return MigrationCollection
43
     */
44 99
    public function loadMigrations($limit = null, $offset = null)
45
    {
46 99
        return $this->loadMigrationsInner(null, null, $limit, $offset);
47
    }
48
49
    /**
50
     * @param int $status
51
     * @param int $limit
52
     * @param int $offset
53
     * @return MigrationCollection
54
     */
55 2
    public function loadMigrationsByStatus($status, $limit = null, $offset = null)
56
    {
57 2
        return $this->loadMigrationsInner($status, null, $limit, $offset);
58
    }
59
60 47
    public function loadMigrationsByPaths($paths, $limit = null, $offset = null)
61
    {
62 47
        return $this->loadMigrationsInner(null, $paths, $limit, $offset);
63
    }
64
65
    /**
66
     * @param int $status
67
     * @param null|string[] $paths
68
     * @param int $limit
69
     * @param int $offset
70
     * @return MigrationCollection
71
     */
72 144
    protected function loadMigrationsInner($status = null, $paths = array(), $limit = null, $offset = null)
73
    {
74 144
        $this->createTableIfNeeded();
75
76
        /** @var \eZ\Publish\Core\Persistence\Database\SelectQuery $q */
77 144
        $q = $this->dbHandler->createSelectQuery();
78 144
        $q->select($this->fieldList)
0 ignored issues
show
Unused Code introduced by
The call to eZ\Publish\Core\Persiste...e\SelectQuery::select() has too many arguments starting with $this->fieldList. ( Ignorable by Annotation )

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

78
        $q->/** @scrutinizer ignore-call */ 
79
            select($this->fieldList)

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
79 144
            ->from($this->tableName)
0 ignored issues
show
Unused Code introduced by
The call to eZ\Publish\Core\Persiste...ase\SelectQuery::from() has too many arguments starting with $this->tableName. ( Ignorable by Annotation )

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

79
            ->/** @scrutinizer ignore-call */ from($this->tableName)

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
80 144
            ->orderBy('migration', SelectQuery::ASC);
81 144
        if ($status !== null || (is_array($paths) && count($paths))) {
82 5
            $exps = [];
83 5
            if ($status !== null) {
84 2
                $exps[] = $q->expr->eq('status', $q->bindValue($status));
85
            }
86 5
            if (is_array($paths)) {
87 3
                foreach ($paths as $i => $path) {
88 3
                    if ($path === '') {
89
                        unset($paths[$i]);
90
                    }
91
                }
92 3
                if (count($paths)) {
93 3
                    $pexps = array();
94 3
                    foreach ($paths as $path) {
95
                        // NB: this works fine only as long both the paths stored in the db and the ones passed in follow
96
                        //     the same convention regarding path normalization
97
                        /// @todo use a proper db-aware escaping function
98 3
                        $pexps[] = $q->expr->like('path', "'" . str_replace(array('_', '%', "'"), array('\_', '\%', "''"), $path) . '%' . "'");
99
                    }
100
                }
101 3
                $exps[] = $q->expr->lor($pexps);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pexps does not seem to be defined for all execution paths leading up to this point.
Loading history...
Unused Code introduced by
The call to eZ\Publish\Core\Persiste...abase\Expression::lOr() has too many arguments starting with $pexps. ( Ignorable by Annotation )

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

101
                /** @scrutinizer ignore-call */ 
102
                $exps[] = $q->expr->lor($pexps);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
102
            }
103 5
            $q->where($q->expr->land($exps));
0 ignored issues
show
Unused Code introduced by
The call to eZ\Publish\Core\Persiste...se\SelectQuery::where() has too many arguments starting with $q->expr->land($exps). ( Ignorable by Annotation )

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

103
            $q->/** @scrutinizer ignore-call */ 
104
                where($q->expr->land($exps));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Unused Code introduced by
The call to eZ\Publish\Core\Persiste...base\Expression::lAnd() has too many arguments starting with $exps. ( Ignorable by Annotation )

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

103
            $q->where($q->expr->/** @scrutinizer ignore-call */ land($exps));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
104
        }
105 144
        if ($limit > 0 || $offset > 0) {
106 1
            if ($limit <= 0) {
107
                $limit = null;
108
            }
109 1
            if ($offset == 0) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $offset of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
110 1
                $offset = null;
111
            }
112 1
            $q->limit($limit, $offset);
113
        }
114 144
        $stmt = $q->prepare();
115 144
        $stmt->execute();
116 144
        $results = $stmt->fetchAll();
117
118 144
        $migrations = array();
119 144
        foreach ($results as $result) {
120 84
            $migrations[$result['migration']] = $this->arrayToMigration($result);
121
        }
122
123 144
        return new MigrationCollection($migrations);
124
    }
125
126
    /**
127
     * @param string $migrationName
128
     * @return APIMigration|null
129
     */
130 108
    public function loadMigration($migrationName)
131
    {
132 108
        $this->createTableIfNeeded();
133
134
        /** @var \eZ\Publish\Core\Persistence\Database\SelectQuery $q */
135 108
        $q = $this->dbHandler->createSelectQuery();
136 108
        $q->select($this->fieldList)
0 ignored issues
show
Unused Code introduced by
The call to eZ\Publish\Core\Persiste...e\SelectQuery::select() has too many arguments starting with $this->fieldList. ( Ignorable by Annotation )

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

136
        $q->/** @scrutinizer ignore-call */ 
137
            select($this->fieldList)

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
137 108
            ->from($this->tableName)
0 ignored issues
show
Unused Code introduced by
The call to eZ\Publish\Core\Persiste...ase\SelectQuery::from() has too many arguments starting with $this->tableName. ( Ignorable by Annotation )

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

137
            ->/** @scrutinizer ignore-call */ from($this->tableName)

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
138 108
            ->where($q->expr->eq('migration', $q->bindValue($migrationName)));
0 ignored issues
show
Unused Code introduced by
The call to eZ\Publish\Core\Persiste...se\SelectQuery::where() has too many arguments starting with $q->expr->eq('migration'...dValue($migrationName)). ( Ignorable by Annotation )

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

138
            ->/** @scrutinizer ignore-call */ where($q->expr->eq('migration', $q->bindValue($migrationName)));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
139 108
        $stmt = $q->prepare();
140 108
        $stmt->execute();
141 108
        $result = $stmt->fetch(\PDO::FETCH_ASSOC);
142
143 108
        if (is_array($result) && !empty($result)) {
144 108
            return $this->arrayToMigration($result);
145
        }
146
147 104
        return null;
148
    }
149
150
    /**
151
     * Creates and stores a new migration (leaving it in TODO status)
152
     * @param MigrationDefinition $migrationDefinition
153
     * @return APIMigration
154
     * @throws \Exception If the migration exists already (we rely on the PK for that)
155
     */
156 85
    public function addMigration(MigrationDefinition $migrationDefinition)
157
    {
158 85
        $this->createTableIfNeeded();
159
160 85
        $conn = $this->getConnection();
161
162 85
        $migration = new APIMigration(
163 85
            $migrationDefinition->name,
164 85
            md5($migrationDefinition->rawDefinition),
165 85
            $migrationDefinition->path,
166 85
            null,
167 85
            APIMigration::STATUS_TODO
168
        );
169
        try {
170 85
            $conn->insert($this->tableName, $this->migrationToArray($migration));
171 1
        } catch (UniqueConstraintViolationException $e) {
172 1
            throw new MigrationBundleException("Migration '{$migrationDefinition->name}' already exists");
173
        }
174
175 85
        return $migration;
176
    }
177
178
    /**
179
     * Starts a migration, given its definition: stores its status in the db, returns the Migration object
180
     *
181
     * @param MigrationDefinition $migrationDefinition
182
     * @param bool $force when true, starts migrations even if they already exist in DONE, SKIPPED status
183
     * @return APIMigration
184
     * @throws \Exception if migration was already executing or already done
185
     * @todo add a parameter to allow re-execution of already-done migrations
186
     */
187 89
    public function startMigration(MigrationDefinition $migrationDefinition, $force = false)
188
    {
189 89
        return $this->createMigration($migrationDefinition, APIMigration::STATUS_STARTED, 'started', $force);
190
    }
191
192
    /**
193
     * Stops a migration by storing it in the db. Migration status can not be 'started'
194
     *
195
     * NB: if this call happens within another DB transaction which has already been flagged for rollback, the result
196
     * will be that a RuntimeException is thrown, as Doctrine does not allow to call commit() after rollback().
197
     * One way to fix the problem would be not to use a transaction and select-for-update here, but since that is the
198
     * best way to insure atomic updates, I am loath to remove it.
199
     * A known workaround is to call the Doctrine Connection method setNestTransactionsWithSavepoints(true); this can
200
     * be achieved as simply as setting the parameter 'use_savepoints' in the doctrine connection configuration.
201
     *
202
     * @param APIMigration $migration
203
     * @param bool $force When true, the migration will be updated even if it was not in 'started' status
204
     * @throws \Exception If the migration was not started (unless $force=true)
205
     */
206 89
    public function endMigration(APIMigration $migration, $force = false)
207
    {
208 89
        if ($migration->status == APIMigration::STATUS_STARTED) {
209
            throw new MigrationBundleException($this->getEntityName($migration)." '{$migration->name}' can not be ended as its status is 'started'...");
210
        }
211
212 89
        $this->createTableIfNeeded();
213
214
        // select for update
215
216
        // annoyingly enough, neither Doctrine nor EZP provide built in support for 'FOR UPDATE' in their query builders...
217
        // at least the doctrine one allows us to still use parameter binding when we add our sql particle
218 89
        $conn = $this->getConnection();
219
220 89
        $qb = $conn->createQueryBuilder();
221 89
        $qb->select('*')
222 89
            ->from($this->tableName, 'm')
223 89
            ->where('migration = ?');
224 89
        $sql = $qb->getSQL() . ' FOR UPDATE';
225
226 89
        $conn->beginTransaction();
227
228 89
        $stmt = $conn->executeQuery($sql, array($migration->name));
229 89
        $existingMigrationData = $stmt->fetch(\PDO::FETCH_ASSOC);
230
231
        // fail if it was not executing
232
233 89
        if (!is_array($existingMigrationData)) {
234
            // commit to release the lock
235
            $conn->commit();
236
            throw new MigrationBundleException($this->getEntityName($migration)." '{$migration->name}' can not be ended as it is not found");
237
        }
238
239 89
        if (($existingMigrationData['status'] != APIMigration::STATUS_STARTED) && !$force) {
240
            // commit to release the lock
241
            $conn->commit();
242
            throw new MigrationBundleException($this->getEntityName($migration)." '{$migration->name}' can not be ended as it is not executing");
243
        }
244
245 89
        $conn->update(
246 89
            $this->tableName,
247
            array(
248 89
                'status' => $migration->status,
249
                /// @todo use mb_substr (if all dbs we support count col length not in bytes but in chars...)
250 89
                'execution_error' => substr($migration->executionError, 0, 4000),
251 89
                'execution_date' => $migration->executionDate
252
            ),
253 89
            array('migration' => $migration->name)
254
        );
255
256 89
        $conn->commit();
257 89
    }
258
259
    /**
260
     * Removes a Migration from the table - regardless of its state!
261
     *
262
     * @param APIMigration $migration
263
     */
264 108
    public function deleteMigration(APIMigration $migration)
265
    {
266 108
        $this->createTableIfNeeded();
267 108
        $conn = $this->getConnection();
268 108
        $conn->delete($this->tableName, array('migration' => $migration->name));
269 108
    }
270
271
    /**
272
     * Skips a migration by storing it in the db. Migration status can not be 'started'
273
     *
274
     * @param MigrationDefinition $migrationDefinition
275
     * @return APIMigration
276
     * @throws \Exception If the migration was already executed or is executing
277
     */
278 1
    public function skipMigration(MigrationDefinition $migrationDefinition)
279
    {
280 1
        return $this->createMigration($migrationDefinition, APIMigration::STATUS_SKIPPED, 'skipped');
281
    }
282
283
    /**
284
     * @param MigrationDefinition $migrationDefinition
285
     * @param int $status NB: atm not all statuses are supported the same way. IE. logical checks against the db data
286
     *                    will be done for some statuses but not for others
287
     * @param string $action
288
     * @param bool $force
289
     * @return APIMigration
290
     * @throws \Exception
291
     */
292 90
    protected function createMigration(MigrationDefinition $migrationDefinition, $status, $action, $force = false)
293
    {
294 90
        $this->createTableIfNeeded();
295
296
        // select for update
297
298
        // annoyingly enough, neither Doctrine nor EZP provide built in support for 'FOR UPDATE' in their query builders...
299
        // at least the doctrine one allows us to still use parameter binding when we add our sql particle
300 90
        $conn = $this->getConnection();
301
302 90
        $qb = $conn->createQueryBuilder();
303 90
        $qb->select('*')
304 90
            ->from($this->tableName, 'm')
305 90
            ->where('migration = ?');
306 90
        $sql = $qb->getSQL() . ' FOR UPDATE';
307
308 90
        $conn->beginTransaction();
309
310 90
        $stmt = $conn->executeQuery($sql, array($migrationDefinition->name));
311 90
        $existingMigrationData = $stmt->fetch(\PDO::FETCH_ASSOC);
312
313 90
        if (is_array($existingMigrationData)) {
314
            // migration exists
315
316
            // fail if it was already executing
317 71
            if ($existingMigrationData['status'] == APIMigration::STATUS_STARTED) {
318
                // commit to release the lock
319
                $conn->commit();
320
                throw new MigrationBundleException("Migration '{$migrationDefinition->name}' can not be $action as it is already executing");
321
            }
322
            // fail if it was already already done, unless in 'force' mode
323 71
            if (!$force) {
324 71
                if ($existingMigrationData['status'] == APIMigration::STATUS_DONE) {
325
                    // commit to release the lock
326
                    $conn->commit();
327
                    throw new MigrationBundleException("Migration '{$migrationDefinition->name}' can not be $action as it was already executed");
328
                }
329 71
                if ($existingMigrationData['status'] == APIMigration::STATUS_SKIPPED) {
330
                    // commit to release the lock
331
                    $conn->commit();
332
                    throw new MigrationBundleException("Migration '{$migrationDefinition->name}' can not be $action as it was already skipped");
333
                }
334
            }
335
336
            // do not set migration start date if we are skipping it
337 71
            $migration = new APIMigration(
338 71
                $migrationDefinition->name,
339 71
                md5($migrationDefinition->rawDefinition),
340 71
                $migrationDefinition->path,
341 71
                ($status == APIMigration::STATUS_SKIPPED ? null : time()),
342
                $status
343
            );
344 71
            $conn->update(
345 71
                $this->tableName,
346
                array(
347 71
                    'execution_date' => $migration->executionDate,
348 71
                    'status' => $status,
349
                    'execution_error' => null
350
                ),
351 71
                array('migration' => $migrationDefinition->name)
352
            );
353 71
            $conn->commit();
354
355
        } else {
356
            // migration did not exist. Create it!
357
358
            // commit immediately, to release the lock and avoid deadlocks
359 19
            $conn->commit();
360
361 19
            $migration = new APIMigration(
362 19
                $migrationDefinition->name,
363 19
                md5($migrationDefinition->rawDefinition),
364 19
                $migrationDefinition->path,
365 19
                ($status == APIMigration::STATUS_SKIPPED ? null : time()),
366
                $status
367
            );
368 19
            $conn->insert($this->tableName, $this->migrationToArray($migration));
369
        }
370
371 90
        return $migration;
372
    }
373
374 1
    public function resumeMigration(APIMigration $migration)
375
    {
376 1
        $this->createTableIfNeeded();
377
378
        // select for update
379
380
        // annoyingly enough, neither Doctrine nor EZP provide built in support for 'FOR UPDATE' in their query builders...
381
        // at least the doctrine one allows us to still use parameter binding when we add our sql particle
382 1
        $conn = $this->getConnection();
383
384 1
        $qb = $conn->createQueryBuilder();
385 1
        $qb->select('*')
386 1
            ->from($this->tableName, 'm')
387 1
            ->where('migration = ?');
388 1
        $sql = $qb->getSQL() . ' FOR UPDATE';
389
390 1
        $conn->beginTransaction();
391
392 1
        $stmt = $conn->executeQuery($sql, array($migration->name));
393 1
        $existingMigrationData = $stmt->fetch(\PDO::FETCH_ASSOC);
394
395 1
        if (!is_array($existingMigrationData)) {
396
            // commit immediately, to release the lock and avoid deadlocks
397
            $conn->commit();
398
            throw new MigrationBundleException($this->getEntityName($migration)." '{$migration->name}' can not be resumed as it is not found");
399
        }
400
401
        // migration exists
402
403
        // fail if it was not suspended
404 1
        if ($existingMigrationData['status'] != APIMigration::STATUS_SUSPENDED) {
405
            // commit to release the lock
406
            $conn->commit();
407
            throw new MigrationBundleException($this->getEntityName($migration)." '{$migration->name}' can not be resumed as it is not suspended");
408
        }
409
410 1
        $migration = new APIMigration(
411 1
            $migration->name,
412 1
            $migration->md5,
413 1
            $migration->path,
414 1
            time(),
415 1
            APIMigration::STATUS_STARTED
416
        );
417
418 1
        $conn->update(
419 1
            $this->tableName,
420
            array(
421 1
                'execution_date' => $migration->executionDate,
422 1
                'status' => APIMigration::STATUS_STARTED,
423
                'execution_error' => null
424
            ),
425 1
            array('migration' => $migration->name)
426
        );
427 1
        $conn->commit();
428
429 1
        return $migration;
430
    }
431
432
    /**
433
     * Removes all migration from storage (regardless of their status)
434
     */
435
    public function deleteMigrations()
436
    {
437
        $this->drop();
438
    }
439
440
    /**
441
     * @throws QueryException
442
     */
443 1
    public function createTable()
444
    {
445
        /** @var \Doctrine\DBAL\Schema\AbstractSchemaManager $sm */
446 1
        $sm = $this->getConnection()->getSchemaManager();
447 1
        $dbPlatform = $sm->getDatabasePlatform();
448
449 1
        $schema = new Schema();
450
451 1
        $t = $schema->createTable($this->tableName);
452 1
        $t->addColumn('migration', 'string', array('length' => 255));
453 1
        $t->addColumn('path', 'string', array('length' => 4000));
454 1
        $t->addColumn('md5', 'string', array('length' => 32));
455 1
        $t->addColumn('execution_date', 'integer', array('notnull' => false));
456 1
        $t->addColumn('status', 'integer', array('default ' => APIMigration::STATUS_TODO));
457 1
        $t->addColumn('execution_error', 'string', array('length' => 4000, 'notnull' => false));
458 1
        $t->setPrimaryKey(array('migration'));
459
        // in case users want to look up migrations by their full path
460
        // NB: disabled for the moment, as it causes problems on some versions of mysql which limit index length to 767 bytes,
461
        // and 767 bytes can be either 255 chars or 191 chars depending on charset utf8 or utf8mb4...
462
        //$t->addIndex(array('path'));
463
464 1
        $this->injectTableCreationOptions($t);
465
466 1
        foreach ($schema->toSql($dbPlatform) as $sql) {
467
            try {
468 1
                $this->dbHandler->exec($sql);
469
            } catch (QueryException $e) {
470
                // work around limitations in both Mysql and Doctrine
471
                // @see https://github.com/kaliop-uk/ezmigrationbundle/issues/176
472
                if (strpos($e->getMessage(), '1071 Specified key was too long; max key length is 767 bytes') !== false &&
473
                    strpos($sql, 'PRIMARY KEY(migration)') !== false) {
474
                    $this->dbHandler->exec(str_replace('PRIMARY KEY(migration)', 'PRIMARY KEY(migration(191))', $sql));
475
                } else {
476
                    throw $e;
477
                }
478
            }
479
        }
480 1
    }
481
482 103
    protected function migrationToArray(APIMigration $migration)
483
    {
484
        return array(
485 103
            'migration' => $migration->name,
486 103
            'md5' => $migration->md5,
487 103
            'path' => $migration->path,
488 103
            'execution_date' => $migration->executionDate,
489 103
            'status' => $migration->status,
490 103
            'execution_error' => $migration->executionError
491
        );
492
    }
493
494 108
    protected function arrayToMigration(array $data)
495
    {
496 108
        return new APIMigration(
497 108
            $data['migration'],
498 108
            $data['md5'],
499 108
            $data['path'],
500 108
            $data['execution_date'],
501 108
            $data['status'],
502 108
            $data['execution_error']
503
        );
504
    }
505
506
    protected function getEntityName($migration)
507
    {
508
        $arr = explode('\\', get_class($migration));
509
        return end($arr);
510
    }
511
}
512