Completed
Pull Request — master (#3711)
by
unknown
65:53
created

testListTablesExcludesViews()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 24
rs 9.8333
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\DBAL\Functional\Schema;
6
7
use Doctrine\DBAL\Platforms\AbstractPlatform;
8
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
9
use Doctrine\DBAL\Schema;
10
use Doctrine\DBAL\Schema\Comparator;
11
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
12
use Doctrine\DBAL\Schema\PostgreSqlSchemaManager;
13
use Doctrine\DBAL\Schema\Table;
14
use Doctrine\DBAL\Schema\TableDiff;
15
use Doctrine\DBAL\Types\BlobType;
16
use Doctrine\DBAL\Types\DecimalType;
17
use Doctrine\DBAL\Types\Type;
18
use Doctrine\DBAL\Types\Types;
19
use function array_map;
20
use function array_pop;
21
use function count;
22
use function current;
23
use function preg_match;
24
use function strtolower;
25
26
class PostgreSqlSchemaManagerTest extends SchemaManagerFunctionalTestCase
27
{
28
    /** @var PostgreSqlSchemaManager */
29
    protected $schemaManager;
30
31
    protected function tearDown() : void
32
    {
33
        parent::tearDown();
34
35
        $this->connection->getConfiguration()->setSchemaAssetsFilter(null);
36
    }
37
38
    /**
39
     * @group DBAL-177
40
     */
41
    public function testGetSearchPath() : void
42
    {
43
        $params = $this->connection->getParams();
44
45
        $paths = $this->schemaManager->getSchemaSearchPaths();
46
        self::assertEquals([$params['user'], 'public'], $paths);
47
    }
48
49
    /**
50
     * @group DBAL-244
51
     */
52
    public function testGetSchemaNames() : void
53
    {
54
        $names = $this->schemaManager->getSchemaNames();
55
56
        self::assertIsArray($names);
57
        self::assertNotEmpty($names);
58
        self::assertContains('public', $names, 'The public schema should be found.');
59
    }
60
61
    /**
62
     * @group DBAL-21
63
     */
64
    public function testSupportDomainTypeFallback() : void
65
    {
66
        $createDomainTypeSQL = 'CREATE DOMAIN MyMoney AS DECIMAL(18,2)';
67
        $this->connection->exec($createDomainTypeSQL);
68
69
        $createTableSQL = 'CREATE TABLE domain_type_test (id INT PRIMARY KEY, value MyMoney)';
70
        $this->connection->exec($createTableSQL);
71
72
        $table = $this->connection->getSchemaManager()->listTableDetails('domain_type_test');
73
        self::assertInstanceOf(DecimalType::class, $table->getColumn('value')->getType());
74
75
        Type::addType('MyMoney', MoneyType::class);
76
        $this->connection->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'MyMoney');
77
78
        $table = $this->connection->getSchemaManager()->listTableDetails('domain_type_test');
79
        self::assertInstanceOf(MoneyType::class, $table->getColumn('value')->getType());
80
    }
81
82
    /**
83
     * @group DBAL-37
84
     */
85
    public function testDetectsAutoIncrement() : void
86
    {
87
        $autoincTable = new Table('autoinc_table');
88
        $column       = $autoincTable->addColumn('id', 'integer');
89
        $column->setAutoincrement(true);
90
        $this->schemaManager->createTable($autoincTable);
91
        $autoincTable = $this->schemaManager->listTableDetails('autoinc_table');
92
93
        self::assertTrue($autoincTable->getColumn('id')->getAutoincrement());
94
    }
95
96
    /**
97
     * @group DBAL-37
98
     */
99
    public function testAlterTableAutoIncrementAdd() : void
100
    {
101
        $tableFrom = new Table('autoinc_table_add');
102
        $column    = $tableFrom->addColumn('id', 'integer');
0 ignored issues
show
Unused Code introduced by
The assignment to $column is dead and can be removed.
Loading history...
103
        $this->schemaManager->createTable($tableFrom);
104
        $tableFrom = $this->schemaManager->listTableDetails('autoinc_table_add');
105
        self::assertFalse($tableFrom->getColumn('id')->getAutoincrement());
106
107
        $tableTo = new Table('autoinc_table_add');
108
        $column  = $tableTo->addColumn('id', 'integer');
109
        $column->setAutoincrement(true);
110
111
        $c    = new Comparator();
112
        $diff = $c->diffTable($tableFrom, $tableTo);
113
114
        self::assertNotNull($diff);
115
116
        $sql = $this->connection->getDatabasePlatform()->getAlterTableSQL($diff);
117
        self::assertEquals([
118
            'CREATE SEQUENCE autoinc_table_add_id_seq',
119
            "SELECT setval('autoinc_table_add_id_seq', (SELECT MAX(id) FROM autoinc_table_add))",
120
            "ALTER TABLE autoinc_table_add ALTER id SET DEFAULT nextval('autoinc_table_add_id_seq')",
121
        ], $sql);
122
123
        $this->schemaManager->alterTable($diff);
124
        $tableFinal = $this->schemaManager->listTableDetails('autoinc_table_add');
125
        self::assertTrue($tableFinal->getColumn('id')->getAutoincrement());
126
    }
127
128
    /**
129
     * @group DBAL-37
130
     */
131
    public function testAlterTableAutoIncrementDrop() : void
132
    {
133
        $tableFrom = new Table('autoinc_table_drop');
134
        $column    = $tableFrom->addColumn('id', 'integer');
135
        $column->setAutoincrement(true);
136
        $this->schemaManager->createTable($tableFrom);
137
        $tableFrom = $this->schemaManager->listTableDetails('autoinc_table_drop');
138
        self::assertTrue($tableFrom->getColumn('id')->getAutoincrement());
139
140
        $tableTo = new Table('autoinc_table_drop');
141
        $column  = $tableTo->addColumn('id', 'integer');
0 ignored issues
show
Unused Code introduced by
The assignment to $column is dead and can be removed.
Loading history...
142
143
        $c    = new Comparator();
144
        $diff = $c->diffTable($tableFrom, $tableTo);
145
146
        self::assertNotNull($diff);
147
148
        self::assertInstanceOf(TableDiff::class, $diff, 'There should be a difference and not false being returned from the table comparison');
149
        self::assertEquals(['ALTER TABLE autoinc_table_drop ALTER id DROP DEFAULT'], $this->connection->getDatabasePlatform()->getAlterTableSQL($diff));
150
151
        $this->schemaManager->alterTable($diff);
152
        $tableFinal = $this->schemaManager->listTableDetails('autoinc_table_drop');
153
        self::assertFalse($tableFinal->getColumn('id')->getAutoincrement());
154
    }
155
156
    /**
157
     * @group DBAL-75
158
     */
159
    public function testTableWithSchema() : void
160
    {
161
        $this->connection->exec('CREATE SCHEMA nested');
162
163
        $nestedRelatedTable = new Table('nested.schemarelated');
164
        $column             = $nestedRelatedTable->addColumn('id', 'integer');
165
        $column->setAutoincrement(true);
166
        $nestedRelatedTable->setPrimaryKey(['id']);
167
168
        $nestedSchemaTable = new Table('nested.schematable');
169
        $column            = $nestedSchemaTable->addColumn('id', 'integer');
170
        $column->setAutoincrement(true);
171
        $nestedSchemaTable->setPrimaryKey(['id']);
172
        $nestedSchemaTable->addForeignKeyConstraint($nestedRelatedTable, ['id'], ['id']);
173
174
        $this->schemaManager->createTable($nestedRelatedTable);
175
        $this->schemaManager->createTable($nestedSchemaTable);
176
177
        $tables = $this->schemaManager->listTableNames();
178
        self::assertContains('nested.schematable', $tables, 'The table should be detected with its non-public schema.');
179
180
        $nestedSchemaTable = $this->schemaManager->listTableDetails('nested.schematable');
181
        self::assertTrue($nestedSchemaTable->hasColumn('id'));
182
        self::assertEquals(['id'], $nestedSchemaTable->getPrimaryKey()->getColumns());
183
184
        $relatedFks = $nestedSchemaTable->getForeignKeys();
185
        self::assertCount(1, $relatedFks);
186
        $relatedFk = array_pop($relatedFks);
187
        self::assertEquals('nested.schemarelated', $relatedFk->getForeignTableName());
188
    }
189
190
    /**
191
     * @group DBAL-91
192
     * @group DBAL-88
193
     */
194
    public function testReturnQuotedAssets() : void
195
    {
196
        $sql = 'create table dbal91_something ( id integer  CONSTRAINT id_something PRIMARY KEY NOT NULL  ,"table"   integer );';
197
        $this->connection->exec($sql);
198
199
        $sql = 'ALTER TABLE dbal91_something ADD CONSTRAINT something_input FOREIGN KEY( "table" ) REFERENCES dbal91_something ON UPDATE CASCADE;';
200
        $this->connection->exec($sql);
201
202
        $table = $this->schemaManager->listTableDetails('dbal91_something');
203
204
        self::assertEquals(
205
            [
206
                'CREATE TABLE dbal91_something (id INT NOT NULL, "table" INT DEFAULT NULL, PRIMARY KEY(id))',
207
                'CREATE INDEX IDX_A9401304ECA7352B ON dbal91_something ("table")',
208
            ],
209
            $this->connection->getDatabasePlatform()->getCreateTableSQL($table)
210
        );
211
    }
212
213
    /**
214
     * @group DBAL-204
215
     */
216
    public function testFilterSchemaExpression() : void
217
    {
218
        $testTable = new Table('dbal204_test_prefix');
219
        $column    = $testTable->addColumn('id', 'integer');
0 ignored issues
show
Unused Code introduced by
The assignment to $column is dead and can be removed.
Loading history...
220
        $this->schemaManager->createTable($testTable);
221
        $testTable = new Table('dbal204_without_prefix');
222
        $column    = $testTable->addColumn('id', 'integer');
223
        $this->schemaManager->createTable($testTable);
224
225
        $this->connection->getConfiguration()->setSchemaAssetsFilter(static function (string $name) : bool {
226
            return preg_match('#^dbal204_#', $name) === 1;
227
        });
228
        $names = $this->schemaManager->listTableNames();
229
        self::assertCount(2, $names);
230
231
        $this->connection->getConfiguration()->setSchemaAssetsFilter(static function (string $name) : bool {
232
            return preg_match('#^dbal204_test#', $name) === 1;
233
        });
234
        $names = $this->schemaManager->listTableNames();
235
        self::assertCount(1, $names);
236
    }
237
238
    public function testListForeignKeys() : void
239
    {
240
        if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) {
241
            $this->markTestSkipped('Does not support foreign key constraints.');
242
        }
243
244
        $fkOptions   = ['SET NULL', 'SET DEFAULT', 'NO ACTION','CASCADE', 'RESTRICT'];
245
        $foreignKeys = [];
246
        $fkTable     = $this->getTestTable('test_create_fk1');
247
        for ($i = 0; $i < count($fkOptions); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
248
            $fkTable->addColumn('foreign_key_test' . $i, 'integer');
249
            $foreignKeys[] = new ForeignKeyConstraint(
250
                ['foreign_key_test' . $i],
251
                'test_create_fk2',
252
                ['id'],
253
                'foreign_key_test' . $i . '_fk',
254
                ['onDelete' => $fkOptions[$i]]
255
            );
256
        }
257
        $this->schemaManager->dropAndCreateTable($fkTable);
258
        $this->createTestTable('test_create_fk2');
259
260
        foreach ($foreignKeys as $foreignKey) {
261
            $this->schemaManager->createForeignKey($foreignKey, 'test_create_fk1');
262
        }
263
        $fkeys = $this->schemaManager->listTableForeignKeys('test_create_fk1');
264
        self::assertEquals(count($foreignKeys), count($fkeys), "Table 'test_create_fk1' has to have " . count($foreignKeys) . ' foreign keys.');
265
        for ($i = 0; $i < count($fkeys); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
266
            self::assertEquals(['foreign_key_test' . $i], array_map('strtolower', $fkeys[$i]->getLocalColumns()));
267
            self::assertEquals(['id'], array_map('strtolower', $fkeys[$i]->getForeignColumns()));
268
            self::assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName()));
