Passed
Push — 2.7 ( 62fb49...c036c0 )
by Luís
08:55
created

testPassColumnOptionsToJoinColumn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 32
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 21
nc 1
nop 0
dl 0
loc 32
rs 9.584
c 0
b 0
f 0
1
<?php
2
3
namespace Doctrine\Tests\ORM\Tools;
4
5
use Doctrine\ORM\Mapping\ClassMetadata;
6
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
7
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
8
use Doctrine\ORM\Tools\SchemaTool;
9
use Doctrine\ORM\Tools\ToolEvents;
10
use Doctrine\Tests\Models\CMS\CmsAddress;
11
use Doctrine\Tests\Models\CMS\CmsArticle;
12
use Doctrine\Tests\Models\CMS\CmsComment;
13
use Doctrine\Tests\Models\CMS\CmsEmployee;
14
use Doctrine\Tests\Models\CMS\CmsGroup;
15
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
16
use Doctrine\Tests\Models\CMS\CmsUser;
17
use Doctrine\Tests\Models\CompositeKeyInheritance\JoinedDerivedChildClass;
18
use Doctrine\Tests\Models\CompositeKeyInheritance\JoinedDerivedIdentityClass;
19
use Doctrine\Tests\Models\CompositeKeyInheritance\JoinedDerivedRootClass;
20
use Doctrine\Tests\Models\Forum\ForumAvatar;
21
use Doctrine\Tests\Models\Forum\ForumBoard;
22
use Doctrine\Tests\Models\Forum\ForumCategory;
23
use Doctrine\Tests\Models\Forum\ForumUser;
24
use Doctrine\Tests\Models\NullDefault\NullDefaultColumn;
25
use Doctrine\Tests\OrmTestCase;
26
27
class SchemaToolTest extends OrmTestCase
28
{
29
    public function testAddUniqueIndexForUniqueFieldAnnotation()
30
    {
31
        $em = $this->_getTestEntityManager();
32
        $schemaTool = new SchemaTool($em);
33
34
        $classes = [
35
            $em->getClassMetadata(CmsAddress::class),
36
            $em->getClassMetadata(CmsArticle::class),
37
            $em->getClassMetadata(CmsComment::class),
38
            $em->getClassMetadata(CmsEmployee::class),
39
            $em->getClassMetadata(CmsGroup::class),
40
            $em->getClassMetadata(CmsPhonenumber::class),
41
            $em->getClassMetadata(CmsUser::class),
42
        ];
43
44
        $schema = $schemaTool->getSchemaFromMetadata($classes);
45
46
        $this->assertTrue($schema->hasTable('cms_users'), "Table cms_users should exist.");
47
        $this->assertTrue($schema->getTable('cms_users')->columnsAreIndexed(['username']), "username column should be indexed.");
48
    }
49
50
    public function testAnnotationOptionsAttribute()
51
    {
52
        $em = $this->_getTestEntityManager();
53
        $schemaTool = new SchemaTool($em);
54
55
        $classes = [
56
            $em->getClassMetadata(TestEntityWithAnnotationOptionsAttribute::class),
57
        ];
58
59
        $schema = $schemaTool->getSchemaFromMetadata($classes);
60
61
        $expected = ['foo' => 'bar', 'baz' => ['key' => 'val']];
62
63
        $this->assertEquals($expected, $schema->getTable('TestEntityWithAnnotationOptionsAttribute')->getOptions(), "options annotation are passed to the tables options");
64
        $this->assertEquals($expected, $schema->getTable('TestEntityWithAnnotationOptionsAttribute')->getColumn('test')->getCustomSchemaOptions(), "options annotation are passed to the columns customSchemaOptions");
65
    }
66
67
    /**
68
     * @group DDC-200
69
     */
70
    public function testPassColumnDefinitionToJoinColumn()
71
    {
72
        $customColumnDef = "MEDIUMINT(6) UNSIGNED NOT NULL";
73
74
        $em = $this->_getTestEntityManager();
75
        $schemaTool = new SchemaTool($em);
76
77
        $avatar = $em->getClassMetadata(ForumAvatar::class);
78
        $avatar->fieldMappings['id']['columnDefinition'] = $customColumnDef;
79
        $user = $em->getClassMetadata(ForumUser::class);
80
81
        $classes = [$avatar, $user];
82
83
        $schema = $schemaTool->getSchemaFromMetadata($classes);
84
85
        $this->assertTrue($schema->hasTable('forum_users'));
86
        $table = $schema->getTable("forum_users");
87
        $this->assertTrue($table->hasColumn('avatar_id'));
88
        $this->assertEquals($customColumnDef, $table->getColumn('avatar_id')->getColumnDefinition());
89
    }
90
91
    /**
92
     * @group 6830
93
     */
94
    public function testPassColumnOptionsToJoinColumn() : void
95
    {
96
        $em = $this->_getTestEntityManager();
97
        $category = $em->getClassMetadata(GH6830Category::class);
98
        $board = $em->getClassMetadata(GH6830Board::class);
99
100
        $schemaTool = new SchemaTool($em);
101
        $schema = $schemaTool->getSchemaFromMetadata([$category, $board]);
102
103
        self::assertTrue($schema->hasTable('GH6830Category'));
104
        self::assertTrue($schema->hasTable('GH6830Board'));
105
106
        $tableCategory = $schema->getTable('GH6830Category');
107
        $tableBoard = $schema->getTable('GH6830Board');
108
109
        self::assertTrue($tableBoard->hasColumn('category_id'));
110
111
        self::assertSame(
112
            $tableCategory->getColumn('id')->getFixed(),
113
            $tableBoard->getColumn('category_id')->getFixed(),
114
            'Foreign key/join column should have the same value of option `fixed` as the referenced column'
115
        );
116
117
        self::assertEquals(
118
            $tableCategory->getColumn('id')->getCustomSchemaOptions(),
119
            $tableBoard->getColumn('category_id')->getCustomSchemaOptions(),
120
            'Foreign key/join column should have the same custom options as the referenced column'
121
        );
122
123
        self::assertEquals(
124
            ['collation' => 'latin1_bin', 'foo' => 'bar'],
125
            $tableBoard->getColumn('category_id')->getCustomSchemaOptions()
126
        );
127
    }
128
129
    /**
130
     * @group DDC-283
131
     */
132
    public function testPostGenerateEvents()
133
    {
134
        $listener = new GenerateSchemaEventListener();
135
136
        $em = $this->_getTestEntityManager();
137
        $em->getEventManager()->addEventListener(
138
            [ToolEvents::postGenerateSchemaTable, ToolEvents::postGenerateSchema], $listener
139
        );
140
        $schemaTool = new SchemaTool($em);
141
142
        $classes = [
143
            $em->getClassMetadata(CmsAddress::class),
144
            $em->getClassMetadata(CmsArticle::class),
145
            $em->getClassMetadata(CmsComment::class),
146
            $em->getClassMetadata(CmsEmployee::class),
147
            $em->getClassMetadata(CmsGroup::class),
148
            $em->getClassMetadata(CmsPhonenumber::class),
149
            $em->getClassMetadata(CmsUser::class),
150
        ];
151
152
        $schema = $schemaTool->getSchemaFromMetadata($classes);
0 ignored issues
show
Unused Code introduced by
The assignment to $schema is dead and can be removed.
Loading history...
153
154
        $this->assertEquals(count($classes), $listener->tableCalls);
155
        $this->assertTrue($listener->schemaCalled);
156
    }
157
158
    public function testNullDefaultNotAddedToCustomSchemaOptions()
159
    {
160
        $em = $this->_getTestEntityManager();
161
        $schemaTool = new SchemaTool($em);
162
163
        $customSchemaOptions = $schemaTool->getSchemaFromMetadata([$em->getClassMetadata(NullDefaultColumn::class)])
164
            ->getTable('NullDefaultColumn')
165
            ->getColumn('nullDefault')
166
            ->getCustomSchemaOptions();
167
168
        $this->assertSame([], $customSchemaOptions);
169
    }
170
171
    /**
172
     * @group DDC-3671
173
     */
174
    public function testSchemaHasProperIndexesFromUniqueConstraintAnnotation()
175
    {
176
        $em         = $this->_getTestEntityManager();
177
        $schemaTool = new SchemaTool($em);
178
        $classes    = [
179
            $em->getClassMetadata(UniqueConstraintAnnotationModel::class),
180
        ];
181
182
        $schema = $schemaTool->getSchemaFromMetadata($classes);
183
184
        $this->assertTrue($schema->hasTable('unique_constraint_annotation_table'));
185
        $table = $schema->getTable('unique_constraint_annotation_table');
186
187
        $this->assertEquals(2, count($table->getIndexes()));
188
        $this->assertTrue($table->hasIndex('primary'));
189
        $this->assertTrue($table->hasIndex('uniq_hash'));
190
    }
191
192
    public function testRemoveUniqueIndexOverruledByPrimaryKey()
193
    {
194
        $em         = $this->_getTestEntityManager();
195
        $schemaTool = new SchemaTool($em);
196
        $classes    = [
197
            $em->getClassMetadata(FirstEntity::class),
198
            $em->getClassMetadata(SecondEntity::class)
199
        ];
200
201
        $schema = $schemaTool->getSchemaFromMetadata($classes);
202
203
        $this->assertTrue($schema->hasTable('first_entity'), "Table first_entity should exist.");
204
205
        $indexes = $schema->getTable('first_entity')->getIndexes();
206
207
        $this->assertCount(1, $indexes, "there should be only one index");
208
        $this->assertTrue(current($indexes)->isPrimary(), "index should be primary");
209
    }
210
211
    public function testSetDiscriminatorColumnWithoutLength() : void
212
    {
213
        $em         = $this->_getTestEntityManager();
214
        $schemaTool = new SchemaTool($em);
215
        $metadata   = $em->getClassMetadata(FirstEntity::class);
216
217
        $metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE);
218
        $metadata->setDiscriminatorColumn(['name' => 'discriminator', 'type' => 'string']);
219
220
        $schema = $schemaTool->getSchemaFromMetadata([$metadata]);
221
222
        $this->assertTrue($schema->hasTable('first_entity'));
223
        $table = $schema->getTable('first_entity');
224
225
        $this->assertTrue($table->hasColumn('discriminator'));
226
        $column = $table->getColumn('discriminator');
227
228
        $this->assertEquals(255, $column->getLength());
229
    }
