Passed
Pull Request — 2.7 (#7875)
by
unknown
08:33
created

MySqlSchemaToolTest::testUpdateSchemaSql()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
c 1
b 0
f 0
dl 0
loc 21
rs 9.7333
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Doctrine\Tests\ORM\Functional\SchemaTool;
4
5
use Doctrine\DBAL\Configuration;
6
use Doctrine\ORM\Tools\SchemaTool;
7
use Doctrine\Tests\OrmFunctionalTestCase;
8
use Doctrine\Tests\Models;
9
use function array_filter;
10
use function current;
11
use function implode;
12
use function method_exists;
13
use function sprintf;
14
use function strpos;
15
16
class MySqlSchemaToolTest extends OrmFunctionalTestCase
17
{
18
    protected function setUp() : void
19
    {
20
        parent::setUp();
21
22
        if ($this->_em->getConnection()->getDatabasePlatform()->getName() !== 'mysql') {
23
            $this->markTestSkipped('The ' . __CLASS__ .' requires the use of mysql.');
24
        }
25
    }
26
27
    protected function tearDown() : void
28
    {
29
        $this->_em->getConnection()->exec('DROP TABLE IF EXISTS entity_to_remove');
30
        $this->_em->getConnection()->exec('DROP TABLE IF EXISTS other_entity_to_remove');
31
32
        parent::tearDown();
33
    }
34
35
    public function testGetCreateSchemaSql()
36
    {
37
        $classes = [
38
            $this->_em->getClassMetadata(Models\CMS\CmsGroup::class),
39
            $this->_em->getClassMetadata(Models\CMS\CmsUser::class),
40
            $this->_em->getClassMetadata(Models\CMS\CmsTag::class),
41
            $this->_em->getClassMetadata(Models\CMS\CmsAddress::class),
42
            $this->_em->getClassMetadata(Models\CMS\CmsEmail::class),
43
            $this->_em->getClassMetadata(Models\CMS\CmsPhonenumber::class),
44
        ];
45
46
        $tool = new SchemaTool($this->_em);
47
        $sql = $tool->getCreateSchemaSql($classes);
48
        $collation = $this->getColumnCollationDeclarationSQL('utf8_unicode_ci');
49
50
        $this->assertEquals('CREATE TABLE cms_groups (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[0]);
51
        $this->assertEquals('CREATE TABLE cms_users (id INT AUTO_INCREMENT NOT NULL, email_id INT DEFAULT NULL, status VARCHAR(50) DEFAULT NULL, username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_3AF03EC5F85E0677 (username), UNIQUE INDEX UNIQ_3AF03EC5A832C1C9 (email_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[1]);
52
        $this->assertEquals('CREATE TABLE cms_users_groups (user_id INT NOT NULL, group_id INT NOT NULL, INDEX IDX_7EA9409AA76ED395 (user_id), INDEX IDX_7EA9409AFE54D947 (group_id), PRIMARY KEY(user_id, group_id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[2]);
53
        $this->assertEquals('CREATE TABLE cms_users_tags (user_id INT NOT NULL, tag_id INT NOT NULL, INDEX IDX_93F5A1ADA76ED395 (user_id), INDEX IDX_93F5A1ADBAD26311 (tag_id), PRIMARY KEY(user_id, tag_id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[3]);
54
        $this->assertEquals('CREATE TABLE cms_tags (id INT AUTO_INCREMENT NOT NULL, tag_name VARCHAR(50) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[4]);
55
        $this->assertEquals('CREATE TABLE cms_addresses (id INT AUTO_INCREMENT NOT NULL, user_id INT DEFAULT NULL, country VARCHAR(50) NOT NULL, zip VARCHAR(50) NOT NULL, city VARCHAR(50) NOT NULL, UNIQUE INDEX UNIQ_ACAC157BA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[5]);
56
        $this->assertEquals('CREATE TABLE cms_emails (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(250) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[6]);
57
        $this->assertEquals('CREATE TABLE cms_phonenumbers (phonenumber VARCHAR(50) NOT NULL, user_id INT DEFAULT NULL, INDEX IDX_F21F790FA76ED395 (user_id), PRIMARY KEY(phonenumber)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[7]);
58
        $this->assertEquals("ALTER TABLE cms_users ADD CONSTRAINT FK_3AF03EC5A832C1C9 FOREIGN KEY (email_id) REFERENCES cms_emails (id)", $sql[8]);
59
        $this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id)", $sql[9]);
60
        $this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AFE54D947 FOREIGN KEY (group_id) REFERENCES cms_groups (id)", $sql[10]);
61
        $this->assertEquals("ALTER TABLE cms_users_tags ADD CONSTRAINT FK_93F5A1ADA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id)", $sql[11]);
62
        $this->assertEquals("ALTER TABLE cms_users_tags ADD CONSTRAINT FK_93F5A1ADBAD26311 FOREIGN KEY (tag_id) REFERENCES cms_tags (id)", $sql[12]);
63
        $this->assertEquals("ALTER TABLE cms_addresses ADD CONSTRAINT FK_ACAC157BA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id)", $sql[13]);
64
        $this->assertEquals("ALTER TABLE cms_phonenumbers ADD CONSTRAINT FK_F21F790FA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id)", $sql[14]);
65
66
        $this->assertEquals(15, count($sql));
67
    }
68
69
    private function getColumnCollationDeclarationSQL(string $collation) : string
70
    {
71
        if (method_exists($this->_em->getConnection()->getDatabasePlatform(), 'getColumnCollationDeclarationSQL')) {
72
            return $this->_em->getConnection()->getDatabasePlatform()->getColumnCollationDeclarationSQL($collation);
73
        }
74
75
        return sprintf('COLLATE %s', $collation);
76
    }
77
78
    public function testGetCreateSchemaSql2()
79
    {
80
        $classes = [
81
            $this->_em->getClassMetadata(Models\Generic\DecimalModel::class)
82
        ];
83
84
        $tool = new SchemaTool($this->_em);
85
        $sql = $tool->getCreateSchemaSql($classes);
86
        $collation = $this->getColumnCollationDeclarationSQL('utf8_unicode_ci');
87
88
        $this->assertEquals(1, count($sql));
89
        $this->assertEquals('CREATE TABLE decimal_model (id INT AUTO_INCREMENT NOT NULL, `decimal` NUMERIC(5, 2) NOT NULL, `high_scale` NUMERIC(14, 4) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[0]);
90
    }
91
92
    public function testGetCreateSchemaSql3()
93
    {
94
        $classes = [
95
            $this->_em->getClassMetadata(Models\Generic\BooleanModel::class)
96
        ];
97
98
        $tool = new SchemaTool($this->_em);
99
        $sql = $tool->getCreateSchemaSql($classes);
100
        $collation = $this->getColumnCollationDeclarationSQL('utf8_unicode_ci');
101
102
        $this->assertEquals(1, count($sql));
103
        $this->assertEquals('CREATE TABLE boolean_model (id INT AUTO_INCREMENT NOT NULL, booleanField TINYINT(1) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[0]);
104
    }
105
106
    /**
107
     * @group DBAL-204
108
     */
109
    public function testGetCreateSchemaSql4()
110
    {
111
        $classes = [
112
            $this->_em->getClassMetadata(MysqlSchemaNamespacedEntity::class)
113
        ];
114
115
        $tool = new SchemaTool($this->_em);
116
        $sql = $tool->getCreateSchemaSql($classes);
117
118
        $this->assertEquals(0, count($sql));
119
    }
120
121
    public function testUpdateSchemaSql() : void
122
    {
123
        $classes = [
124
            $this->_em->getClassMetadata(MyEntityToRemove::class),
125
        ];
126
        $tool    = new SchemaTool($this->_em);
127
        $sqls    = $tool->getUpdateSchemaSql($classes);
128
        $sqls    = $this->filterSqls($sqls, ['entity_to_remove']);
129
        self::assertCount(1, $sqls);
130
        self::assertContains('CREATE TABLE entity_to_remove (id INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(id))', implode("\n", $sqls));
131
132
        $this->_em->getConnection()->exec(current($sqls));
133
        $sqls = $tool->getUpdateSchemaSql($classes);
134
        $sqls = $this->filterSqls($sqls, ['entity_to_remove']);
135
        self::assertCount(0, $sqls);
136
137
        $classes[] = $this->_em->getClassMetadata(MyOtherEntityToRemove::class);
138
        $sqls      = $tool->getUpdateSchemaSql($classes);
139
        $sqls      = $this->filterSqls($sqls, ['entity_to_remove', 'other_entity_to_remove']);
140
        self::assertCount(1, $sqls);
141
        self::assertContains('CREATE TABLE other_entity_to_remove (id INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(id))', implode("\n", $sqls));
142
    }
143
144
    public function provideUpdateSchemaSqlWithSchemaAssetFilter() : array
145
    {
146
        return [
147
            ['/^(?!entity_to_r)/', null],
148
            [
149
                null,
150
                static function ($assetName) : bool {
151
                    return $assetName !== 'entity_to_remove';
152
                },
153
            ],
154
        ];
155
    }
156
157
    /**
158
     * @dataProvider provideUpdateSchemaSqlWithSchemaAssetFilter
159
     */
160
    public function testUpdateSchemaSqlWithSchemaAssetFilter(?string $filterRegex, ?callable $filterCallback) : void
161
    {
162
        if ($filterRegex && ! method_exists(Configuration::class, 'setFilterSchemaAssetsExpression')) {
163
            self::markTestSkipped(sprintf('Test require %s::setFilterSchemaAssetsExpression method', Configuration::class));
164
        }
165
166
        $classes = [$this->_em->getClassMetadata(MyEntityToRemove::class)];
167
168
        $tool = new SchemaTool($this->_em);
169
        $tool->createSchema($classes);
170
171
        $config = $this->_em->getConnection()->getConfiguration();
172
        if ($filterRegex) {
173
            $config->setFilterSchemaAssetsExpression($filterRegex);
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Configurat...chemaAssetsExpression() has been deprecated: Use Configuration::setSchemaAssetsFilter() instead ( Ignorable by Annotation )

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

173
            /** @scrutinizer ignore-deprecated */ $config->setFilterSchemaAssetsExpression($filterRegex);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
174
        } else {
175
            $config->setSchemaAssetsFilter($filterCallback);
176
        }
177
178
        $sqls = $tool->getUpdateSchemaSql($classes);
179
        $sqls = $this->filterSqls($sqls, ['entity_to_remove']);
180
        self::assertCount(0, $sqls);
181
182
        if ($filterRegex) {
183
            self::assertEquals($filterRegex, $config->getFilterSchemaAssetsExpression());
184
        } else {
185
            self::assertSame($filterCallback, $config->getSchemaAssetsFilter());
186
        }
187
    }
188
189
    private function filterSqls(array $sqls, array $needles) : array
190
    {
191
        return array_filter($sqls, static function ($sql) use ($needles) {
192
            foreach ($needles as $needle) {
193
                if (strpos($sql, $needle) !== false) {
194
                    return true;
195
                }
196
            }
197
            return false;
198
        });
199
    }
200
}
201
202
/**
203
 * @Entity
204
 * @Table("namespace.entity")
205
 */
206
class MysqlSchemaNamespacedEntity
207
{
208
    /** @Column(type="integer") @Id @GeneratedValue */
209
    public $id;
210
}
211
212
/**
213
 * @Entity
214
 * @Table(name="entity_to_remove")
215
 */
216
class MyEntityToRemove
217
{
218
    /**
219
     * @Id @Column(type="integer")
220
     * @GeneratedValue(strategy="AUTO")
221
     */
222
    public $id;
223
}
224
225
/**
226
 * @Entity
227
 * @Table(name="other_entity_to_remove")
228
 */
229
class MyOtherEntityToRemove
230
{
231
    /**
232
     * @Id @Column(type="integer")
233
     * @GeneratedValue(strategy="AUTO")
234
     */
235
    public $id;
236
}
237