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\Models; |
8
|
|
|
use Doctrine\Tests\OrmFunctionalTestCase; |
9
|
|
|
use function array_filter; |
10
|
|
|
use function method_exists; |
11
|
|
|
use function sprintf; |
12
|
|
|
use function strpos; |
13
|
|
|
|
14
|
|
|
class PostgreSqlSchemaToolTest extends OrmFunctionalTestCase |
15
|
|
|
{ |
16
|
|
|
protected function setUp() |
17
|
|
|
{ |
18
|
|
|
parent::setUp(); |
19
|
|
|
|
20
|
|
|
if ($this->_em->getConnection()->getDatabasePlatform()->getName() !== 'postgresql') { |
21
|
|
|
$this->markTestSkipped('The ' . __CLASS__ .' requires the use of postgresql.'); |
22
|
|
|
} |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
protected function tearDown() |
26
|
|
|
{ |
27
|
|
|
$this->_em->getConnection()->exec('DROP TABLE IF EXISTS pg_entity_to_remove'); |
28
|
|
|
$this->_em->getConnection()->exec('DROP SEQUENCE IF EXISTS pg_entity_to_remove_id_seq'); |
29
|
|
|
|
30
|
|
|
parent::tearDown(); |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
public function testPostgresMetadataSequenceIncrementedBy10() |
34
|
|
|
{ |
35
|
|
|
$address = $this->_em->getClassMetadata(Models\CMS\CmsAddress::class); |
36
|
|
|
|
37
|
|
|
$this->assertEquals(1, $address->sequenceGeneratorDefinition['allocationSize']); |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
public function testGetCreateSchemaSql() |
41
|
|
|
{ |
42
|
|
|
$classes = [ |
43
|
|
|
$this->_em->getClassMetadata(Models\CMS\CmsAddress::class), |
44
|
|
|
$this->_em->getClassMetadata(Models\CMS\CmsUser::class), |
45
|
|
|
$this->_em->getClassMetadata(Models\CMS\CmsPhonenumber::class), |
46
|
|
|
]; |
47
|
|
|
|
48
|
|
|
$tool = new SchemaTool($this->_em); |
49
|
|
|
$sql = $tool->getCreateSchemaSql($classes); |
50
|
|
|
$sqlCount = count($sql); |
51
|
|
|
|
52
|
|
|
$this->assertEquals("CREATE TABLE cms_addresses (id INT NOT NULL, user_id INT DEFAULT NULL, country VARCHAR(50) NOT NULL, zip VARCHAR(50) NOT NULL, city VARCHAR(50) NOT NULL, PRIMARY KEY(id))", array_shift($sql)); |
53
|
|
|
$this->assertEquals("CREATE UNIQUE INDEX UNIQ_ACAC157BA76ED395 ON cms_addresses (user_id)", array_shift($sql)); |
54
|
|
|
$this->assertEquals("CREATE TABLE cms_users (id INT NOT NULL, email_id INT DEFAULT NULL, status VARCHAR(50) DEFAULT NULL, username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))", array_shift($sql)); |
55
|
|
|
$this->assertEquals("CREATE UNIQUE INDEX UNIQ_3AF03EC5F85E0677 ON cms_users (username)", array_shift($sql)); |
56
|
|
|
$this->assertEquals("CREATE UNIQUE INDEX UNIQ_3AF03EC5A832C1C9 ON cms_users (email_id)", array_shift($sql)); |
57
|
|
|
$this->assertEquals("CREATE TABLE cms_users_groups (user_id INT NOT NULL, group_id INT NOT NULL, PRIMARY KEY(user_id, group_id))", array_shift($sql)); |
58
|
|
|
$this->assertEquals("CREATE INDEX IDX_7EA9409AA76ED395 ON cms_users_groups (user_id)", array_shift($sql)); |
59
|
|
|
$this->assertEquals("CREATE INDEX IDX_7EA9409AFE54D947 ON cms_users_groups (group_id)", array_shift($sql)); |
60
|
|
|
$this->assertEquals("CREATE TABLE cms_users_tags (user_id INT NOT NULL, tag_id INT NOT NULL, PRIMARY KEY(user_id, tag_id))", array_shift($sql)); |
61
|
|
|
$this->assertEquals("CREATE INDEX IDX_93F5A1ADA76ED395 ON cms_users_tags (user_id)", array_shift($sql)); |
62
|
|
|
$this->assertEquals("CREATE INDEX IDX_93F5A1ADBAD26311 ON cms_users_tags (tag_id)", array_shift($sql)); |
63
|
|
|
$this->assertEquals("CREATE TABLE cms_phonenumbers (phonenumber VARCHAR(50) NOT NULL, user_id INT DEFAULT NULL, PRIMARY KEY(phonenumber))", array_shift($sql)); |
64
|
|
|
$this->assertEquals("CREATE INDEX IDX_F21F790FA76ED395 ON cms_phonenumbers (user_id)", array_shift($sql)); |
65
|
|
|
$this->assertEquals("CREATE SEQUENCE cms_addresses_id_seq INCREMENT BY 1 MINVALUE 1 START 1", array_shift($sql)); |
66
|
|
|
$this->assertEquals("CREATE SEQUENCE cms_users_id_seq INCREMENT BY 1 MINVALUE 1 START 1", array_shift($sql)); |
67
|
|
|
$this->assertEquals("ALTER TABLE cms_addresses ADD CONSTRAINT FK_ACAC157BA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); |
68
|
|
|
$this->assertEquals("ALTER TABLE cms_users ADD CONSTRAINT FK_3AF03EC5A832C1C9 FOREIGN KEY (email_id) REFERENCES cms_emails (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); |
69
|
|
|
$this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); |
70
|
|
|
$this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AFE54D947 FOREIGN KEY (group_id) REFERENCES cms_groups (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); |
71
|
|
|
$this->assertEquals("ALTER TABLE cms_users_tags ADD CONSTRAINT FK_93F5A1ADA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); |
72
|
|
|
$this->assertEquals("ALTER TABLE cms_users_tags ADD CONSTRAINT FK_93F5A1ADBAD26311 FOREIGN KEY (tag_id) REFERENCES cms_tags (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); |
73
|
|
|
$this->assertEquals("ALTER TABLE cms_phonenumbers ADD CONSTRAINT FK_F21F790FA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); |
74
|
|
|
|
75
|
|
|
$this->assertEquals([], $sql, "SQL Array should be empty now."); |
76
|
|
|
$this->assertEquals(22, $sqlCount, "Total of 22 queries should be executed"); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
public function testGetCreateSchemaSql2() |
80
|
|
|
{ |
81
|
|
|
$classes = [ |
82
|
|
|
$this->_em->getClassMetadata(Models\Generic\DecimalModel::class) |
83
|
|
|
]; |
84
|
|
|
|
85
|
|
|
$tool = new SchemaTool($this->_em); |
86
|
|
|
$sql = $tool->getCreateSchemaSql($classes); |
87
|
|
|
|
88
|
|
|
$this->assertEquals(2, count($sql)); |
89
|
|
|
|
90
|
|
|
$this->assertEquals('CREATE TABLE decimal_model (id INT NOT NULL, "decimal" NUMERIC(5, 2) NOT NULL, "high_scale" NUMERIC(14, 4) NOT NULL, PRIMARY KEY(id))', $sql[0]); |
91
|
|
|
$this->assertEquals("CREATE SEQUENCE decimal_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
public function testGetCreateSchemaSql3() |
95
|
|
|
{ |
96
|
|
|
$classes = [ |
97
|
|
|
$this->_em->getClassMetadata(Models\Generic\BooleanModel::class) |
98
|
|
|
]; |
99
|
|
|
|
100
|
|
|
$tool = new SchemaTool($this->_em); |
101
|
|
|
$sql = $tool->getCreateSchemaSql($classes); |
102
|
|
|
|
103
|
|
|
$this->assertEquals(2, count($sql)); |
104
|
|
|
$this->assertEquals("CREATE TABLE boolean_model (id INT NOT NULL, booleanField BOOLEAN NOT NULL, PRIMARY KEY(id))", $sql[0]); |
105
|
|
|
$this->assertEquals("CREATE SEQUENCE boolean_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
public function testGetDropSchemaSql() |
109
|
|
|
{ |
110
|
|
|
$classes = [ |
111
|
|
|
$this->_em->getClassMetadata(Models\CMS\CmsAddress::class), |
112
|
|
|
$this->_em->getClassMetadata(Models\CMS\CmsUser::class), |
113
|
|
|
$this->_em->getClassMetadata(Models\CMS\CmsPhonenumber::class), |
114
|
|
|
]; |
115
|
|
|
|
116
|
|
|
$tool = new SchemaTool($this->_em); |
117
|
|
|
$sql = $tool->getDropSchemaSQL($classes); |
118
|
|
|
|
119
|
|
|
$this->assertEquals(17, count($sql)); |
120
|
|
|
|
121
|
|
|
$dropSequenceSQLs = 0; |
122
|
|
|
|
123
|
|
|
foreach ($sql AS $stmt) { |
124
|
|
|
if (strpos($stmt, "DROP SEQUENCE") === 0) { |
125
|
|
|
$dropSequenceSQLs++; |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
$this->assertEquals(4, $dropSequenceSQLs, "Expect 4 sequences to be dropped."); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* @group DDC-1657 |
133
|
|
|
*/ |
134
|
|
|
public function testUpdateSchemaWithPostgreSQLSchema() |
135
|
|
|
{ |
136
|
|
|
$classes = [ |
137
|
|
|
$this->_em->getClassMetadata(DDC1657Screen::class), |
138
|
|
|
$this->_em->getClassMetadata(DDC1657Avatar::class), |
139
|
|
|
]; |
140
|
|
|
|
141
|
|
|
$tool = new SchemaTool($this->_em); |
142
|
|
|
$tool->createSchema($classes); |
143
|
|
|
|
144
|
|
|
$sql = $tool->getUpdateSchemaSql($classes); |
145
|
|
|
$sql = array_filter($sql, function($sql) { return (strpos($sql, "DROP SEQUENCE stonewood.") === 0); }); |
146
|
|
|
|
147
|
|
|
$this->assertCount(0, $sql, implode("\n", $sql)); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
public function provideUpdateSchemaSqlWithSchemaAssetFilter() : array |
151
|
|
|
{ |
152
|
|
|
return [ |
153
|
|
|
['/^(?!pg_entity_to_r)/', null], |
154
|
|
|
[ |
155
|
|
|
null, |
156
|
|
|
static function ($assetName) : bool { |
157
|
|
|
return $assetName !== 'pg_entity_to_remove'; |
158
|
|
|
}, |
159
|
|
|
], |
160
|
|
|
]; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* @dataProvider provideUpdateSchemaSqlWithSchemaAssetFilter |
165
|
|
|
*/ |
166
|
|
|
public function testUpdateSchemaSqlWithSchemaAssetFilter(?string $filterRegex, ?callable $filterCallback) |
167
|
|
|
{ |
168
|
|
|
if (! method_exists(Configuration::class, 'setSchemaAssetsFilter')) { |
169
|
|
|
$this->markTestSkipped(sprintf('Test require %s::setSchemaAssetsFilter method', Configuration::class)); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
if ($filterRegex && ! method_exists(Configuration::class, 'setFilterSchemaAssetsExpression')) { |
173
|
|
|
$this->markTestSkipped(sprintf('Test require %s::setFilterSchemaAssetsExpression method', Configuration::class)); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
$classes = [$this->_em->getClassMetadata(PgMyEntityToRemove::class)]; |
177
|
|
|
|
178
|
|
|
$tool = new SchemaTool($this->_em); |
179
|
|
|
$tool->createSchema($classes); |
180
|
|
|
|
181
|
|
|
$config = $this->_em->getConnection()->getConfiguration(); |
182
|
|
|
if ($filterRegex) { |
183
|
|
|
$config->setFilterSchemaAssetsExpression($filterRegex); |
|
|
|
|
184
|
|
|
} else { |
185
|
|
|
$config->setSchemaAssetsFilter($filterCallback); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
$sqls = $tool->getUpdateSchemaSql($classes); |
189
|
|
|
$sqls = array_filter($sqls, static function ($sql) { |
190
|
|
|
return strpos($sql, 'pg_entity_to_remove') !== false; |
191
|
|
|
}); |
192
|
|
|
$this->assertCount(0, $sqls); |
193
|
|
|
|
194
|
|
|
if ($filterRegex) { |
195
|
|
|
$this->assertEquals($filterRegex, $config->getFilterSchemaAssetsExpression()); |
196
|
|
|
} else { |
197
|
|
|
$this->assertSame($filterCallback, $config->getSchemaAssetsFilter()); |
198
|
|
|
} |
199
|
|
|
} |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* @Entity |
204
|
|
|
* @Table(name="stonewood.screen") |
205
|
|
|
*/ |
206
|
|
|
class DDC1657Screen |
207
|
|
|
{ |
208
|
|
|
/** |
209
|
|
|
* Identifier |
210
|
|
|
* @var int |
211
|
|
|
* |
212
|
|
|
* @Id |
213
|
|
|
* @GeneratedValue(strategy="IDENTITY") |
214
|
|
|
* @Column(name="pk", type="integer", nullable=false) |
215
|
|
|
*/ |
216
|
|
|
private $pk; |
|
|
|
|
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Title |
220
|
|
|
* @var string |
221
|
|
|
* |
222
|
|
|
* @Column(name="title", type="string", length=255, nullable=false) |
223
|
|
|
*/ |
224
|
|
|
private $title; |
|
|
|
|
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* Path |
228
|
|
|
* @var string |
229
|
|
|
* |
230
|
|
|
* @Column(name="path", type="string", length=255, nullable=false) |
231
|
|
|
*/ |
232
|
|
|
private $path; |
|
|
|
|
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Register date |
236
|
|
|
* @var Date |
|
|
|
|
237
|
|
|
* |
238
|
|
|
* @Column(name="ddate", type="date", nullable=false) |
239
|
|
|
*/ |
240
|
|
|
private $ddate; |
|
|
|
|
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* Avatar |
244
|
|
|
* @var Stonewood\Model\Entity\Avatar |
|
|
|
|
245
|
|
|
* |
246
|
|
|
* @ManyToOne(targetEntity="DDC1657Avatar") |
247
|
|
|
* @JoinColumn(name="pk_avatar", referencedColumnName="pk", nullable=true, onDelete="CASCADE") |
248
|
|
|
*/ |
249
|
|
|
private $avatar; |
|
|
|
|
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* @Entity |
254
|
|
|
* @Table(name="stonewood.avatar") |
255
|
|
|
*/ |
256
|
|
|
class DDC1657Avatar |
257
|
|
|
{ |
258
|
|
|
/** |
259
|
|
|
* Identifier |
260
|
|
|
* @var int |
261
|
|
|
* |
262
|
|
|
* @Id |
263
|
|
|
* @GeneratedValue(strategy="IDENTITY") |
264
|
|
|
* @Column(name="pk", type="integer", nullable=false) |
265
|
|
|
*/ |
266
|
|
|
private $pk; |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
/** |
270
|
|
|
* @Entity |
271
|
|
|
* @Table(name="pg_entity_to_remove") |
272
|
|
|
*/ |
273
|
|
|
class PgMyEntityToRemove |
274
|
|
|
{ |
275
|
|
|
/** |
276
|
|
|
* @Id @Column(type="integer") |
277
|
|
|
* @GeneratedValue(strategy="AUTO") |
278
|
|
|
*/ |
279
|
|
|
public $id; |
280
|
|
|
} |
281
|
|
|
|
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.