Completed
Push — master ( f6c233...37689c )
by Joao
03:06
created

Migration::addCallbackProgress()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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