user attach role

This commit is contained in:
JaguarJack 2022-12-11 22:26:21 +08:00
parent c4270a2fc8
commit b63cd5d01c
73 changed files with 224 additions and 5871 deletions

View File

@ -1,4 +1,11 @@
<?php return array (
'catchadmin/core' =>
array (
'providers' =>
array (
0 => 'Catch\\Providers\\CatchAdminServiceProvider',
),
),
'laravel/tinker' =>
array (
'providers' =>

View File

@ -23,17 +23,18 @@
19 => 'Illuminate\\Translation\\TranslationServiceProvider',
20 => 'Illuminate\\Validation\\ValidationServiceProvider',
21 => 'Illuminate\\View\\ViewServiceProvider',
22 => 'Laravel\\Tinker\\TinkerServiceProvider',
23 => 'Carbon\\Laravel\\ServiceProvider',
24 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
25 => 'Termwind\\Laravel\\TermwindServiceProvider',
26 => 'Pest\\Laravel\\PestServiceProvider',
27 => 'Tymon\\JWTAuth\\Providers\\LaravelServiceProvider',
28 => 'Catch\\Providers\\CatchAdminServiceProvider',
29 => 'App\\Providers\\AppServiceProvider',
30 => 'App\\Providers\\AuthServiceProvider',
31 => 'App\\Providers\\EventServiceProvider',
32 => 'App\\Providers\\RouteServiceProvider',
22 => 'Catch\\Providers\\CatchAdminServiceProvider',
23 => 'Laravel\\Tinker\\TinkerServiceProvider',
24 => 'Carbon\\Laravel\\ServiceProvider',
25 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
26 => 'Termwind\\Laravel\\TermwindServiceProvider',
27 => 'Pest\\Laravel\\PestServiceProvider',
28 => 'Tymon\\JWTAuth\\Providers\\LaravelServiceProvider',
29 => 'Catch\\Providers\\CatchAdminServiceProvider',
30 => 'App\\Providers\\AppServiceProvider',
31 => 'App\\Providers\\AuthServiceProvider',
32 => 'App\\Providers\\EventServiceProvider',
33 => 'App\\Providers\\RouteServiceProvider',
),
'eager' =>
array (
@ -47,16 +48,17 @@
7 => 'Illuminate\\Pagination\\PaginationServiceProvider',
8 => 'Illuminate\\Session\\SessionServiceProvider',
9 => 'Illuminate\\View\\ViewServiceProvider',
10 => 'Carbon\\Laravel\\ServiceProvider',
11 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
12 => 'Termwind\\Laravel\\TermwindServiceProvider',
13 => 'Pest\\Laravel\\PestServiceProvider',
14 => 'Tymon\\JWTAuth\\Providers\\LaravelServiceProvider',
15 => 'Catch\\Providers\\CatchAdminServiceProvider',
16 => 'App\\Providers\\AppServiceProvider',
17 => 'App\\Providers\\AuthServiceProvider',
18 => 'App\\Providers\\EventServiceProvider',
19 => 'App\\Providers\\RouteServiceProvider',
10 => 'Catch\\Providers\\CatchAdminServiceProvider',
11 => 'Carbon\\Laravel\\ServiceProvider',
12 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
13 => 'Termwind\\Laravel\\TermwindServiceProvider',
14 => 'Pest\\Laravel\\PestServiceProvider',
15 => 'Tymon\\JWTAuth\\Providers\\LaravelServiceProvider',
16 => 'Catch\\Providers\\CatchAdminServiceProvider',
17 => 'App\\Providers\\AppServiceProvider',
18 => 'App\\Providers\\AuthServiceProvider',
19 => 'App\\Providers\\EventServiceProvider',
20 => 'App\\Providers\\RouteServiceProvider',
),
'deferred' =>
array (

View File

@ -1,145 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
return [
/*
|--------------------------------------------------------------------------
| catch-admin default middleware
|--------------------------------------------------------------------------
|
| where you can set default middlewares
|
*/
'middleware_group' => [
],
/*
|--------------------------------------------------------------------------
| catch-admin catch_auth_middleware_alias
|--------------------------------------------------------------------------
|
| where you can set default middlewares
|
*/
'catch_auth_middleware_alias' => [
],
/*
|--------------------------------------------------------------------------
| catch-admin super admin id
|--------------------------------------------------------------------------
|
| where you can set super admin id
|
*/
'super_admin' => 1,
/*
|--------------------------------------------------------------------------
| catch-admin module setting
|--------------------------------------------------------------------------
|
| the root where module generate
| the namespace is module root namespace
| the default dirs is module generate default dirs
*/
'module' => [
'root' => 'modules',
'namespace' => 'Modules',
'default' => ['develop', 'user', 'permission'],
'default_dirs' => [
'Http'.DIRECTORY_SEPARATOR,
'Http'.DIRECTORY_SEPARATOR.'Requests'.DIRECTORY_SEPARATOR,
'Http'.DIRECTORY_SEPARATOR.'Controllers'.DIRECTORY_SEPARATOR,
'Models'.DIRECTORY_SEPARATOR,
'views'.DIRECTORY_SEPARATOR,
],
// storage module information
// which driver should be used?
'driver' => [
// currently, catchadmin support file and database
// the default is driver
'default' => 'file',
// use database driver
'table_name' => 'admin_modules'
]
],
/*
|--------------------------------------------------------------------------
| catch-admin response
|--------------------------------------------------------------------------
*/
'response' => [
// it's a controller middleware, it's set in CatchController
// if you not need json response, don't extend CatchController
'always_json' => \Catch\Middleware\JsonResponseMiddleware::class,
// response listener
// it listens [RequestHandled] event, if you don't need this
// you can change this config
'request_handled_listener' => \Catch\Listeners\RequestHandledListener::class
],
/*
|--------------------------------------------------------------------------
| catch-admin auth setting
|--------------------------------------------------------------------------
*/
'auth' => [
'guards' => [
'admin' => [
'driver' => 'jwt',
'provider' => 'admin_users',
],
],
'providers' => [
'admin_users' => [
'driver' => 'eloquent',
'model' => \Modules\User\Models\Users::class
]
]
],
/*
|--------------------------------------------------------------------------
| database sql log
|--------------------------------------------------------------------------
*/
'listen_db_log' => true,
/*
|--------------------------------------------------------------------------
| route config
|--------------------------------------------------------------------------
*/
'route' => [
'prefix' => 'api',
'middlewares' => [
\Catch\Middleware\AuthMiddleware::class,
\Catch\Middleware\JsonResponseMiddleware::class
]
],
];

View File

@ -1,49 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class () extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//
Schema::create(config('catch.module.table_name'), function (Blueprint $table) {
$table->increments('id');
$table->string('title')->comment('模块标题');
$table->string('name')->comment('模块名称');
$table->string('path', 20)->comment('模块目录');
$table->string('description')->comment('模块描述');
$table->string('keywords')->comment('模块关键字');
$table->string('version', 20)->comment('模块版本号')->default('1.0.0');
$table->boolean('status')->comment('模块状态')->default(1);
$table->unsignedInteger('created_at')->comment('创建时间')->default(0);
$table->unsignedInteger('updated_at')->comment('更新时间')->default(0);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schema::dropIfExists(config('catch.module.table_name'));
}
};

View File

@ -1,42 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Base;
use Catch\Enums\Code;
use Catch\Exceptions\FailedException;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
/**
* base catch controller
*/
abstract class CatchController extends Controller
{
/**
* @param $guard
* @return Authenticatable
*/
protected function getLoginUser($guard = null): Authenticatable
{
$user = Auth::guard($guard ?: getGuardName())->user();
if (! $user) {
throw new FailedException('登录失效, 请重新登录', Code::LOST_LOGIN);
}
return $user;
}
}

View File

@ -1,89 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Base;
use Catch\Support\DB\SoftDelete;
use Catch\Traits\DB\BaseOperate;
use Catch\Traits\DB\ScopeTrait;
use Catch\Traits\DB\Trans;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
/**
*
* @mixin Builder
* @mixin \Illuminate\Database\Eloquent\Builder
*/
abstract class CatchModel extends Model
{
use BaseOperate, Trans, SoftDeletes, ScopeTrait;
/**
* unix timestamp
*
* @var string
*/
protected $dateFormat = 'U';
/**
* paginate limit
*/
protected $perPage = 10;
/**
* @var string[]
*/
protected $hidden = ['deleted_at'];
/**
* @var string[]
*/
protected $casts = [
'created_at' => 'datetime:Y-m-d H:i:s',
'updated_at' => 'datetime:Y-m-d H:i:s',
'deleted_at' => 'datetime:Y-m-d H:i:s'
];
/**
* @var array
*/
protected array $fieldsInList = ['*'];
/**
* @var bool
*/
protected bool $isPaginate = true;
/**
* @var array $searchable
*/
public array $searchable = [];
/**
* soft delete
*
* @time 2021年08月09日
* @return void
*/
public static function bootSoftDeletes(): void
{
static::addGlobalScope(new SoftDelete());
}
}

View File

@ -1,380 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017 ~ now https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch;
use Catch\Support\Module\Installer;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
class CatchAdmin
{
public const VERSION = '0.1.0';
/**
* version
*
*/
public static function version(): string
{
return static::VERSION;
}
/**
* module root path
*
* @return string
*/
public static function moduleRootPath(): string
{
return self::makeDir(base_path(config('catch.module.root')).DIRECTORY_SEPARATOR);
}
/**
* make dir
*
* @param string $dir
* @return string
*/
public static function makeDir(string $dir): string
{
if (! File::isDirectory($dir) && ! File::makeDirectory($dir, 0777, true)) {
throw new \RuntimeException(sprintf('Directory %s created Failed', $dir));
}
return $dir;
}
/**
* module dir
*
* @param string $module
* @param bool $make
* @return string
*/
public static function getModulePath(string $module, bool $make = true): string
{
if ($make) {
return self::makeDir(self::moduleRootPath().ucfirst($module).DIRECTORY_SEPARATOR);
}
return self::moduleRootPath().ucfirst($module).DIRECTORY_SEPARATOR;
}
/**
* delete module path
*
* @param string $module
* @return bool
*/
public static function deleteModulePath(string $module): bool
{
if (self::isModulePathExist($module)) {
File::deleteDirectory(self::getModulePath($module));
}
return true;
}
/**
* module path exists
*
* @param string $module
* @return bool
*/
public static function isModulePathExist(string $module): bool
{
return File::isDirectory(self::moduleRootPath().ucfirst($module).DIRECTORY_SEPARATOR);
}
/**
* module migration dir
*
* @param string $module
* @return string
*/
public static function getModuleMigrationPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'database'.DIRECTORY_SEPARATOR.'migrations'.DIRECTORY_SEPARATOR);
}
/**
* module seeder dir
*
* @param string $module
* @return string
*/
public static function getModuleSeederPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'database'.DIRECTORY_SEPARATOR.'seeder'.DIRECTORY_SEPARATOR);
}
/**
* get modules dir
*
* @return array
*/
public static function getModulesPath(): array
{
return File::directories(self::moduleRootPath());
}
/**
* get module root namespace
*
* @return string
*/
public static function getModuleRootNamespace(): string
{
return config('catch.module.namespace').'\\';
}
/**
* get module root namespace
*
* @param $moduleName
* @return string
*/
public static function getModuleNamespace($moduleName): string
{
return self::getModuleRootNamespace().ucfirst($moduleName).'\\';
}
/**
* model namespace
*
* @param $moduleName
* @return string
*/
public static function getModuleModelNamespace($moduleName): string
{
return self::getModuleNamespace($moduleName).'Models\\';
}
/**
* getServiceProviders
*
* @param $moduleName
* @return string
*/
public static function getModuleServiceProviderNamespace($moduleName): string
{
return self::getModuleNamespace($moduleName).'Providers\\';
}
/**
*
* @param $moduleName
* @return string
*/
public static function getModuleServiceProvider($moduleName): string
{
return self::getModuleServiceProviderNamespace($moduleName).ucfirst($moduleName).'ServiceProvider';
}
/**
* controller namespace
*
* @param $moduleName
* @return string
*/
public static function getModuleControllerNamespace($moduleName): string
{
return self::getModuleNamespace($moduleName).'Http\\Controllers\\';
}
/**
* getModuleRequestNamespace
*
* @param $moduleName
* @return string
*/
public static function getModuleRequestNamespace($moduleName): string
{
return self::getModuleNamespace($moduleName).'Http\\Requests\\';
}
/**
* getModuleRequestNamespace
*
* @param $moduleName
* @return string
*/
public static function getModuleEventsNamespace($moduleName): string
{
return self::getModuleNamespace($moduleName).'Events\\';
}
/**
* getModuleRequestNamespace
*
* @param $moduleName
* @return string
*/
public static function getModuleListenersNamespace($moduleName): string
{
return self::getModuleNamespace($moduleName).'Listeners\\';
}
/**
* module provider dir
*
* @param string $module
* @return string
*/
public static function getModuleProviderPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'Providers'.DIRECTORY_SEPARATOR);
}
/**
* module model dir
*
* @param string $module
* @return string
*/
public static function getModuleModelPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'Models'.DIRECTORY_SEPARATOR);
}
/**
* module controller dir
*
* @param string $module
* @return string
*/
public static function getModuleControllerPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'Http'.DIRECTORY_SEPARATOR.'Controllers'.DIRECTORY_SEPARATOR);
}
/**
* module request dir
*
* @param string $module
* @return string
*/
public static function getModuleRequestPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'Http'.DIRECTORY_SEPARATOR.'Requests'.DIRECTORY_SEPARATOR);
}
/**
* module request dir
*
* @param string $module
* @return string
*/
public static function getModuleEventPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'Events'.DIRECTORY_SEPARATOR);
}
/**
* module request dir
*
* @param string $module
* @return string
*/
public static function getModuleListenersPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'Listeners'.DIRECTORY_SEPARATOR);
}
/**
* commands path
*
* @param string $module
* @return string
*/
public static function getCommandsPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'Commands'.DIRECTORY_SEPARATOR);
}
/**
* commands namespace
*
* @param string $module
* @return string
*/
public static function getCommandsNamespace(string $module): string
{
return self::getModuleNamespace($module).'Commands\\';
}
/**
* module route
*
* @param string $module
* @param string $routeName
* @return string
*/
public static function getModuleRoutePath(string $module, string $routeName = 'route.php'): string
{
return self::getModulePath($module).$routeName;
}
/**
* module route.php exists
*
* @param string $module
* @return bool
*/
public static function isModuleRouteExists(string $module): bool
{
return File::exists(self::getModuleRoutePath($module));
}
/**
* module views path
*
* @param string $module
* @return string
*/
public static function getModuleViewsPath(string $module): string
{
return self::makeDir(self::getModulePath($module).'views'.DIRECTORY_SEPARATOR);
}
/**
* relative path
*
* @param $path
* @return string
*/
public static function getModuleRelativePath($path): string
{
return Str::replaceFirst(base_path(), '.', $path);
}
/**
*
* @param string $module
* @return Installer
*/
public static function getModuleInstaller(string $module): Installer
{
$installer = self::getModuleServiceProviderNamespace($module).'Installer';
if (class_exists($installer)) {
return app($installer);
}
throw new \RuntimeException("Installer [$installer] Not Found");
}
}

