<?php
/**
 * @link      http://www.u-bo.com
 * @copyright 南京友博网络科技有限公司 
 * @license   http://www.u-bo.com/license/
 */

namespace qcbase\models;

use Yii;
use yii\helpers\FileHelper;
use yii\db\Query;
use yii\base\ErrorException;

/**
 * This is the model class for table "{{%module}}".
 * 
 * 模块管理,包括模块安装卸载
 *
 * @property string $module_id  (模块id)
 * @property string $module_name  (模块名称)
 * @property string $version  (版本)
 * @property string $author  (作者)
 * @property text $description  (模块描述)
 * @property integer $install_time  (安装时间)
 * @property integer $upgrade_time  (升级时间)
 *
 * @author legendjw http://blog.u-bo.com
 * @since 0.1
 */
class Module extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%module}}';
    }

    /**
     * 获取模块列表
	 * 
	 * 模块统一放在程序目录下packages文件夹下
	 * 
	 * @return array 所有的模块信息
	 */
    public static function getList()
    {
        $packagesPath = Yii::getAlias('@packages'); 
        $d = dir($packagesPath);
        $modules = [];
        while (false !== ($entry = $d->read())) {
            $entryPath = $packagesPath.DIRECTORY_SEPARATOR.$entry;
            $configFile = $entryPath.DIRECTORY_SEPARATOR.'config.php';
            if ($entry !='.' && $entry !='..' && is_dir($entryPath) && is_file($configFile)) {
                $configs = require($configFile);
                $configs['packagePath'] = $entryPath;
                $modules[$entry] = $configs;
            }
        }
        return $modules;
    }

	/**
	 * 安装模块
	 * 
	 * @param type $id 要安装的模块id
	 * 
	 */
	public static function install($id)
	{
		$modules = self::getList();
		if (!isset($modules[$id])) {
			throw new ErrorException('要安装的模块不存在！');
		} 
        $packagesPath = Yii::getAlias('@packages'); 
		$module = $modules[$id];
		//判断是否已经安装
		$row = static::findOne($module['id']);
		if ($row) {
			throw new ErrorException($module['name'].'已经安装，请不要重复安装！');
		}
		//判断依赖关系
		if (isset($module['depends']) && count($module['depends']) > 0) {
			foreach ($module['depends'] as $dependModId) {
				if (!$row = static::findOne($dependModId)) {
					\common\components\Tool::dump($row);
					throw new ErrorException(isset($modules[$dependModId]) ? '请先安装'.$modules[$dependModId]['name'] :'id为'.$dependModId.'的依赖模块不存在！');
				}
			}
		}



		if (!isset($module['modules']) || count($module['modules']) == 0) {
			throw new ErrorException('要安装的模块至少包含一个子模块！');
		}

		foreach ($module['modules'] as $folder => $subMod) {
			$subModDir = $module['packagePath'].DIRECTORY_SEPARATOR.$folder;//子模块源程序目录
			$installDir = Yii::getAlias($subMod['installDir']).DIRECTORY_SEPARATOR.(isset($subMod['id']) ? $subMod['id'] : $module['id']);//要安装的目录
			//如果安装目录已经存在则直接删除
			if (is_dir($installDir)) {
				FileHelper::removeDirectory($installDir);
			}
			//复制子模块到指定目录
			FileHelper::copyDirectory($subModDir, $installDir, ['except' => ['install/','uninstall/']]);

			//若有数据库操作，执行数据库脚本
			$installConfigFile = $subModDir.DIRECTORY_SEPARATOR.'install'.DIRECTORY_SEPARATOR.'config.php';
			if (is_file($installConfigFile) && ($installConfigs = require $installConfigFile) && isset($installConfigs['datasource'])) {
				//执行脚本
				foreach ($installConfigs['datasource'] as $source) {
					$source['path'] = $subModDir.DIRECTORY_SEPARATOR.'install'.DIRECTORY_SEPARATOR.$source['path'];
					self::parseSource($source);
				}
			}

		}
		//安装成功后记录到数据表
		$command = Yii::$app->db->createCommand()->insert('{{%module}}', [
			'module_id' => $module['id'],
			'module_name' => $module['name'],
			'version' => $module['version'],
			'author' => $module['author'],
			'description' => $module['description'],
			'install_time' => time(),
		])->execute();
		
		return true;
	}

	/**
	 * 模块卸载
	 * 
	 * @param type $id
	 */
	public static function uninstall($id)
	{
		$modules = self::getList();
		if (!isset($modules[$id])) {
			throw new ErrorException('要卸载的模块不存在！');
		} 
        $packagesPath = Yii::getAlias('@packages'); 
		$module = $modules[$id];
		//判断是否已经安装
		$row = static::findOne($module['id']);
		if (!$row) {
			throw new ErrorException($module['name'].'没有安装无法卸载！');
		}

		foreach ($module['modules'] as $folder => $subMod) {
			$subModDir = $module['packagePath'].DIRECTORY_SEPARATOR.$folder;//子模块源程序目录
			$installDir = Yii::getAlias($subMod['installDir']).DIRECTORY_SEPARATOR.(isset($subMod['id']) ? $subMod['id'] : $module['id']);//要安装的目录
			//如果有目录直接卸载
			if (is_dir($installDir)) {
				FileHelper::removeDirectory($installDir);
			}

			//若有数据库操作，执行数据库脚本
			$installConfigFile = $subModDir.DIRECTORY_SEPARATOR.'uninstall'.DIRECTORY_SEPARATOR.'config.php';
			if (is_file($installConfigFile) && ($installConfigs = require $installConfigFile) && isset($installConfigs['datasource'])) {
				//执行脚本
				foreach ($installConfigs['datasource'] as $source) {
					$source['path'] = $subModDir.DIRECTORY_SEPARATOR.'uninstall'.DIRECTORY_SEPARATOR.$source['path'];
					self::parseSource($source);
				}
			}

		}
		//卸载成功后删除数据
		$command = Yii::$app->db->createCommand()->delete('{{%module}}', [
			'module_id' => $module['id'],
		])->execute();

		return true;
	}

	/**
	 * 解析数据资源
	 * 
	 * @param type $source
	 */
	public static function parseSource($source)
	{
		if (is_file($source['path']) && isset($source['type'])) {
			if ($source['type'] == 'sql') {
				$sqlStr = file_get_contents($source['path']);
				self::executeSql($sqlStr);
			}
			elseif ($source['type'] == 'php') {
				require $source['path'];
			}
		}

	}
 
	/**
	 * 执行sql语句
	 * 
	 * @param type $sqlStr sql语句
	 */
	public static function executeSql($sqlStr)
	{
		if (empty($sqlStr)) {
			return ;
		}
		$sqls = [];
		$sqlStr = str_replace(["\r\n", "\r"], "\n", trim($sqlStr));
		$i = 0;
		//组装sql
		foreach (explode(";\n", $sqlStr) as $str) {
			$sqls[$i] = '';
			$sqlArr = explode("\n", trim($str));
			foreach ($sqlArr as $sql) {
				if (substr($sql, 0, 1) != '#' && substr($sql, 0, 3) != '-- ') {
					$sqls[$i] .= $sql; 
				}
			}
			$i++;
		}

		$connect = \Yii::$app->db;
		//执行sql
		foreach ($sqls as $sql) {
			$connect->createCommand($sql)->execute();
		}

	}
    
}