230
231
    public function testDerivedCompositeKey() : void
232
    {
233
        $em         = $this->_getTestEntityManager();
234
        $schemaTool = new SchemaTool($em);
235
236
        $schema = $schemaTool->getSchemaFromMetadata(
237
            [
238
                $em->getClassMetadata(JoinedDerivedIdentityClass::class),
239
                $em->getClassMetadata(JoinedDerivedRootClass::class),
240
                $em->getClassMetadata(JoinedDerivedChildClass::class),
241
            ]
242
        );
243
244
        self::assertTrue($schema->hasTable('joined_derived_identity'));
245
        self::assertTrue($schema->hasTable('joined_derived_root'));
246
        self::assertTrue($schema->hasTable('joined_derived_child'));
247
248
        $rootTable = $schema->getTable('joined_derived_root');
249
        self::assertNotNull($rootTable->getPrimaryKey());
250
        self::assertSame(['keyPart1_id', 'keyPart2'], $rootTable->getPrimaryKey()->getColumns());
251
252
        $childTable = $schema->getTable('joined_derived_child');
253
        self::assertNotNull($childTable->getPrimaryKey());
254
        self::assertSame(['keyPart1_id', 'keyPart2'], $childTable->getPrimaryKey()->getColumns());
255
256
        $childTableForeignKeys = $childTable->getForeignKeys();
257
258
        self::assertCount(2, $childTableForeignKeys);
259
260
        $expectedColumns = [
261
            'joined_derived_identity' => [['keyPart1_id'], ['id']],
262
            'joined_derived_root'     => [['keyPart1_id', 'keyPart2'], ['keyPart1_id', 'keyPart2']],
263
        ];
264
265
        foreach ($childTableForeignKeys as $foreignKey) {
266
            self::assertArrayHasKey($foreignKey->getForeignTableName(), $expectedColumns);
267
268
            [$localColumns, $foreignColumns] = $expectedColumns[$foreignKey->getForeignTableName()];
269
270
            self::assertSame($localColumns, $foreignKey->getLocalColumns());
271
            self::assertSame($foreignColumns, $foreignKey->getForeignColumns());
272
        }
273
    }