View File

@ -1,141 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017 ~ now https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Catch\Facade\Module;
use function Termwind\ask;
use function Termwind\render;
abstract class CatchCommand extends Command
{
/**
* @var string
*/
protected $name;
public function __construct()
{
parent::__construct();
if (! property_exists($this, 'signature')
&& property_exists($this, 'name')
&& $this->name
) {
$this->signature = $this->name.' {module}';
}
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return void
*/
protected function initialize(InputInterface $input, OutputInterface $output): void
{
if ($input->hasArgument('module')
&& ! Module::getEnabled()->pluck('name')->merge(Collection::make(config('catch.module.default')))->contains(lcfirst($input->getArgument('module')))
) {
$this->error(sprintf('Module [%s] Not Found', $input->getArgument('module')));
exit;
}
}
/**
*
* @param string $question
* @param null $default
* @param bool $isChoice
* @return string|int|null
*/
public function askFor(string $question, $default = null, bool $isChoice = false): string|null|int
{
$_default = $default ? "<em class='pl-1 text-rose-600'>[$default]</em>" : '';
$choice = $isChoice ? '<em class="bg-indigo-600 w-5 pl-1 ml-1 mr-1">Yes</em>OR<em class="bg-rose-600 w-4 pl-1 ml-1">No</em>' : '';
$answer = ask(
<<<HTML
<div>
<div class="px-1 bg-indigo-700">CatchAdmin</div>
<em class="ml-1">
<em class="text-green-700">$question</em>
$_default
$choice
<em class="ml-1">:</em><em class="ml-1"></em>
</em>
</div>
HTML
);
$this->newLine();
if ($default && ! $answer) {
return $default;
}
return $answer;
}
/**
* info
*
* @param $string
* @param null $verbosity
* @return void
*/
public function info($string, $verbosity = null): void
{
render(
<<<HTML
<div>
<div class="px-1 bg-indigo-700">CatchAdmin</div>
<em class="ml-1">
<em class="text-green-700">$string</em>
</em>
</div>
HTML
);
}
/**
* error
*
* @param $string
* @param null $verbosity
* @return void
*/
public function error($string, $verbosity = null): void
{
render(
<<<HTML
<div>
<div class="px-1 bg-indigo-700">CatchAdmin</div>
<em class="ml-1">
<em class="text-rose-700">$string</em>
</em>
</div>
HTML
);
}
}

View File

@ -1,100 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Commands\Create;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
;
class Controller extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:make:controller {module} {name}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'create catch controller';
public function handle()
{
$controllerPath = CatchAdmin::getModuleControllerPath($this->argument('module'));
$file = $controllerPath.$this->getControllerFile();
if (File::exists($file)) {
$answer = $this->ask($file.' already exists, Did you want replace it?', 'Y');
if (! Str::of($answer)->lower()->exactly('y')) {
exit;
}
}
File::put($file, Str::of($this->getStubContent())->replace([
'{namespace}', '{controller}'
], [trim(CatchAdmin::getModuleControllerNamespace($this->argument('module')), '\\'), $this->getControllerName()])->toString());
if (File::exists($file)) {
$this->info($file.' has been created');
} else {
$this->error($file.' create failed');
}
}
/**
*
*
* @return string
*/
protected function getControllerFile(): string
{
return $this->getControllerName().'.php';
}
/**
*
*
* @return string
*/
protected function getControllerName(): string
{
return Str::of($this->argument('name'))
->whenContains('Controller', function ($str) {
return $str;
}, function ($str) {
return $str->append('Controller');
})->ucfirst()->toString();
}
/**
* get stub content
*
* @return string
*/
protected function getStubContent(): string
{
return File::get(dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'controller.stub');
}
}

View File

@ -1,100 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Commands\Create;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
;
class Event extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:make:event {module} {name}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'create catch module event';
public function handle()
{
$eventPath = CatchAdmin::getModuleEventPath($this->argument('module'));
$file = $eventPath.$this->getEventFile();
if (File::exists($file)) {
$answer = $this->ask($file.' already exists, Did you want replace it?', 'Y');
if (! Str::of($answer)->lower()->exactly('y')) {
exit;
}
}
File::put($file, Str::of($this->getStubContent())->replace([
'{namespace}', '{event}'
], [trim(CatchAdmin::getModuleEventsNamespace($this->argument('module')), '\\'), $this->getEventName()])->toString());
if (File::exists($file)) {
$this->info($file.' has been created');
} else {
$this->error($file.' create failed');
}
}
/**
*
*
* @return string
*/
protected function getEventFile(): string
{
return $this->getEventName().'.php';
}
/**
*
*
* @return string
*/
protected function getEventName(): string
{
return Str::of($this->argument('name'))
->whenContains('Event', function ($str) {
return $str;
}, function ($str) {
return $str->append('Event');
})->ucfirst()->toString();
}
/**
* get stub content
*
* @return string
*/
protected function getStubContent(): string
{
return File::get(dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'event.stub');
}
}

View File

@ -1,103 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Commands\Create;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
;
class Listener extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:make:listener {module} {name}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'create catch module event';
public function handle()
{
$eventPath = CatchAdmin::getModuleListenersPath($this->argument('module'));
$file = $eventPath.$this->getListenerFile();
if (File::exists($file)) {
$answer = $this->ask($file.' already exists, Did you want replace it?', 'Y');
if (! Str::of($answer)->lower()->exactly('y')) {
exit;
}
}
File::put($file, Str::of($this->getStubContent())->replace([
'{namespace}', '{listener}'
], [
trim(CatchAdmin::getModuleListenersNamespace($this->argument('module')), '\\'),
$this->getListenerName()])->toString());
if (File::exists($file)) {
$this->info($file.' has been created');
} else {
$this->error($file.' create failed');
}
}
/**
*
*
* @return string
*/
protected function getListenerFile(): string
{
return $this->getListenerName().'.php';
}
/**
*
*
* @return string
*/
protected function getListenerName(): string
{
return Str::of($this->argument('name'))
->whenContains('Listener', function ($str) {
return $str;
}, function ($str) {
return $str->append('Listener');
})->ucfirst()->toString();
}
/**
* get stub content
*
* @return string
*/
protected function getStubContent(): string
{
return File::get(dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'listener.stub');
}
}

View File

@ -1,174 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Commands\Create;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
class Model extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:make:model {module} {model} {--t= : the model of table name}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'create catch module';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
if (! Schema::hasTable($this->getTableName())) {
$this->error('Schema ['.$this->getTableName().'] not found');
exit;
}
$modelPath = CatchAdmin::getModuleModelPath($this->argument('module'));
$file = $modelPath.$this->getModelFile();
if (File::exists($file)) {
$answer = $this->ask($file.' already exists, Did you want replace it?', 'Y');
if (! Str::of($answer)->lower()->exactly('y')) {
exit;
}
}
File::put($file, $this->getModelContent());
if (File::exists($file)) {
$this->info($file.' has been created');
} else {
$this->error($file.' create failed');
}
}
/**
*
*
* @return string
*/
protected function getModelFile(): string
{
return $this->getModelName().'.php';
}
/**
*
*
* @return string
*/
protected function getModelName(): string
{
return Str::of($this->argument('model'))->ucfirst()->toString();
}
/**
* get stub content
*
* @return string
*/
protected function getStubContent(): string
{
return File::get(dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'model.stub');
}
/**
* get model content
*
* @return string
*/
protected function getModelContent(): string
{
return Str::of($this->getStubContent())
->replace(
[
'{namespace}', '{model}', '{table}', '{fillable}'
],
[
$this->getModelNamespace(), $this->getModelName(),
$this->getTableName(), $this->getFillable()
]
)->toString();
}
/**
* get namespace
*
* @return string
*/
protected function getModelNamespace(): string
{
return trim(CatchAdmin::getModuleModelNamespace($this->argument('module')), '\\');
}
/**
* get table name
*
* @return string
*/
protected function getTableName(): string
{
return $this->option('t') ? $this->option('t') :
Str::of($this->argument('model'))
->snake()->lcfirst()->toString();
}
/**
*
*
* @return string
*/
protected function getFillable(): string
{
$fillable = Str::of('');
foreach (getTableColumns($this->getTableName()) as $column) {
$fillable = $fillable->append("'{$column}', ");
}
return $fillable->trim(',')->toString();
}
}

View File

