Passed
Push — master ( 3d1903...d04c40 )
by Anton
06:59
created

GenerateMigrations::generateName()   F

Complexity

Conditions 14
Paths 516

Size

Total Lines 62
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 32
c 1
b 0
f 0
nc 516
nop 1
dl 0
loc 62
rs 2.7722

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Migrations;
13
14
use Cycle\Schema\GeneratorInterface;
15
use Cycle\Schema\Registry;
16
use Spiral\Database\Schema\AbstractTable;
17
use Spiral\Migrations\Atomizer\Atomizer;
18
use Spiral\Migrations\Atomizer\Renderer;
19
use Spiral\Migrations\Atomizer\RendererInterface;
20
use Spiral\Migrations\Config\MigrationConfig;
21
use Spiral\Migrations\Migration;
22
use Spiral\Migrations\RepositoryInterface;
23
use Spiral\Reactor\ClassDeclaration;
24
use Spiral\Reactor\FileDeclaration;
25
26
/**
27
 * Migration generator creates set of migrations needed to sync database schema with desired state. Each database will
28
 * receive it's own migration.
29
 */
30
class GenerateMigrations implements GeneratorInterface
31
{
32
    /** @var int */
33
    private static $sec = 0;
34
35
    /** @var RepositoryInterface */
36
    private $repository;
37
38
    /** @var RendererInterface */
39
    private $renderer;
40
41
    /** @var MigrationConfig $migrationConfig */
42
    private $migrationConfig;
43
44
    /**
45
     * GenerateMigrations constructor.
46
     *
47
     * @param RepositoryInterface    $migrationRepository
48
     * @param MigrationConfig        $migrationConfig
49
     * @param RendererInterface|null $renderer
50
     */
51
    public function __construct(
52
        RepositoryInterface $migrationRepository,
53
        MigrationConfig $migrationConfig,
54
        RendererInterface $renderer = null
55
    ) {
56
        $this->repository = $migrationRepository;
57
        $this->migrationConfig = $migrationConfig;
58
        $this->renderer = $renderer ?? new Renderer();
59
    }
60
61
    /**
62
     * @param Registry $registry
63
     * @return Registry
64
     */
65
    public function run(Registry $registry): Registry
66
    {
67
        $databases = [];
68
        foreach ($registry as $e) {
69
            if ($registry->hasTable($e)) {
70
                $databases[$registry->getDatabase($e)][] = $registry->getTableSchema($e);
71
            }
72
        }
73
74
        foreach ($databases as $database => $tables) {
75
            list($name, $class, $file) = $this->generate($database, $tables);
76
            if ($class === null || $file === null) {
77
                // no changes
78
                continue;
79
            }
80
81
            $this->repository->registerMigration($name, $class, $file->render());
82
        }
83
84
        return $registry;
85
    }
86
87
    /**
88
     * @param string          $database
89
     * @param AbstractTable[] $tables
90
     * @return array [string, FileDeclaration]
91
     */
92
    protected function generate(string $database, array $tables): array
93
    {
94
        $atomizer = new Atomizer(new Renderer());
95
96
        $reasonable = false;
97
        foreach ($tables as $table) {
98
            if ($table->getComparator()->hasChanges()) {
99
                $reasonable = true;
100
                $atomizer->addTable($table);
101
            }
102
        }
103
104
        if (!$reasonable) {
105
            return [null, null, null];
106
        }
107
108
        // unique class name for the migration
109
        $name = sprintf(
110
            'orm_%s_%s',
111
            $database,
112
            md5(microtime(true) . microtime(false))
113
        );
114
115
        $class = new ClassDeclaration($name, 'Migration');
116
        $class->constant('DATABASE')->setProtected()->setValue($database);
117
118
        $class->method('up')->setPublic();
119
        $class->method('down')->setPublic();
120
121
        $atomizer->declareChanges($class->method('up')->getSource());
122
        $atomizer->revertChanges($class->method('down')->getSource());
123
124
        $file = new FileDeclaration($this->migrationConfig->getNamespace());
125
        $file->addUse(Migration::class);
126
        $file->addElement($class);
127
128
        return [
129
            substr(sprintf(
130
                '%s_%s_%s',
131
                self::$sec++,
132
                $database,
133
                $this->generateName($atomizer)
134
            ), 0, 128),
135
            $class->getName(),
136
            $file
137
        ];
138
    }
139
140
    /**
141
     * @param Atomizer $atomizer
142
     * @return string
143
     */
144
    private function generateName(Atomizer $atomizer): string
145
    {
146
        $name = [];
147
148
        foreach ($atomizer->getTables() as $table) {
149
            if ($table->getStatus() === AbstractTable::STATUS_NEW) {
150
                $name[] = 'create_' . $table->getName();
151
                continue;
152
            }
153
154
            if ($table->getStatus() === AbstractTable::STATUS_DECLARED_DROPPED) {
155
                $name[] = 'drop_' . $table->getName();
156
                continue;
157
            }
158
159
            if ($table->getComparator()->isRenamed()) {
160
                $name[] = 'rename_' . $table->getInitialName();
161
                continue;
162
            }
163
164
            $name[] = 'change_' . $table->getName();
165
166
            $comparator = $table->getComparator();
167
168
            foreach ($comparator->addedColumns() as $column) {
169
                $name[] = 'add_' . $column->getName();
170
            }
171
172
            foreach ($comparator->droppedColumns() as $column) {
173
                $name[] = 'rm_' . $column->getName();
174
            }
175
176
            foreach ($comparator->alteredColumns() as $column) {
177
                $name[] = 'alter_' . $column[0]->getName();
178
            }
179
180
            foreach ($comparator->addedIndexes() as $index) {
181
                $name[] = 'add_index_' . $index->getName();
182
            }
183
184
            foreach ($comparator->droppedIndexes() as $index) {
185
                $name[] = 'rm_index_' . $index->getName();
186
            }
187
188
            foreach ($comparator->alteredIndexes() as $index) {
189
                $name[] = 'alter_index_' . $index[0]->getName();
190
            }
191
192
            foreach ($comparator->addedForeignKeys() as $fk) {
193
                $name[] = 'add_fk_' . $fk->getName();
194
            }
195
196
            foreach ($comparator->droppedForeignKeys() as $fk) {
197
                $name[] = 'rm_fk_' . $fk->getName();
198
            }
199
200
            foreach ($comparator->alteredForeignKeys() as $fk) {
201
                $name[] = 'alter_fk_' . $fk[0]->getName();
202
            }
203
        }
204
205
        return join('_', $name);
206
    }
207
}
208