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

MySqlSchemaToolTest::testGetCreateSchemaSql3()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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

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