269
            if ($foreignKeys[$i]->getOption('onDelete') === 'NO ACTION') {
270
                self::assertFalse($fkeys[$i]->hasOption('onDelete'), 'Unexpected option: ' . $fkeys[$i]->getOption('onDelete'));
271
            } else {
272
                self::assertEquals($foreignKeys[$i]->getOption('onDelete'), $fkeys[$i]->getOption('onDelete'));
273
            }
274
        }
275
    }
276
277
    /**
278
     * @group DBAL-511
279
     */
280
    public function testDefaultValueCharacterVarying() : void
281
    {
282
        $testTable = new Table('dbal511_default');
283
        $testTable->addColumn('id', 'integer');
284
        $testTable->addColumn('def', 'string', ['default' => 'foo']);
285
        $testTable->setPrimaryKey(['id']);
286
287
        $this->schemaManager->createTable($testTable);
288
289
        $databaseTable = $this->schemaManager->listTableDetails($testTable->getName());
290
291
        self::assertEquals('foo', $databaseTable->getColumn('def')->getDefault());
292
    }
293
294
    /**
295
     * @group DDC-2843
296
     */
297
    public function testBooleanDefault() : void
298
    {
299
        $table = new Table('ddc2843_bools');
300
        $table->addColumn('id', 'integer');
301
        $table->addColumn('checked', 'boolean', ['default' => false]);
302
303
        $this->schemaManager->createTable($table);
304
305
        $databaseTable = $this->schemaManager->listTableDetails($table->getName());
306
307
        $c    = new Comparator();
308
        $diff = $c->diffTable($table, $databaseTable);
309
310
        self::assertNull($diff);
311
    }
