扩展功能
This commit is contained in:
parent
397c8bb7f7
commit
5c7765c97f
325
extend/catcher/CatchAdmin.php
Normal file
325
extend/catcher/CatchAdmin.php
Normal file
@ -0,0 +1,325 @@
|
||||
<?php
|
||||
namespace catcher;
|
||||
|
||||
use think\helper\Arr;
|
||||
|
||||
class CatchAdmin
|
||||
{
|
||||
public const NAME = 'catchAdmin';
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return string
|
||||
*/
|
||||
public static function directory(): string
|
||||
{
|
||||
return app()->getRootPath() . self::NAME . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月04日
|
||||
* @param $module
|
||||
* @return string
|
||||
*/
|
||||
public static function moduleDirectory($module): string
|
||||
{
|
||||
$directory = self::directory() . $module . DIRECTORY_SEPARATOR;
|
||||
|
||||
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年11月30日
|
||||
* @return string
|
||||
*/
|
||||
public static function cacheDirectory(): string
|
||||
{
|
||||
$directory = app()->getRuntimePath() . self::NAME . DIRECTORY_SEPARATOR;
|
||||
|
||||
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日
|
||||
* @param $module
|
||||
* @return string
|
||||
*/
|
||||
public static function moduleMigrationsDirectory($module): string
|
||||
{
|
||||
return self::directory() . $module . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR. 'migrations' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $module
|
||||
* @return string
|
||||
*/
|
||||
public static function moduleSeedsDirectory($module): string
|
||||
{
|
||||
return self::directory() . $module . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR. 'seeds' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块 view path
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $module
|
||||
* @return string
|
||||
*/
|
||||
public static function getModuleViewPath($module): string
|
||||
{
|
||||
$directory = self::directory() . $module . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR;
|
||||
|
||||
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日
|
||||
* @param $module
|
||||
* @return string
|
||||
*/
|
||||
public static function getModuleModelDirectory($module): string
|
||||
{
|
||||
$directory = self::directory() . $module . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR;
|
||||
|
||||
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年11月30日
|
||||
* @return array
|
||||
*/
|
||||
public static function getModulesDirectory(): array
|
||||
{
|
||||
$modules = glob(self::directory() . '*');
|
||||
|
||||
foreach ($modules as $key => &$module) {
|
||||
if (!is_dir($module)) {
|
||||
unset($modules[$key]);
|
||||
}
|
||||
|
||||
$module .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return array
|
||||
*/
|
||||
protected static function getModuleServices(): array
|
||||
{
|
||||
$services = [];
|
||||
|
||||
foreach (self::getModulesDirectory() as $module) {
|
||||
if (is_dir($module)) {
|
||||
$moduleInfo = self::getModuleInfo($module);
|
||||
if (isset($moduleInfo['services']) && !empty($moduleInfo['services'])) {
|
||||
$services = array_merge($services, $moduleInfo['services']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $services;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return array
|
||||
*/
|
||||
protected static function getModuleViews(): array
|
||||
{
|
||||
$views = [];
|
||||
|
||||
foreach (self::getModulesDirectory() as $module) {
|
||||
if (is_dir($module . 'view')) {
|
||||
$moduleInfo = self::getModuleInfo($module);
|
||||
$moduleName = $moduleInfo['alias'] ?? Arr::last(explode('/', $module));
|
||||
$views[$moduleName] = $module . 'view' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
||||
return $views;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块信息
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @param $module
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getModuleInfo($module)
|
||||
{
|
||||
if (file_exists($module . DIRECTORY_SEPARATOR . 'module.json')) {
|
||||
return \json_decode(file_get_contents($module . DIRECTORY_SEPARATOR . 'module.json'), true);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return array
|
||||
*/
|
||||
public static function getServices(): array
|
||||
{
|
||||
if (file_exists(self::getCacheServicesFile())) {
|
||||
return self::getCacheServices();
|
||||
}
|
||||
|
||||
return self::getModuleServices();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return string
|
||||
*/
|
||||
public static function getRoutes(): string
|
||||
{
|
||||
if (file_exists(self::getCacheViewsFile())) {
|
||||
return self::getCacheRoutesFile();
|
||||
}
|
||||
|
||||
self::cacheRoutes();
|
||||
|
||||
return self::getCacheRoutesFile();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return array|mixed
|
||||
*/
|
||||
public static function getViews()
|
||||
{
|
||||
if (file_exists(self::getCacheViewsFile())) {
|
||||
return self::getCacheViews();
|
||||
}
|
||||
|
||||
return self::getModuleViews();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return false|int
|
||||
*/
|
||||
public static function cacheRoutes()
|
||||
{
|
||||
$routeFiles = [];
|
||||
foreach (self::getModulesDirectory() as $module) {
|
||||
if (file_exists($module . 'route.php')) {
|
||||
$routeFiles[] = $module . 'route.php';
|
||||
}
|
||||
}
|
||||
$routes = '';
|
||||
foreach ($routeFiles as $route) {
|
||||
$routes .= trim(str_replace('<?php', '', file_get_contents($route))) . PHP_EOL;
|
||||
}
|
||||
|
||||
return file_put_contents(self::getCacheRoutesFile(), "<?php\r\n " . $routes);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return false|int
|
||||
*/
|
||||
public static function cacheServices()
|
||||
{
|
||||
return file_put_contents(self::getCacheServicesFile(), "<?php\r\n return "
|
||||
. var_export(self::getModuleServices(), true) . ';');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return false|int
|
||||
*/
|
||||
public static function cacheViews()
|
||||
{
|
||||
return file_put_contents(self::getCacheViewsFile(), "<?php\r\n return "
|
||||
. var_export(self::getModuleViews(), true) . ';');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function getCacheViews()
|
||||
{
|
||||
return include self::getCacheViewsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function getCacheServices()
|
||||
{
|
||||
return include self::getCacheServicesFile();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function getCacheViewsFile()
|
||||
{
|
||||
return self::cacheDirectory() . 'views.php';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function getCacheServicesFile()
|
||||
{
|
||||
return self::cacheDirectory() . 'services.php';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return string
|
||||
*/
|
||||
protected static function getCacheRoutesFile(): string
|
||||
{
|
||||
return self::cacheDirectory() . 'routes.php';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
174
extend/catcher/CatchForm.php
Normal file
174
extend/catcher/CatchForm.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
namespace catcher;
|
||||
|
||||
/**
|
||||
* Class CatchForm
|
||||
* @package catcher
|
||||
*
|
||||
*
|
||||
* @method text($column, $label = ''): self
|
||||
* @method image($column, $label = ''): self
|
||||
* @method radio($column, $label = ''): self
|
||||
* @method select($column, $label = ''): self
|
||||
* @method textarea($column, $label = ''): self
|
||||
*
|
||||
*/
|
||||
class CatchForm
|
||||
{
|
||||
protected $name;
|
||||
|
||||
private $fields = [];
|
||||
|
||||
public function id($id)
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'id' => $id,
|
||||
]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function class($class='', $labelClass = '', $inlineClass = '')
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'class' => $class,
|
||||
'labelClass' => $labelClass,
|
||||
'inlineClass' => $inlineClass,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function options(array $options)
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'options' => $options,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function default($value)
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'default' => $value,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function disabled()
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'disabled' => '',
|
||||
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
public function placeholder($content)
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'placeholder' => 'placeholder='.$content,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function readonly()
|
||||
{
|
||||
$this->fields[$this->name] = array_merge($this->fields[$this->name], [
|
||||
'readonly' => 'readonly',
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function render()
|
||||
{
|
||||
$form = '';
|
||||
foreach ($this->fields as $field) {
|
||||
$form .= sprintf($this->baseField(),
|
||||
$field['labelClass'] ?? '',
|
||||
$field['label'],
|
||||
$field['inlineClass'] ?? '',
|
||||
$this->{$field['type'].'Field'}($field));
|
||||
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
// TODO: Implement __call() method.
|
||||
$this->name = $arguments[0] ?? '';
|
||||
$label = $arguments[1] ?? '';
|
||||
|
||||
$this->fields[$this->name] = [
|
||||
'name' => $this->name,
|
||||
'type' => $method,
|
||||
'label' => $label,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function inline()
|
||||
{
|
||||
$this->fields[] = array_merge($this->fields, [
|
||||
'inline' => true,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function baseField()
|
||||
{
|
||||
return
|
||||
'<div class="layui-inline">
|
||||
<label class="layui-form-label %s">%s: </label>
|
||||
<div class="layui-input-inline %s">
|
||||
%s
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
private function textField($field)
|
||||
{
|
||||
return
|
||||
sprintf('<input name="%s" class="layui-input %s" value="%s" type="text" %s %s %s>',
|
||||
$field['name'],
|
||||
$field['class'],
|
||||
$field['default'] ?? '',
|
||||
$field['readonly'] ?? '',
|
||||
$field['placeholder'] ?? '',
|
||||
$field['disabled'] ?? ''
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private function selectField($field)
|
||||
{
|
||||
$select = sprintf('<select name="%s">', $field['name']);
|
||||
|
||||
$default = $field['default'] ?? '';
|
||||
|
||||
foreach ($field['options'] as $key => $option) {
|
||||
$select .= sprintf('<option value="%s"%s>%s</option>', $key, $default == $key ? ' selected' : '',$option);
|
||||
}
|
||||
|
||||
return $select . '</select>';
|
||||
}
|
||||
|
||||
private function radioField()
|
||||
{}
|
||||
|
||||
private function textareaField()
|
||||
{}
|
||||
|
||||
private function imageField()
|
||||
{}
|
||||
|
||||
}
|
39
extend/catcher/CatchResponse.php
Normal file
39
extend/catcher/CatchResponse.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace catcher;
|
||||
|
||||
class CatchResponse
|
||||
{
|
||||
/**
|
||||
* 成功的响应
|
||||
*
|
||||
* @time 2019年12月02日
|
||||
* @param array $data
|
||||
* @param $msg
|
||||
* @param int $code
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public static function success($data = [], $msg = '', $code = 10000): \think\response\Json
|
||||
{
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误的响应
|
||||
*
|
||||
* @time 2019年12月02日
|
||||
* @param string $msg
|
||||
* @param int $code
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public static function fail($msg = '', $code = 10001): \think\response\Json
|
||||
{
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
]);
|
||||
}
|
||||
}
|
7
extend/catcher/Form.php
Normal file
7
extend/catcher/Form.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace catcher;
|
||||
|
||||
class Form
|
||||
{
|
||||
|
||||
}
|
63
extend/catcher/base/BaseController.php
Normal file
63
extend/catcher/base/BaseController.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace catcher\base;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\facade\View;
|
||||
|
||||
abstract class BaseController
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月28日
|
||||
* @param array $data
|
||||
* @param string $template
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function fetch(array $data = [], $template = ''): string
|
||||
{
|
||||
$stack = \debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
|
||||
|
||||
$end = end($stack);
|
||||
|
||||
View::config([
|
||||
'view_path' => CatchAdmin::getViews()[$this->getModule($end['class'])]
|
||||
]);
|
||||
|
||||
return View::fetch($template ? : $this->getTemp($end['class'], $end['function']), $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $class
|
||||
* @param $func
|
||||
* @return string
|
||||
*/
|
||||
protected function getTemp($class, $func)
|
||||
{
|
||||
$viewPath = CatchAdmin::getModuleViewPath($this->getModule($class));
|
||||
|
||||
$class = explode('\\', $class);
|
||||
|
||||
$className = strtolower(end($class));
|
||||
|
||||
if (is_dir($viewPath . $className)) {
|
||||
return sprintf('%s/%s', $className, $func);
|
||||
}
|
||||
|
||||
return $func;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $class
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getModule($class)
|
||||
{
|
||||
return explode('\\', $class)[1];
|
||||
}
|
||||
}
|
20
extend/catcher/base/BaseModel.php
Normal file
20
extend/catcher/base/BaseModel.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace catcher\base;
|
||||
|
||||
use catcher\traits\db\BaseOptionsTrait;
|
||||
use catcher\traits\db\TransTrait;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
abstract class BaseModel extends \think\Model
|
||||
{
|
||||
use SoftDelete;
|
||||
use TransTrait;
|
||||
use BaseOptionsTrait;
|
||||
|
||||
protected $createTime = 'create_at';
|
||||
|
||||
protected $updateTime = 'update_at';
|
||||
|
||||
protected $deleteTime = 'delete_at';
|
||||
|
||||
}
|
42
extend/catcher/base/BaseRequest.php
Normal file
42
extend/catcher/base/BaseRequest.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
namespace catcher\base;
|
||||
|
||||
use app\Request;
|
||||
use catcher\exceptions\ValidateFailedException;
|
||||
use think\Validate;
|
||||
|
||||
abstract class BaseRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Request constructor.
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化验证
|
||||
*
|
||||
* @time 2019年11月27日
|
||||
* @throws \Exception
|
||||
* @return mixed
|
||||
*/
|
||||
protected function validate()
|
||||
{
|
||||
$validate = new Validate();
|
||||
|
||||
if (!$validate->check(request()->param(), $this->rules())) {
|
||||
throw new ValidateFailedException($validate->getError());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract protected function rules(): array;
|
||||
|
||||
abstract protected function message(): array;
|
||||
}
|
37
extend/catcher/base/BaseValidate.php
Normal file
37
extend/catcher/base/BaseValidate.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace catcher\base;
|
||||
|
||||
use catcher\validates\Uniques;
|
||||
use think\Validate;
|
||||
|
||||
abstract class BaseValidate extends Validate
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->register();
|
||||
|
||||
$this->rule = $this->getRules();
|
||||
}
|
||||
|
||||
|
||||
abstract protected function getRules(): array ;
|
||||
|
||||
|
||||
private function register()
|
||||
{
|
||||
if (!empty($this->newValidates())) {
|
||||
foreach ($this->newValidates() as $validate) {
|
||||
$this->extend($validate->type(), [$validate, 'verify'], $validate->message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function newValidates()
|
||||
{
|
||||
return [
|
||||
];
|
||||
}
|
||||
}
|
329
extend/catcher/command/InstallCommand.php
Normal file
329
extend/catcher/command/InstallCommand.php
Normal file
@ -0,0 +1,329 @@
|
||||
<?php
|
||||
namespace catcher\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Console;
|
||||
use think\facade\Db;
|
||||
|
||||
class InstallCommand extends Command
|
||||
{
|
||||
|
||||
protected $dataInstall = true;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('install:project')
|
||||
// ->addArgument('module', Argument::REQUIRED, 'module name')
|
||||
->setDescription('install project');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月29日
|
||||
* @param Input $input
|
||||
* @param Output $output
|
||||
* @return int|void|null
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$this->detectionEnvironment();
|
||||
|
||||
$this->firstStep();
|
||||
|
||||
$this->secondStep();
|
||||
|
||||
$this->thirdStep();
|
||||
|
||||
$this->finished();
|
||||
|
||||
$this->project();
|
||||
}
|
||||
|
||||
/**
|
||||
* 环境检测
|
||||
*
|
||||
* @time 2019年11月29日
|
||||
* @return void
|
||||
*/
|
||||
protected function detectionEnvironment(): void
|
||||
{
|
||||
$this->output->info('environment begin to check...');
|
||||
|
||||
if (version_compare(PHP_VERSION, '7.1.0', '<')) {
|
||||
$this->output->error('php version should >= 7.1.0');
|
||||
exit();
|
||||
}
|
||||
|
||||
$this->output->info('php version ' . PHP_VERSION);
|
||||
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$this->output->error('mbstring extension not install');exit();
|
||||
}
|
||||
$this->output->info('mbstring extension is installed');
|
||||
|
||||
if (!extension_loaded('json')) {
|
||||
$this->output->error('json extension not install');
|
||||
exit();
|
||||
}
|
||||
$this->output->info('json extension is installed');
|
||||
|
||||
if (!extension_loaded('openssl')) {
|
||||
$this->output->error('openssl extension not install');
|
||||
exit();
|
||||
}
|
||||
$this->output->info('openssl extension is installed');
|
||||
|
||||
if (!extension_loaded('pdo')) {
|
||||
$this->output->error('pdo extension not install');
|
||||
exit();
|
||||
}
|
||||
$this->output->info('pdo extension is installed');
|
||||
|
||||
if (!extension_loaded('xml')) {
|
||||
$this->output->error('xml extension not install');
|
||||
exit();
|
||||
}
|
||||
|
||||
$this->output->info('xml extension is installed');
|
||||
|
||||
$this->output->info('🎉 environment checking finished');
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装第一步
|
||||
*
|
||||
* @time 2019年11月29日
|
||||
* @return bool
|
||||
*/
|
||||
protected function firstStep(): bool
|
||||
{
|
||||
if (file_exists($this->app->getRootPath() . '.env')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$answer = strtolower($this->output->ask($this->input, '🤔️ Did You Need to Set Database information? (Y/N): '));
|
||||
|
||||
if ($answer === 'y' || $answer === 'yes') {
|
||||
$charset = $this->output->ask($this->input, '👉 please input database charset, default (utf8mb4):') ? : 'utf8mb4';
|
||||
$database = '';
|
||||
while (!$database) {
|
||||
$database = $this->output->ask($this->input, '👉 please input database name: ');
|
||||
if ($database) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$host = $this->output->ask($this->input, '👉 please input database host, default (127.0.0.1):') ? : '127.0.0.1';
|
||||
$port = $this->output->ask($this->input, '👉 please input database host port, default (3306):') ? : '3306';
|
||||
$prefix = $this->output->ask($this->input, '👉 please input table prefix, default (null):') ? : '';
|
||||
$username = $this->output->ask($this->input, '👉 please input database username default (root): ') ? : 'root';
|
||||
$password = '';
|
||||
while (!$password) {
|
||||
$password = $this->output->ask($this->input, '👉 please input database password: ');
|
||||
if ($password) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->generateEnvFile($host, $database, $username, $password, $port, $charset, $prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装第二部
|
||||
*
|
||||
* @time 2019年11月29日
|
||||
* @return void
|
||||
*/
|
||||
protected function secondStep(): void
|
||||
{
|
||||
$modulePaths = glob(root_path('module') . '*');
|
||||
|
||||
$this->checkRootDatabase();
|
||||
|
||||
foreach ($modulePaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$moduleDatabasePath = $path . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR;
|
||||
if (is_dir($moduleDatabasePath)) {
|
||||
if (is_dir($moduleDatabasePath . 'migrations' . DIRECTORY_SEPARATOR)) {
|
||||
$migrationFiles = glob($moduleDatabasePath . 'migrations' . DIRECTORY_SEPARATOR . '*.php');
|
||||
foreach ($migrationFiles as $file) {
|
||||
copy($file,
|
||||
root_path('database') . 'migrations'. DIRECTORY_SEPARATOR .
|
||||
pathinfo($file, PATHINFO_BASENAME));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dir($moduleDatabasePath . 'seeds' . DIRECTORY_SEPARATOR)) {
|
||||
$seedFiles = glob($moduleDatabasePath . 'seeds' . DIRECTORY_SEPARATOR . '*.php');
|
||||
foreach ($seedFiles as $file) {
|
||||
copy($file,
|
||||
root_path('database') . 'seeds' . DIRECTORY_SEPARATOR .
|
||||
pathinfo($file, PATHINFO_BASENAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装第四步
|
||||
*
|
||||
* @time 2019年11月29日
|
||||
* @return void
|
||||
*/
|
||||
protected function thirdStep(): void
|
||||
{
|
||||
Console::call('catch:cache');
|
||||
}
|
||||
|
||||
/**
|
||||
* finally
|
||||
*
|
||||
* @time 2019年11月30日
|
||||
* @return void
|
||||
*/
|
||||
protected function finished(): void
|
||||
{
|
||||
// todo something
|
||||
if ($this->dataInstall) {
|
||||
rmdir($this->app->getRootPath() . 'database');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generate env file
|
||||
*
|
||||
* @time 2019年11月29日
|
||||
* @param $host
|
||||
* @param $database
|
||||
* @param $username
|
||||
* @param $password
|
||||
* @param $port
|
||||
* @param $charset
|
||||
* @param $prefix
|
||||
* @return void
|
||||
*/
|
||||
protected function generateEnvFile($host, $database, $username, $password, $port, $charset, $prefix): void
|
||||
{
|
||||
$env = \parse_ini_file(root_path() . '.example.env', true);
|
||||
|
||||
$env['DATABASE']['HOSTNAME'] = $host;
|
||||
$env['DATABASE']['DATABASE'] = $database;
|
||||
$env['DATABASE']['USERNAME'] = $username;
|
||||
$env['DATABASE']['PASSWORD'] = $password;
|
||||
$env['DATABASE']['HOSTPORT'] = $port;
|
||||
$env['DATABASE']['CHARSET'] = $charset;
|
||||
if ($prefix) {
|
||||
$env['DATABASE']['PREFIX'] = $prefix;
|
||||
}
|
||||
$dotEnv = '';
|
||||
foreach ($env as $key => $e) {
|
||||
if (is_string($e)) {
|
||||
$dotEnv .= sprintf('%s = %s', $key, $e === '1' ? 'true' : ($e === '' ? 'false' : $e)) . PHP_EOL;
|
||||
$dotEnv .= PHP_EOL;
|
||||
} else {
|
||||
$dotEnv .= sprintf('[%s]', $key) . PHP_EOL;
|
||||
foreach ($e as $k => $v) {
|
||||
$dotEnv .= sprintf('%s = %s', $k, $v === '1' ? 'true' : ($v === '' ? 'false' : $v)) . PHP_EOL;
|
||||
}
|
||||
|
||||
$dotEnv .= PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents(root_path() . '.env', $dotEnv);
|
||||
|
||||
if ($this->getEnvFile()) {
|
||||
$this->output->info('env file has been generated');
|
||||
}
|
||||
|
||||
if ((new \mysqli($host, $username, $password, null, $port))->query(sprintf('CREATE DATABASE IF NOT EXISTS %s DEFAULT CHARSET %s COLLATE %s_general_ci;',
|
||||
$database, $charset, $charset))) {
|
||||
$this->output->info(sprintf('🎉 create database %s successfully', $database));
|
||||
|
||||
exec(sprintf('%s %s migrate:run', getenv('_'), root_path() . DIRECTORY_SEPARATOR . 'think'));
|
||||
|
||||
$this->output->info('🎉 database table install successfully');
|
||||
|
||||
exec(sprintf('%s %s seed:run', getenv('_'),root_path() . DIRECTORY_SEPARATOR . 'think'));
|
||||
|
||||
$this->output->info('🎉 Fill database table successfully ');
|
||||
} else {
|
||||
$this->dataInstall = false;
|
||||
$this->output->warning(sprintf('create database %s failed, you should create it by yourself', $database));
|
||||
$this->output->warning('you should use `php think migrate:run` to create tables');
|
||||
$this->output->warning('you should use `php think seed:run` to fill tables data');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年11月29日
|
||||
* @return string
|
||||
*/
|
||||
protected function getEnvFile(): string
|
||||
{
|
||||
return file_exists(root_path() . '.env') ? root_path() . '.env' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测根目录
|
||||
*
|
||||
* @time 2019年11月28日
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkRootDatabase(): bool
|
||||
{
|
||||
$databasePath = root_path('database');
|
||||
|
||||
if (!is_dir($databasePath)) {
|
||||
if (!mkdir($databasePath, 0777, true) && !is_dir($databasePath)) {
|
||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $databasePath));
|
||||
}
|
||||
}
|
||||
|
||||
$migrationPath = $databasePath . DIRECTORY_SEPARATOR . 'migrations' . DIRECTORY_SEPARATOR;
|
||||
|
||||
$seedPath = $databasePath . DIRECTORY_SEPARATOR . 'seeds' . DIRECTORY_SEPARATOR;
|
||||
|
||||
if (!is_dir($migrationPath)) {
|
||||
if (!mkdir($migrationPath, 0777, true) && !is_dir($migrationPath)) {
|
||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $migrationPath));
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_dir($seedPath)) {
|
||||
if (!mkdir($seedPath, 0777, true) && !is_dir($seedPath)) {
|
||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $seedPath));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected function project()
|
||||
{
|
||||
$year = date('Y');
|
||||
|
||||
$this->output->info('🎉 project is installed, welcome!');
|
||||
|
||||
$this->output->info(sprintf('
|
||||
/-------------------- welcome to use -------------------------\
|
||||
| __ __ ___ __ _ |
|
||||
| _________ _/ /______/ /_ / | ____/ /___ ___ (_)___ |
|
||||
| / ___/ __ `/ __/ ___/ __ \ / /| |/ __ / __ `__ \/ / __ \ |
|
||||
| / /__/ /_/ / /_/ /__/ / / / / ___ / /_/ / / / / / / / / / / |
|
||||
| \___/\__,_/\__/\___/_/ /_/ /_/ |_\__,_/_/ /_/ /_/_/_/ /_/ |
|
||||
| |
|
||||
\ __ __ __ __ _ __ _ __ enjoy it ! _ __ __ __ __ __ __ ___ _ @ 2017 ~ %s
|
||||
|
||||
', $year));
|
||||
|
||||
}
|
||||
}
|
64
extend/catcher/command/MigrateRunCommand.php
Normal file
64
extend/catcher/command/MigrateRunCommand.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace catcher\command;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
use think\migration\command\migrate\Run;
|
||||
|
||||
class MigrateRunCommand extends Run
|
||||
{
|
||||
protected $module;
|
||||
|
||||
public function configure()
|
||||
{
|
||||
$this->setName('catch-migrate:run')
|
||||
->setDescription('Migrate the database')
|
||||
->addArgument('module', Argument::REQUIRED, 'migrate the module database')
|
||||
->addOption('--target', '-t', InputOption::VALUE_REQUIRED, 'The version number to migrate to')
|
||||
->addOption('--date', '-d', InputOption::VALUE_REQUIRED, 'The date to migrate to')
|
||||
->setHelp(<<<EOT
|
||||
The <info>migrate:run</info> command runs all available migrations, optionally up to a specific version
|
||||
|
||||
<info>php think catch-migrate:run module</info>
|
||||
<info>php think catch-migrate:run -t 20110103081132</info>
|
||||
<info>php think catch-migrate:run -d 20110103</info>
|
||||
<info>php think catch-migrate:run -v</info>
|
||||
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$this->module = strtolower($input->getArgument('module'));
|
||||
$version = $input->getOption('target');
|
||||
$date = $input->getOption('date');
|
||||
|
||||
// run the migrations
|
||||
$start = microtime(true);
|
||||
if (null !== $date) {
|
||||
$this->migrateToDateTime(new \DateTime($date));
|
||||
} else {
|
||||
$this->migrate($version);
|
||||
}
|
||||
$end = microtime(true);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 migration path
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $module
|
||||
* @return string
|
||||
*/
|
||||
protected function getPath()
|
||||
{
|
||||
return CatchAdmin::moduleMigrationsDirectory($this->module);
|
||||
}
|
||||
}
|
95
extend/catcher/command/ModelGeneratorCommand.php
Normal file
95
extend/catcher/command/ModelGeneratorCommand.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace catcher\command;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option as InputOption;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
use think\helper\Str;
|
||||
|
||||
class ModelGeneratorCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('create:model')
|
||||
->addArgument('model', Argument::REQUIRED, 'model name')
|
||||
->addArgument('module', Argument::REQUIRED, 'module name')
|
||||
->setDescription('create model');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$model = ucfirst($input->getArgument('model'));
|
||||
$module = strtolower($input->getArgument('module'));
|
||||
|
||||
$table = Str::snake($model);
|
||||
|
||||
$modelFile= CatchAdmin::getModuleModelDirectory($module) . $model . '.php';
|
||||
|
||||
file_put_contents($modelFile, $this->replaceContent([
|
||||
$module, $model, $table, $this->generateFields($this->getTableFields($table))
|
||||
]));
|
||||
|
||||
if (file_exists($modelFile)) {
|
||||
$output->info(sprintf('%s Create Successfully!', $modelFile));
|
||||
} else {
|
||||
$output->error(sprintf('%s Create Failed!', $modelFile));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function getTableFields($table): array
|
||||
{
|
||||
$fields = Db::query('show full columns from ' .
|
||||
config('database.connections.mysql.prefix') . $table);
|
||||
|
||||
$new = [];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$new[$field['Field']] = $field['Comment'];
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
private function generateFields($fields)
|
||||
{
|
||||
$f = '';
|
||||
foreach ($fields as $field => $comment) {
|
||||
$f .= sprintf("'%s', // %s" . "\r\n\t\t\t", $field, $comment);
|
||||
}
|
||||
|
||||
return $f;
|
||||
}
|
||||
|
||||
private function replaceContent(array $replace)
|
||||
{
|
||||
return str_replace([
|
||||
'{Module}', '{Class}', '{Name}', '{Field}'
|
||||
], $replace, $this->content());
|
||||
}
|
||||
|
||||
private function content()
|
||||
{
|
||||
return <<<EOT
|
||||
<?php
|
||||
namespace catchAdmin\{Module}\model;
|
||||
|
||||
use cather\Model;
|
||||
|
||||
class {Class} extends Model
|
||||
{
|
||||
protected \$name = '{Name}';
|
||||
|
||||
protected \$field = [
|
||||
{Field}
|
||||
];
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
}
|
30
extend/catcher/command/ModuleCacheCommand.php
Normal file
30
extend/catcher/command/ModuleCacheCommand.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace catcher\command;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
|
||||
class ModuleCacheCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('catch:cache')
|
||||
->setDescription('cache routes, views, services of module');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
CatchAdmin::cacheRoutes();
|
||||
CatchAdmin::cacheServices();
|
||||
CatchAdmin::cacheViews();
|
||||
// 指令输出
|
||||
$output->info('succeed!');
|
||||
}
|
||||
}
|
25
extend/catcher/event/LoadModuleRoutes.php
Normal file
25
extend/catcher/event/LoadModuleRoutes.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace catcher\event;
|
||||
|
||||
use catcher\CatchAdmin;
|
||||
use think\Route;
|
||||
|
||||
class LoadModuleRoutes
|
||||
{
|
||||
/**
|
||||
* 处理
|
||||
*
|
||||
* @time 2019年11月29日
|
||||
* @return void
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$router = app(Route::class);
|
||||
|
||||
$router->group(function () use ($router) {
|
||||
include CatchAdmin::getRoutes();
|
||||
});
|
||||
}
|
||||
}
|
7
extend/catcher/exceptions/LoginFailedException.php
Normal file
7
extend/catcher/exceptions/LoginFailedException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace cather\exceptions;
|
||||
|
||||
class LoginFailedException extends \Exception
|
||||
{
|
||||
protected $code = 10002;
|
||||
}
|
7
extend/catcher/exceptions/ValidateFailedException.php
Normal file
7
extend/catcher/exceptions/ValidateFailedException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace catcher\exceptions;
|
||||
|
||||
class ValidateFailedException extends \Exception
|
||||
{
|
||||
protected $code = 10001;
|
||||
}
|
73
extend/catcher/traits/db/BaseOptionsTrait.php
Normal file
73
extend/catcher/traits/db/BaseOptionsTrait.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace catcher\traits\db;
|
||||
|
||||
trait BaseOptionsTrait
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function storeBy(array $data)
|
||||
{
|
||||
foreach ($data as $field => $value) {
|
||||
if (in_array($field, $this->field)) {
|
||||
$this->{$field} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $id
|
||||
* @param $data
|
||||
* @return bool
|
||||
*/
|
||||
public function updateBy($id, $data)
|
||||
{
|
||||
$model = $this->findBy($id);
|
||||
foreach ($data as $field => $value) {
|
||||
if (in_array($field, $this->field)) {
|
||||
$model->{$field} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($model->save()) {
|
||||
$model->id;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function findBy($id, array $field = ['*'])
|
||||
{
|
||||
return static::where($this->getPk(), $id)->select($field)->find();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function deleteBy($id)
|
||||
{
|
||||
return static::destory($id);
|
||||
}
|
||||
}
|
48
extend/catcher/traits/db/TransTrait.php
Normal file
48
extend/catcher/traits/db/TransTrait.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace catcher\traits\db;
|
||||
|
||||
use think\facade\Db;
|
||||
|
||||
trait TransTrait
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @return void
|
||||
*/
|
||||
public function startTrans()
|
||||
{
|
||||
Db::startTrans();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @return void
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
Db::commit();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @return void
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
Db::rollback();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param \Closure $function
|
||||
* @return void
|
||||
*/
|
||||
public function transaction(\Closure $function)
|
||||
{
|
||||
Db::transaction($function());
|
||||
}
|
||||
}
|
11
extend/catcher/validates/ValidateInterface.php
Normal file
11
extend/catcher/validates/ValidateInterface.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace catcher\validates;
|
||||
|
||||
interface ValidateInterface
|
||||
{
|
||||
public function type(): string ;
|
||||
|
||||
public function verify($value, $field): bool ;
|
||||
|
||||
public function message(): string ;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user