5 class Migrate extends \Rsi\Fred\Component{
15 public $test = false; //!< Execute the 'test
' part of the migration file. 17 protected $_db = null; 18 protected $_currentPath = null; //!< Path with current files (keep out of version control; empty = path + "current/"). 20 protected $_current = null; 22 protected function flatten($sql){ 23 return md5(preg_replace('/\\s+/
','',$sql)); 30 protected function dir($path){
32 foreach((new \GlobIterator($path . $this->mask,\GlobIterator::NEW_CURRENT_AND_KEY)) as $filename => $info)
33 $dir[$filename] = file_get_contents($path . $filename);
41 public function diff(){
42 $diff = array_fill_keys(array_keys($this->current),self::ACTION_UNDO);
44 foreach($this->dir($this->path) as $filename => $sql) $diff[$filename] = array_key_exists($filename,$this->current)
45 ? ($redo || ($redo = $this->flatten($this->current[$filename]) != $this->flatten($sql)) ? self::ACTION_REDO : null) //redo all after first redo
48 return array_filter($diff);
51 protected function split($sql){
53 $delimiter = '/(?:$|
' . str_replace('\\[action\\]
','(
' . implode('|
',$this->constants('ACTION_
')) . ')
',preg_quote($this->delimiter,'/
')) . ')/
'; 54 $action = self::ACTION_EXEC; 55 while(preg_match($delimiter,$sql,$match,PREG_OFFSET_CAPTURE)) switch(count($match)){ 57 $parts[$action] = $sql; 60 $parts[$action] = substr($sql,0,$match[0][1]); 61 $sql = substr($sql,$match[1][1] + strlen($action = $match[1][0])); 71 public function execute(){
72 $log = $this->component('log
'); 73 if($diff = $this->diff()){ 76 foreach(array_reverse($diff) as $filename => $action) switch($action){ 77 case self::ACTION_UNDO: 78 case self::ACTION_REDO: 79 $log->info("Migrate: undo $filename",__FILE__,__LINE__); 80 if(trim($sql = $this->split($this->current[$filename])[$action] ?? null)) $this->_db->execute($sql); 83 foreach($diff as $filename => $action) switch($action){ 84 case self::ACTION_TEST: if(!$this->test) break; 85 case self::ACTION_REDO: 86 case self::ACTION_EXEC: 87 $log->info("Migrate: $action $filename",__FILE__,__LINE__); 88 if(trim($sql = $this->split(file_get_contents($this->path . $filename))[$action] ?? null)) $this->_db->execute($sql); 91 $this->current = $this->dir($this->path); 95 $this->_db->rollBack(); 102 protected function getCurrent(){ 103 if($this->_current === null) $this->_current = $this->dir($this->currentPath); 104 return $this->_current; 107 protected function setCurrent($value){ 108 foreach($this->dir($this->current) as $filename => $sql) unlink($this->currentPath . $filename); 109 foreach(($this->_current = $value) as $filename => $sql) file_put_contents($this->currentPath . $filename,$sql); 112 protected function getCurrentPath(){ 113 return $this->_currentPath ?: $this->path . 'current/
'; $delimiter
Delimiter for the migration file parts ([action] holds the action).
$path
Directory with migration files (including trailing delimiter).
const ACTION_REDO
Changed.
const ACTION_UNDO
Removed.
const ACTION_TEST
Testing.
$mask
Format for migration files.