274
}
275
276
/**
277
 * @Entity
278
 * @Table(options={"foo": "bar", "baz": {"key": "val"}})
279
 */
280
class TestEntityWithAnnotationOptionsAttribute
281
{
282
    /** @Id @Column */
283
    private $id;
0 ignored issues
show
introduced by
The private property $id is not used, and could be removed.
Loading history...
284
285
    /**
286
     * @Column(type="string", options={"foo": "bar", "baz": {"key": "val"}})
287
     */
288
    private $test;
0 ignored issues
show
introduced by
The private property $test is not used, and could be removed.
Loading history...
289
}
290
291
class GenerateSchemaEventListener
292
{
293
    public $tableCalls = 0;
294
    public $schemaCalled = false;
295
296
    public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs)
0 ignored issues
show
Unused Code introduced by
The parameter $eventArgs is not used and could be removed. ( Ignorable by Annotation )

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

296
    public function postGenerateSchemaTable(/** @scrutinizer ignore-unused */ GenerateSchemaTableEventArgs $eventArgs)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
297
    {
298
        $this->tableCalls++;
299
    }
300
301
    public function postGenerateSchema(GenerateSchemaEventArgs $eventArgs)
0 ignored issues
show
Unused Code introduced by
The parameter $eventArgs is not used and could be removed. ( Ignorable by Annotation )

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

