Completed
Pull Request — master (#1)
by Joao
04:35
created

Migration::getDbDataset()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace ByJG\DbMigration;
4
5
use ByJG\AnyDataset\DbDriverInterface;
6
use ByJG\AnyDataset\Factory;
7
use ByJG\DbMigration\Commands\CommandInterface;
8
use ByJG\Util\Uri;
9
10
class Migration
11
{
12
    /**
13
     * @var Uri
14
     */
15
    protected $uri;
16
17
    /**
18
     * @var string
19
     */
20
    protected $_folder;
21
22
    /**
23
     * @var DbDriverInterface
24
     */
25
    protected $dbDriver;
26
27
    /**
28
     * @var CommandInterface
29
     */
30
    protected $_dbCommand;
31
32
    /**
33
     * @var Callable
34
     */
35
    protected $_callableProgress;
36
    
37
    /**
38
     * Migration constructor.
39
     *
40
     * @param Uri $uri
41
     * @param string $_folder
42
     */
43
    public function __construct(Uri $uri, $_folder)
44
    {
45
        $this->uri = $uri;
46
        $this->_folder = $_folder;
47
48
        if (!file_exists($this->_folder . '/base.sql')) {
49
            throw new \InvalidArgumentException("Migration script '{$this->_folder}/base.sql' not found");
50
        }
51
    }
52
53
    /**
54
     * @return DbDriverInterface
55
     */
56
    public function getDbDriver()
57
    {
58
        if (is_null($this->dbDriver)) {
59
            $this->dbDriver = Factory::getDbRelationalInstance($this->uri->__toString());
60
        }
61
        return $this->dbDriver;
62
    }
63
64
    /**
65
     * @return CommandInterface
66
     */
67
    public function getDbCommand()
68
    {
69
        if (is_null($this->_dbCommand)) {
70
            $class = $this->getCommandClassName();
71
            $this->_dbCommand = new $class($this->getDbDriver());
72
        }
73
        return $this->_dbCommand;
74
    }
75
76
    protected function getCommandClassName()
77
    {
78
        return "\\ByJG\\DbMigration\\Commands\\" . ucfirst($this->uri->getScheme()) . "Command";
79
    }
80
81
    /**
82
     * Get the full path and name of the "base.sql" script
83
     *
84
     * @return string
85
     */
86
    public function getBaseSql()
87
    {
88
        return $this->_folder . "/base.sql";
89
    }
90
91
    /**
92
     * Get the full path script based on the version
93
     *
94
     * @param $version
95
     * @param $increment
96
     * @return string
97
     */
98
    public function getMigrationSql($version, $increment)
99
    {
100
        $result = glob(
101
            $this->_folder
102
            . "/migrations"
103
            . "/" . ($increment < 0 ? "down" : "up")
104
            . "/*$version.sql"
105
        );
106
107
        foreach ($result as $file) {
108
            if (intval(basename($file)) == $version) {
109
                return $file;
110
            }
111
        }
112
    }
113
114
    /**
115
     * Create the database it it does not exists. Does not use this methos in a production environment; 
116
     */
117
    public function prepareEnvironment()
118
    {
119
        $class = $this->getCommandClassName();
120
        $class::prepareEnvironment($this->uri);
121
    }
122
    
123
    /**
124
     * Restore the database using the "base.sql" script and run all migration scripts
125
     * Note: the database must exists. If dont exist run the method prepareEnvironment.  
126
     *
127
     * @param int $upVersion
128
     */
129
    public function reset($upVersion = null)
130
    {
131
        if ($this->_callableProgress) {
132
            call_user_func_array($this->_callableProgress, ['reset', 0]);
133
        }
134
        $this->getDbCommand()->dropDatabase();
135
        $this->getDbCommand()->createDatabase();
136
        $this->getDbCommand()->executeSql(file_get_contents($this->getBaseSql()));
137
        $this->getDbCommand()->createVersion();
138
        $this->up($upVersion);
139
    }
140
141
    /**
142
     * Get the current database version
143
     *
144
     * @return int
145
     */
146
    public function getCurrentVersion()
147
    {
148
        return intval($this->getDbCommand()->getVersion());
149
    }
150
151
    /**
152
     * @param $currentVersion
153
     * @param $upVersion
154
     * @param $increment
155
     * @return bool
156
     */
157
    protected function canContinue($currentVersion, $upVersion, $increment)
158
    {
159
        $existsUpVersion = ($upVersion !== null);
160
        $compareVersion = strcmp(
161
                str_pad($currentVersion, 5, '0', STR_PAD_LEFT),
162
                str_pad($upVersion, 5, '0', STR_PAD_LEFT)
163
            ) == $increment;
164
165
        return !($existsUpVersion && $compareVersion);
166
    }
167
168
    /**
169
     * Method for execute the migration.
170
     *
171
     * @param int $upVersion
172
     * @param int $increment Can accept 1 for UP or -1 for down
173
     */
174
    protected function migrate($upVersion, $increment)
175
    {
176
        $currentVersion = $this->getCurrentVersion() + $increment;
177
        
178
        while ($this->canContinue($currentVersion, $upVersion, $increment)
179
            && file_exists($file = $this->getMigrationSql($currentVersion, $increment))
180
        ) {
181
            if ($this->_callableProgress) {
182
                call_user_func_array($this->_callableProgress, ['migrate', $currentVersion]);
183
            }
184
185
            $this->getDbCommand()->executeSql(file_get_contents($file));
186
            $this->getDbCommand()->setVersion($currentVersion);
187
            $currentVersion = $currentVersion + $increment;
188
        }
189
    }
190
191
    /**
192
     * Run all scripts to up the database version from current up to latest version or the specified version.
193
     *
194
     * @param int $upVersion
195
     */
196
    public function up($upVersion = null)
197
    {
198
        $this->migrate($upVersion, 1);
199
    }
200
201
    /**
202
     * Run all scripts to down the database version from current version up to the specified version.
203
     *
204
     * @param int $upVersion
205
     */
206
    public function down($upVersion)
207
    {
208
        $this->migrate($upVersion, -1);
209
    }
210
    
211
    public function addCallbackProgress(Callable $callable)
212
    {
213
        $this->_callableProgress = $callable;
214
    }
215
}
216