@ -1,316 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017 ~ now https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace Catch\Commands;
use Catch\CatchAdmin;
use Illuminate\Console\Application;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Database\Connectors\ConnectionFactory;
use Illuminate\Foundation\Bootstrap\LoadConfiguration;
use Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Catch\Support\Composer;
class InstallCommand extends CatchCommand
{
protected $signature = 'catch:install';
protected $description = 'install catch admin';
/**
* @var array|string[]
*/
private array $defaultExtensions = ['BCMath', 'Ctype', 'DOM', 'Fileinfo', 'JSON', 'Mbstring', 'OpenSSL', 'PCRE', 'PDO', 'Tokenizer', 'XML'];
/**
* handle
*
* @return void
*/
public function handle(): void
{
try {
$this->detectionEnvironment();
$this->copyEnvFile();
$this->askForCreatingDatabase();
$this->publishConfig();
$this->installed();
} catch (\Throwable $e) {
File::delete(app()->environmentFilePath());
$this->error($e->getMessage());
}
}
/**
* 环境检测
*
* @return void
*/
protected function detectionEnvironment(): void
{
$this->checkPHPVersion();
$this->checkExtensions();
}
/**
* check needed php extensions
*/
private function checkExtensions()
{
/* @var Collection $loadedExtensions */
$loadedExtensions = Collection::make(get_loaded_extensions())->map(function ($item) {
return strtolower($item);
});
Collection::make($this->defaultExtensions)
->each(function ($extension) use ($loadedExtensions, &$continue) {
$extension = strtolower($extension);
if (! $loadedExtensions->contains($extension)) {
$this->error("$extension extension 未安装");
}
});
}
/**
* check php version
*/
private function checkPHPVersion()
{
if (version_compare(PHP_VERSION, '8.1.0', '<')) {
// $this->error('php version should >= 8.1');
}
}
/**
* create database
*
* @param string $databaseName
* @return void
* @throws BindingResolutionException
*/
private function createDatabase(string $databaseName): void
{
$databaseConfig = config('database.connections.'.DB::getDefaultConnection());
$databaseConfig['database'] = null;
app(ConnectionFactory::class)->make($databaseConfig)->select(sprintf("create database if not exists $databaseName default charset %s collate %s", 'utf8mb4', 'utf8mb4_general_ci'));
}
/**
* copy .env
*
* @return void
*/
protected function copyEnvFile(): void
{
if (! File::exists(app()->environmentFilePath())) {
File::copy(app()->environmentFilePath().'.example', app()->environmentFilePath());
}
if (! File::exists(app()->environmentFilePath())) {
$this->error('【.env】创建失败, 请重新尝试或者手动创建!');
}
File::put(app()->environmentFile(), implode("\n", explode("\n", $this->getEnvFileContent())));
}
/**
* get env file content
*
* @return string
*/
protected function getEnvFileContent(): string
{
return File::get(app()->environmentFile());
}
/**
* publish config
*
* @return void
*/
protected function publishConfig(): void
{
// can't use Artisan::call, it will block the process, no reason found, just block!!!
exec(Application::formatCommandString('key:generate'));
exec(Application::formatCommandString('vendor:publish --tag=catch-config'));
exec(Application::formatCommandString('vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"'));
exec(Application::formatCommandString('jwt:secret'));
}
/**
* create database
*/
protected function askForCreatingDatabase()
{
$appUrl = $this->askFor('请配置应用的 URL');
if ($appUrl && ! Str::contains($appUrl, 'http://') && ! Str::contains($appUrl, 'https://')) {
$appUrl = 'http://'.$appUrl;
}
$databaseName = $this->askFor('请输入数据库名称');
$prefix = $this->askFor('请输入数据库表前缀', '');
$dbHost = $this->askFor('请输入数据库主机地址', '127.0.0.1');
$dbPort = $this->askFor('请输入数据的端口号', 3306);
$dbUsername = $this->askFor('请输入数据的用户名', 'root');
$dbPassword = $this->askFor('请输入数据库密码');
if (! $dbPassword) {
$dbPassword = $this->askFor('确认数据库密码为空吗?');
}
// set env
$env = explode("\n", $this->getEnvFileContent());
foreach ($env as &$value) {
foreach ([
'APP_URL' => $appUrl,
'DB_HOST' => $dbHost,
'DB_PORT' => $dbPort,
'DB_DATABASE' => $databaseName,
'DB_USERNAME' => $dbUsername,
'DB_PASSWORD' => $dbPassword,
'DB_PREFIX' => $prefix
] as $key => $newValue) {
if (Str::contains($value, $key)) {
$value = $this->resetEnvValue($value, $newValue);
}
}
}
// add vite config
$env[] = 'VITE_BASE_URL=${APP_URL}/api/';
File::put(app()->environmentFile(), implode("\n", $env));
app()->bootstrapWith([
LoadEnvironmentVariables::class,
LoadConfiguration::class
]);
$this->info("正在创建数据库[$databaseName]...");
$this->createDatabase($databaseName);
$this->info("创建数据库[$databaseName] 成功");
}
/**
* @param $originValue
* @param $newValue
* @return string
*/
protected function resetEnvValue($originValue, $newValue): string
{
if (Str::contains($originValue, '=')) {
$originValue = explode('=', $originValue);
$originValue[1] = $newValue;
return implode('=', $originValue);
}
return $originValue;
}
/**
* add prs4 autoload
*/
protected function addPsr4Autoload()
{
$composerFile = base_path().DIRECTORY_SEPARATOR.'composer.json';
$composerJson = json_decode(File::get(base_path().DIRECTORY_SEPARATOR.'composer.json'), true);
$composerJson['autoload']['psr-4'][CatchAdmin::getModuleRootNamespace()] = str_replace('\\', '/', config('catch.module.root'));
File::put($composerFile, json_encode($composerJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$this->info('composer dump autoload..., 请耐心等待');
app(Composer::class)->dumpAutoloads();
}
/**
* admin installed
*/
public function installed()
{
$this->addPsr4Autoload();
$this->info('🎉 CatchAdmin 已安装, 欢迎!');
$this->output->info(sprintf('
/------------------------ welcome ----------------------------\
| __ __ ___ __ _ |
| _________ _/ /______/ /_ / | ____/ /___ ___ (_)___ |
| / ___/ __ `/ __/ ___/ __ \ / /| |/ __ / __ `__ \/ / __ \ |
| / /__/ /_/ / /_/ /__/ / / / / ___ / /_/ / / / / / / / / / / |
| \___/\__,_/\__/\___/_/ /_/ /_/ |_\__,_/_/ /_/ /_/_/_/ /_/ |
| |
\ __ __ __ __ _ __ _ __ enjoy it ! _ __ __ __ __ __ __ ___ _ @
版本: %s
初始账号: catch@admin.com
初始密码: catchadmin', CatchAdmin::VERSION));
$this->support();
}
/**
* support
*
* @return void
*/
protected function support(): void
{
$answer = $this->askFor('支持我们! 感谢在 Github 上 star 该项目', 'yes', true);
if (in_array(strtolower($answer), ['yes', 'y'])) {
if (PHP_OS_FAMILY == 'Darwin') {
exec('open https://github.com/JaguarJack/catch-admin');
}
if (PHP_OS_FAMILY == 'Windows') {
exec('start https://github.com/JaguarJack/catch-admin');
}
if (PHP_OS_FAMILY == 'Linux') {
exec('xdg-open https://github.com/JaguarJack/catch-admin');
}
}
$this->info('支 持: https://github.com/jaguarjack/catchadmin');
$this->info('文 档: https://catchadmin.com/docs/3.0/intro');
$this->info('官 网: https://catchadmin.com');
}
}

View File

@ -1,55 +0,0 @@
<?php
namespace Catch\Commands\Migrate;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
class MigrateFresh extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:migrate:fresh {module} {--force}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'catch migrate fresh';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$module = $this->argument('module');
if (! File::isDirectory(CatchAdmin::getModuleMigrationPath($module))) {
Artisan::call('migration:fresh', [
'--path' => CatchAdmin::getModuleRelativePath(CatchAdmin::getModuleMigrationPath($module)),
'--force' => $this->option('force')
]);
} else {
$this->error('No migration files in module');
}
}
}

View File

@ -1,91 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace Catch\Commands\Migrate;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
class MigrateMake extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:make:migration {module : The module of the migration created at}
{table : The name of the table to migration}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'create module migration';
/**
*
*
* @return void
*/
public function handle(): void
{
$migrationPath = CatchAdmin::getModuleMigrationPath($this->argument('module'));
$file = $migrationPath.$this->getMigrationFile();
File::put($file, Str::of($this->getStubContent())->replace(
'{table}',
$this->getTable()
)->toString());
if (File::exists($file)) {
$this->info($file.' has been created');
} else {
$this->error($file.' create failed');
}
}
/**
*
*
* @return string
*/
protected function getMigrationFile(): string
{
return date('Y_m_d_His').'_create_'.$this->getTable().'.php';
}
/**
*
*
* @return string
*/
protected function getTable(): string
{
return Str::of($this->argument('table'))->ucfirst()->snake()->lower()->toString();
}
/**
* get stub content
*
* @return string
*/
protected function getStubContent(): string
{
return File::get(dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'migration.stub');
}
}

View File

@ -1,74 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace Catch\Commands\Migrate;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
class MigrateRun extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:migrate {module} {--force}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'migrate catch module';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$module = $this->argument('module');
if (File::isDirectory(CatchAdmin::getModuleMigrationPath($module))) {
foreach (File::files(CatchAdmin::getModuleMigrationPath($module)) as $file) {
$path = Str::of(CatchAdmin::getModuleRelativePath(CatchAdmin::getModuleMigrationPath($module)))
->remove('.')->append($file->getFilename());
Artisan::call('migrate', [
'--path' => $path,
'--force' => $this->option('force')
]);
}
$this->info("Module [$module] migrate success");
} else {
$this->error('No migration files in module');
}
}
}

View File

@ -1,65 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace Catch\Commands\Migrate;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
class MigrationRollback extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:migrate:rollback {module} {--force}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'rollback module tables';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$module = $this->argument('module');
if (! File::isDirectory(CatchAdmin::getModuleMigrationPath($module))) {
Artisan::call('migration:rollback', [
'--path' => CatchAdmin::getModuleRelativePath(CatchAdmin::getModuleMigrationPath($module)),
'--force' => $this->option('force')
]);
} else {
$this->error('No migration files in module');
}
}
}

View File

@ -1,88 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace Catch\Commands\Migrate;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\File;
class SeedRun extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:db:seed {module} {--class=}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'catch db seed';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$classes = $this->loadModuleSeeders();
if ($class = $this->option('class')) {
(new $class())->run();
} else {
foreach ($classes as $class) {
$class = new $class();
if (method_exists($class, 'run')) {
$class->run();
}
}
}
$this->info('Seed run successfully');
}
/**
*
* @time 2021年07月31日
* @return array
*/
protected function loadModuleSeeders(): array
{
$files = File::allFiles(CatchAdmin::getModuleSeederPath($this->argument('module')));
$fileNames = [];
foreach ($files as $file) {
require_once $file->getRealPath();
$fileNames[] = pathinfo($file->getBasename(), PATHINFO_FILENAME);
}
return $fileNames;
}
}

View File

@ -1,88 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace Catch\Commands\Migrate;
use Catch\CatchAdmin;
use Catch\Commands\CatchCommand;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use PhpParser\Node\Name;
class SeederMake extends CatchCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catch:make:seeder {module} {name}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'make module seeder';
/**
*
* @return void
* @throws \Exception
* @author CatchAdmin
* @time 2021年08月01日
*/
public function handle(): void
{
$seederPath = CatchAdmin::getModuleSeederPath($this->argument('module'));
$file = $seederPath.$this->getSeederName().'.php';
if (File::exists($file)) {
$answer = $this->ask($file.' already exists, Did you want replace it?', 'Y');
if (! Str::of($answer)->lower()->exactly('y')) {
exit;
}
}
File::put($file, $this->getSeederContent());
if (File::exists($file)) {
$this->info($file.' has been created');
} else {
$this->error($file.' create failed');
}
}
/**
* seeder content
*
* @return string
* @throws \Exception
*/
protected function getSeederContent(): string
{
return File::get(dirname(__DIR__).DIRECTORY_SEPARATOR.'stubs'.DIRECTORY_SEPARATOR.'seeder.stub');
}
/**
* seeder name
*
* @return string
*/
protected function getSeederName(): string
{
return Str::of($this->argument('name'))->ucfirst()->toString();
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace {namespace};
use Catch\Base\CatchController;
use Illuminate\Http\Request;
class {controller} extends CatchController
{
public function index(Request $request)
{
}
public function store(Request $request)
{
}
public function show($id)
{
}
public function update($id, Request $request)
{
}
public function destroy($id)
{
}
}

View File

@ -1,36 +0,0 @@
<?php
namespace {namespace};
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class {event}
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(): void
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace {namespace};
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class {listener}
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct(): void
{
//
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event): void
{
//
}
}

View File

@ -1,31 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Schema::create('{table}', function (Blueprint $table) {
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
}
};

View File

@ -1,16 +0,0 @@
<?php
namespace {namespace};
use Catch\Base\CatchModel as Model;
class {model} extends Model
{
protected $table = '{table}';
protected $fillable = [
{fillable}
];
}

View File

@ -1,18 +0,0 @@
<?php
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
return new class extends Seeder
{
/**
* Run the seeder.
*
* @return void
*/
public function run(): void
{
}
};

View File

@ -1,37 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Contracts;
use Illuminate\Support\Collection;
interface ModuleRepositoryInterface
{
public function all(array $search): Collection;
public function create(array $module): bool|int;
public function show(string $name): Collection;
public function update(string $name, array $module): bool|int;
public function delete(string $name): bool|int;
public function disOrEnable(string $name): bool|int;
public function getEnabled(): Collection;
public function enabled(string $moduleName): bool;
}

View File

@ -1,79 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace Catch\Enums;
enum Code: int implements Enum
{
case SUCCESS = 10000; // 成功
case LOST_LOGIN = 10001; // 登录失效
case VALIDATE_FAILED = 10002; // 验证错误
case PERMISSION_FORBIDDEN = 10003; // 权限禁止
case LOGIN_FAILED = 10004; // 登录失败
case FAILED = 10005; // 操作失败
case LOGIN_EXPIRED = 10006; // 登录失效
case LOGIN_BLACKLIST = 10007; // 黑名单
case USER_FORBIDDEN = 10008; // 账户被禁
case WECHAT_RESPONSE_ERROR = 40000;
/**
* message
*
*/
public function message(): string
{
return $this->name();
}
/**
* get value
*
* @return int
*/
public function value(): int
{
return match ($this) {
Code::SUCCESS => 10000,
Code::LOST_LOGIN => 10001,
Code::VALIDATE_FAILED => 10002,
Code::PERMISSION_FORBIDDEN => 10003,
Code::LOGIN_FAILED => 10004,
Code::FAILED => 10005,
Code::LOGIN_EXPIRED => 10006,
Code::LOGIN_BLACKLIST => 10007,
Code::USER_FORBIDDEN => 10008,
Code::WECHAT_RESPONSE_ERROR => 40000,
};
}
/**
* name
*
* @return string
*/
public function name(): string
{
return match ($this) {
self::SUCCESS => '操作成功',
self::LOST_LOGIN => '登陆失效',
self::VALIDATE_FAILED => '验证失败',
self::PERMISSION_FORBIDDEN => '权限禁止',
self::LOGIN_FAILED => '登陆失败',
self::FAILED => '操作失败',
self::LOGIN_EXPIRED => '登陆过期',
self::LOGIN_BLACKLIST => '已被加入黑名单',
self::USER_FORBIDDEN => '账户被禁用',
self::WECHAT_RESPONSE_ERROR => '微信响应错误'
};
}
}

View File

@ -1,10 +0,0 @@
<?php
namespace Catch\Enums;
interface Enum
{
public function value(): int;
public function name(): string;
}

View File

