MigrationsCreator   B
last analyzed

Complexity

Total Complexity 51

Size/Duplication

Total Lines 460
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 158
c 2
b 0
f 1
dl 0
loc 460
rs 7.92
wmc 51

31 Methods

Rating   Name   Duplication   Size   Complexity  
A getVerbose() 0 3 1
A setVerbose() 0 4 1
A outError() 0 4 2
A getServerType() 0 3 1
A createBlankMigrationClassFile() 0 3 1
A setServerType() 0 4 1
A setDescription() 0 4 1
A getVersion() 0 3 1
A setVersion() 0 4 1
A setPathTimeStamp() 0 5 1
A getPathTimeStamp() 0 3 1
A __construct() 0 11 1
A getName() 0 3 1
A setBaseMigrationsPath() 0 5 1
B writeMigrationClassFile() 0 60 6
B setSeedsPath() 0 18 7
A createSiteMigrationClassFile() 0 6 1
A createResourceMigrationClassFile() 0 9 1
A createChunkMigrationClassFile() 0 8 1
A getLogData() 0 3 1
A createPluginMigrationClassFile() 0 8 1
A getDescription() 0 3 1
A setLog() 0 4 1
A out() 0 8 3
A createMediaSourceMigrationClassFile() 0 8 1
A createTemplateMigrationClassFile() 0 8 1
A createSystemSettingsMigrationClassFile() 0 8 1
A createContextMigrationClassFile() 0 8 1
A createSnippetMigrationClassFile() 0 8 1
A setName() 0 4 1
B setMigrationsPath() 0 18 7

How to fix   Complexity   

Complex Class

Complex classes like MigrationsCreator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MigrationsCreator, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace LCI\Blend\Migrations;
4
5
use LCI\Blend\Blender;
6
use LCI\Blend\Helpers\Format;
7
use LCI\MODX\Console\Helpers\UserInteractionHandler;
8
9
/**
10
 * Class MigrationsCreator ~ will create Migrations
11
 * @package xPDO\Migrations
12
 */
