ModelAnnotationsTaskTest::testSetUtil()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace CSoellinger\SilverStripe\ModelAnnotations\Test\Unit\Task;
4
5
// phpcs:disable
6
require_once __DIR__ . '/../../mockup.php';
7
// phpcs:enable
8
9
use CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask;
10
use CSoellinger\SilverStripe\ModelAnnotations\Test\PhpUnitHelper;
11
use CSoellinger\SilverStripe\ModelAnnotations\Test\Unit\Player;
12
use CSoellinger\SilverStripe\ModelAnnotations\Test\Unit\Supporter;
13
use CSoellinger\SilverStripe\ModelAnnotations\Test\Unit\Team;
14
use CSoellinger\SilverStripe\ModelAnnotations\Test\Unit\TeamSupporter;
15
use CSoellinger\SilverStripe\ModelAnnotations\Util\Util;
16
use Monolog\Logger;
17
use Psr\Log\LoggerInterface;
18
use SilverStripe\Control\HTTPRequest;
19
use SilverStripe\Core\Config\Config;
20
use SilverStripe\Core\Injector\Injector;
21
use SilverStripe\Core\Kernel;
22
use SilverStripe\Dev\CLI;
23
use SilverStripe\Dev\SapphireTest;
24
25
define('TASK_PATH', realpath(implode(DIRECTORY_SEPARATOR, [
26
    __DIR__,
27
    '..',
28
    '..',
29
    '..',
30
    'src',
31
    'Task',
32
    'ModelAnnotationsTask.php',
33
])));
34
35
define('ERROR_URL', 'IN GET /dev/tasks/ModelAnnotationsTask');
36
define('ERROR_LINE', 'Line 0 in ');
37
38
/**
39
 * @internal
40
 *
41
 * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask
42
 */