@ -1,49 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Enums;
enum Status: int implements Enum
{
case Enable = 1;
case Disable = 2;
/**
* @desc name
*
*/
public function name(): string
{
return match ($this) {
Status::Enable => '启用',
Status::Disable => '禁用'
};
}
/**
* get value
*
* @return int
*/
public function value(): int
{
return match ($this) {
Status::Enable => 1,
Status::Disable => 2,
};
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace Catch\Events\Module;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class Created
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(public array $module)
{
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace Catch\Events\Module;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class Creating
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(public array $module)
{
}
}

View File

@ -1,22 +0,0 @@
<?php
namespace Catch\Events\Module;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;
class Deleted
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(public Collection $module)
{
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace Catch\Events\Module;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class Updated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(public string $originName, public array $module)
{
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace Catch\Events\Module;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class Updating
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(public string $originName, public array $module)
{
}
}

View File

@ -1,27 +0,0 @@
<?php
namespace Catch\Events;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class User
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public Authenticatable|Model $user;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Authenticatable|Model $user)
{
//
$this->user = $user;
}
}

View File

@ -1,65 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Exceptions;
use Catch\Enums\Enum;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Catch\Enums\Code;
abstract class CatchException extends HttpException
{
protected $code = 0;
/**
* @param string $message
* @param int|Code $code
*/
public function __construct(string $message = '', int|Code $code = 0)
{
if ($code instanceof Enum) {
$code = $code->value();
}
if ($this->code instanceof Enum && ! $code) {
$code = $this->code->value();
}
parent::__construct($this->statusCode(), $message ?: $this->message, null, [], $code);
}
/**
* status code
*
* @return int
*/
public function statusCode(): int
{
return 500;
}
/**
* render
*
* @return array
*/
public function render(): array
{
return [
'code' => $this->code,
'message' => $this->message
];
}
}

View File

@ -1,22 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Exceptions;
use Catch\Enums\Code;
class FailedException extends CatchException
{
protected $code = Code::FAILED;
}

View File

@ -1,34 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* register
*
* @return void
*/
public function register(): void
{
if (config('catch')) {
$this->dontReport = config('catch.exception.dont_report');
$this->dontFlash = config('catch.exception.dont_flash');
}
}
}

View File

@ -1,22 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Exceptions;
use Catch\Enums\Code;
class UnMatchedTokenException extends CatchException
{
protected $code = Code::FAILED;
}

View File

