* $setup = new Setup('test.xml'); * $setup->set('target', 'dst'); * $setup->executeActions('install'); * */ namespace ctiso; use ctiso\Tools\SQLStatementExtractor; use ctiso\Path; class FakeZipArchive { public $base; function open($path) { $this->base = $path; } function getFromName($file) { return file_get_contents(Path::join($this->base, $file)); } } class Setup { protected $actions = array(); public $context = array(); protected $file; protected $action; protected $node; protected $stack = array(); public $zip; public $target; public $source; public function __construct($file) { $this->file = $file; $this->node = simplexml_load_file($file); $this->target = ''; $this->source = ''; $this->zip = new FakeZipArchive(); $this->zip->open(dirname($this->file) . '/' . $this->node->attributes()['dir']); array_push($this->stack, $this->node); $this->registerAction('copy', [$this, 'copyFile']); $this->registerAction('make-directory', [$this, 'makeDirectory']); $this->registerAction('make-link', [$this, 'makeLink']); $this->registerAction('include', [$this, 'includeFile']); $this->registerAction('when', [$this, 'testWhen']); } /** * Регистрация новых действия для установки */ public function registerAction($name, $action) { $this->actions[$name] = $action; } /** * Установка переменных для шаблона */ public function set($name, $value) { $this->context[$name] = $value; } function replaceFn($matches) { if (isset($this->context[$matches[2]])) { $v = $this->context[$matches[2]]; } else { $v = $matches[2]; } if ($matches[1] == '*') { return addslashes($v); } return $v; } public function fileContent($file, array $tpl) { $result = $this->zip->getFromName($file); $result = preg_replace_callback('/\{\{\s*(\*?)(\w+)\s*\}\}/', [$this, 'replaceFn'], $result); return $result; } function callAction($name, array $attributes) { if(isset($this->actions[$name])) { call_user_func_array($this->actions[$name], $attributes); } } /** * Заменяет переменные на их значения в строке */ function replaceVariable(array $match) { if (isset($this->context[$match[1]])) { return $this->context[$match[1]]; } return $match[0]; } /** * Для всех аттрибутов заменяет переменные на их значения */ function resolve($attributes) { $result = []; foreach ($attributes as $key => $value) { $result [$key] = preg_replace_callback("/\\\${(\w+)}/", [$this, 'replaceVariable'], $value); } return $result; } /** * Выполняет список действий если для действия не указан аттрибут when то оно выполняется всегда * * @param string $action специальное действие */ function executeActions($action = "install") { $this->action = $action; if ($this->stack[count($this->stack) - 1] === false) { return; } $item/*: \SimpleXMLElement*/ = $this->stack[count($this->stack) - 1]; $root = $item->children(); foreach ($root as $node) { $attributes = $node->attributes(); array_push($this->stack, $node); $this->callAction($node->getName(), [$this->resolve($attributes)]); array_pop($this->stack); } } /** * Копирования файла * preserve - Не переписывать файл если он существует * template Файл является шаблоном подставить параметры до копирования * src Исходный файл * dst Новый файл * * @param array{preserve?: string, template: string, src: string, dst: string} $attributes */ public function copyFile(array $attributes) { $path = $this->targetPath($attributes['dst']); if (!(file_exists($path) && isset($attributes['preserve']))) { file_put_contents($path, $this->fileContent($attributes['src'], $this->context)); } } /** * Создает символическую ссылку на папку/файл * @param array{target: string, link: string} $attributes */ public function makeLink(array $attributes) { if (function_exists('symlink')) { symlink($attributes['target'], $attributes['link']); } } /** * Подключение файла установки * @param array{file: string} $attributes Имя подключаемого файла */ public function includeFile(array $attributes) { $file = basename($this->file) . "/" . $attributes['file']; $setup = new Setup($file); $setup->context = $this->context; $setup->executeActions(); } function targetPath($s) { return $this->target . '/' . $s; } /** * Создает новую папку * dst Имя папки * * @param array{dst:string} $attributes */ public function makeDirectory(array $attributes) { $path = $this->targetPath($attributes['dst']); if (!file_exists($path)) { mkdir($path); } } function testWhen(array $attributes) { if (!isset($attributes['test']) || $attributes['test'] == $this->action) { $this->executeActions($this->action); } } /** * Выполнение Списка SQL команд */ function batchSQLZip($conn/*: Database*/, $file) { $stmtList = SQLStatementExtractor::extract($this->zip->getFromName($file)); foreach ($stmtList as $stmt) { $conn->executeQuery ($stmt); } } static function batchSQL($conn/*: Database*/, $file) { $stmtList = SQLStatementExtractor::extractFile($file); foreach ($stmtList as $stmt) { $conn->executeQuery ($stmt); } } }