312
313
    public function testListTableWithBinary() : void
314
    {
315
        $tableName = 'test_binary_table';
316
317
        $table = new Table($tableName);
318
        $table->addColumn('id', 'integer');
319
        $table->addColumn('column_varbinary', 'binary', []);
320
        $table->addColumn('column_binary', 'binary', ['fixed' => true]);
321
        $table->setPrimaryKey(['id']);
322
323
        $this->schemaManager->createTable($table);
324
325
        $table = $this->schemaManager->listTableDetails($tableName);
326
327
        self::assertInstanceOf(BlobType::class, $table->getColumn('column_varbinary')->getType());
328
        self::assertFalse($table->getColumn('column_varbinary')->getFixed());
329
330
        self::assertInstanceOf(BlobType::class, $table->getColumn('column_binary')->getType());
331
        self::assertFalse($table->getColumn('column_binary')->getFixed());
332
    }
333
334
    public function testListQuotedTable() : void
335
    {
336
        $offlineTable = new Schema\Table('user');
337
        $offlineTable->addColumn('id', 'integer');
338
        $offlineTable->addColumn('username', 'string');
339
        $offlineTable->addColumn('fk', 'integer');
340
        $offlineTable->setPrimaryKey(['id']);
341
        $offlineTable->addForeignKeyConstraint($offlineTable, ['fk'], ['id']);
342
343
        $this->schemaManager->dropAndCreateTable($offlineTable);
344
345
        $onlineTable = $this->schemaManager->listTableDetails('"user"');
346
347
        $comparator = new Schema\Comparator();
348
349
        self::assertNull($comparator->diffTable($offlineTable, $onlineTable));
350
    }