301
    public function postGenerateSchema(/** @scrutinizer ignore-unused */ GenerateSchemaEventArgs $eventArgs)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
302
    {
303
        $this->schemaCalled = true;
304
    }
305
}
306
307
/**
308
 * @Entity
309
 * @Table(name="unique_constraint_annotation_table", uniqueConstraints={
310
 *   @UniqueConstraint(name="uniq_hash", columns={"hash"})
311
 * })
312
 */
313
class UniqueConstraintAnnotationModel
314
{
315
    /** @Id @Column */
316
    private $id;
317
318
    /**
319
     * @Column(name="hash", type="string", length=8, nullable=false, unique=true)
320
     */
321
    private $hash;
0 ignored issues
show
introduced by
The private property $hash is not used, and could be removed.
Loading history...
322
}
323
324
/**
325
 * @Entity
326
 * @Table(name="first_entity")
327
 */
328
class FirstEntity
329
{
330
    /**
331
     * @Id
332
     * @Column(name="id")
333
     */
334
    public $id;
335
336
    /**
337
     * @OneToOne(targetEntity="SecondEntity")
338
     * @JoinColumn(name="id", referencedColumnName="fist_entity_id")
339
     */
340
    public $secondEntity;
341
342
    /**
343
     * @Column(name="name")
344
     */
345
    public $name;
346
}
347
348
/**
349
 * @Entity
350
 * @Table(name="second_entity")
351
 */
352
class SecondEntity
353
{
354
    /**
355
     * @Id
356
     * @Column(name="fist_entity_id")
357
     */
358
    public $fist_entity_id;
359
360
    /**
361
     * @Column(name="name")
362
     */
363
    public $name;
364
}
365
366
/**
367
 * @Entity
368
 */
369
class GH6830Board
370
{
371
    /**
372
     * @Id
373
     * @Column(type="integer")
374
     */
375
    public $id;
376
377
    /**
378
     * @ManyToOne(targetEntity=GH6830Category::class, inversedBy="boards")
379
     * @JoinColumn(name="category_id", referencedColumnName="id")
380
     */
381
    public $category;
382
}
383
384
/**
385
 * @Entity
386
 */
387
class GH6830Category
388
{
389
    /**
390
     * @Id
391
     * @Column(type="string", length=8, options={"fixed":true, "collation":"latin1_bin", "foo":"bar"})
392
     *
393
     * @var string
394
     */
395
    public $id;
396
397
    /**
398
     * @OneToMany(targetEntity=GH6830Board::class, mappedBy="category")
399
     */
400
    public $boards;
401
}
402