Issues (3627)

IntegrationsBundle/Migration/AbstractMigration.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
* @copyright   2019 Mautic, Inc. All rights reserved
7
* @author      Mautic, Inc.
8
*
9
* @link        https://mautic.com
10
*
11
* @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
12
*/
13
14
namespace Mautic\IntegrationsBundle\Migration;
15
16
use Doctrine\DBAL\Schema\Schema;
17
use Doctrine\ORM\EntityManager;
18
19
abstract class AbstractMigration implements MigrationInterface
20
{
21
    /**
22
     * @var EntityManager
23
     */
24
    protected $entityManager;
25
26
    /**
27
     * @var string
28
     */
29
    protected $tablePrefix;
30
31
    /**
32
     * @var string[]
33
     */
34
    private $queries = [];
35
36
    public function __construct(EntityManager $entityManager, string $tablePrefix)
37
    {
38
        $this->entityManager = $entityManager;
39
        $this->tablePrefix   = $tablePrefix;
40
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    public function shouldExecute(): bool
46
    {
47
        return $this->isApplicable($this->entityManager->getConnection()->getSchemaManager()->createSchema());
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     *
53
     * @throws \Doctrine\DBAL\DBALException
54
     */
55
    public function execute(): void
56
    {
57
        $this->up();
58
59
        if (!$this->queries) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->queries of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
60
            return;
61
        }
62
63
        $connection = $this->entityManager->getConnection();
64
65
        foreach ($this->queries as $sql) {
66
            $stmt = $connection->prepare($sql);
67
            $stmt->execute();
68
        }
69
    }
70
71
    /**
72
     * Generate the ALTER TABLE query that adds the foreign key.
73
     *
74
     * @param string[] $columns
75
     * @param string[] $referenceColumns
76
     * @param string   $suffix           usually a 'ON DELETE ...' statement
77
     */
78
    protected function generateAlterTableForeignKeyStatement(
79
        string $table,
80
        array $columns,
81
        string $referenceTable,
82
        array $referenceColumns,
83
        string $suffix = ''
84
    ): string {
85
        return "ALTER TABLE {$this->concatPrefix($table)} 
86
            ADD CONSTRAINT {$this->generatePropertyName($table, 'fk', $columns)} 
87
            FOREIGN KEY ({$this->columnsToString($columns)}) 
88
            REFERENCES {$this->concatPrefix($referenceTable)} ({$this->columnsToString($referenceColumns)}) {$suffix}
89
        ";
90
    }
91
92
    /**
93
     * @param string[] $columns
94
     */
95
    protected function generateIndexStatement(string $table, array $columns): string
96
    {
97
        return "INDEX {$this->generatePropertyName($table, 'idx', $columns)} ({$this->columnsToString($columns)})";
98
    }
99
100
    /**
101
     * @param string[] $columns
102
     */
103
    protected function columnsToString(array $columns): string
104
    {
105
        return implode(',', $columns);
106
    }
107
108
    /**
109
     * Generate the name for the property.
110
     *
111
     * This method was copied from AbstractMauticMigration.
112
     *
113
     * @param string[] $columnNames
114
     */
115
    protected function generatePropertyName(string $table, string $type, array $columnNames): string
116
    {
117
        $columnNames = array_merge([$this->tablePrefix.$table], $columnNames);
118
        $hash        = implode(
119
            '',
120
            array_map(
121
                function ($column) {
122
                    return dechex(crc32($column));
123
                },
124
                $columnNames
125
            )
126
        );
127
128
        return substr(strtoupper($type.'_'.$hash), 0, 63);
129
    }
130
131
    protected function addSql(string $sql): void
132
    {
133
        $this->queries[] = $sql;
134
    }
135
136
    /**
137
     * Concatenates table/index prefix to the provided name.
138
     */
139
    protected function concatPrefix(string $name): string
140
    {
141
        return $this->tablePrefix.$name;
142
    }
143
144
    /**
145
     * Define in the child migration whether the migration should be executed.
146
     * Check if the migration is applied in the schema already.
147
     */
148
    abstract protected function isApplicable(Schema $schema): bool;
149
150
    /**
151
     * Define queries for migration up.
152
     */
153
    abstract protected function up(): void;
154
}
155