351
352
    public function testListTablesExcludesViews() : void
353
    {
354
        $this->createTestTable('list_tables_excludes_views');
355
356
        $name = 'list_tables_excludes_views_test_view';
357
        $sql  = 'SELECT * from list_tables_excludes_views';
358
359
        $view = new Schema\View($name, $sql);
360
361
        $this->schemaManager->dropAndCreateView($view);
362
363
        $tables = $this->schemaManager->listTables();
364
365
        $foundTable = false;
366
        foreach ($tables as $table) {
367
            self::assertInstanceOf(Table::class, $table, 'No Table instance was found in tables array.');
368
            if (strtolower($table->getName()) !== 'list_tables_excludes_views_test_view') {
369
                continue;
370
            }
371
372
            $foundTable = true;
373
        }
374
375
        self::assertFalse($foundTable, 'View "list_tables_excludes_views_test_view" must not be found in table list');
376
    }
377
378
    /**
379
     * @group DBAL-1033
380
     */
381
    public function testPartialIndexes() : void
382
    {
383
        $offlineTable = new Schema\Table('person');
384
        $offlineTable->addColumn('id', 'integer');
385
        $offlineTable->addColumn('name', 'string');
386
        $offlineTable->addColumn('email', 'string');
387
        $offlineTable->addUniqueIndex(['id', 'name'], 'simple_partial_index', ['where' => '(id IS NULL)']);
388
389
        $this->schemaManager->dropAndCreateTable($offlineTable);
390
391
        $onlineTable = $this->schemaManager->listTableDetails('person');
392
393
        $comparator = new Schema\Comparator();
394
395
        self::assertNull($comparator->diffTable($offlineTable, $onlineTable));
396
        self::assertTrue($onlineTable->hasIndex('simple_partial_index'));
397
        self::assertTrue($onlineTable->getIndex('simple_partial_index')->hasOption('where'));
398
        self::assertSame('(id IS NULL)', $onlineTable->getIndex('simple_partial_index')->getOption('where'));
399
    }