@ -1,25 +0,0 @@
<?php
declare(strict_types=1);
namespace Catch\Facade;
use Illuminate\Support\Facades\Facade;
/**
* @method static all()
* @method static create(array $module)
* @method static update(string $name, array $module)
* @method static delete(string $name)
* @method static disOrEnable(string $name)
*
* @see ModuleRepository
* Class Module
*/
class Module extends Facade
{
public static function getFacadeAccessor(): string
{
return 'module';
}
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace Catch\Facade;
use Illuminate\Support\Facades\Facade;
use Catch\Support\Zip\Zipper as Zip;
/**
* @method static Zip make(string $pathToFile)
* @method static Zip zip(string $pathToFile)
* @method static Zip phar(string $pathToFile)
*
* @see Zipper
* Class Module
*/
class Zipper extends Facade
{
public static function getFacadeAccessor(): string
{
return Zip::class;
}
}

View File

@ -1,57 +0,0 @@
<?php
namespace Catch\Listeners;
use Catch\Enums\Code;
use Illuminate\Foundation\Http\Events\RequestHandled;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
use Illuminate\Http\JsonResponse;
class RequestHandledListener
{
/**
* Handle the event.
*
* @param RequestHandled $event
* @return void
*/
public function handle(RequestHandled $event): void
{
$response = $event->response;
if ($response instanceof JsonResponse) {
$exception = $response->exception;
if ($response->getStatusCode() == SymfonyResponse::HTTP_OK && ! $exception) {
$response->setData($this->formatData($response->getData()));
}
}
}
/**
* @param mixed $data
* @return array
*/
protected function formatData(mixed $data): array
{
$responseData = [
'code' => Code::SUCCESS->value(),
'message' => Code::SUCCESS->message(),
];
if (is_object($data) && property_exists($data, 'per_page')
&& property_exists($data, 'total')
&& property_exists($data, 'current_page')) {
$responseData['data'] = $data->data;
$responseData['total'] = $data->total;
$responseData['limit'] = $data->per_page;
$responseData['page'] = $data->current_page;
return $responseData;
}
$responseData['data'] = $data;
return $responseData;
}
}

View File

@ -1,43 +0,0 @@
<?php
namespace Catch\Middleware;
use Catch\Enums\Code;
use Catch\Events\User as UserEvent;
use Catch\Exceptions\FailedException;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Event;
use Throwable;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
class AuthMiddleware
{
public function handle(Request $request, \Closure $next)
{
try {
$guardName = getGuardName();
if (! $user = Auth::guard($guardName)->user()) {
throw new AuthenticationException();
}
Event::dispatch(new UserEvent($user));
return $next($request);
} catch (Exception|Throwable $e) {
if ($e instanceof TokenExpiredException) {
throw new FailedException(Code::LOGIN_EXPIRED->message(), Code::LOGIN_EXPIRED);
}
if ($e instanceof TokenBlacklistedException) {
throw new FailedException(Code::LOGIN_BLACKLIST->message(), Code::LOGIN_BLACKLIST);
}
throw new FailedException(Code::LOST_LOGIN->message().":{$e->getMessage()}", Code::LOST_LOGIN);
}
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace Catch\Middleware;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class JsonResponseMiddleware
{
public function handle(Request $request, \Closure $next)
{
$response = $next($request);
if ($response instanceof Response) {
return new JsonResponse($response->getContent());
}
return $response;
}
}

View File

@ -1,229 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017 ~ now https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace Catch\Providers;
use Catch\CatchAdmin;
use Catch\Contracts\ModuleRepositoryInterface;
use Catch\Exceptions\Handler;
use Catch\Support\DB\Query;
use Catch\Support\Module\ModuleManager;
use Illuminate\Container\Container;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Foundation\Http\Events\RequestHandled;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use ReflectionException;
use Catch\Support\Macros\Register as MacrosRegister;
/**
* CatchAmin Service Provider
*/
class CatchAdminServiceProvider extends ServiceProvider
{
/**
* boot
*
* @return void
* @throws NotFoundExceptionInterface
* @throws ContainerExceptionInterface
*/
public function boot(): void
{
$this->bootDefaultModuleProviders();
$this->bootModuleProviders();
$this->registerEvents();
$this->listenDBLog();
$this->mergeAuthConfig();
// $this->registerExceptionHandler();
MacrosRegister::boot();
}
/**
* register
*
* @return void
* @throws ReflectionException
*/
public function register(): void
{
$this->registerCommands();
$this->registerModuleRepository();
$this->publishConfig();
$this->publishModuleMigration();
}
/**
* register commands
*
* @return void
* @throws ReflectionException
*/
protected function registerCommands(): void
{
loadCommands(dirname(__DIR__).DIRECTORY_SEPARATOR.'Commands', 'Catch\\');
}
/**
* register exception handler
*
* @return void
*/
protected function registerExceptionHandler(): void
{
$this->app->singleton(
ExceptionHandler::class,
Handler::class
);
}
/**
* bind module repository
*
* @return void
*/
protected function registerModuleRepository(): void
{
// register module manager
$this->app->singleton(ModuleManager::class, function () {
return new ModuleManager(fn () => Container::getInstance());
});
// register module repository
$this->app->singleton(ModuleRepositoryInterface::class, function () {
return $this->app->make(ModuleManager::class)->driver();
});
$this->app->alias(ModuleRepositoryInterface::class, 'module');
}
/**
* register events
*
* @return void
*/
protected function registerEvents(): void
{
Event::listen(RequestHandled::class, config('catch.response.request_handled_listener'));
}
/**
* publish config
*
* @return void
*/
protected function publishConfig(): void
{
if ($this->app->runningInConsole()) {
$from = dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'catch.php';
$to = config_path('catch.php');
$this->publishes([$from => $to], 'catch-config');
}
}
/**
* publish module migration
*
* @return void
*/
protected function publishModuleMigration(): void
{
if ($this->app->runningInConsole()) {
$form = dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'database'.DIRECTORY_SEPARATOR.'migrations'.DIRECTORY_SEPARATOR.'2022_11_14_034127_module.php';
$to = database_path('migrations').DIRECTORY_SEPARATOR.'2022_11_14_034127_module.php';
$this->publishes([$form => $to], 'catch-module');
}
}
/**
*
* @return void
* @throws NotFoundExceptionInterface
* @throws ContainerExceptionInterface
*/
protected function bootDefaultModuleProviders(): void
{
foreach ($this->app['config']->get('catch.module.default') as $module) {
$provider = CatchAdmin::getModuleServiceProvider($module);
if (class_exists($provider)) {
$this->app->register($provider);
}
}
}
/**
* boot module
*
* @throws BindingResolutionException
*/
protected function bootModuleProviders()
{
foreach ($this->app->make(ModuleRepositoryInterface::class)->getEnabled() as $module) {
if (class_exists($module['provider'])) {
$this->app->register($module['provider']);
}
}
}
/**
* listen db log
*
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @return void
*/
protected function listenDBLog(): void
{
if ($this->app['config']->get('catch.listen_db_log')) {
Query::listen();
$this->app->terminating(function () {
Query::log();
});
}
}
/**
* merge auth config
*
* @throws BindingResolutionException
* @return void
*/
protected function mergeAuthConfig(): void
{
if (! $this->app->configurationIsCached()) {
$config = $this->app->make('config');
$config->set('auth', array_merge_recursive(
$config->get('catch.auth', []),
$config->get('auth', [])
));
}
}
}

View File

@ -1,63 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017 ~ now https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
namespace Catch\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
abstract class CatchModuleServiceProvider extends ServiceProvider
{
protected array $events = [];
/**
* register
*
* @return void
* @throws NotFoundExceptionInterface
* @throws ContainerExceptionInterface
*/
public function boot(): void
{
$this->registerModuleRoute();
foreach ($this->events as $event => $listener) {
Event::listen($event, $listener);
}
}
/**
* load module router
*
* @return void
* @throws NotFoundExceptionInterface
* @throws ContainerExceptionInterface
*/
protected function registerModuleRoute(): void
{
$route = $this->app['config']->get('catch.route');
Route::prefix($route['prefix'])
->middleware($route['middlewares'])
->group($this->routePath());
}
/**
* route path
*
* @return string|array
*/
abstract protected function routePath(): string | array;
}

View File

@ -1,108 +0,0 @@
<?php
namespace Catch\Support;
use Illuminate\Support\Composer as LaravelComposer;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\File;
use Laravel\SerializableClosure\Exceptions\PhpVersionNotSupportedException;
class Composer extends LaravelComposer
{
protected bool $ignorePlatformReqs = false;
/**
* require package
* @param string $package
* @return string
* @throws PhpVersionNotSupportedException
*/
public function require(string $package): string
{
$this->checkPHPVersion();
$command = ['require', $package];
return $this->runCommand($command);
}
/**
* require dev-package
*
* @param string $package
* @return string
* @throws PhpVersionNotSupportedException
*/
public function requireDev(string $package): string
{
$this->checkPHPVersion();
$command = ['require', '--dev', $package];
return $this->runCommand($command);
}
/**
* remove
*
* @param string $package
*/
public function remove(string $package)
{
$this->runCommand([
'remove', $package
]);
}
/**
*
* @param array $command
* @return string
*/
protected function runCommand(array $command): string
{
$command = array_merge($this->findComposer(), $command);
if ($this->ignorePlatformReqs) {
$command[] = '--ignore-platform-reqs';
}
$process = $this->getProcess($command);
$process->run();
return $process->getOutput();
}
/**
*
* @throws PhpVersionNotSupportedException
* @return void
*/
protected function checkPHPVersion(): void
{
$composerJson = json_decode(File::get(base_path().DIRECTORY_SEPARATOR.'composer.json'), true);
$phpVersion = PHP_VERSION;
$needPHPVersion = Str::of($composerJson['require']['php'])->remove('^');
if (version_compare($phpVersion, $needPHPVersion, '<') && ! $this->ignorePlatformReqs) {
throw new PhpVersionNotSupportedException("PHP $phpVersion 版本太低, 需要 PHP {$needPHPVersion}!如果想忽略版本要求, s可使用 {ignorePlatFormReqs} 方法然后安装");
}
}
/**
*
* @return $this
*/
public function ignorePlatFormReqs(): static
{
$this->ignorePlatformReqs = true;
return $this;
}
}

View File

@ -1,55 +0,0 @@
<?php
namespace Catch\Support\DB;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class Query
{
/**
* @var string|null
*/
protected static string|null $log = null;
/**
* @return void
*/
public static function listen(): void
{
DB::listen(function ($query) {
$sql = str_replace(
'?',
'%s',
sprintf('[%s] '.$query->sql.' | %s ms'.PHP_EOL, date('Y-m-d H:i'), $query->time)
);
static::$log .= vsprintf($sql, $query->bindings);
});
}
/**
* @return void
*/
public static function log(): void
{
if (static::$log) {
$sqlLogPath = storage_path('logs'.DIRECTORY_SEPARATOR.'query'.DIRECTORY_SEPARATOR);
if (! File::isDirectory($sqlLogPath)) {
File::makeDirectory($sqlLogPath, 0777, true);
}
$logFile = $sqlLogPath.date('Ymd').'.log';
if (! File::exists($logFile)) {
File::put($logFile, '', true);
}
file_put_contents($logFile, static::$log.PHP_EOL, LOCK_EX | FILE_APPEND);
static::$log = null;
}
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace Catch\Support\DB;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class SoftDelete extends SoftDeletingScope
{
/**
* @param Builder $builder
* @param Model $model
*/
public function apply(Builder $builder, Model $model)
{
$builder->where($model->getQualifiedDeletedAtColumn(), '=', 0);
}
}

View File

@ -1,140 +0,0 @@
<?php
declare(strict_types=1);
namespace Catch\Support\Macros;
use Illuminate\Database\Schema\Blueprint as LaravelBlueprint;
class Blueprint
{
/**
* boot;
*/
public static function boot(): void
{
$bluePrint = new static();
$bluePrint->createdAt();
$bluePrint->updatedAt();
$bluePrint->deletedAt();
$bluePrint->status();
$bluePrint->creatorId();
$bluePrint->unixTimestamp();
$bluePrint->parentId();
$bluePrint->sort();
}
/**
* created unix timestamp
*
* @return void
*/
public function createdAt(): void
{
LaravelBlueprint::macro(__FUNCTION__, function () {
$this->unsignedInteger('created_at')->default(0)->comment('created time');
});
}
/**
* update unix timestamp
*
* @return void
*/
public function updatedAt(): void
{
LaravelBlueprint::macro(__FUNCTION__, function () {
$this->unsignedInteger('updated_at')->default(0)->comment('updated time');
});
}
/**
* soft delete
*
* @return void
*/
public function deletedAt(): void
{
LaravelBlueprint::macro(__FUNCTION__, function () {
$this->unsignedInteger('deleted_at')->default(0)->comment('delete time');
});
}
/**
* unix timestamp
*
* @param bool $softDeleted
* @return void
*/
public function unixTimestamp(bool $softDeleted = true): void
{
LaravelBlueprint::macro(__FUNCTION__, function () use ($softDeleted) {
$this->createdAt();
$this->updatedAt();
if ($softDeleted) {
$this->deletedAt();
}
});
}
/**
* creator id
*
* @return void
*/
public function creatorId(): void
{
LaravelBlueprint::macro(__FUNCTION__, function () {
$this->unsignedInteger('creator_id')->default(0)->comment('creator id');
});
}
/**
* parent ID
*
* @return void
*/
public function parentId(): void
{
LaravelBlueprint::macro(__FUNCTION__, function () {
$this->unsignedInteger('parent_id')->default(0)->comment('parent id');
});
}
/**
* status
*
* @return void
*/
public function status(): void
{
LaravelBlueprint::macro(__FUNCTION__, function ($default = 1) {
$this->tinyInteger('status')->default($default)->comment('1:normal 2: forbidden');
});
}
/**
* sort
*
* @param int $default
* @return void
*/
public function sort(int $default = 1): void
{
LaravelBlueprint::macro(__FUNCTION__, function () use ($default) {
$this->integer('sort')->comment('sort')->default($default);
});
}
}

View File

@ -1,107 +0,0 @@
<?php
declare(strict_types=1);
namespace Catch\Support\Macros;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Builder as LaravelBuilder;
class Builder
{
/**
* boot
*/
public static function boot(): void
{
$builder = new static();
$builder->whereLike();
$builder->quickSearch();
$builder->tree();
}
/**
* where like
*
* @return void
*/
public function whereLike(): void
{
LaravelBuilder::macro(__FUNCTION__, function ($filed, $value) {
return $this->where($filed, 'like', "%$value%");
});
}
/**
* quick search
*
* @return void
*/
public function quickSearch(): void
{
LaravelBuilder::macro(__FUNCTION__, function (array $params = []) {
$params = array_merge(request()->all(), $params);
if (! property_exists($this->model, 'searchable')) {
return $this;
}
// filter null & empty string
$params = array_filter($params, function ($value) {
return (is_string($value) && strlen($value)) || is_numeric($value);
});
$wheres = [];
if (! empty($this->model->searchable)) {
foreach ($this->model->searchable as $field => $op) {
// 临时变量
$_field = $field;
// contains alias
if (str_contains($field, '.')) {
[, $_field] = explode('.', $field);
}
if (isset($params[$_field])) {
$opString = Str::of($op)->lower();
if ($opString->exactly('op')) {
$value = implode(',', $params[$_field]);
} elseif ($opString->exactly('like')) {
$value = "%{$params[$_field]}%";
} elseif ($opString->exactly('rlike')) {
$value = "{$params[$_field]}%";
} elseif ($opString->exactly('llike')) {
$value = "%{$params[$_field]}";
} else {
$value = $params[$_field];
}
$wheres[] = [$field, $op, $value];
}
}
}
$this->where($wheres);
return $this;
});
}
/**
* where like
*
* @time 2021年08月06日
* @return void
*/
public function tree(): void
{
LaravelBuilder::macro(__FUNCTION__, function (string $id, string $parentId, ...$fields) {
$fields = array_merge([$id, $parentId], $fields);
return $this->get($fields)->toTree(0, $parentId);
});
}
}

View File

@ -1,65 +0,0 @@
<?php
declare(strict_types=1);
namespace Catch\Support\Macros;
use Catch\Support\Tree;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Collection as LaravelCollection;
class Collection
{
/**
* boot
*/
public static function boot(): void
{
$collection = new static();
$collection->toOptions();
$collection->toTree();
}
/**
* collection to tree
*
* @return void
*/
public function toTree(): void
{
LaravelCollection::macro(__FUNCTION__, function (int $pid = 0, string $pidField = 'parent_id', string $child = 'children') {
return Tree::done($this->all(), $pid, $pidField, $child);
});
}
/**
* toOptions
*
* @return void
*/
public function toOptions(): void
{
LaravelCollection::macro(__FUNCTION__, function () {
return $this->transform(function ($item, $key) use (&$options) {
if ($item instanceof Arrayable) {
$item = $item->toArray();
}
if (is_array($item)) {
$item = array_values($item);
return [
'value' => $item[0],
'label' => $item[1]
];
} else {
return [
'value' => $key,
'label' => $item
];
}
})->values();
});
}
}

View File

@ -1,23 +0,0 @@
<?php
declare(strict_types=1);
namespace Catch\Support\Macros;
/**
* boot
*/
class Register
{
/**
* macros boot
*/
public static function boot(): void
{
Blueprint::boot();
Collection::boot();
Builder::boot();
}
}

View File

@ -1,180 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Support\Module\Driver;
use Catch\CatchAdmin;
use Catch\Contracts\ModuleRepositoryInterface;
use Catch\Enums\Status;
use Catch\Exceptions\FailedException;
use Illuminate\Container\Container;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
/**
* DatabaseDriver
*/
class DatabaseDriver implements ModuleRepositoryInterface
{
protected Model $model;
public function __construct()
{
$this->model = $this->createModuleModel();
}
/**
* all
*
* @param array $search
* @return Collection
*/
public function all(array $search): Collection
{
return $this->model::query()
->when($search['title'] ?? false, function ($query) use ($search) {
$query->where('title', 'like', '%'.$search['title'].'%');
})->get();
}
/**
* create module json
*
* @param array $module
* @return bool|int
*/
public function create(array $module): bool|int
{
$this->hasSameModule($module);
return $this->model->save([
'title' => $module['title'],
'path' => $module['path'],
'description' => $module['desc'],
'keywords' => $module['keywords'],
'provider' => sprintf('\\%s%s', CatchAdmin::getModuleNamespace($module['name']), ucfirst($module['name']).'ServiceProvider'),
]);
}
/**
* module info
*
* @param string $name
* @return Collection
*/
public function show(string $name): Collection
{
return $this->model->where('name', $name)->first();
}
/**
* update module json
*
* @param string $name
* @param array $module
* @return bool|int
*/
public function update(string $name, array $module): bool|int
{
return $this->model->where('name', $name)
->update([
'title' => $module['title'],
'name' => $module['path'],
'path' => $module['path'],
'description' => $module['desc'],
'keywords' => $module['keywords'],
]);
}
/**
* delete module json
*
* @param string $name
* @return bool|int
*/
public function delete(string $name): bool|int
{
return $this->model->where('name', $name)->delete();
}
/**
* disable or enable
*
* @param $name
* @return bool|int
*/
public function disOrEnable($name): bool|int
{
$module = $this->show($name);
$module->enable = (int) $module->enable;
return $module->save();
}
/**
* get enabled
*
* @return Collection
*/
public function getEnabled(): Collection
{
// TODO: Implement getEnabled() method.
return $this->model->where('enable', Status::Enable->value())->get();
}
/**
* enabled
*
* @param string $moduleName
* @return bool
*/
public function enabled(string $moduleName): bool
{
// TODO: Implement enabled() method.
return $this->getEnabled()->pluck('name')->contains($moduleName);
}
/**
*
* @param array $module
* @return void
*/
protected function hasSameModule(array $module): void
{
if ($this->model->where('name', $module['name'])->first()) {
throw new FailedException(sprintf('Module [%s] has been created', $module['name']));
}
}
/**
* create model
* @return Model
*/
protected function createModuleModel(): Model
{
return new class () extends Model {
protected $table;
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->table = Container::getInstance()->make('config')->get('catch.module.driver.table_name');
}
};
}
}

View File

@ -1,215 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Support\Module\Driver;
use Catch\CatchAdmin;
use Catch\Contracts\ModuleRepositoryInterface;
use Catch\Exceptions\FailedException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
/**
* FileDriver
*/
class FileDriver implements ModuleRepositoryInterface
{
protected string $moduleJson;
/**
* construct
*/
public function __construct()
{
$this->moduleJson = storage_path('app').DIRECTORY_SEPARATOR.'modules.json';
}
/**
* all
*
* @param array $search
* @return Collection
*/
public function all(array $search = []): Collection
{
if (! File::exists($this->moduleJson)) {
return Collection::make([]);
}
if (! Str::length(File::get($this->moduleJson))) {
return Collection::make([]);
}
$modules = Collection::make(\json_decode(File::get($this->moduleJson), true))->values();
$title = $search['title'] ?? '';
if (! $title) {
return $modules;
}
return $modules->filter(function ($module) use ($title) {
return Str::of($module['title'])->contains($title);
});
}
/**
* create module json
*
* @param array $module
* @return bool
*/
public function create(array $module): bool
{
$modules = $this->all();
$this->hasSameModule($module, $modules);
$module['provider'] = sprintf('\\%s', CatchAdmin::getModuleServiceProvider($module['path']));
$module['version'] = '1.0.0';
$module['enable'] = true;
$this->removeDirs($module);
File::put($this->moduleJson, $modules->push($module)->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
return true;
}
/**
* module info
*
* @param string $name
* @return Collection
*/
public function show(string $name): Collection
{
foreach ($this->all() as $module) {
if (Str::of($module['name'])->exactly($name)) {
return Collection::make($module);
}
}
throw new FailedException("Module [$name] not Found");
}
/**
* update module json
*
* @param string $name
* @param array $module
* @return bool
*/
public function update(string $name, array $module): bool
{
File::put($this->moduleJson, $this->all()->map(function ($m) use ($module, $name) {
if (Str::of($name)->exactly($m['name'])) {
$m['name'] = $module['name'];
$m['title'] = $module['title'];
$m['description'] = $module['description'] ?? '';
$m['keywords'] = $module['keywords'] ?? '';
$m['enable'] = $module['enable'];
}
$this->removeDirs($m);
return $m;
})->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
return true;
}
/**
* delete module json
*
* @param string $name
* @return bool
*/
public function delete(string $name): bool
{
File::put($this->moduleJson, $this->all()->filter(function ($module) use ($name) {
if (! Str::of($name)->exactly($module['name'])) {
return $module;
}
})->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
return true;
}
/**
* disable or enable
*
* @param $name
* @return bool|int
*/
public function disOrEnable($name): bool|int
{
return File::put($this->moduleJson, $this->all()->map(function ($module) use ($name) {
if (Str::of($module['name'])->exactly($name)) {
$module['enable'] = ! $module['enable'];
}
return $module;
})->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}
/**
* get enabled
*
* @return Collection
*/
public function getEnabled(): Collection
{
// TODO: Implement getEnabled() method.
return $this->all()->where('enable', true)->values();
}
/**
* enabled
* @param string $moduleName
* @return bool
*/
public function enabled(string $moduleName): bool
{
// TODO: Implement enabled() method.
return $this->getEnabled()->pluck('name')->contains($moduleName);
}
/**
*
* @param array $module
* @param Collection $modules
* @return void
*/
protected function hasSameModule(array $module, Collection $modules): void
{
if ($modules->count()) {
if ($modules->pluck('name')->contains($module['name'])) {
throw new FailedException(sprintf('Module [%s] has been created', $module['name']));
}
}
}
/**
* remove dirs
*
* @param array $modules
*/
protected function removeDirs(array &$modules)
{
if ($modules['dirs'] ?? false) {
unset($modules['dirs']);
}
}
}

View File

@ -1,97 +0,0 @@
<?php
namespace Catch\Support\Module;
use Catch\Contracts\ModuleRepositoryInterface;
use Catch\Support\Composer;
/**
* installer
*/
abstract class Installer
{
/**
* construct
*
* @param ModuleRepositoryInterface $moduleRepository
*/
public function __construct(protected ModuleRepositoryInterface $moduleRepository)
{
}
/**
* module info
*
* @return array
*/
abstract protected function info(): array;
/**
* migration
*
* @return string
*/
abstract protected function migration(): string;
/**
* seed
*
* @return string
*/
abstract protected function seeder(): string;
/**
* require packages
*
* @return void
*/
abstract protected function requirePackages(): void;
/**
* remove packages
*
* @return void
*/
abstract protected function removePackages(): void;
/**
* uninstall
*
* @return void
*/
public function uninstall(): void
{
$this->moduleRepository->delete($this->info()['name']);
$this->removePackages();
}
/**
* invoke
*
* @return void
*/
public function install(): void
{
// TODO: Implement __invoke() method.
$this->moduleRepository->create($this->info());
// migration
// seed
$this->requirePackages();
}
/**
* composer installer
*
* @return Composer
*/
protected function composer(): Composer
{
return app(Composer::class);
}
}

View File

@ -1,63 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Support\Module;
use Catch\Support\Module\Driver\DatabaseDriver;
use Catch\Support\Module\Driver\FileDriver;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Manager;
class ModuleManager extends Manager
{
public function __construct(Container|\Closure $container)
{
if ($container instanceof \Closure) {
$container = $container();
}
parent::__construct($container);
}
/**
* @return string
*/
public function getDefaultDriver(): string
{
// TODO: Implement getDefaultDriver() method.
return $this->config->get('catch.module.driver.default');
}
/**
* create file driver
*
* @return FileDriver
*/
public function createFileDriver(): FileDriver
{
return new FileDriver();
}
/**
* create database driver
*
* @return DatabaseDriver
*/
public function createDatabaseDriver(): DatabaseDriver
{
return new DatabaseDriver();
}
}

View File

@ -1,159 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Support\Module;
use Catch\Contracts\ModuleRepositoryInterface;
use Catch\Events\Module\Created;
use Catch\Events\Module\Creating;
use Catch\Events\Module\Deleted;
use Catch\Events\Module\Updated;
use Catch\Events\Module\Updating;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Event;
/**
* FileDriver
*/
class ModuleRepository
{
protected ModuleRepositoryInterface $moduleRepository;
/**
* construct
*/
public function __construct(ModuleRepositoryInterface $moduleRepository)
{
$this->moduleRepository = $moduleRepository;
}
/**
* all
*
* @param array $search
* @return Collection
*/
public function all(array $search): Collection
{
return $this->moduleRepository->all($search);
}
/**
* create module json
*
* @param array $module
* @return bool
*/
public function create(array $module): bool
{
$module['name'] = lcfirst($module['path']);
Event::dispatch(new Creating($module));
$this->moduleRepository->create($module);
Event::dispatch(new Created($module));
return true;
}
/**
* module info
*
* @param string $name
* @return Collection
* @throws Exception
*/
public function show(string $name): Collection
{
try {
return $this->moduleRepository->show($name);
} catch (Exception $e) {
throw new $e();
}
}
/**
* update module json
*
* @param string $name
* @param array $module
* @return bool
*/
public function update(string $name, array $module): bool
{
$module['name'] = lcfirst($module['path']);
Event::dispatch(new Updating($name, $module));
$this->moduleRepository->update($name, $module);
Event::dispatch(new Updated($name, $module));
return true;
}
/**
* delete module json
*
* @param string $name
* @return bool
* @throws Exception
*/
public function delete(string $name): bool
{
$module = $this->show($name);
$this->moduleRepository->delete($name);
Event::dispatch(new Deleted($module));
return true;
}
/**
* disable or enable
*
* @param string $name
* @return bool|int
*/
public function disOrEnable(string $name): bool|int
{
return $this->moduleRepository->disOrEnable($name);
}
/**
* get enabled
*
* @return Collection
*/
public function getEnabled(): Collection
{
// TODO: Implement getEnabled() method.
return $this->moduleRepository->getEnabled();
}
/**
* enabled
*
* @param string $moduleName
* @return bool
*/
public function enabled(string $moduleName): bool
{
return $this->moduleRepository->enabled($moduleName);
}
}

View File

@ -1,61 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Support;
class Tree
{
protected static string $pk = 'id';
/**
*
* @param string $pk
* @return Tree
*/
public static function setPk(string $pk): Tree
{
self::$pk = $pk;
return new self();
}
/**
* return done
*
* @param array $items
* @param int $pid
* @param string $pidField
* @param string $child
* @return array
*/
public static function done(array $items, int $pid = 0, string $pidField = 'parent_id', string $child = 'children'): array
{
$tree = [];
foreach ($items as $item) {
if ($item[$pidField] == $pid) {
$children = self::done($items, $item[self::$pk], $pidField, $child);
if (count($children)) {
$item[$child] = $children;
}
$tree[] = $item;
}
}
return $tree;
}
}

View File

@ -1,200 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Support\Zip;
use Exception;
use ZipArchive;
class ZipRepository
{
private mixed $archive;
/**
* Construct with a given path
*
* @param $filePath
* @param bool $create
* @param $archive
*
* @return void
* @throws Exception
*
*/
public function __construct($filePath, bool $create, $archive = null)
{
//Check if ZipArchive is available
if (! class_exists('ZipArchive')) {
throw new Exception('Error: Your PHP version is not compiled with zip support');
}
$this->archive = $archive ? $archive : new ZipArchive();
$res = $this->archive->open($filePath, ($create ? ZipArchive::CREATE : 0));
if ($res !== true) {
throw new Exception("Error: Failed to open $filePath! Error: ".$this->getErrorMessage($res));
}
}
/**
* Add a file to the opened Archive
*
* @param $pathToFile
* @param $pathInArchive
*/
public function addFile($pathToFile, $pathInArchive): void
{
$this->archive->addFile($pathToFile, $pathInArchive);
}
/**
* Add an empty directory
*
* @param $dirName
*/
public function addEmptyDir($dirName): void
{
$this->archive->addEmptyDir($dirName);
}
/**
* Add a file to the opened Archive using its contents
*
* @param string $name
* @param $content
*/
public function addFromString(string $name, $content): void
{
$this->archive->addFromString($name, $content);
}
/**
* Remove a file permanently from the Archive
*
* @param string $pathInArchive
*/
public function removeFile(string $pathInArchive): void
{
$this->archive->deleteName($pathInArchive);
}
/**
* Get the content of a file
*
* @param string $pathInArchive
*
* @return string
*/
public function getFileContent(string $pathInArchive): string
{
return $this->archive->getFromName($pathInArchive);
}
/**
* Get the stream of a file
*
* @param string $pathInArchive
*
* @return bool
*/
public function getFileStream(string $pathInArchive): bool
{
return $this->archive->getStream($pathInArchive);
}
/**
* Will loop over every item in the archive and will execute the callback on them
* Will provide the filename for every item
*
* @param $callback
*/
public function each($callback): void
{
for ($i = 0; $i < $this->archive->numFiles; ++$i) {
//skip if folder
$stats = $this->archive->statIndex($i);
if ($stats['size'] === 0 && $stats['crc'] === 0) {
continue;
}
call_user_func_array($callback, [
'file' => $this->archive->getNameIndex($i),
'stats' => $this->archive->statIndex($i)
]);
}
}
/**
* Checks whether the file is in the archive
*
* @param $fileInArchive
*
* @return bool
*/
public function fileExists($fileInArchive): bool
{
return $this->archive->locateName($fileInArchive) !== false;
}
/**
* Sets the password to be used for decompressing
* function named usePassword for clarity
*
* @param $password
*
* @return bool
*/
public function usePassword($password): bool
{
return $this->archive->setPassword($password);
}
/**
* Returns the status of the archive as a string
*
* @return string
*/
public function getStatus(): string
{
return $this->archive->getStatusString();
}
/**
* Closes the archive and saves it
*/
public function close(): void
{
@$this->archive->close();
}
/**
* get error message
*
* @param $resultCode
* @return string
*/
private function getErrorMessage($resultCode): string
{
return match ($resultCode) {
ZipArchive::ER_EXISTS => 'ZipArchive::ER_EXISTS - File already exists.',
ZipArchive::ER_INCONS => 'ZipArchive::ER_INCONS - Zip archive inconsistent.',
ZipArchive::ER_MEMORY => 'ZipArchive::ER_MEMORY - Malloc failure.',
ZipArchive::ER_NOENT => 'ZipArchive::ER_NOENT - No such file.',
ZipArchive::ER_NOZIP => 'ZipArchive::ER_NOZIP - Not a zip archive.',
ZipArchive::ER_OPEN => 'ZipArchive::ER_OPEN - Can\'t open file.',
ZipArchive::ER_READ => 'ZipArchive::ER_READ - Read error.',
ZipArchive::ER_SEEK => 'ZipArchive::ER_SEEK - Seek error.',
default => "An unknown error [$resultCode] has occurred.",
};
}
}

View File

@ -1,626 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Support\Zip;
use Exception;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Str;
use InvalidArgumentException;
use RuntimeException;
/**
* This Zipper class is a wrapper around the ZipArchive methods with some handy functions
*
* Class Zipper
*
*/
class Zipper
{
/**
* Constant for extracting
*/
public const WHITELIST = 1;
/**
* Constant for extracting
*/
public const BLACKLIST = 2;
/**
* Constant for matching only strictly equal file names
*/
public const EXACT_MATCH = 4;
/**
* @var string Represents the current location in the archive
*/
private string $currentFolder = '';
/**
* @var Filesystem Handler to the file system
*/
private Filesystem $file;
/**
* @var ZipRepository|null Handler to the archive
*/
private ?ZipRepository $repository;
/**
* @var string The path to the current zip file
*/
private string $filePath;
/**
* Constructor
*
* @param Filesystem|null $fs
*/
public function __construct(Filesystem $fs = null)
{
$this->file = $fs ? $fs : new Filesystem();
}
/**
* Destructor
*/
public function __destruct()
{
if (is_object($this->repository)) {
$this->repository->close();
}
}
/**
* Create a new zip Archive if the file does not exists
* opens a zip archive if the file exists
*
* @param $pathToFile string The file to open
* @return $this Zipper instance
* @throws Exception
*/
public function make(string $pathToFile): Zipper
{
$new = $this->createArchiveFile($pathToFile);
$this->repository = new ZipRepository($pathToFile, $new);
$this->filePath = $pathToFile;
return $this;
}
/**
* Create a new zip archive or open an existing one
*
* @param $pathToFile
*
* @return $this
* @throws Exception
*
*/
public function zip($pathToFile): Zipper
{
$this->make($pathToFile);
return $this;
}
/**
* Create a new phar file or open one
*
* @param $pathToFile
*
* @return $this
* @throws Exception
*
*/
public function phar($pathToFile): Zipper
{
$this->make($pathToFile, 'phar');
return $this;
}
/**
* Create a new rar file or open one
*
* @param $pathToFile
*
* @return $this
* @throws Exception
*
*/
public function rar($pathToFile): Zipper
{
$this->make($pathToFile, 'rar');
return $this;
}
/**
* Extracts the opened zip archive to the specified location <br/>
* you can provide an array of files and folders and define if they should be a white list
* or a black list to extract. By default this method compares file names using "string starts with" logic
*
* @param $path string The path to extract to
* @param array $files An array of files
* @param int $methodFlags The Method the files should be treated
*
* @throws Exception
*/
public function extractTo(string $path, array $files = [], int $methodFlags = self::BLACKLIST): void
{
if (! $this->file->exists($path) && ! $this->file->makeDirectory($path, 0755, true)) {
throw new RuntimeException('Failed to create folder');
}
if ($methodFlags & self::EXACT_MATCH) {
$matchingMethod = function ($haystack) use ($files) {
return in_array($haystack, $files, true);
};
} else {
$matchingMethod = function ($haystack) use ($files) {
return Str::startsWith($haystack, $files);
};
}
if ($methodFlags & self::WHITELIST) {
$this->extractFilesInternal($path, $matchingMethod);
} else {
// blacklist - extract files that do not match with $matchingMethod
$this->extractFilesInternal($path, function ($filename) use ($matchingMethod) {
return ! $matchingMethod($filename);
});
}
}
/**
* Extracts matching files/folders from the opened zip archive to the specified location.
*
* @param string $extractToPath The path to extract to
* @param string $regex regular expression used to match files. See @link http://php.net/manual/en/reference.pcre.pattern.syntax.php
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function extractMatchingRegex(string $extractToPath, string $regex): void
{
if (empty($regex)) {
throw new InvalidArgumentException('Missing pass valid regex parameter');
}
$this->extractFilesInternal($extractToPath, function ($filename) use ($regex) {
$match = preg_match($regex, $filename);
if ($match === 1) {
return true;
} elseif ($match === false) {
//invalid pattern for preg_match raises E_WARNING and returns FALSE
//so if you have custom error_handler set to catch and throw E_WARNINGs you never end up here
//but if you have not - this will throw exception
throw new RuntimeException("regular expression match on '$filename' failed with error. Please check if pattern is valid regular expression.");
}
return false;
});
}
/**
* Gets the content of a single file if available
*
* @param $filePath string The full path (including all folders) of the file in the zip
*
* @return string returns the content or throws an exception
* @throws Exception
*
*/
public function getFileContent(string $filePath): string
{
if ($this->repository->fileExists($filePath) === false) {
throw new Exception(sprintf('The file "%s" cannot be found', $filePath));
}
return $this->repository->getFileContent($filePath);
}
/**
* Add one or multiple files to the zip.
*
* @param $pathToAdd array|string An array or string of files and folders to add
* @param mixed|null $fileName
*
* @return $this Zipper instance
*/
public function add(array|string $pathToAdd, mixed $fileName = null): Zipper
{
if (is_array($pathToAdd)) {
foreach ($pathToAdd as $key => $dir) {
if (! is_int($key)) {
$this->add($dir, $key);
} else {
$this->add($dir);
}
}
} elseif ($this->file->isFile($pathToAdd)) {
if ($fileName) {
$this->addFile($pathToAdd, $fileName);
} else {
$this->addFile($pathToAdd);
}
} else {
$this->addDir($pathToAdd);
}
return $this;
}
/**
* Add an empty directory
*
* @param $dirName
*
* @return Zipper
*/
public function addEmptyDir($dirName): Zipper
{
$this->repository->addEmptyDir($dirName);
return $this;
}
/**
* Add a file to the zip using its contents
*
* @param $filename string The name of the file to create
* @param $content string The file contents
*
* @return $this Zipper instance
*/
public function addString(string $filename, string $content): Zipper
{
$this->addFromString($filename, $content);
return $this;
}
/**
* Gets the status of the zip.
*
* @return string The status of the internal zip file
*/
public function getStatus(): string
{
return $this->repository->getStatus();
}
/**
* Remove a file or array of files and folders from the zip archive
*
* @param $fileToRemove array|string The path/array to the files in the zip
*
* @return $this Zipper instance
*/
public function remove(array|string $fileToRemove): Zipper
{
if (is_array($fileToRemove)) {
$self = $this;
$this->repository->each(function ($file) use ($fileToRemove, $self) {
if (Str::startsWith($file, $fileToRemove)) {
$self->getRepository()->removeFile($file);
}
});
} else {
$this->repository->removeFile($fileToRemove);
}
return $this;
}
/**
* Returns the path of the current zip file if there is one.
*
* @return string The path to the file
*/
public function getFilePath(): string
{
return $this->filePath;
}
/**
* Sets the password to be used for decompressing
*
* @param $password
*
* @return bool
*/
public function usePassword($password): bool
{
return $this->repository->usePassword($password);
}
/**
* Closes the zip file and frees all handles
*/
public function close(): void
{
if (null !== $this->repository) {
$this->repository->close();
}
$this->filePath = '';
}
/**
* Sets the internal folder to the given path.<br/>
* Useful for extracting only a segment of a zip file.
*
* @param string $path
*
* @return $this
*/
public function folder(string $path): Zipper
{
$this->currentFolder = $path;
return $this;
}
/**
* Resets the internal folder to the root of the zip file.
*
* @return $this
*/
public function home(): Zipper
{
$this->currentFolder = '';
return $this;
}
/**
* Deletes the archive file
*/
public function delete(): void
{
if (null !== $this->repository) {
$this->repository->close();
}
$this->file->delete($this->filePath);
$this->filePath = '';
}
/**
* Get the type of the Archive
*
* @return string
*/
public function getArchiveType(): string
{
return get_class($this->repository);
}
/**
* Get the current internal folder pointer
*
* @return string
*/
public function getCurrentFolderPath(): string
{
return $this->currentFolder;
}
/**
* Checks if a file is present in the archive
*
* @param $fileInArchive
*
* @return bool
*/
public function contains($fileInArchive): bool
{
return $this->repository->fileExists($fileInArchive);
}
/**
* @return ZipRepository
*/
public function getRepository(): ZipRepository
{
return $this->repository;
}
/**
* @return Filesystem
*/
public function getFileHandler(): Filesystem
{
return $this->file;
}
/**
* Gets the path to the internal folder
*
* @return string
*/
public function getInternalPath(): string
{
return empty($this->currentFolder) ? '' : $this->currentFolder.'/';
}
/**
* List all files that are within the archive
*
* @param string|null $regexFilter regular expression to filter returned files/folders. See @link http://php.net/manual/en/reference.pcre.pattern.syntax.php
*
* @throws RuntimeException
*
* @return array
*/
public function listFiles(string $regexFilter = null): array
{
$filesList = [];
if ($regexFilter) {
$filter = function ($file) use (&$filesList, $regexFilter) {
// push/pop an error handler here to to make sure no error/exception thrown if $expected is not a regex
set_error_handler(function () {
});
$match = preg_match($regexFilter, $file);
restore_error_handler();
if ($match === 1) {
$filesList[] = $file;
} elseif ($match === false) {
throw new RuntimeException("regular expression match on '$file' failed with error. Please check if pattern is valid regular expression.");
}
};
} else {
$filter = function ($file) use (&$filesList) {
$filesList[] = $file;
};
}
$this->repository->each($filter);
return $filesList;
}
private function getCurrentFolderWithTrailingSlash(): string
{
if (empty($this->currentFolder)) {
return '';
}
$lastChar = mb_substr($this->currentFolder, -1);
if ($lastChar !== '/' || $lastChar !== '\\') {
return $this->currentFolder.'/';
}
return $this->currentFolder;
}
//---------------------PRIVATE FUNCTIONS-------------
/**
* @param $pathToZip
*
* @return bool
* @throws Exception
*
*/
private function createArchiveFile($pathToZip): bool
{
if (! $this->file->exists($pathToZip)) {
$dirname = dirname($pathToZip);
if (! $this->file->exists($dirname) && ! $this->file->makeDirectory($dirname, 0755, true)) {
throw new RuntimeException('Failed to create folder');
} elseif (! $this->file->isWritable($dirname)) {
throw new Exception(sprintf('The path "%s" is not writeable', $pathToZip));
}
return true;
}
return false;
}
/**
* @param $pathToDir
*/
private function addDir($pathToDir): void
{
// First go over the files in this directory and add them to the repository.
foreach ($this->file->files($pathToDir) as $file) {
$this->addFile($pathToDir.'/'.basename($file));
}
// Now let's visit the subdirectories and add them, too.
foreach ($this->file->directories($pathToDir) as $dir) {
$old_folder = $this->currentFolder;
$this->currentFolder = empty($this->currentFolder) ? basename($dir) : $this->currentFolder.'/'.basename($dir);
$this->addDir($pathToDir.'/'.basename($dir));
$this->currentFolder = $old_folder;
}
}
/**
* Add the file to the zip
*
* @param string $pathToAdd
* @param string|null $fileName
*/
private function addFile(string $pathToAdd, string $fileName = null): void
{
if (! $fileName) {
$info = pathinfo($pathToAdd);
$fileName = isset($info['extension']) ?
$info['filename'].'.'.$info['extension'] :
$info['filename'];
}
$this->repository->addFile($pathToAdd, $this->getInternalPath().$fileName);
}
/**
* Add the file to the zip from content
*
* @param $filename
* @param $content
*/
private function addFromString($filename, $content): void
{
$this->repository->addFromString($this->getInternalPath().$filename, $content);
}
private function extractFilesInternal($path, callable $matchingMethod): void
{
$self = $this;
$this->repository->each(function ($fileName) use ($path, $matchingMethod, $self) {
$currentPath = $self->getCurrentFolderWithTrailingSlash();
if (! empty($currentPath) && ! Str::startsWith($fileName, $currentPath)) {
return;
}
$filename = str_replace($self->getInternalPath(), '', $fileName);
if ($matchingMethod($filename)) {
$self->extractOneFileInternal($fileName, $path);
}
});
}
/**
* @param $fileName
* @param $path
*
* @throws RuntimeException
*/
private function extractOneFileInternal($fileName, $path): void
{
$tmpPath = str_replace($this->getInternalPath(), '', $fileName);
//Prevent Zip traversal attacks
if (str_contains($fileName, '../') || str_contains($fileName, '..\\')) {
throw new RuntimeException('Special characters found within filenames');
}
// We need to create the directory first in case it doesn't exist
$dir = pathinfo($path.DIRECTORY_SEPARATOR.$tmpPath, PATHINFO_DIRNAME);
if (! $this->file->exists($dir) && ! $this->file->makeDirectory($dir, 0755, true, true)) {
throw new RuntimeException('Failed to create folders');
}
$toPath = $path.DIRECTORY_SEPARATOR.$tmpPath;
$fileStream = $this->getRepository()->getFileStream($fileName);
$this->getFileHandler()->put($toPath, $fileStream);
}
}

View File

@ -1,122 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
use Illuminate\Console\Application as Artisan;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Symfony\Component\Finder\Finder;
use Symfony\Component\VarDumper\VarDumper;
/**
* load commands
*/
if (! function_exists('loadCommands')) {
/**
* @throws ReflectionException
*/
function loadCommands($paths, $namespace, $searchPath = null): void
{
if (! $searchPath) {
$searchPath = dirname($paths).DIRECTORY_SEPARATOR;
}
$paths = Collection::make(Arr::wrap($paths))->unique()->filter(function ($path) {
return is_dir($path);
});
if ($paths->isEmpty()) {
return;
}
foreach ((new Finder())->in($paths->toArray())->files() as $command) {
$command = $namespace.str_replace(['/', '.php'], ['\\', ''], Str::after($command->getRealPath(), $searchPath));
if (is_subclass_of($command, Command::class) &&
! (new ReflectionClass($command))->isAbstract()) {
Artisan::starting(function ($artisan) use ($command) {
$artisan->resolve($command);
});
}
}
}
}
/**
* table prefix
*/
if (! function_exists('withTablePrefix')) {
function withTablePrefix(string $table): string
{
return DB::connection()->getTablePrefix().$table;
}
}
/**
* get guard name
*/
if (! function_exists('getGuardName')) {
function getGuardName(): string
{
$guardKeys = array_keys(config('catch.auth.guards'));
if (count($guardKeys)) {
return $guardKeys[0];
}
return 'admin';
}
}
/**
* get table columns
*/
if (! function_exists('getTableColumns')) {
function getTableColumns(string $table): array
{
$SQL = 'desc '.withTablePrefix($table);
$columns = [];
foreach (DB::select($SQL) as $column) {
$columns[] = $column->Field;
}
return $columns;
}
}
if (! function_exists('dd_')) {
/**
* @param mixed ...$vars
* @return never
*/
function dd_(...$vars): never
{
if (! in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && ! headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: *');
header('Access-Control-Allow-Headers: *');
foreach ($vars as $v) {
VarDumper::dump($v);
}
exit(1);
}
}

View File

@ -1,288 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Traits\DB;
use Catch\Enums\Status;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Request;
/**
* base operate
*/
trait BaseOperate
{
protected string $sortField = 'sort';
protected bool $sortDesc = true;
/**
* @var string
*/
protected string $parentId = 'parent_id';
/**
*
*
* @return void
*/
public function initializeBaseOperate(): void
{
if (property_exists($this, 'mergeCasts')) {
$this->mergeCasts($this->mergeCasts);
}
if (property_exists($this, 'mergeHidden')) {
$this->makeHidden($this->mergeHidden);
}
}
/**
* @return mixed
*/
public function getList(): mixed
{
$queryBuilder = self::query()->select($this->fieldsInList)->quickSearch();
if (in_array($this->sortField, $this->getFillable())) {
$queryBuilder = $queryBuilder->orderBy($this->sortField, $this->sortDesc ? 'desc' : 'asc');
}
$queryBuilder = $queryBuilder->orderByDesc('id');
if ($this->isPaginate) {
return $queryBuilder->paginate(Request::get('limit', $this->perPage));
}
return $queryBuilder->get();
}
/**
* save
*
* @param array $data
* @return false|mixed
*/
public function storeBy(array $data): mixed
{
if ($this->fill($this->filterData($data))->save()) {
return $this->getKey();
}
return false;
}
/**
* create
*
* @param array $data
* @return false|mixed
*/
public function createBy(array $data): mixed
{
$model = $this->newInstance();
if ($model->fill($this->filterData($data))->save()) {
return $model->getKey();
}
return false;
}
/**
* update
*
* @param $id
* @param array $data
* @return mixed
*/
public function updateBy($id, array $data): mixed
{
return $this->where($this->getKeyName(), $id)->update($this->filterData($data));
}
/**
* filter data/ remove null && empty string
*
* @param array $data
* @return array
*/
protected function filterData(array $data): array
{
// 表单保存的数据集合
$form = property_exists($this, 'form') ? $this->form : [];
foreach ($data as $k => $val) {
if (is_null($val) || (is_string($val) && ! $val)) {
unset($data[$k]);
}
if (! empty($form) && ! in_array($k, $form)) {
unset($data[$k]);
}
}
return $data;
}
/**
* get first by ID
*
* @param $id
* @param string[] $columns
* @return ?Model
*/
public function firstBy($id, array $columns = ['*']): ?Model
{
return static::where($this->getKeyName(), $id)->first($columns);
}
/**
* delete model
*
* @param $id
* @param bool $force
* @return bool|null
*/
public function deleteBy($id, bool $force = false): ?bool
{
/* @var Model $model */
$model = self::find($id);
if ($force) {
return $model->forceDelete();
}
return $model->delete();
}
/**
* disable or enable
*
* @param $id
* @param string $field
* @return bool
*/
public function disOrEnable($id, string $field = 'status'): bool
{
$model = self::firstBy($id);
$model->{$field} = $model->{$field} == Status::Enable->value() ? Status::Disable->value() : Status::Enable->value();
if ($model->save() && in_array($this->parentId, $this->getFillable())) {
$this->updateChildren($id, $field, $model->{$field});
}
return true;
}
/**
* 递归处理
*
* @param int|array $parentId
* @param string $field
* @param int $value
*/
public function updateChildren(mixed $parentId, string $field, mixed $value): void
{
if (! $parentId instanceof Arrayable) {
$parentId = Collection::make([$parentId]);
}
$childrenId = $this->whereIn('parent_id', $parentId)->pluck('id');
if ($childrenId->count()) {
if ($this->whereIn('parent_id', $parentId)->update([
$field => $value
])) {
$this->updateChildren($childrenId, $field, $value);
}
}
}
/**
* alias field
*
* @param string|array $fields
* @return string|array
*/
public function aliasField(string|array $fields): string|array
{
$table = $this->getTable();
if (is_string($fields)) {
return "{$table}.{$fields}";
}
foreach ($fields as &$field) {
$field = "{$table}.{$field}";
}
return $fields;
}
/**
* get updated at column
*
* @return string|null
*/
public function getUpdatedAtColumn(): ?string
{
$updatedAtColumn = parent::getUpdatedAtColumn();
if (! in_array(parent::getUpdatedAtColumn(), $this->getFillable())) {
$updatedAtColumn = null;
}
return $updatedAtColumn;
}
/**
* get created at column
*
* @return string|null
*/
public function getCreatedAtColumn(): ?string
{
$createdAtColumn = parent::getCreatedAtColumn();
if (! in_array(parent::getUpdatedAtColumn(), $this->getFillable())) {
$createdAtColumn = null;
}
return $createdAtColumn;
}
/**
* whit form data
*
* @return $this
*/
public function withoutForm(): static
{
if (property_exists($this, 'form') && ! empty($this->form)) {
$this->form = [];
}
return $this;
}
}

View File

@ -1,20 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Traits\DB;
trait ScopeTrait
{
// todo
}

View File

@ -1,57 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | CatchAdmin [Just Like ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2021 https://catchadmin.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://github.com/JaguarJack/catchadmin-laravel/blob/master/LICENSE.md )
// +----------------------------------------------------------------------
// | Author: JaguarJack [ njphper@gmail.com ]
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace Catch\Traits\DB;
use Illuminate\Support\Facades\DB;
/**
* transaction
*/
trait Trans
{
/**
* begin transaction
*/
public function beginTransaction(): void
{
DB::beginTransaction();
}
/**
* commit
*/
public function commit(): void
{
DB::commit();
}
/**
* rollback
*/
public function rollback(): void
{
DB::rollBack();
}
/**
* transaction
*
* @param \Closure $closure
*/
public function transaction(\Closure $closure): void
{
DB::transaction($closure);
}
}

View File

@ -11,6 +11,7 @@
"php": "^8.1",
"ext-pdo": "*",
"ext-zip": "*",
"catchadmin/core": "dev-main",
"doctrine/dbal": "^3.4",
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^9.33",
@ -73,4 +74,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}

60
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c454b8140a5fcc9a6f5d7fcbcc0afca9",
"content-hash": "d6223e0562e61f80c73a071631bcd7f4",
"packages": [
{
"name": "brick/math",
@ -62,6 +62,63 @@
],
"time": "2022-08-10T22:54:19+00:00"
},
{
"name": "catchadmin/core",
"version": "dev-main",
"source": {
"type": "git",
"url": "https://github.com/catch-admin/core.git",
"reference": "077ec15337596a66d39aad836e18dcf1a5ae5e27"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/catch-admin/core/zipball/077ec15337596a66d39aad836e18dcf1a5ae5e27",
"reference": "077ec15337596a66d39aad836e18dcf1a5ae5e27",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-pdo": "*",
"ext-zip": "*",
"php": "^8.1",
"tymon/jwt-auth": "dev-develop"
},
"default-branch": true,
"type": "library",
"extra": {
"laravel": {
"providers": [
"Catch\\Providers\\CatchAdminServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Catch\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "JaguarJack",
"email": "njphper@gmail.com"
}
],
"description": "catchadmin core package",
"support": {
"issues": "https://github.com/catch-admin/core/issues",
"source": "https://github.com/catch-admin/core/tree/main"
},
"time": "2022-12-10T10:30:05+00:00"
},
{
"name": "dflydev/dot-access-data",
"version": "v3.0.2",
@ -8414,6 +8471,7 @@
"aliases": [],
"minimum-stability": "dev",
"stability-flags": {
"catchadmin/core": 20,
"tymon/jwt-auth": 20
},
"prefer-stable": true,

View File

@ -35,4 +35,4 @@ const router: RouteRecordRaw[] = [
},
]
export default []
export default router

View File

@ -0,0 +1,43 @@
<template>
<div class="w-[28rem] min-h-[30rem] bg-white">
<el-tree :data="departments" :props="{ label: 'department_name', value: 'id'}" @node-click="clickDepartment" class="p-5" :expand-on-click-node="false" :highlight-current="true"/>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import http from '/admin/support/http'
const props = defineProps({
modelValue: {
type: Number,
default: 0
}
})
const departments = ref()
onMounted(() => {
http.get('permissions/departments').then(r => {
departments.value = r.data.data
})
})
const emits = defineEmits(['update:modelValue', 'searchDepartmentUsers'])
const clickDepartment = (node) => {
emits('update:modelValue', node.id)
emits('searchDepartmentUsers')
}
</script>
<style scoped lang="scss">
:deep(.el-tree .el-tree-node) {
@apply p-0.5
}
:deep(.el-tree .el-tree-node .el-tree-node__content) {
@apply h-8 rounded
}
</style>

View File

@ -1,35 +1,53 @@
<template>
<el-form :model="formData" label-width="120px" ref="form" v-loading="loading" class="pr-4">
<el-form-item
label="昵称"
prop="username"
:rules="[
{
required: true,
message: '昵称必须填写',
},
]"
>
<el-input v-model="formData.username" placeholder="请填写昵称" />
</el-form-item>
<el-form-item
label="邮箱"
prop="email"
:rules="[
{
required: true,
message: '邮箱必须填写',
},
{
type: 'email',
message: '邮箱格式不正确',
},
]"
>
<el-input v-model="formData.email" placeholder="请填写邮箱" />
</el-form-item>
<el-form-item label="密码" prop="password" :rules="passwordRules">
<el-input v-model="formData.password" type="password" show-password placeholder="请输入密码" />
<el-form :model="formData" label-width="80px" ref="form" v-loading="loading" class="pr-4">
<div class="flex flex-row justify-between">
<div :class="hasRoles ? 'w-1/2' : 'w-full'">
<el-form-item
label="昵称"
prop="username"
:rules="[
{
required: true,
message: '昵称必须填写',
},
]"
>
<el-input v-model="formData.username" placeholder="请填写昵称" />
</el-form-item>
<el-form-item
label="邮箱"
prop="email"
:rules="[
{
required: true,
message: '邮箱必须填写',
},
{
type: 'email',
message: '邮箱格式不正确',
},
]"
>
<el-input v-model="formData.email" placeholder="请填写邮箱" />
</el-form-item>
<el-form-item label="密码" prop="password" :rules="passwordRules">
<el-input v-model="formData.password" type="password" show-password placeholder="请输入密码" />
</el-form-item>
</div>
<div class="w-1/2" v-if="hasRoles">
<el-form-item label="部门" prop="department_id">
<el-tree-select v-model="formData.department_id" :data="departments" check-strictly :props="{ label: 'department_name', value: 'id' }" />
</el-form-item>
<el-form-item label="岗位" prop="department_id">
<el-select v-model="formData.jobs" multiple>
<el-option v-for="item in jobs" :key="item.id" :label="item.job_name" :value="item.id" />
</el-select>
</el-form-item>
</div>
</div>
<el-form-item label="角色" prop="role_id" :rules="[{ required: true, message: '请选择角色' }]">
<el-tree v-model="formData.role_id" empty-text="" :data="roles" check-strictly :props="{ label: 'role_name', value: 'id' }" show-checkbox class="w-full mt-1" default-checked-keys />
</el-form-item>
<div class="flex justify-end">
<el-button type="primary" @click="submitForm(form)">{{ $t('system.confirm') }}</el-button>
@ -42,10 +60,15 @@ import { useCreate } from '/admin/composables/curd/useCreate'
import { useShow } from '/admin/composables/curd/useShow'
import { onMounted, watch, ref } from 'vue'
import http from '../../../../resources/admin/support/http'
const props = defineProps({
primary: String | Number,
api: String,
hasRoles: {
type: Boolean,
default: true,
},
})
const passwordRules = [
@ -63,19 +86,31 @@ if (props.primary) {
passwordRules.shift()
}
const { formData, form, loading, submitForm, isClose } = useCreate(props.api, props.primary)
const { formData, form, loading, submitForm, close } = useCreate(props.api, props.primary)
if (props.primary) {
useShow(props.api, props.primary, formData)
}
const emit = defineEmits(['close'])
watch(isClose, function (value) {
if (value) {
emit('close')
}
})
const departments = ref()
const jobs = ref()
const roles = ref()
onMounted(() => {
if (props.primary) {
useShow(props.api, props.primary).then(r => {
formData.value = r.data
close(() => emit('close'))
if (props.hasRoles) {
http.get('permissions/roles').then(r => {
roles.value = r.data.data
})
http.get('permissions/departments').then(r => {
departments.value = r.data.data
})
http.get('permissions/jobs').then(r => {
jobs.value = r.data.data
})
}
})

View File

@ -1,5 +1,7 @@
<template>
<div>
<div class="flex flex-col sm:flex-row w-full justify-between">
<Department v-model="query.department_id" @searchDepartmentUsers="search" v-if="false"/>
<div class="w-full ml-5">
<Search :search="search" :reset="reset">
<template v-slot:body>
<el-form-item label="用户名">
@ -13,8 +15,8 @@
</el-form-item>
</template>
</Search>
<div class="pl-2 pr-2 bg-white dark:bg-regal-dark rounded-lg mt-4">
<Operate :show="show" />
<div class="pl-2 pr-2 bg-white dark:bg-regal-dark rounded-lg mt-4 pb-6">
<Operate :show="open" />
<el-table :data="tableData" class="mt-3" v-loading="loading">
<el-table-column prop="username" label="用户名" width="180" />
<el-table-column prop="avatar" label="头像" width="180" />
@ -27,7 +29,7 @@
<el-table-column prop="created_at" label="创建时间" />
<el-table-column label="操作" width="200">
<template #default="scope">
<Update @click="show(scope.row.id)" />
<Update @click="open(scope.row.id)" />
<Destroy @click="destroy(api, scope.row.id)" />
</template>
</el-table-column>
@ -40,36 +42,25 @@
<Create @close="close" :primary="id" :api="api" />
</Dialog>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'
import { computed, onMounted } from 'vue'
import Create from './create.vue'
import { useGetList } from '/admin/composables/curd/useGetList'
import { useDestroy } from '/admin/composables/curd/useDestroy'
import { t } from '/admin/support/helper'
import { useOpen } from '/admin/composables/curd/useOpen'
import Department from './components/department.vue'
const visible = ref<boolean>(false)
const id = ref(null)
const api = 'users'
const title = ref<string>('')
const { data, query, search, reset, loading } = useGetList(api)
const { destroy, deleted } = useDestroy()
const { open, close, title, visible, id } = useOpen()
const tableData = computed(() => data.value?.data)
const close = () => {
visible.value = false
reset()
}
const show = primary => {
title.value = primary ? t('system.edit') : t('system.add')
id.value = primary
visible.value = true
}
onMounted(() => {
search()

View File

@ -6,7 +6,7 @@ export function useOpen() {
const id = ref(null)
const title = ref<string>('')
const open = (primary: any) => {
const open = (primary: any = null) => {
title.value = primary ? t('system.edit') : t('system.add')
id.value = primary
visible.value = true

View File

@ -6,7 +6,7 @@ import { constantRoutes } from '/admin/router'
import { RouteRecordRaw } from 'vue-router'
import { toRaw } from 'vue'
import { getModuleViewComponents } from '/admin/router/constantRoutes'
const layout = '/admin/layout/index.vue'
interface Permissions {
menus: Menu[]
@ -131,7 +131,7 @@ export const usePermissionsStore = defineStore('PermissionsStore', {
// menu
let importComponent
if (permission.type === MenuType.TOP_TYPE) {
importComponent = () => import(permission.component)
importComponent = () => import('/admin/layout/index')
} else {
importComponent = viewComponents['/modules' + permission.component]
}