233 lines
6.6 KiB
PHP
233 lines
6.6 KiB
PHP
<?php
|
||
|
||
/**
|
||
* <code>
|
||
* $setup = new Setup('test.xml');
|
||
* $setup->set('target', 'dst');
|
||
* $setup->executeActions('install');
|
||
* </code>
|
||
*/
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|