Test Failed
Push — develop ( 12e168...c96bee )
by nguereza
02:42
created

AbstractCommand::createMigrationTable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 10
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 13
rs 9.9332
1
<?php
2
3
/**
4
 * Platine Framework
5
 *
6
 * Platine Framework is a lightweight, high-performance, simple and elegant
7
 * PHP Web framework
8
 *
9
 * This content is released under the MIT License (MIT)
10
 *
11
 * Copyright (c) 2020 Platine Framework
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy
14
 * of this software and associated documentation files (the "Software"), to deal
15
 * in the Software without restriction, including without limitation the rights
16
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
 * copies of the Software, and to permit persons to whom the Software is
18
 * furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
 * SOFTWARE.
30
 */
31
32
/**
33
 *  @file AbstractCommand.php
34
 *
35
 *  The Base migration command class
36
 *
37
 *  @package    Platine\Framework\Migration\Command
38
 *  @author Platine Developers team
39
 *  @copyright  Copyright (c) 2020
40
 *  @license    http://opensource.org/licenses/MIT  MIT License
41
 *  @link   http://www.iacademy.cf
42
 *  @version 1.0.0
43
 *  @filesource
44
 */
45
46
declare(strict_types=1);
47
48
namespace Platine\Framework\Migration\Command;
49
50
use Platine\Config\Config;
51
use Platine\Console\Command\Command;
52
use Platine\Database\Connection;
53
use Platine\Filesystem\DirectoryInterface;
54
use Platine\Filesystem\FileInterface;
55
use Platine\Filesystem\Filesystem;
56
use Platine\Framework\App\Application;
57
use Platine\Framework\Migration\AbstractMigration;
58
use Platine\Framework\Migration\MigrationRepository;
59
use Platine\Stdlib\Helper\Path;
60
use Platine\Stdlib\Helper\Str;
61
use RuntimeException;
62
63
/**
64
 * class AbstractCommand
65
 * @package Platine\Framework\Migration\Command
66
 */
67
abstract class AbstractCommand extends Command
68
{
69
70
    /**
71
     * The migration repository
72
     * @var MigrationRepository
73
     */
74
    protected MigrationRepository $repository;
75
76
    /**
77
     * The configuration to use
78
     * @var Config
79
     */
80
    protected Config $config;
81
82
    /**
83
     * The file system to use
84
     * @var Filesystem
85
     */
86
    protected Filesystem $filesystem;
87
88
    /**
89
     * The Platine Application
90
     * @var Application
91
     */
92
    protected Application $application;
93
94
    /**
95
     * The migration files path
96
     * @var string
97
     */
98
    protected string $migrationPath = '';
99
100
    /**
101
     * The migration table
102
     * @var string
103
     */
104
    protected string $table;
105
106
    /**
107
     * Create new instance
108
     * @param Application $app
109
     * @param MigrationRepository $repository
110
     * @param Config $config
111
     * @param Filesystem $filesystem
112
     */
113
    public function __construct(
114
        Application $app,
115
        MigrationRepository $repository,
116
        Config $config,
117
        Filesystem $filesystem
118
    ) {
119
        parent::__construct('migration', 'Command to manage database migration');
120
        $this->application = $app;
121
        $this->repository = $repository;
122
        $this->config = $config;
123
        $this->filesystem = $filesystem;
124
        $path = Path::convert2Absolute($config->get('migration.path', 'migrations'));
125
        $this->migrationPath = Path::normalizePathDS($path, true);
126
        $this->table = $config->get('migration.table', 'migrations');
127
    }
128
129
    /**
130
     * Check the migration directory
131
     * @return void
132
     */
133
    protected function checkMigrationPath(): void
134
    {
135
        $directory = $this->filesystem->directory($this->migrationPath);
136
137
        if (!$directory->exists() || !$directory->isWritable()) {
138
            throw new RuntimeException(sprintf(
139
                'Migration directory [%s] does not exist or is writable',
140
                $this->migrationPath
141
            ));
142
        }
143
    }
144
145
    /**
146
     * Create migration class for the given version
147
     * @param string $description
148
     * @param string $version
149
     * @return AbstractMigration
150
     */
151
    protected function createMigrationClass(
152
        string $description,
153
        string $version
154
    ): AbstractMigration {
155
        $this->checkMigrationPath();
156
157
        $className = $this->getMigrationClassName($description, $version);
158
        $filename = $this->getFilenameFromClass($className, $version);
159
        $fullPath = $this->migrationPath . $filename;
160
161
        $file = $this->filesystem->file($fullPath);
162
        $fullClasName = 'Platine\\Framework\\Migration\\' . $className;
163
164
        if (!$file->exists()) {
165
            throw new RuntimeException(sprintf(
166
                'Migration file [%s] does not exist',
167
                $fullPath
168
            ));
169
        }
170
171
        require_once $fullPath;
172
173
        if (!class_exists($fullClasName)) {
174
            throw new RuntimeException(sprintf(
175
                'Migration class [%s] does not exist',
176
                $fullClasName
177
            ));
178
        }
179
180
        $connection = $this->application->get(Connection::class);
181
182
        return new $fullClasName($connection);
183
    }
184
185
    /**
186
     * Return all migrations files available
187
     * @return array<string, string>
188
     */
189
    protected function getMigrations(): array
190
    {
191
        $this->checkMigrationPath();
192
193
        $directory = $this->filesystem->directory($this->migrationPath);
194
        $result = [];
195
        /** @var FileInterface[] $files */
196
        $files = $directory->read(DirectoryInterface::FILE);
197
        foreach ($files as $file) {
198
            $matches = [];
199
            if (preg_match('/^([0-9_]+)_([a-z_]+)\.php$/i', $file->getName(), $matches)) {
200
                $result[$matches[1]] = $matches[2];
201
            }
202
        }
203
204
        ksort($result);
205
206
        return $result;
207
    }
208
209
    /**
210
     * Return the executed migration
211
     * @param string $orderDir
212
     * @return array<string, Entity>
213
     */
214
    protected function getExecuted(string $orderDir = 'ASC'): array
215
    {
216
        $migrations = $this->repository
217
                           ->query()
218
                           ->orderBy('version', $orderDir)
219
                           ->all();
220
        $result = [];
221
222
        foreach ($migrations as $entity) {
223
            $result[$entity->version] = $entity;
224
        }
225
226
        return $result;
227
    }
228
229
    /**
230
     * Return the migration class name for the given name
231
     * @param string $description
232
     * @param string $version
233
     * @return string
234
     */
235
    protected function getMigrationClassName(string $description, string $version): string
236
    {
237
        return Str::camel($description, false)
238
               . Str::replaceFirst('_', '', $version);
239
    }
240
241
    /**
242
     * Return the name of the migration file
243
     * @param string $className
244
     * @param string $version
245
     * @return string
246
     */
247
    protected function getFilenameFromClass(string $className, string $version): string
248
    {
249
        return $filename = sprintf(
0 ignored issues
show
Unused Code introduced by
The assignment to $filename is dead and can be removed.
Loading history...
250
            '%s_%s.php',
251
            $version,
252
            str_replace(Str::replaceFirst('_', '', $version), '', Str::snake($className))
253
        );
254
    }
255
}
256