diff --git a/extend/catcher/CatchAdmin.php b/extend/catcher/CatchAdmin.php index f8c9f9f..6044e6f 100644 --- a/extend/catcher/CatchAdmin.php +++ b/extend/catcher/CatchAdmin.php @@ -50,6 +50,23 @@ class CatchAdmin return $directory; } + /** + * 备份地址 + * + * @time 2019年12月13日 + * @return string + */ + public static function backupDirectory(): string + { + $directory = root_path('database/backup'); + + if (!is_dir($directory) && !mkdir($directory, 0777, true) && !is_dir($directory)) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $directory)); + } + + return $directory; + } + /** * * @time 2019年12月03日 diff --git a/extend/catcher/base/CatchController.php b/extend/catcher/base/CatchController.php index d895071..71f1211 100644 --- a/extend/catcher/base/CatchController.php +++ b/extend/catcher/base/CatchController.php @@ -8,6 +8,8 @@ abstract class CatchController { protected $middleware = ['check_auth']; + protected $data = []; + /** * * @time 2019年11月28日 @@ -26,6 +28,10 @@ abstract class CatchController 'view_path' => CatchAdmin::getViews()[$this->getModule($end['class'])] ]); + if (!empty($this->data)) { + $data = array_merge($this->data, $data); + } + return View::fetch($template ? : $this->getTemp($end['class'], $end['function']), $data); } @@ -62,4 +68,27 @@ abstract class CatchController { return explode('\\', $class)[1]; } + + /** + * + * @time 2019年12月13日 + * @param $name + * @param $value + * @return void + */ + public function __set($name, $value) + { + // TODO: Implement __set() method. + $this->data[$name] = $value; + } + + public function __get($name) + { + // TODO: Implement __get() method. + } + + public function __isset($name) + { + // TODO: Implement __isset() method. + } } diff --git a/extend/catcher/base/CatchModel.php b/extend/catcher/base/CatchModel.php index 5b5485a..4202d8f 100644 --- a/extend/catcher/base/CatchModel.php +++ b/extend/catcher/base/CatchModel.php @@ -17,6 +17,8 @@ abstract class CatchModel extends \think\Model protected $deleteTime = 'deleted_at'; + protected $defaultSoftDelete = 0; + protected $autoWriteTimestamp = true; protected $limit = 10; diff --git a/extend/catcher/base/CatchRequest.php b/extend/catcher/base/CatchRequest.php index 622fac1..fd2668f 100644 --- a/extend/catcher/base/CatchRequest.php +++ b/extend/catcher/base/CatchRequest.php @@ -5,7 +5,7 @@ use app\Request; use catcher\exceptions\ValidateFailedException; use think\Validate; -abstract class CatchRequest extends Request +class CatchRequest extends Request { /** * Request constructor. @@ -35,8 +35,4 @@ abstract class CatchRequest extends Request return true; } - - abstract protected function rules(): array; - - abstract protected function message(): array; } diff --git a/extend/catcher/command/BackupCommand.php b/extend/catcher/command/BackupCommand.php index b3d9bbc..18d904d 100644 --- a/extend/catcher/command/BackupCommand.php +++ b/extend/catcher/command/BackupCommand.php @@ -1 +1,182 @@ setName('backup:data') + ->addArgument('tables', Argument::REQUIRED, 'backup tables') + ->addOption('zip', 'z',Option::VALUE_REQUIRED, 'is need zip') + ->setDescription('backup data you need'); + } + + protected function execute(Input $input, Output $output) + { + $tables = $this->input->getArgument('tables'); + + $isZip = $this->input->getOption('zip') ?? true; + + $this->generator(explode(',', $tables), CatchAdmin::backupDirectory()); + + if ($isZip) { + $this->zip(); + } + + $output->info('succeed!'); + } + + + /** + * + * @time 2019年09月30日 + * @param $tables + * @param $format + * @param $path + * @return void + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\db\exception\DataNotFoundException + */ + public function generator($tables, $path) + { + foreach ($tables as $table) { + $this->table = $table; + + $this->createDataFile(); + } + } + + /** + * 创建数据文件 + * + * @time 2019年09月27日 + * @param $format + * @return void + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\db\exception\DataNotFoundException + */ + public function createDataFile(): void + { + $file = CatchAdmin::backupDirectory() . $this->table . '.sql'; + + $handle = fopen($file, 'wb+'); + + fwrite($handle, $begin = "BEGIN;\r\n", \strlen($begin)); + $this->createClass($this->table, $handle); + fwrite($handle, $end = 'COMMIT;', \strlen($end)); + + fclose($handle); + } + + /** + * 创建了临时模型 + * + * @time 2019年09月27日 + * @param $table + * @param $format + * @param $handle + * @return void + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\db\exception\DataNotFoundException + */ + protected function createClass($table, $handle) + { + $this->setUnbuffered(); + + // 防止 IO 多次写入 + $buffer = []; + + // 记录中记录 + $total = Db::table($table)->count(); + + $limit = 1000; + + // 生成器减少内存 + while ($total > 0) { + $items = Db::table($table)->limit($limit)->select(); + + $this->writeIn($handle, $items); + + $total -= $limit; + } + } + + /** + * sql 文件格式 + * + * @time 2019年09月27日 + * @param $handle + * @param $data + * @return void + */ + protected function writeIn($handle, $datas) + { + $values = ''; + $sql = ''; + foreach ($datas as $data) { + foreach ($data as $value) { + $values .= sprintf("'%s'", $value) . ','; + } + + $sql .= sprintf('INSERT INTO `%s` VALUE (%s);' . "\r\n", $this->table, rtrim($values, ',')); + $values = ''; + } + + fwrite($handle, $sql, strlen($sql)); + } + + + /** + * 设置未缓存模式 + * + * @time 2019年09月29日 + * @return void + */ + protected function setUnbuffered() + { + $connections = \config('database.connections'); + + $connections['mysql']['params'] = [ + \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false + ]; + + \config($connections,'database'); + + } + + protected function zip() + { + if (extension_loaded('zip')) { + $files = glob(CatchAdmin::backupDirectory() . '*.sql'); + $zip = new \ZipArchive(); + $zip->open(root_path('database/') . 'backup.zip', \ZipArchive::CREATE); + $zip->addEmptyDir('backup'); + foreach ($files as $file) { + $zip->addFile($file, 'backup/'. basename($file)); + } + $zip->close(); + + foreach ($files as $file) { + unlink($file); + } + rmdir(CatchAdmin::backupDirectory()); + } + } +}