400
401
    public function testJsonbColumn() : void
402
    {
403
        if (! $this->schemaManager->getDatabasePlatform() instanceof PostgreSqlPlatform) {
404
            $this->markTestSkipped('Requires PostgresSQL 9.4+');
405
406
            return;
407
        }
408
409
        $table = new Schema\Table('test_jsonb');
410
        $table->addColumn('foo', Types::JSON)->setPlatformOption('jsonb', true);
411
        $this->schemaManager->dropAndCreateTable($table);
412
413
        $columns = $this->schemaManager->listTableColumns('test_jsonb');
414
415
        self::assertSame(Types::JSON, $columns['foo']->getType()->getName());
416
        self::assertTrue($columns['foo']->getPlatformOption('jsonb'));
417
    }
418
419
    /**
420
     * @group DBAL-2427
421
     */
422
    public function testListNegativeColumnDefaultValue() : void
423
    {
424
        $table = new Schema\Table('test_default_negative');
425
        $table->addColumn('col_smallint', 'smallint', ['default' => -1]);
426
        $table->addColumn('col_integer', 'integer', ['default' => -1]);
427
        $table->addColumn('col_bigint', 'bigint', ['default' => -1]);
428
        $table->addColumn('col_float', 'float', ['default' => -1.1]);
429
        $table->addColumn('col_decimal', 'decimal', ['default' => -1.1]);
430
        $table->addColumn('col_string', 'string', ['default' => '(-1)']);
431
432
        $this->schemaManager->dropAndCreateTable($table);
433
434
        $columns = $this->schemaManager->listTableColumns('test_default_negative');
435
436
        self::assertEquals(-1, $columns['col_smallint']->getDefault());
437
        self::assertEquals(-1, $columns['col_integer']->getDefault());
438
        self::assertEquals(-1, $columns['col_bigint']->getDefault());
439
        self::assertEquals(-1.1, $columns['col_float']->getDefault());
440
        self::assertEquals(-1.1, $columns['col_decimal']->getDefault());
441
        self::assertEquals('(-1)', $columns['col_string']->getDefault());
442
    }
443
444
    /**
445
     * @return mixed[][]
446
     */