43
class ModelAnnotationsTaskTest extends SapphireTest
44
{
45
    protected static ModelAnnotationsTask $task;
46
47
    public static function setUpBeforeClass(): void
48
    {
49
        parent::setUpBeforeClass();
50
51
        Injector::nest();
52
        Injector::inst()->registerService(new HTTPRequest('GET', '/'), HTTPRequest::class);
53
    }
54
55
    public function setUp(): void
56
    {
57
        parent::setUp();
58
59
        PhpUnitHelper::$phpSapiName = 'cli';
60
61
        /** @var ModelAnnotationsTask $task */
62
        $task = Injector::inst()->create(ModelAnnotationsTask::class);
63
        self::$task = $task;
64
65
        $config = Config::forClass(ModelAnnotationsTask::class);
66
        $config->set('createBackupFile', false);
67
        $config->set('dryRun', false);
68
        $config->set('quiet', false);
69
        $config->set('addUseStatements', false);
70
        $config->set('ignoreFields', [
71
            'LinkTracking',
72
            'FileTracking',
73
        ]);
74
    }
75
76
    public static function setUpAfterClass(): void
77
    {
78
        Injector::unnest();
79
    }
80
81
    /**
82
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::__construct
83
     */
84
    public function testInitialized(): void
85
    {
86
        $modelAnnotationsTask = new ModelAnnotationsTask();
87
        self::assertInstanceOf(ModelAnnotationsTask::class, $modelAnnotationsTask);
88
    }
89
90
    /**
91
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::__construct
92
     */
93
    public function testInitializedBrowser(): void
94
    {
95
        PhpUnitHelper::$phpSapiName = 'apache';
96
97
        $modelAnnotationsTask = new ModelAnnotationsTask();
98
        self::assertInstanceOf(ModelAnnotationsTask::class, $modelAnnotationsTask);
99
    }
100
101
    /**
102
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::getTitle
103
     */
104
    public function testGetTitle(): void
105
    {
106
        self::assertEquals('Model Annotations Generator', self::$task->getTitle());
107
    }
108
109
    /**
110
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::getDescription
111
     */
112
    public function testGetDescription(): void
113
    {
114
        $description = "
115
        Add ide annotations for dataobject models. This is helpful to get auto
116
        completions for db fields and relations in your ide (most should
117
        support it). This task (over)write files so it's always a good idea to
118
        make a dryRun and/or backup files.
119
120
		Parameters (optional):
121
        - dataClass: Generate annotations only for one class. If not set all found data object classes will be used.
122
		- createBackupFile: Create a backup before writing a file. (default: FALSE)
123
		- addUseStatements: Add use statements for data types which are not declared (default: FALSE)
124
		- dryRun: Only print changes and don't write file (default: TRUE)
125
		- quiet: No outputs (default: FALSE)
126
	";
127
128
        self::assertEquals($description, self::$task->getDescription());
129
    }
130
131
    /**
132
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::setUtil
133
     */
134
    public function testSetUtil(): void
135
    {
136
        self::$task->setUtil(new Util());
137
138
        self::assertInstanceOf(ModelAnnotationsTask::class, self::$task);
139
    }
140
141
    /**
142
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::setRequest
143
     */
144
    public function testSetRequest(): void
145
    {
146
        self::$task->setRequest(new HTTPRequest('GET', '/'));
147
148
        self::assertInstanceOf(ModelAnnotationsTask::class, self::$task);
149
    }
150
151
    /**
152
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::setLogger
153
     */
154
    public function testSetLogger(): void
155
    {
156
        /** @var Logger $logger */
157
        $logger = Injector::inst()->get(LoggerInterface::class);
158
159
        self::$task->setLogger($logger);
160
161
        self::assertInstanceOf(ModelAnnotationsTask::class, self::$task);
162
    }
163
164
    /**
165
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::run
166
     * @group ExpectedOutput
167
     */
168
    public function testTaskRunNotOnDev(): void
169
    {
170
        /** @var Kernel $kernel */
171
        $kernel = Injector::inst()->get(Kernel::class);
172
        $kernel->setEnvironment('live');
173
        $output = CLI::text(
174
            'ERROR [Alert]: You can run this task only inside a dev environment. Your environment is: live' . PHP_EOL
175
                . ERROR_URL . PHP_EOL,
176
            'red',
177
            null,
178
            true
179
        );
180
        $output .= CLI::text(ERROR_LINE . TASK_PATH . PHP_EOL . PHP_EOL, 'red');
181
182
        $this->expectOutputString($output);
183
        $this->expectError();
184
185
        $request = $this->getRequest(Player::class);
186
        self::$task->setRequest($request);
187
        self::$task->run($request);
188
189
        /** @var Kernel $kernel */
190
        $kernel = Injector::inst()->get(Kernel::class);
191
        $kernel->setEnvironment('dev');
192
    }
193
194
    /**
195
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::run
196
     * @group ExpectedOutput
197
     */
198
    public function testTaskRunErrorSilently(): void
199
    {
200
        /** @var Kernel $kernel */
201
        $kernel = Injector::inst()->get(Kernel::class);
202
        $kernel->setEnvironment('live');
203
204
        $this->expectOutputString('');
205
        $this->expectError();
206
207
        $config = Config::forClass(ModelAnnotationsTask::class);
208
        $config->set('quiet', true);
209
210
        $request = $this->getRequest(Player::class);
211
        self::$task->setRequest($request);
212
        self::$task->run($request);
213
214
        /** @var Kernel $kernel */
215
        $kernel = Injector::inst()->get(Kernel::class);
216
        $kernel->setEnvironment('dev');
217
    }
218
219
    /**
220
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::run
221
     * @group ExpectedOutput
222
     */
223
    public function testTaskRunNotAdminNotCli(): void
224
    {
225
        PhpUnitHelper::$phpSapiName = 'apache';
226
227
        $output = CLI::text(
228
            'ERROR [Alert]: Inside browser only admins are allowed to run this task.' . PHP_EOL
229
                . ERROR_URL . PHP_EOL,
230
            'red',
231
            null,
232
            true
233
        );
234
        $output .= CLI::text(ERROR_LINE . TASK_PATH . PHP_EOL . PHP_EOL, 'red');
235
236
        $this->expectOutputString($output);
237
        $this->expectError();
238
239
        $request = $this->getRequest(Player::class);
240
        self::$task->setRequest($request);
241
        self::$task->run($request);
242
    }
243
244
    /**
245
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::run
246
     * @dataProvider provideFqnArray
247
     * @group ExpectedOutput
248
     */
249
    public function testTaskRunWithDryRunForOneClass(string $fqn, string $expectedOutput): void
250
    {
251
        $this->expectOutputString($expectedOutput);
252
253
        $request = $this->getRequest($fqn);
254
        self::$task->setRequest($request);
255
        self::$task->run($request);
256
    }
257
258
    /**
259
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::run
260
     * @group ExpectedOutput
261
     */
262
    public function testTaskRunWithDryRunForOneClassWithCollectedUse(): void
263
    {
264
        $fqn = $this->provideFqnArray()[2][0];
265
        $expected = $this->provideFqnArray()[2][2];
266
267
        $this->expectOutputString($expected);
268
269
        $config = Config::forClass(ModelAnnotationsTask::class);
270
        $config->set('addUseStatements', true);
271
272
        $request = $this->getRequest($fqn);
273
        self::$task->setRequest($request);
274
        self::$task->run($request);
275
    }
276
277
    /**
278
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::run
279
     * @group ExpectedOutput
280
     */
281
    public function testTaskRunWithNotExistingClass(): void
282
    {
283
        $output = implode(PHP_EOL, [
284
            'PARAMS',
285
            '| dataClass: \Not\Existing\Class | dryRun: true | addUseStatements: false | createBackupFile: false',
286
            '| quiet: false |',
287
            '----------------------------------------------------------------------------------------------------',
288
            '',
289
            '',
290
            '',
291
        ]);
292
293
        $output .= CLI::text(
294
            'ERROR [Alert]: Data class "\not\existing\class" does not exist' . PHP_EOL
295
                . ERROR_URL . PHP_EOL,
296
            'red',
297
            null,
298
            true
299
        );
300
        $output .= CLI::text(ERROR_LINE . TASK_PATH . PHP_EOL . PHP_EOL, 'red');
301
302
        $this->expectError();
303
        $this->expectOutputString($output);
304
305
        $request = $this->getRequest('\\Not\\Existing\\Class');
306
        self::$task->setRequest($request);
307
        self::$task->run($request);
308
    }
309
310
    /**
311
     * @covers \CSoellinger\SilverStripe\ModelAnnotations\Task\ModelAnnotationsTask::run
312
     * @group ExpectedOutput
313
     */
314
    public function testTaskRunWritingFile(): void
315
    {
316
        $fqn = $this->provideFqnArray()[2][0];
317
318
        $expected = implode(PHP_EOL, [
319
            'PARAMS',
320
            '| dataClass: CSoellinger\SilverStripe\ModelAnnotations\Test\Unit\Team | dryRun: false |',
321
            'addUseStatements: false | createBackupFile: false | quiet: false |',
322
            '----------------------------------------------------------------------------------------------------',
323
            '',
324
            '',
325
            'CSoellinger\SilverStripe\ModelAnnotations\Test\Unit\Team',
326
            'File: ' . realpath(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Team.php'])),
327
            '',
328
            'Generating annotations done',
329
            '',
330
            '',
331
        ]);
332
        $expectedFile = $this->provideFqnArray()[2][3];
333
334
        $this->expectOutputString($expected);
335
336
        $modelFile = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Team.php';
337
        $testBackup = implode(DIRECTORY_SEPARATOR, [
338
            __DIR__,
339
            '..',
340
            '..',
341
            '..',
342
            'build',
343
            'cache',
344
            'Team.php.test',
345
        ]);
346
347
        copy($modelFile, $testBackup);
348
349
        $request = $this->getRequest($fqn, 0);
350
351
        self::$task->setRequest($request);
352
        self::$task->run($request);
353
354
        self::assertEquals($expectedFile, file_get_contents($modelFile));
355
356
        unlink($modelFile);
357
        copy($testBackup, $modelFile);
358
        unlink($testBackup);
359
    }
360
361
    /**
362
     * @return array<int,string[]>
363
     */
364
    public function provideFqnArray()
365
    {
366
        return [
367
            [
368
                Player::class,
369
                implode(PHP_EOL, [
370
                    'PARAMS',
371
                    '| dataClass: ' . Player::class . ' | dryRun: true |',
372
                    'addUseStatements: false | createBackupFile: false | quiet: false |',
373
                    '--------------------------------------------------------------------------------------------' .
374
                        '--------',
375
                    '',
376
                    '',
377
                    Player::class,
378
                    'File: ' .
379
                    realpath(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Player.php'])),
380
                    '',
381
                    'Generating annotations done',
382
                    '',
383
                    '<?php',
384
                    '',
385
                    'namespace CSoellinger\SilverStripe\ModelAnnotations\Test\Unit;',
386
                    '',
387
                    'use SilverStripe\Dev\TestOnly;',
388
                    'use SilverStripe\ORM\DataObject;',
389
                    '',
390
                    '/**',
391
                    ' * @internal Testing model',
392
                    ' *',
393
                    ' * @property string $Name ...',
394
                    ' *',
395
                    ' * @property Team $Team   Has one Team {@see Team}',
396
                    ' * @property int  $TeamID Team ID',
397
                    ' */',
398
                    ...$this->getPlayerModelOutput(),
399
                    '',
400
                    '',
401
                    '',
402
                ]),
403
            ],
404
            [
405
                Supporter::class,
406
                implode(PHP_EOL, [
407
                    'PARAMS',
408
                    '| dataClass: ' . Supporter::class . ' | dryRun: true |',
409
                    'addUseStatements: false | createBackupFile: false | quiet: false |',
410
                    '--------------------------------------------------------------------------------------------' .
411
                        '--------',
412
                    '',
413
                    '',
414
                    Supporter::class,
415
                    'File: ' .
416
                    realpath(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Supporter.php'])),
417
                    '',
418
                    'Generating annotations done',
419
                    '',
420
                    '<?php',
421
                    '',
422
                    'namespace CSoellinger\SilverStripe\ModelAnnotations\Test\Unit;',
423
                    '',
424
                    'use SilverStripe\Dev\TestOnly;',
425
                    'use SilverStripe\ORM\DataObject;',
426
                    'use SilverStripe\ORM\ManyManyList;',
427
                    '',
428
                    '/**',
429
                    ' * @internal Testing model',
430
                    ' *',
431
                    ' * @method ManyManyList Supports() ...',
432
                    ' */',
433
                    ...$this->getSupporterModelOutput(),
434
                    '',
435
                    '',
436
                    '',
437
                ]),
438
            ],
439
            [
440
                Team::class,
441
                implode(PHP_EOL, [
442
                    'PARAMS',
443
                    '| dataClass: ' . Team::class . ' | dryRun: true |',
444
                    'addUseStatements: false | createBackupFile: false | quiet: false |',
445
                    '----------------------------------------------------------------------------------------------' .
446
                        '------',
447
                    '',
448
                    '',
449
                    Team::class,
450
                    'File: ' .
451
                    realpath(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Team.php'])),
452
                    '',
453
                    'Generating annotations done',
454
                    '',
455
                    '<?php',
456
                    '',
457
                    'namespace CSoellinger\SilverStripe\ModelAnnotations\Test\Unit;',
458
                    '',
459
                    'use SilverStripe\Assets\Image;',
460
                    'use SilverStripe\Dev\TestOnly;',
461
                    'use SilverStripe\ORM\DataObject;',
462
                    '',
463
                    '/**',
464
                    ' * @property string $Name   Name ...',
465
                    ' * @property string $Origin Origin ...',
466
                    ' *',
467
                    ' * @method \SilverStripe\ORM\HasManyList  Players()    Has many Players {@see Player}',
468
                    ' * @method \SilverStripe\ORM\ManyManyList Supporters() Many many Supporters {@see TeamSupporter}',
469
                    ' * @method \SilverStripe\ORM\ManyManyList Images()     Many many Images {@see Image}',
470
                    ' */',
471
                    ...$this->getTeamModelOutput(),
472
                    '',
473
                    '',
474
                    '',
475
                ]),
476
                implode(PHP_EOL, [
477
                    'PARAMS',
478
                    '| dataClass: ' . Team::class . ' | dryRun: true |',
479
                    'addUseStatements: true | createBackupFile: false | quiet: false |',
480
                    '-----------------------------------------------------------------------------------------------' .
481
                        '-----',
482
                    '',
483
                    '',
484
                    Team::class,
485
                    'File: ' .
486
                    realpath(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'Team.php'])),
487
                    '',
488
                    'Generating annotations done',
489
                    '',
490
                    '<?php',
491
                    '',
492
                    'namespace CSoellinger\SilverStripe\ModelAnnotations\Test\Unit;',
493
                    '',
494
                    'use SilverStripe\Assets\Image;',
495
                    'use SilverStripe\Dev\TestOnly;',
496
                    'use SilverStripe\ORM\DataObject;',
497
                    'use SilverStripe\ORM\HasManyList;',
498
                    'use SilverStripe\ORM\ManyManyList;',
499
                    '',
500
                    '/**',
501
                    ' * @property string $Name   Name ...',
502
                    ' * @property string $Origin Origin ...',
503
                    ' *',
504
                    ' * @method HasManyList  Players()    Has many Players {@see Player}',
505
                    ' * @method ManyManyList Supporters() Many many Supporters {@see TeamSupporter}',
506
                    ' * @method ManyManyList Images()     Many many Images {@see Image}',
507
                    ' */',
508
                    ...$this->getTeamModelOutput(),
509
                    '',
510
                    '',
511
                    '',
512
                ]),
513
                implode(PHP_EOL, [
514
                    '<?php',
515
                    '',
516
                    'namespace CSoellinger\SilverStripe\ModelAnnotations\Test\Unit;',
517
                    '',
518
                    'use SilverStripe\Assets\Image;',
519
                    'use SilverStripe\Dev\TestOnly;',
520
                    'use SilverStripe\ORM\DataObject;',
521
                    '',
522
                    '/**',
523
                    ' * @property string $Name   Name ...',
524
                    ' * @property string $Origin Origin ...',
525
                    ' *',
526
                    ' * @method \SilverStripe\ORM\HasManyList  Players()    Has many Players {@see Player}',
527
                    ' * @method \SilverStripe\ORM\ManyManyList Supporters() Many many Supporters {@see TeamSupporter}',
528
                    ' * @method \SilverStripe\ORM\ManyManyList Images()     Many many Images {@see Image}',
529
                    ' */',
530
                    ...$this->getTeamModelOutput(),
531
                    '',
532
                ]),
533
            ],
534
            [
535
                TeamSupporter::class,
536
                implode(PHP_EOL, [
537
                    'PARAMS',
538
                    '| dataClass: ' . TeamSupporter::class . ' | dryRun: true |',
539
                    'addUseStatements: false | createBackupFile: false | quiet: false |',
540
                    '-----------------------------------------------------------------------------------------------'.
541
                        '-----',
542
                    '',
543
                    '',
544
                    TeamSupporter::class,
545
                    'File: ' .
546
                    realpath(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', 'TeamSupporter.php'])),
547
                    '',
548
                    'Generating annotations done',
549
                    '',
550
                    '<?php',
551
                    '',
552
                    'namespace CSoellinger\SilverStripe\ModelAnnotations\Test\Unit;',
553
                    '',
554
                    'use SilverStripe\Dev\TestOnly;',
555
                    'use SilverStripe\ORM\DataObject;',
556
                    '',
557
                    '/**',
558
                    ' * @property int       $Ranking     Ranking ...',
559
                    ' * @property int       $TeamID      Team ID',
560
                    ' * @property Supporter $Supporter   Has one Supporter',
561
                    ' *',
562
                    ' * @property Team $Team        Has one Team {@see Team}',
563
                    ' * @property int  $SupporterID Supporter ID',
564
                    ' */',
565
                    ...$this->getTeamSupporterModelOutput(),
566
                    '',
567
                    '',
568
                    '',
569
                ]),
570
            ],
571
        ];
572
    }
573
574
    private function getRequest(
575
        string $dataClass = null,
576
        int $dryRun = 1,
577
        string $method = 'GET',
578
        string $url = '/dev/tasks/ModelAnnotationsTask'
579
    ): HTTPRequest {
580
        $opts = ['dryRun' => $dryRun];
581
582
        if ($dataClass !== null) {
583
            $opts['dataClass'] = $dataClass;
584
        }
585
586
        /** @var HTTPRequest */
587
        return Injector::inst()->createWithArgs(HTTPRequest::class, [
588
            $method,
589
            $url,
590
            $opts,
591
        ]);
592
    }
593
594
    /**
595
     * @return string[]
596
     */
597
    private function getPlayerModelOutput(): array
598
    {
599
        return [
600
            'class Player extends DataObject implements TestOnly',
601
            '{',
602
            '    /**',
603
            '     * @var array<string,string> undocumented variable',
604
            '     */',
605
            '    private static $db = [',
606
            '        \'Name\' => \'Varchar(255)\',',
607
            '    ];',
608
            '',
609
            '    /**',
610
            '     * @var array<string,string> undocumented variable',
611
            '     */',
612
            '    private static $has_one = [',
613
            '        \'Team\' => Team::class . \'.ID\',',
614
            '    ];',
615
            '}',
616
        ];
617
    }
618
619
    /**
620
     * @return string[]
621
     */
622
    private function getSupporterModelOutput(): array
623
    {
624
        return [
625
            'class Supporter extends DataObject implements TestOnly',
626
            '{',
627
            '    /**',
628
            '     * @var array<string,string> undocumented variable',
629
            '     */',
630
            '    private static $belongs_many_many = [',
631
            '        \'Supports\' => Team::class . \'.Supporters\',',
632
            '    ];',
633
            '}',
634
        ];
635
    }
636
637
    /**
638
     * @return string[]
639
     */
640
    private function getTeamSupporterModelOutput(): array
641
    {
642
        return [
643
            'class TeamSupporter extends DataObject implements TestOnly',
644
            '{',
645
            '    /**',
646
            '     * @var array<string,string> undocumented variable',
647
            '     */',
648
            '    private static $db = [',
649
            '        \'Ranking\' => \'Int\',',
650
            '    ];',
651
            '',
652
            '    /**',
653
            '     * @var array<string,string> undocumented variable',
654
            '     */',
655
            '    private static $has_one = [',
656
            '        \'Team\' => Team::class,',
657
            '        \'Supporter\' => Supporter::class,',
658
            '    ];',
659
            '}',
660
        ];
661
    }
662
663
    /**
664
     * Undocumented function.
665
     *
666
     * @return string[]
667
     */
668
    private function getTeamModelOutput(): array
669
    {
670
        return [
671
            'class Team extends DataObject implements TestOnly',
672
            '{',
673
            '    /**',
674
            '     * @var array<string,string> undocumented variable',
675
            '     */',
676
            '    private static $db = [',
677
            '        \'Name\' => \'Varchar(255)\',',
678
            '        \'Origin\' => \'Varchar(255)\',',
679
            '        \'LinkTracking\' => \'Boolean\',',
680
            '    ];',
681
            '',
682
            '    /**',
683
            '     * @var array<string,string> undocumented variable',
684
            '     */',
685
            '    private static $has_many = [',
686
            '        \'Players\' => Player::class,',
687
            '        \'FileTracking\' => Image::class,',
688
            '    ];',
689
            '',
690
            '    /**',
691
            '     * @var array<string,array<string,string>|string> undocumented variable',
692
            '     */',
693
            '    private static $many_many = [',
694
            '        \'Supporters\' => [',
695
            '            \'through\' => TeamSupporter::class,',
696
            '            \'from\' => \'Team\',',
697
            '            \'to\' => \'Supporter\',',
698
            '        ],',
699
            '        \'Images\' => Image::class,',
700
            '    ];',
701
            '}',
702
        ];
703
    }
704
}
705