13
class MigrationsCreator
14
{
15
    /** @var array  */
16
    protected $class_data = [];
17
18
    /** @var string */
19
    protected $description;
20
21
    /** @var string */
22
    protected $name;
23
24
    /** @var array  */
25
    protected $log_data = [];
26
27
    /** @var array  */
28
    protected $placeholders = [];
29
30
    /** @var string  */
31
    protected $server_type = 'master';
32
33
    /** @var false|string  */
34
    protected $path_time_stamp;
35
36
    /** @var string  */
37
    protected $migration_template = 'blank.txt';
38
39
    /** @var string ~ 1.0.0 the version of the migration file or related project */
40
    protected $version = '';
41
42
    /** @var Format */
43
    protected $format;
44
45
    protected $migration_templates_path;
46
    protected $migrations_path;
47
    protected $seeds_path;
48
49
    /** @var \LCI\MODX\Console\Helpers\UserInteractionHandler */
50
    protected $userInteractionHandler;
51
52
    /** @var int @see https://symfony.com/doc/current/console/verbosity.html */
53
    protected $verbose = Blender::VERBOSITY_NORMAL;
54
55
    /**
56
     * MigrationsCreator constructor.
57
     * @param UserInteractionHandler $userInteractionHandler
58
     * @param array $class_data
59
     */
60
    public function __construct(UserInteractionHandler $userInteractionHandler, $class_data = [])
61
    {
62
        $this->class_data = $class_data;
63
64
        $this->userInteractionHandler = $userInteractionHandler;
65
66
        $this->path_time_stamp = date('Y_m_d_His');
67
        $this->format = new Format($this->path_time_stamp);
68
69
        $this->migration_templates_path = __DIR__.'/templates/';
70
        $this->setBaseMigrationsPath(dirname(__DIR__).DIRECTORY_SEPARATOR);
71
    }
72
73
    /**
74
     * @return int
75
     */
76
    public function getVerbose(): int
77
    {
78
        return $this->verbose;
79
    }
80
81
    /**
82
     * @param int $verbose
83
     * @see https://symfony.com/doc/current/console/verbosity.html
84
     * @return $this
85
     */
86
    public function setVerbose(int $verbose)
87
    {
88
        $this->verbose = $verbose;
89
        return $this;
90
    }
91
92
    /**
93
     * @param string $path ~ like /var/www/public/core/components/blend/
94
     * @param bool $append ~ if true will create database/migrations with in the path
95
     * @return $this
96
     */
97
    public function setMigrationsPath($path, $append = false)
98
    {
99
        $this->migrations_path = rtrim($path, '\/\\') . DIRECTORY_SEPARATOR;
100
101
        if (file_exists($path) && $append) {
102
            if (!file_exists($path.'database')) {
103
                mkdir($path.'database');
104
            }
105
            if (!file_exists($path.'database/migrations')) {
106
                mkdir($path.'database/migrations');
107
            }
108
            $this->migrations_path = $path.'database/migrations/';
109
110
        } elseif (!file_exists($path) && !$append) {
111
            mkdir($path, 0755, true);
112
        }
113
114
        return $this;
115
    }
116
117
    /**
118
     * @param string $path ~ like /var/www/public/core/components/blend/
119
     * @param bool $append ~ if true will create database/seeds with in the path
120
     * @return $this
121
     */
122
    public function setSeedsPath($path, $append = false)
123
    {
124
        $this->seeds_path = rtrim($path, '\/\\') . DIRECTORY_SEPARATOR;
125
126
        if (file_exists($path) && $append) {
127
            if (!file_exists($path.'database')) {
128
                mkdir($path.'database');
129
            }
130
            if (!file_exists($path.'database/seeds')) {
131
                mkdir($path.'database/seeds');
132
            }
133
            $this->seeds_path = $path.'database/seeds/';
134
135
        } elseif (!file_exists($path) && !$append) {
136
            mkdir($path, 0755, true);
137
        }
138
139
        return $this;
140
    }
141
142
    /**
143
     * @param string $path ~ like /var/www/public/core/components/blend/ And then will create database/migrations and
144
     *      database/seeds
145
     * @return $this
146
     */
147
    public function setBaseMigrationsPath($path)
148
    {
149
        $this->setMigrationsPath($path, true);
150
        $this->setSeedsPath($path, true);
151
        return $this;
152
    }
153
    /**
154
     * @return bool
155
     */
156
    public function createBlankMigrationClassFile()
157
    {
158
        return $this->writeMigrationClassFile('blank');
0 ignored issues
show
Unused Code introduced by
The call to LCI\Blend\Migrations\Mig...iteMigrationClassFile() has too many arguments starting with 'blank'. ( Ignorable by Annotation )

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

158
        return $this->/** @scrutinizer ignore-call */ writeMigrationClassFile('blank');

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug Best Practice introduced by
The expression return $this->writeMigrationClassFile('blank') also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
159
    }
160
161
    /**
162
     * @return bool
163
     */
164
    public function createChunkMigrationClassFile()
165
    {
166
        $this->migration_template = 'chunk.txt';
167
        $this->placeholders['chunkData'] = $this->format->prettyVarExport($this->class_data);
168
        $this->placeholders['classUpInners'] = '$this->blender->blendManyChunks($this->chunks, $this->getSeedsDir());';
169
        $this->placeholders['classDownInners'] = '$this->blender->revertBlendManyChunks($this->chunks, $this->getSeedsDir());';
170
171
        return $this->writeMigrationClassFile();
172
    }
173
174
    /**
175
     * @return bool
176
     */
177
    public function createContextMigrationClassFile()
178
    {
179
        $this->migration_template = 'context.txt';
180
        $this->placeholders['contextData'] = $this->format->prettyVarExport($this->class_data);
181
        $this->placeholders['classUpInners'] = '$this->blender->blendManyContexts($this->contexts, $this->getSeedsDir());';
182
        $this->placeholders['classDownInners'] = '$this->blender->revertBlendManyContexts($this->contexts, $this->getSeedsDir());';
183
184
        return $this->writeMigrationClassFile();
185
    }
186
187
    /**
188
     * @return bool
189
     */
190
    public function createMediaSourceMigrationClassFile()
191
    {
192
        $this->migration_template = 'mediaSource.txt';
193
        $this->placeholders['mediaSourceData'] = $this->format->prettyVarExport($this->class_data);
194
        $this->placeholders['classUpInners'] = '$this->blender->blendManyMediaSources($this->media_sources, $this->getSeedsDir());';
195
        $this->placeholders['classDownInners'] = '$this->blender->revertBlendManyMediaSources($this->media_sources, $this->getSeedsDir());';
196
197
        return $this->writeMigrationClassFile();
198
    }
199
200
    /**
201
     * @return bool
202
     */
203
    public function createPluginMigrationClassFile()
204
    {
205
        $this->migration_template = 'plugin.txt';
206
        $this->placeholders['pluginData'] = $this->format->prettyVarExport($this->class_data);
207
        $this->placeholders['classUpInners'] = '$this->blender->blendManyPlugins($this->plugins, $this->getSeedsDir());';
208
        $this->placeholders['classDownInners'] = '$this->blender->revertBlendManyPlugins($this->plugins, $this->getSeedsDir());';
209
210
        return $this->writeMigrationClassFile();
211
    }
212
213
    /**
214
     * @return bool
215
     */
216
    public function createResourceMigrationClassFile()
217
    {
218
        $this->migration_template = 'resource.txt';
219
220
        $this->placeholders['resourceData'] = $this->format->prettyVarExport($this->class_data);
221
        $this->placeholders['classUpInners'] = '$this->blender->blendManyResources($this->resources, $this->getSeedsDir());';
222
        $this->placeholders['classDownInners'] = '$this->blender->revertBlendManyResources($this->resources, $this->getSeedsDir());';
223
224
        return $this->writeMigrationClassFile();
225
    }
226
227
    /**
228
     * @return bool
229
     */
230
    public function createSnippetMigrationClassFile()
231
    {
232
        $this->migration_template = 'snippet.txt';
233
        $this->placeholders['snippetData'] = $this->format->prettyVarExport($this->class_data);
234
        $this->placeholders['classUpInners'] = '$this->blender->blendManySnippets($this->snippets, $this->getSeedsDir());';
235
        $this->placeholders['classDownInners'] = '$this->blender->revertBlendManySnippets($this->snippets, $this->getSeedsDir());';
236
237
        return $this->writeMigrationClassFile();
238
    }
239
240
    /**
241
     * @return bool
242
     */
243
    public function createSystemSettingsMigrationClassFile()
244
    {
245
        $this->migration_template = 'systemSettings.txt';
246
        $this->placeholders['settingsData'] = $this->format->prettyVarExport($this->class_data);
247
        $this->placeholders['classUpInners'] = '$this->blender->blendManySystemSettings($this->settings, $this->getSeedsDir());';
248
        $this->placeholders['classDownInners'] = '$this->blender->revertBlendManySystemSettings($this->settings, $this->getSeedsDir());';
249
250
        return $this->writeMigrationClassFile();
251
    }
252
253
    public function createTemplateMigrationClassFile()
254
    {
255
        $this->migration_template = 'template.txt';
256
        $this->placeholders['templateData'] = $this->format->prettyVarExport($this->class_data);
257
        $this->placeholders['classUpInners'] = '$this->blender->blendManyTemplates($this->templates, $this->getSeedsDir());';
258
        $this->placeholders['classDownInners'] = '$this->blender->revertBlendManyTemplates($this->templates, $this->getSeedsDir());';
259
260
        return $this->writeMigrationClassFile();
261
    }
262
263
    /**
264
     * @return bool
265
     */
266
    public function createSiteMigrationClassFile()
267
    {
268
        $this->migration_template = 'site.txt';
269
        $this->placeholders['siteData'] = $this->format->prettyVarExport($this->class_data);
270
271
        return $this->writeMigrationClassFile();
272
    }
273
274
    /**
275
     * @return string
276
     */
277
    public function getDescription()
278
    {
279
        return $this->description;
280
    }
281
282
    /**
283
     * @return array
284
     */
285
    public function getLogData()
286
    {
287
        return $this->log_data;
288
    }
289
290
    /**
291
     * @return string
292
     */
293
    public function getName()
294
    {
295
        return $this->name;
296
    }
297
298
    /**
299
     * @return false|string
300
     */
301
    public function getPathTimeStamp()
302
    {
303
        return $this->path_time_stamp;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->path_time_stamp also could return the type boolean which is incompatible with the documented return type false|string.
Loading history...
304
    }
305
306
    /**
307
     * @return string
308
     */
309
    public function getServerType()
310
    {
311
        return $this->server_type;
312
    }
313
314
    /**
315
     * @return string
316
     */
317
    public function getVersion()
318
    {
319
        return $this->version;
320
    }
321
322
323
    /**
324
     * @param string $description
325
     * @return MigrationsCreator
326
     */
327
    public function setDescription($description)
328
    {
329
        $this->description = $description;
330
        return $this;
331
    }
332
333
    /**
334
     * @param bool $log
335
     * @return MigrationsCreator
336
     */
337
    public function setLog($log)
338
    {
339
        $this->log = $log;
0 ignored issues
show
Bug Best Practice introduced by
The property log does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
340
        return $this;
341
    }
342
343
    /**
344
     * @param string $name
345
     * @return $this
346
     */
347
    public function setName($name)
348
    {
349
        $this->name = $name;
350
        return $this;
351
    }
352
353
    /**
354
     * @param false|string $path_time_stamp
355
     * @return MigrationsCreator
356
     */
357
    public function setPathTimeStamp($path_time_stamp)
358
    {
359
        $this->format = new Format($path_time_stamp);
360
        $this->path_time_stamp = $path_time_stamp;
361
        return $this;
362
    }
363
364
    /**
365
     * @param string $server_type
366
     * @return MigrationsCreator
367
     */
368
    public function setServerType($server_type)
369
    {
370
        $this->server_type = $server_type;
371
        return $this;
372
    }
373
374
    /**
375
     * @param string $version
376
     * @return MigrationsCreator
377
     */
378
    public function setVersion($version)
379
    {
380
        $this->version = $version;
381
        return $this;
382
    }
383
384
    /**
385
     * @return bool
386
     */
387
    protected function writeMigrationClassFile()
388
    {
389
        $class_name = $this->format->getMigrationName(substr($this->migration_template, 0, -4), $this->name);
390
391
        $placeholders = array_merge(
392
            [
393
                'classCreateDate' => date('Y/m/d'),
394
                'classCreateTime' => date('G:i:s T P'),
395
                'className' => $class_name,
396
                'classUpInners' => '//@TODO',
397
                'classDownInners' => '//@TODO',
398
                'description' => $this->getDescription(),
399
                'serverType' => $this->getServerType(),
400
                'seeds_dir' => $class_name,
401
                'version' => $this->getVersion()
402
            ],
403
            $this->placeholders
404
        );
405
406
        $file_contents = '';
407
408
        $migration_template = $this->migration_templates_path.$this->migration_template;
409
        if (file_exists($migration_template)) {
410
            $file_contents = file_get_contents($migration_template);
411
        } else {
412
            $this->outError('Migration template file not found: '.$migration_template);
413
        }
414
415
        foreach ($placeholders as $name => $value) {
416
            $file_contents = str_replace('[[+'.$name.']]', $value, $file_contents);
417
        }
418
419
        $this->out($this->migrations_path.$class_name.'.php');
420
421
        $write = false;
422
        if (file_exists($this->migrations_path.$class_name.'.php')) {
423
            $this->outError($this->migrations_path.$class_name.'.php migration file already exists');
424
425
        } else {
426
            try {
427
                $write = file_put_contents($this->migrations_path.$class_name.'.php', $file_contents);
428
                 $this->log_data = [
429
                    'name' => $class_name,
430
                    'type' => $this->getServerType(),
431
                    'description' => $this->getDescription(),
432
                    'version' => $this->getVersion(),
433
                    'status' => 'seed export',
434
                    'created_at' => date('Y-m-d H:i:s')
435
                ];
436
            } catch (\Exception $exception) {
437
                $this->outError($exception->getMessage());
438
            }
439
440
            if (!$write) {
441
                $this->outError($this->migrations_path.$class_name.'.php Did not write to file');
442
                $this->outError('Verify that the folders exists and are writable by PHP');
443
            }
444
        }
445
446
        return $write;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $write also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
447
    }
448
449
    /**
450
     * @param string $message
451
     * @param int $verbose
452
     * @param bool $error
453
     */
454
    public function out($message, $verbose=Blender::VERBOSITY_NORMAL, $error = false)
455
    {
456
        if ($this->getVerbose() >= $verbose) {
457
            if ($error) {
458
                $this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_ERROR);
459
460
            } else {
461
                $this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_STRING);
462
            }
463
        }
464
    }
465
    /**
466
     * @param string $message
467
     * @param int $verbose
468
     */
469
    public function outError($message, $verbose=Blender::VERBOSITY_NORMAL)
470
    {
471
        if ($this->getVerbose() >= $verbose) {
472
            $this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_ERROR);
473
        }
474
    }
475
476
}