447
    public static function serialTypes() : iterable
448
    {
449
        return [
450
            ['integer'],
451
            ['bigint'],
452
        ];
453
    }
454
455
    /**
456
     * @dataProvider serialTypes
457
     * @group 2906
458
     */
459
    public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValue(string $type) : void
460
    {
461
        $tableName = 'test_serial_type_' . $type;
462
463
        $table = new Schema\Table($tableName);
464
        $table->addColumn('id', $type, ['autoincrement' => true, 'notnull' => false]);
465
466
        $this->schemaManager->dropAndCreateTable($table);
467
468
        $columns = $this->schemaManager->listTableColumns($tableName);
469
470
        self::assertNull($columns['id']->getDefault());
471
    }
472
473
    /**
474
     * @dataProvider serialTypes
475
     * @group 2906
476
     */
477
    public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValueEvenWhenDefaultIsSet(string $type) : void
478
    {
479
        $tableName = 'test_serial_type_with_default_' . $type;
480
481
        $table = new Schema\Table($tableName);
482
        $table->addColumn('id', $type, ['autoincrement' => true, 'notnull' => false, 'default' => 1]);
483
484
        $this->schemaManager->dropAndCreateTable($table);
485
486
        $columns = $this->schemaManager->listTableColumns($tableName);
487
488
        self::assertNull($columns['id']->getDefault());
489
    }
490
491
    /**
492
     * @group 2916
493
     * @dataProvider autoIncrementTypeMigrations
494
     */
495
    public function testAlterTableAutoIncrementIntToBigInt(string $from, string $to, string $expected) : void
496
    {
497
        $tableFrom = new Table('autoinc_type_modification');
498
        $column    = $tableFrom->addColumn('id', $from);
499
        $column->setAutoincrement(true);
500
        $this->schemaManager->dropAndCreateTable($tableFrom);
501
        $tableFrom = $this->schemaManager->listTableDetails('autoinc_type_modification');
502
        self::assertTrue($tableFrom->getColumn('id')->getAutoincrement());
503
504
        $tableTo = new Table('autoinc_type_modification');
505
        $column  = $tableTo->addColumn('id', $to);
506
        $column->setAutoincrement(true);
507
508
        $c    = new Comparator();
509
        $diff = $c->diffTable($tableFrom, $tableTo);
510
        self::assertInstanceOf(TableDiff::class, $diff, 'There should be a difference and not false being returned from the table comparison');
511
        self::assertSame(['ALTER TABLE autoinc_type_modification ALTER id TYPE ' . $expected], $this->connection->getDatabasePlatform()->getAlterTableSQL($diff));
512
513
        $this->schemaManager->alterTable($diff);
514
        $tableFinal = $this->schemaManager->listTableDetails('autoinc_type_modification');
515
        self::assertTrue($tableFinal->getColumn('id')->getAutoincrement());
516
    }
517
518
    public function testQuotingMixedCaseAssets() : void
519
    {
520
        $table = new Table('mixedCaseTable');
521
        $table->addColumn('mixedCaseColumn', 'text');
522
        $this->schemaManager->createTable($table);
523
        $columns = $this->schemaManager->listTableColumns('mixedCaseTable');
524
        self::assertCount(1, $columns);
525
        self::assertSame('mixedCaseColumn', current($columns)->getName());
526
    }
527
528
    /**
529
     * @return mixed[][]
530
     */
531
    public static function autoIncrementTypeMigrations() : iterable
532
    {
533
        return [
534
            'int->bigint' => ['integer', 'bigint', 'BIGINT'],
535
            'bigint->int' => ['bigint', 'integer', 'INT'],
536
        ];
537
    }
538
}
539
540
class MoneyType extends Type
541
{
542
    /**
543
     * {@inheritDoc}
544
     */
545
    public function getName() : string
546
    {
547
        return 'MyMoney';
548
    }
549
550
    /**
551
     * {@inheritDoc}
552
     */
553
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) : string
554
    {
555
        return 'MyMoney';
556
    }
557
}
558