feat(log): 添加操作日志记录功能
- 新增 ChangeLogLogic 和 ChangeLog 模型用于记录数据变更日志 - 引入 third-party 包 chance-fyi/operation-log 实现日志记录功能 - 在 composer.json 和 config/thinkorm.php 中添加相关配置
This commit is contained in:
parent
53cb5d8f06
commit
b21bfe7657
24
app/common/logic/ChangeLogLogic.php
Normal file
24
app/common/logic/ChangeLogLogic.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\model\change_log\ChangeLog;
|
||||
|
||||
class ChangeLogLogic extends BaseLogic
|
||||
{
|
||||
|
||||
public function insert($model='',$link_id=0,$nums=0,$pm=0,$url=''):void
|
||||
{
|
||||
$info=\Chance\Log\facades\OperationLog::getLog();
|
||||
ChangeLog::create([
|
||||
'model' => $model,
|
||||
'link_id' => $link_id,
|
||||
'nums' => $nums,
|
||||
'pm' => $pm,
|
||||
'mark' => $info,
|
||||
'url' => $url,
|
||||
'create_time' => time()
|
||||
]);
|
||||
\Chance\Log\facades\OperationLog::clearLog();
|
||||
}
|
||||
}
|
19
app/common/model/change_log/ChangeLog.php
Normal file
19
app/common/model/change_log/ChangeLog.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\change_log;
|
||||
|
||||
use app\common\model\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
|
||||
/**
|
||||
* 数据变更记录模型
|
||||
* Class ChangeLog
|
||||
* @package app\common\model\change_log
|
||||
*/
|
||||
class ChangeLog extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
protected $deleteTime = 'delete_time';
|
||||
}
|
@ -57,7 +57,8 @@
|
||||
"intervention/image": "^3.6",
|
||||
"picqer/php-barcode-generator": "^2.4",
|
||||
"overtrue/easy-sms": "^2.6",
|
||||
"phpoffice/phpword": "^1.3"
|
||||
"phpoffice/phpword": "^1.3",
|
||||
"chance-fyi/operation-log": "^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-event": "For better performance. "
|
||||
|
63
composer.lock
generated
63
composer.lock
generated
@ -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": "e624460001f6646c62934c275bd79785",
|
||||
"content-hash": "005401e7f7b2cce665fa8d6a9a1cb808",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aliyuncs/oss-sdk-php",
|
||||
@ -132,6 +132,67 @@
|
||||
],
|
||||
"time": "2024-02-09T16:56:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "chance-fyi/operation-log",
|
||||
"version": "v3.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Chance-fyi/operation-log.git",
|
||||
"reference": "bfb73bc1c3dddf91772de4f37b42a41c519c67e5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Chance-fyi/operation-log/zipball/bfb73bc1c3dddf91772de4f37b42a41c519c67e5",
|
||||
"reference": "bfb73bc1c3dddf91772de4f37b42a41c519c67e5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.21@dev",
|
||||
"friendsofphp/php-cs-fixer": "dev-master",
|
||||
"hyperf/config": "^3.0@dev",
|
||||
"hyperf/database": "^3.0@dev",
|
||||
"hyperf/di": "^3.0@dev",
|
||||
"hyperf/pimple": "^2.1",
|
||||
"illuminate/database": "^8.0",
|
||||
"phpstan/phpstan": "1.11.x-dev",
|
||||
"phpunit/phpunit": "9.6.x-dev",
|
||||
"topthink/think-orm": "2.0.x-dev"
|
||||
},
|
||||
"bin": [
|
||||
"bin/chance-fyi-operation-log"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"hyperf": {
|
||||
"config": "Chance\\Log\\orm\\hyperf\\ConfigProvider"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Chance\\Log\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "chance",
|
||||
"email": "ctx_ya@qq.com"
|
||||
}
|
||||
],
|
||||
"description": "Elegant logging of operations",
|
||||
"support": {
|
||||
"issues": "https://github.com/Chance-fyi/operation-log/issues",
|
||||
"source": "https://github.com/Chance-fyi/operation-log/tree/v3.0.7"
|
||||
},
|
||||
"time": "2023-12-22T08:06:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "1.14.3",
|
||||
|
@ -25,7 +25,17 @@ return [
|
||||
// 关闭SQL监听日志
|
||||
'trigger_sql' => false,
|
||||
// 自定义分页类
|
||||
'bootstrap' => ''
|
||||
'bootstrap' => '',
|
||||
// 数据库类型
|
||||
'type' => \Chance\Log\orm\think\MySqlConnection::class,
|
||||
// 指定查询对象
|
||||
"query" => \Chance\Log\orm\think\Query::class,
|
||||
// Builder类
|
||||
"builder" => \think\db\builder\Mysql::class,
|
||||
// 模型所在的命名空间
|
||||
"modelNamespace" => "common\model",
|
||||
// 日志记录的主键
|
||||
"logKey" => "id",
|
||||
],
|
||||
'demo' => [
|
||||
// 数据库类型
|
||||
|
119
vendor/bin/chance-fyi-operation-log
vendored
Normal file
119
vendor/bin/chance-fyi-operation-log
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Proxy PHP file generated by Composer
|
||||
*
|
||||
* This file includes the referenced bin path (../chance-fyi/operation-log/bin/chance-fyi-operation-log)
|
||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
||||
*
|
||||
* @generated
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
||||
|
||||
if (PHP_VERSION_ID < 80000) {
|
||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class BinProxyWrapper
|
||||
{
|
||||
private $handle;
|
||||
private $position;
|
||||
private $realpath;
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
||||
$opened_path = substr($path, 17);
|
||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
||||
$opened_path = $this->realpath;
|
||||
$this->handle = fopen($this->realpath, $mode);
|
||||
$this->position = 0;
|
||||
|
||||
return (bool) $this->handle;
|
||||
}
|
||||
|
||||
public function stream_read($count)
|
||||
{
|
||||
$data = fread($this->handle, $count);
|
||||
|
||||
if ($this->position === 0) {
|
||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
||||
}
|
||||
|
||||
$this->position += strlen($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function stream_cast($castAs)
|
||||
{
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
public function stream_close()
|
||||
{
|
||||
fclose($this->handle);
|
||||
}
|
||||
|
||||
public function stream_lock($operation)
|
||||
{
|
||||
return $operation ? flock($this->handle, $operation) : true;
|
||||
}
|
||||
|
||||
public function stream_seek($offset, $whence)
|
||||
{
|
||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
||||
$this->position = ftell($this->handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function stream_eof()
|
||||
{
|
||||
return feof($this->handle);
|
||||
}
|
||||
|
||||
public function stream_stat()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function stream_set_option($option, $arg1, $arg2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function url_stat($path, $flags)
|
||||
{
|
||||
$path = substr($path, 17);
|
||||
if (file_exists($path)) {
|
||||
return stat($path);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
||||
) {
|
||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/chance-fyi/operation-log/bin/chance-fyi-operation-log');
|
||||
}
|
||||
}
|
||||
|
||||
return include __DIR__ . '/..'.'/chance-fyi/operation-log/bin/chance-fyi-operation-log';
|
57
vendor/chance-fyi/operation-log/.github/workflows/test.yml
vendored
Normal file
57
vendor/chance-fyi/operation-log/.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
name: PHPUnit
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php: [ 8.0, 8.1, 8.2 ]
|
||||
swoole: [ '', swoole ]
|
||||
|
||||
name: PHP ${{ matrix.php }} ${{ matrix.swoole }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Start MySQL
|
||||
run: docker compose up -d mysql mysql1
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: pdo, pdo_mysql, ${{ matrix.swoole }}
|
||||
ini-values: error_reporting=E_ALL
|
||||
tools: composer:v2
|
||||
coverage: none
|
||||
|
||||
- name: Composer install
|
||||
run: composer install
|
||||
|
||||
- name: Static analysis
|
||||
run: composer analyse
|
||||
|
||||
- name: Wait for MySQL
|
||||
run: |
|
||||
while ! docker compose exec mysql mysql --user=root --password=root -e "SELECT 1" >/dev/null 2>&1 || ! docker compose exec mysql1 mysql --user=root --password=root -e "SELECT 1" >/dev/null 2>&1; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
MYSQL_HOST: 127.0.0.1
|
||||
MYSQL_PORT: 33060
|
||||
MYSQL1_PORT: 33061
|
||||
run: composer test
|
||||
|
||||
- name: Close MySQL
|
||||
run: docker compose down
|
28
vendor/chance-fyi/operation-log/.php-cs-fixer.php
vendored
Normal file
28
vendor/chance-fyi/operation-log/.php-cs-fixer.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use PhpCsFixer\Config;
|
||||
use PhpCsFixer\Finder;
|
||||
|
||||
return (new Config())
|
||||
->setFinder(
|
||||
Finder::create()
|
||||
->in(__DIR__)
|
||||
->exclude('vendor')
|
||||
)
|
||||
->setRules([
|
||||
'@Symfony' => true,
|
||||
'@PhpCsFixer' => true,
|
||||
'@DoctrineAnnotation' => true,
|
||||
'list_syntax' => [
|
||||
'syntax' => 'short'
|
||||
],
|
||||
'concat_space' => [
|
||||
'spacing' => 'one'
|
||||
],
|
||||
'global_namespace_import' => [
|
||||
'import_classes' => true,
|
||||
'import_constants' => true,
|
||||
'import_functions' => true,
|
||||
],
|
||||
])
|
||||
->setUsingCache(false);
|
21
vendor/chance-fyi/operation-log/LICENSE
vendored
Normal file
21
vendor/chance-fyi/operation-log/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Chance
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
247
vendor/chance-fyi/operation-log/README.md
vendored
Normal file
247
vendor/chance-fyi/operation-log/README.md
vendored
Normal file
@ -0,0 +1,247 @@
|
||||
支持 Laravel 的 ORM 、Hyperf 的 ORM 与 ThinkPHP 的 ORM 。可以生成增、删、改,包括批量增、删、改,以及 使用 DB 操作的日志。
|
||||
|
||||
通过~~模型事件~~与获取器,自动生成可读性高的操作日志。2.0 版本已弃用模型事件,因为批量操作没有触发模型事件,使用模型事件无法覆盖所有模型对数据库的操作以及 DB 操作。
|
||||
|
||||
### 安装
|
||||
|
||||
> composer require chance-fyi/operation-log
|
||||
|
||||
### 注意
|
||||
|
||||
> 因为使用了单例,所以在常驻内存的框架中使用一定要在每次请求结束之后将生成的日志清空。
|
||||
|
||||
### 使用 Laravel 的 ORM
|
||||
|
||||
首先在数据库的配置文件 `config/database.php` 中增加两个配置项 `modelNamespace` 和 `logKey`。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
return [
|
||||
'default' => env('DB_CONNECTION', 'mysql'),
|
||||
...
|
||||
'connections' => [
|
||||
'mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'forge'),
|
||||
'username' => env('DB_USERNAME', 'forge'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
...
|
||||
...
|
||||
// 模型所在的命名空间
|
||||
"modelNamespace" => "Chance\Log\Test\model",
|
||||
// 日志记录的主键
|
||||
"logKey" => "id",
|
||||
],
|
||||
...
|
||||
]
|
||||
...
|
||||
];
|
||||
```
|
||||
|
||||
然后注册 MySQL 数据库连接的解析器。
|
||||
|
||||
```php
|
||||
\Illuminate\Database\Connection::resolverFor('mysql', function ($connection, $database, $prefix, $config) {
|
||||
return new \Chance\Log\orm\illuminate\MySqlConnection($connection, $database, $prefix, $config);
|
||||
});
|
||||
```
|
||||
|
||||
### 使用 ThinkPHP 的 ORM
|
||||
|
||||
在数据库的配置文件 config/database.php 中增加三个配置项 `query`、`modelNamespace` 和 `logKey`,并修改 `type` 与 `builder`。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
return [
|
||||
'default' => env('database.driver', 'mysql'),
|
||||
...
|
||||
'connections' => [
|
||||
'mysql' => [
|
||||
// 服务器地址
|
||||
'hostname' => env('database.hostname', '127.0.0.1'),
|
||||
// 数据库名
|
||||
'database' => env('database.database', ''),
|
||||
// 用户名
|
||||
'username' => env('database.username', 'root'),
|
||||
// 密码
|
||||
'password' => env('database.password', ''),
|
||||
// 端口
|
||||
'hostport' => env('database.hostport', '3306'),
|
||||
...
|
||||
...
|
||||
// 数据库类型
|
||||
'type' => \Chance\Log\orm\think\MySqlConnection::class,
|
||||
// 指定查询对象
|
||||
"query" => \Chance\Log\orm\think\Query::class,
|
||||
// Builder类
|
||||
"builder" => \think\db\builder\Mysql::class,
|
||||
// 模型所在的命名空间
|
||||
"modelNamespace" => "Chance\Log\Test\model",
|
||||
// 日志记录的主键
|
||||
"logKey" => "id",
|
||||
],
|
||||
// 更多的数据库配置信息
|
||||
...
|
||||
],
|
||||
...
|
||||
];
|
||||
```
|
||||
|
||||
### 日志主键
|
||||
|
||||
可在模型中设置`$logKey`属性修改需要记录的主键名称。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace Chance\Log\Test\model;
|
||||
|
||||
class User extends BaseModel
|
||||
{
|
||||
// 日志记录的主键名称
|
||||
public string $logKey = 'id';
|
||||
}
|
||||
```
|
||||
|
||||
### 可读性设置
|
||||
|
||||
通过表注释、字段注释与获取器来生成可读性的日志。
|
||||
|
||||
**表注释与字段注释**
|
||||
|
||||

|
||||
|
||||
也可以在模型中通过`$tableComment`与`$columnComment`设置表注释与字段注释。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace Chance\Log\Test\model;
|
||||
|
||||
class User extends BaseModel
|
||||
{
|
||||
// 表注释
|
||||
public $tableComment = '用户';
|
||||
// 字段注释
|
||||
public $columnComment = [
|
||||
'name' => '姓名',
|
||||
'sex' => '性别',
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
**获取器**
|
||||
|
||||
设置一个名为`字段名_text`的获取器。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace Chance\Log\Test\model;
|
||||
|
||||
class User extends BaseModel
|
||||
{
|
||||
// Laravel ORM 获取器设置方法
|
||||
public function getSexTextAttribute($key): string
|
||||
{
|
||||
return ['女','男'][($key ?? $this->sex)] ?? '未知';
|
||||
}
|
||||
|
||||
// ThinkPHP ORM 获取器设置方法
|
||||
public function getSexTextAttr($key): string
|
||||
{
|
||||
return ['女','男'][($key ?? $this->sex)] ?? '未知';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 日志生成忽略的字段
|
||||
|
||||
可在模型中通过 `$ignoreLogFields` 设置该表不希望生成日志的字段。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace Chance\Log\Test\model;
|
||||
|
||||
class User extends BaseModel
|
||||
{
|
||||
// 日志生成忽略的字段
|
||||
public $ignoreLogFields = [
|
||||
'create_time',
|
||||
'update_time',
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
### 数据表不生成日志
|
||||
|
||||
可在模型中通过 `$doNotRecordLog` 设置该表不在生成日志。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace Chance\Log\Test\model;
|
||||
|
||||
class User extends BaseModel
|
||||
{
|
||||
// 不生成该表的日志
|
||||
public $doNotRecordLog = true;
|
||||
}
|
||||
```
|
||||
|
||||
### 表模型映射关系
|
||||
|
||||
如果模型文件名与表名不相同,将查找不到表所对应的模型。也就无法完成上面一些,需要在模型中设置的功能。所以可以设置一个表与模型的映射关系,来帮助查找表所对应的模型。
|
||||
|
||||
如果是在 ThinkPHP、Laravel、webman 框架中使用,可使用 `php vendor/bin/chance-fyi-operation-log 模型所在目录` 命令来自动构建所选目录中递归查找到的所有模型与表的映射关系。如果命令执行失败,也可选择手动维护映射关系,并通过以下方法手动注入表模型映射关系。
|
||||
|
||||
```php
|
||||
\Chance\Log\facades\OperationLog::setTableModelMapping([
|
||||
"database1" => [
|
||||
"table1" => "app\\model\\Table1",
|
||||
"table2" => "app\\model\\Table2",
|
||||
],
|
||||
"database2" => [],
|
||||
]);
|
||||
```
|
||||
|
||||
### 获取日志信息
|
||||
|
||||
```php
|
||||
\Chance\Log\facades\OperationLog::getLog();
|
||||
```
|
||||
|
||||
### 清除日志信息
|
||||
|
||||
```php
|
||||
\Chance\Log\facades\OperationLog::clearLog();
|
||||
```
|
||||
|
||||
### 启用禁用
|
||||
|
||||
```php
|
||||
# 启用 (默认)
|
||||
\Chance\Log\facades\OperationLog::enable();
|
||||
# 禁用
|
||||
\Chance\Log\facades\OperationLog::disable();
|
||||
```
|
||||
|
||||
### 效果图
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
117
vendor/chance-fyi/operation-log/bin/chance-fyi-operation-log
vendored
Normal file
117
vendor/chance-fyi/operation-log/bin/chance-fyi-operation-log
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2023/1/11 15:34
|
||||
*/
|
||||
|
||||
$dir = __DIR__ . "/..";
|
||||
if (!file_exists($dir . "/autoload.php")) {
|
||||
$dir = __DIR__ . "/../vendor";
|
||||
}
|
||||
if (!file_exists($dir . "/autoload.php")) {
|
||||
$dir = __DIR__ . "/../../..";
|
||||
}
|
||||
if (!file_exists($dir . "/autoload.php")) {
|
||||
echo "Autoload not found." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
require $dir . "/autoload.php";
|
||||
|
||||
// ThinkPHP
|
||||
if (class_exists(think\App::class)) {
|
||||
(new think\App())->initialize();
|
||||
}// Laravel
|
||||
elseif (class_exists(Illuminate\Foundation\Application::class)) {
|
||||
$app = new Illuminate\Foundation\Application($dir . "/../");
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Http\Kernel::class,
|
||||
App\Http\Kernel::class
|
||||
);
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Debug\ExceptionHandler::class,
|
||||
App\Exceptions\Handler::class
|
||||
);
|
||||
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
|
||||
$kernel->bootstrap();
|
||||
}// webman
|
||||
elseif (class_exists(support\App::class)) {
|
||||
support\App::loadAllConfig();
|
||||
support\bootstrap\LaravelDb::start(null);
|
||||
}
|
||||
|
||||
array_shift($argv);
|
||||
$map = [];
|
||||
foreach ($argv as $directory) {
|
||||
if (!is_dir($directory)) {
|
||||
echo "$directory is not a directory" . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
$files = new RegexIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)), "/\.php$/");
|
||||
foreach ($files as $file) {
|
||||
$class = getClassNamespaceFromFile($file);
|
||||
if (!class_exists($class)) {
|
||||
continue;
|
||||
}
|
||||
$reflect = new ReflectionClass($class);
|
||||
if (
|
||||
!preg_match("/\\\\model(s)?\\\\/i", $class)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$object = $reflect->newInstanceArgs();
|
||||
if (class_exists(think\Model::class) && $object instanceof think\Model) {
|
||||
$map[$object->getConfig("database")][$object->getTable()] = $class;
|
||||
continue;
|
||||
}
|
||||
if (class_exists(Illuminate\Database\Eloquent\Model::class) && $object instanceof Illuminate\Database\Eloquent\Model) {
|
||||
$map[$object->getConnection()->getDatabaseName()][$object->getConnection()->getTablePrefix() . $object->getTable()] = $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data = <<<HEREA
|
||||
<?php
|
||||
|
||||
return %s;
|
||||
HEREA;
|
||||
file_put_contents("$dir/chance-fyi/operation-log/cache/table-model-mapping.php", sprintf($data, var_export($map, true)));
|
||||
|
||||
echo "Success" . PHP_EOL;
|
||||
|
||||
function getClassNamespaceFromFile($file): string
|
||||
{
|
||||
$content = file_get_contents($file->getRealPath());
|
||||
$tokens = token_get_all($content);
|
||||
$namespace = "";
|
||||
$class = "";
|
||||
$count = count($tokens);
|
||||
$i = 0;
|
||||
while ($i < $count) {
|
||||
$token = $tokens[$i];
|
||||
if (is_array($token) && $token[0] == T_NAMESPACE) {
|
||||
while (++$i < $count) {
|
||||
if ($tokens[$i] === ';') {
|
||||
$namespace = trim($namespace);
|
||||
break;
|
||||
}
|
||||
$namespace .= is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i];
|
||||
}
|
||||
}
|
||||
if (
|
||||
is_array($token)
|
||||
&& $i >= 2
|
||||
&& $tokens[$i - 2][0] == T_CLASS
|
||||
&& $tokens[$i - 1][0] == T_WHITESPACE
|
||||
&& $token[0] == T_STRING
|
||||
) {
|
||||
$class = trim($tokens[$i][1]);
|
||||
break;
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $namespace . "\\" . $class;
|
||||
}
|
9
vendor/chance-fyi/operation-log/cache/table-model-mapping.php
vendored
Normal file
9
vendor/chance-fyi/operation-log/cache/table-model-mapping.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'database1' => [
|
||||
'table1' => 'app\\model\\Table1',
|
||||
'table2' => 'app\\model\\Table2',
|
||||
],
|
||||
'database2' => [],
|
||||
];
|
52
vendor/chance-fyi/operation-log/composer.json
vendored
Normal file
52
vendor/chance-fyi/operation-log/composer.json
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "chance-fyi/operation-log",
|
||||
"description": "Elegant logging of operations",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Chance\\Log\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Chance\\Log\\Test\\": "tests/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "chance",
|
||||
"email": "ctx_ya@qq.com"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/database": "^8.0",
|
||||
"topthink/think-orm": "2.0.x-dev",
|
||||
"fakerphp/faker": "^1.21@dev",
|
||||
"friendsofphp/php-cs-fixer": "dev-master",
|
||||
"phpunit/phpunit": "9.6.x-dev",
|
||||
"phpstan/phpstan": "1.11.x-dev",
|
||||
"hyperf/database": "^3.0@dev",
|
||||
"hyperf/di": "^3.0@dev",
|
||||
"hyperf/pimple": "^2.1",
|
||||
"hyperf/config": "^3.0@dev"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit",
|
||||
"cs-fix": "php-cs-fixer fix $1",
|
||||
"analyse": "phpstan analyse --memory-limit=-1"
|
||||
},
|
||||
"bin": [
|
||||
"bin/chance-fyi-operation-log"
|
||||
],
|
||||
"extra": {
|
||||
"hyperf": {
|
||||
"config": "Chance\\Log\\orm\\hyperf\\ConfigProvider"
|
||||
}
|
||||
}
|
||||
}
|
36
vendor/chance-fyi/operation-log/src/Facade.php
vendored
Normal file
36
vendor/chance-fyi/operation-log/src/Facade.php
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/9/28 17:15.
|
||||
*/
|
||||
|
||||
namespace Chance\Log;
|
||||
|
||||
abstract class Facade
|
||||
{
|
||||
protected static array $resolvedInstance;
|
||||
|
||||
public static function __callStatic($method, $args)
|
||||
{
|
||||
$class = static::getFacadeClass();
|
||||
$instance = self::$resolvedInstance[$class] ?? new $class();
|
||||
self::$resolvedInstance[$class] = $instance;
|
||||
|
||||
return call_user_func_array([$instance, $method], $args);
|
||||
}
|
||||
|
||||
public static function setResolvedInstance($class, $instance): void
|
||||
{
|
||||
self::$resolvedInstance[$class] = $instance;
|
||||
}
|
||||
|
||||
public static function getResolvedInstance($class)
|
||||
{
|
||||
return self::$resolvedInstance[$class] ?? null;
|
||||
}
|
||||
|
||||
protected static function getFacadeClass(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
289
vendor/chance-fyi/operation-log/src/OperationLog.php
vendored
Normal file
289
vendor/chance-fyi/operation-log/src/OperationLog.php
vendored
Normal file
@ -0,0 +1,289 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/3/9 10:27.
|
||||
*/
|
||||
|
||||
namespace Chance\Log;
|
||||
|
||||
use Chance\Log\facades\OperationLog as OperationLogFacade;
|
||||
use Hyperf\Context\Context as HyperfContext;
|
||||
use Hyperf\Database\Model\Model as HyperfModel;
|
||||
use Illuminate\Database\Eloquent\Model as LaravelModel;
|
||||
use think\Model as ThinkModel;
|
||||
use Webman\Context as WebmanContext;
|
||||
|
||||
/**
|
||||
* @method getPk($model)
|
||||
* @method getTableName($model)
|
||||
* @method getDatabaseName($model)
|
||||
* @method executeSQL($model, $sql)
|
||||
* @method getAttributes($model)
|
||||
* @method getChangedAttributes($model)
|
||||
* @method getValue($model, string $key)
|
||||
* @method getOldValue($model, string $key)
|
||||
*/
|
||||
class OperationLog
|
||||
{
|
||||
public const CREATED = 'created';
|
||||
public const BATCH_CREATED = 'batch_created';
|
||||
public const UPDATED = 'updated';
|
||||
public const BATCH_UPDATED = 'batch_updated';
|
||||
public const DELETED = 'deleted';
|
||||
public const BATCH_DELETED = 'batch_deleted';
|
||||
private const CONTEXT_LOG = 'context_operation_log';
|
||||
private const CONTEXT_STATUS = 'context_operation_log_status';
|
||||
|
||||
protected array $tableComment;
|
||||
|
||||
protected array $columnComment;
|
||||
|
||||
protected array $log = [''];
|
||||
|
||||
protected array $tableModelMapping = [];
|
||||
|
||||
protected bool $status = true;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (Facade::getResolvedInstance(self::class)) {
|
||||
$this->setTableModelMapping(OperationLogFacade::getTableModelMapping());
|
||||
}
|
||||
Facade::setResolvedInstance(self::class, $this);
|
||||
}
|
||||
|
||||
public function getLog(): string
|
||||
{
|
||||
$log = $this->getRawLog();
|
||||
$this->clearLog();
|
||||
|
||||
return trim(implode('', $log), PHP_EOL);
|
||||
}
|
||||
|
||||
public function clearLog(): void
|
||||
{
|
||||
$this->setRawLog(['']);
|
||||
}
|
||||
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
$log = $this->getRawLog();
|
||||
$log[] = '';
|
||||
$this->setRawLog($log);
|
||||
}
|
||||
|
||||
public function rollBackTransaction(int $toLevel): void
|
||||
{
|
||||
$this->setRawLog(array_slice($this->getRawLog(), 0, $toLevel));
|
||||
if (0 === count($this->getRawLog())) {
|
||||
$this->clearLog();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get table comment.
|
||||
*/
|
||||
public function getTableComment(ThinkModel|LaravelModel|HyperfModel $model): string
|
||||
{
|
||||
$table = $this->getTableName($model);
|
||||
if (isset($model->tableComment)) {
|
||||
return $model->tableComment ?: $table;
|
||||
}
|
||||
|
||||
$databaseName = $this->getDatabaseName($model);
|
||||
$comment = '';
|
||||
|
||||
if (empty($this->tableComment[$databaseName])) {
|
||||
$this->tableComment[$databaseName] = $this->executeSQL($model, "SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = '{$databaseName}'");
|
||||
}
|
||||
|
||||
foreach ($this->tableComment[$databaseName] as $item) {
|
||||
if (is_array($item) && $item['TABLE_NAME'] == $table) {
|
||||
$comment = $item['TABLE_COMMENT'];
|
||||
|
||||
break;
|
||||
}
|
||||
if (is_object($item) && $item->TABLE_NAME == $table) {
|
||||
$comment = $item->TABLE_COMMENT;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (string) ($comment ?: $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field comment.
|
||||
*/
|
||||
public function getColumnComment(ThinkModel|LaravelModel|HyperfModel $model, string $field): string
|
||||
{
|
||||
if (isset($model->columnComment)) {
|
||||
return $model->columnComment[$field] ?? $field;
|
||||
}
|
||||
|
||||
$databaseName = $this->getDatabaseName($model);
|
||||
$table = $this->getTableName($model);
|
||||
$comment = '';
|
||||
|
||||
if (empty($this->columnComment[$databaseName])) {
|
||||
$this->columnComment[$databaseName] = $this->executeSQL($model, "SELECT TABLE_NAME,COLUMN_NAME,COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '{$databaseName}'");
|
||||
}
|
||||
foreach ($this->columnComment[$databaseName] as $item) {
|
||||
if (is_array($item) && $item['TABLE_NAME'] == $table && $item['COLUMN_NAME'] == $field) {
|
||||
$comment = $item['COLUMN_COMMENT'];
|
||||
|
||||
break;
|
||||
}
|
||||
if (is_object($item) && $item->TABLE_NAME == $table && $item->COLUMN_NAME == $field) {
|
||||
$comment = $item->COLUMN_COMMENT;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (string) ($comment ?: $field);
|
||||
}
|
||||
|
||||
public function generateLog(ThinkModel|LaravelModel|HyperfModel $model, string $type): void
|
||||
{
|
||||
if ($model->doNotRecordLog ?? false) {
|
||||
return;
|
||||
}
|
||||
$logKey = $model->logKey ?? $this->getPk($model);
|
||||
$typeText = [
|
||||
self::CREATED => '创建',
|
||||
self::BATCH_CREATED => '批量创建',
|
||||
self::UPDATED => '修改',
|
||||
self::BATCH_UPDATED => '批量修改',
|
||||
self::DELETED => '删除',
|
||||
self::BATCH_DELETED => '批量删除',
|
||||
][$type];
|
||||
$logHeader = "{$typeText} {$this->getTableComment($model)}" .
|
||||
(in_array($type, [self::CREATED, self::UPDATED, self::BATCH_UPDATED, self::DELETED, self::BATCH_DELETED]) ? " ({$this->getColumnComment($model, $logKey)}:{$model->{$logKey}}):" : ':');
|
||||
$log = '';
|
||||
|
||||
switch ($type) {
|
||||
case self::CREATED:
|
||||
case self::BATCH_CREATED:
|
||||
case self::DELETED:
|
||||
case self::BATCH_DELETED:
|
||||
foreach ($this->getAttributes($model) as $key => $value) {
|
||||
if ($logKey === $key
|
||||
|| (isset($model->ignoreLogFields) && is_array($model->ignoreLogFields) && in_array($key, $model->ignoreLogFields))) {
|
||||
continue;
|
||||
}
|
||||
$log .= "{$this->getColumnComment($model, $key)}:{$this->getValue($model, $key)},";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case self::UPDATED:
|
||||
case self::BATCH_UPDATED:
|
||||
foreach ($this->getChangedAttributes($model) as $key => $value) {
|
||||
$keys = explode('.', $key);
|
||||
$key = end($keys);
|
||||
if ($logKey === $key
|
||||
|| (isset($model->ignoreLogFields) && is_array($model->ignoreLogFields) && in_array($key, $model->ignoreLogFields))) {
|
||||
continue;
|
||||
}
|
||||
$log .= "{$this->getColumnComment($model, $key)}由:{$this->getOldValue($model, $key)} 改为:{$this->getValue($model, $key)},";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if (!empty($log)) {
|
||||
$log = mb_substr($log, 0, mb_strlen($log, 'utf8') - 1, 'utf8');
|
||||
$logs = $this->getRawLog();
|
||||
array_splice($logs, -1, 1, end($logs) . $logHeader . $log . PHP_EOL);
|
||||
$this->setRawLog($logs);
|
||||
}
|
||||
}
|
||||
|
||||
public function setTableModelMapping(array $map): void
|
||||
{
|
||||
$this->tableModelMapping = $map;
|
||||
}
|
||||
|
||||
public function getTableModelMapping(): array
|
||||
{
|
||||
return $this->tableModelMapping;
|
||||
}
|
||||
|
||||
public function status(): bool
|
||||
{
|
||||
if (extension_loaded('swoole') && class_exists(HyperfContext::class)) {
|
||||
return HyperfContext::get(self::CONTEXT_STATUS, true);
|
||||
}
|
||||
|
||||
if (class_exists(WebmanContext::class)) {
|
||||
return WebmanContext::get(self::CONTEXT_STATUS) ?? true;
|
||||
}
|
||||
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function enable(): void
|
||||
{
|
||||
if (extension_loaded('swoole') && class_exists(HyperfContext::class)) {
|
||||
HyperfContext::set(self::CONTEXT_STATUS, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (class_exists(WebmanContext::class)) {
|
||||
WebmanContext::set(self::CONTEXT_STATUS, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->status = true;
|
||||
}
|
||||
|
||||
public function disable(): void
|
||||
{
|
||||
if (extension_loaded('swoole') && class_exists(HyperfContext::class)) {
|
||||
HyperfContext::set(self::CONTEXT_STATUS, false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (class_exists(WebmanContext::class)) {
|
||||
WebmanContext::set(self::CONTEXT_STATUS, false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->status = false;
|
||||
}
|
||||
|
||||
private function getRawLog()
|
||||
{
|
||||
if (extension_loaded('swoole') && class_exists(HyperfContext::class)) {
|
||||
return HyperfContext::get(self::CONTEXT_LOG, ['']);
|
||||
}
|
||||
|
||||
if (class_exists(WebmanContext::class)) {
|
||||
return WebmanContext::get(self::CONTEXT_LOG) ?? [''];
|
||||
}
|
||||
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
private function setRawLog(array $log): void
|
||||
{
|
||||
if (extension_loaded('swoole') && class_exists(HyperfContext::class)) {
|
||||
HyperfContext::set(self::CONTEXT_LOG, $log);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (class_exists(WebmanContext::class)) {
|
||||
WebmanContext::set(self::CONTEXT_LOG, $log);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log = $log;
|
||||
}
|
||||
}
|
60
vendor/chance-fyi/operation-log/src/OperationLogInterface.php
vendored
Normal file
60
vendor/chance-fyi/operation-log/src/OperationLogInterface.php
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/3/9 9:48.
|
||||
*/
|
||||
|
||||
namespace Chance\Log;
|
||||
|
||||
use Hyperf\Database\Model\Model as HyperfModel;
|
||||
use Illuminate\Database\Eloquent\Model as LaravelModel;
|
||||
use think\Model as ThinkModel;
|
||||
|
||||
interface OperationLogInterface
|
||||
{
|
||||
/**
|
||||
* Get primary key.
|
||||
*/
|
||||
public function getPk(ThinkModel|LaravelModel|HyperfModel $model): string;
|
||||
|
||||
/**
|
||||
* Get table name.
|
||||
*/
|
||||
public function getTableName(ThinkModel|LaravelModel|HyperfModel $model): string;
|
||||
|
||||
/**
|
||||
* Get database name.
|
||||
*/
|
||||
public function getDatabaseName(ThinkModel|LaravelModel|HyperfModel $model): string;
|
||||
|
||||
/**
|
||||
* Execute SQL.
|
||||
*/
|
||||
public function executeSQL(ThinkModel|LaravelModel|HyperfModel $model, string $sql): mixed;
|
||||
|
||||
/**
|
||||
* Obtain all current attributes on the model.
|
||||
*/
|
||||
public function getAttributes(ThinkModel|LaravelModel|HyperfModel $model): array;
|
||||
|
||||
/**
|
||||
* Obtain the currently modified properties on the model.
|
||||
*/
|
||||
public function getChangedAttributes(ThinkModel|LaravelModel|HyperfModel $model): array;
|
||||
|
||||
public function getValue(ThinkModel|LaravelModel|HyperfModel $model, string $key): string;
|
||||
|
||||
public function getOldValue(ThinkModel|LaravelModel|HyperfModel $model, string $key): string;
|
||||
|
||||
public function created(ThinkModel|LaravelModel|HyperfModel $model, array $data): void;
|
||||
|
||||
public function updated(ThinkModel|LaravelModel|HyperfModel $model, array $oldData, array $data): void;
|
||||
|
||||
public function deleted(ThinkModel|LaravelModel|HyperfModel $model, array $data): void;
|
||||
|
||||
public function batchCreated(ThinkModel|LaravelModel|HyperfModel $model, array $data): void;
|
||||
|
||||
public function batchUpdated(ThinkModel|LaravelModel|HyperfModel $model, array $oldData, array $data): void;
|
||||
|
||||
public function batchDeleted($model, array $data): void;
|
||||
}
|
32
vendor/chance-fyi/operation-log/src/facades/HyperfOrmLog.php
vendored
Normal file
32
vendor/chance-fyi/operation-log/src/facades/HyperfOrmLog.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/10/6 15:15.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\facades;
|
||||
|
||||
use Chance\Log\Facade;
|
||||
use Chance\Log\orm\hyperf\Log;
|
||||
use Hyperf\Database\Model\Model;
|
||||
|
||||
/**
|
||||
* @mixin Log
|
||||
*
|
||||
* @method static created(Model $model, array $data)
|
||||
* @method static updated(Model $model, array $oldData, array $data)
|
||||
* @method static deleted(Model $model, array $data)
|
||||
* @method static batchCreated(Model $model, array $data)
|
||||
* @method static batchUpdated(Model $model, array $oldData, array $data)
|
||||
* @method static batchDeleted(Model $model, array $data)
|
||||
* @method static beginTransaction()
|
||||
* @method static rollBackTransaction(int $toLevel)
|
||||
* @method static status()
|
||||
*/
|
||||
class HyperfOrmLog extends Facade
|
||||
{
|
||||
protected static function getFacadeClass(): string
|
||||
{
|
||||
return Log::class;
|
||||
}
|
||||
}
|
32
vendor/chance-fyi/operation-log/src/facades/IlluminateOrmLog.php
vendored
Normal file
32
vendor/chance-fyi/operation-log/src/facades/IlluminateOrmLog.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/10/6 15:15.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\facades;
|
||||
|
||||
use Chance\Log\Facade;
|
||||
use Chance\Log\orm\illuminate\Log;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @mixin Log
|
||||
*
|
||||
* @method static created(Model $model, array $data)
|
||||
* @method static updated(Model $model, array $oldData, array $data)
|
||||
* @method static deleted(Model $model, array $data)
|
||||
* @method static batchCreated(Model $model, array $data)
|
||||
* @method static batchUpdated(Model $model, array $oldData, array $data)
|
||||
* @method static batchDeleted(Model $model, array $data)
|
||||
* @method static beginTransaction()
|
||||
* @method static rollBackTransaction(int $toLevel)
|
||||
* @method static status()
|
||||
*/
|
||||
class IlluminateOrmLog extends Facade
|
||||
{
|
||||
protected static function getFacadeClass(): string
|
||||
{
|
||||
return Log::class;
|
||||
}
|
||||
}
|
27
vendor/chance-fyi/operation-log/src/facades/OperationLog.php
vendored
Normal file
27
vendor/chance-fyi/operation-log/src/facades/OperationLog.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/9/28 17:15.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\facades;
|
||||
|
||||
use Chance\Log\Facade;
|
||||
|
||||
/**
|
||||
* @mixin \Chance\Log\OperationLog
|
||||
*
|
||||
* @method static getLog()
|
||||
* @method static clearLog()
|
||||
* @method static setTableModelMapping(array $map)
|
||||
* @method static getTableModelMapping()
|
||||
* @method static enable()
|
||||
* @method static disable()
|
||||
*/
|
||||
class OperationLog extends Facade
|
||||
{
|
||||
protected static function getFacadeClass(): string
|
||||
{
|
||||
return \Chance\Log\OperationLog::class;
|
||||
}
|
||||
}
|
32
vendor/chance-fyi/operation-log/src/facades/ThinkOrmLog.php
vendored
Normal file
32
vendor/chance-fyi/operation-log/src/facades/ThinkOrmLog.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/10/6 15:14.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\facades;
|
||||
|
||||
use Chance\Log\Facade;
|
||||
use Chance\Log\orm\think\Log;
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin Log
|
||||
*
|
||||
* @method static created(Model $model, array $data)
|
||||
* @method static updated(Model $model, array $oldData, array $data)
|
||||
* @method static deleted(Model $model, array $data)
|
||||
* @method static batchCreated(Model $param, array $data)
|
||||
* @method static batchUpdated(Model $model, $oldData, array $data)
|
||||
* @method static batchDeleted(Model $model, array $data)
|
||||
* @method static beginTransaction()
|
||||
* @method static rollBackTransaction(int $toLevel)
|
||||
* @method static status()
|
||||
*/
|
||||
class ThinkOrmLog extends Facade
|
||||
{
|
||||
protected static function getFacadeClass(): string
|
||||
{
|
||||
return Log::class;
|
||||
}
|
||||
}
|
146
vendor/chance-fyi/operation-log/src/orm/hyperf/Builder.php
vendored
Normal file
146
vendor/chance-fyi/operation-log/src/orm/hyperf/Builder.php
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2023/7/11 13:56.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\hyperf;
|
||||
|
||||
use Chance\Log\facades\HyperfOrmLog;
|
||||
use Chance\Log\facades\OperationLog;
|
||||
use Hyperf\Database\Connection;
|
||||
use Hyperf\Database\Model\Model;
|
||||
use Hyperf\Stringable\Str;
|
||||
|
||||
class Builder extends \Hyperf\Database\Query\Builder
|
||||
{
|
||||
public function insert(array $values): bool
|
||||
{
|
||||
$result = parent::insert($values);
|
||||
|
||||
$this->insertLog($values);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function insertGetId(array $values, $sequence = null): int
|
||||
{
|
||||
$id = parent::insertGetId($values, $sequence);
|
||||
|
||||
$this->insertLog($values);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function insertOrIgnore(array $values): int
|
||||
{
|
||||
$result = parent::insertOrIgnore($values);
|
||||
|
||||
$this->insertLog($values);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function update(array $values): int
|
||||
{
|
||||
if (HyperfOrmLog::status()) {
|
||||
$oldData = $this->get()->toArray();
|
||||
if (!empty($oldData)) {
|
||||
$model = $this->generateModel();
|
||||
if (count($oldData) > 1) {
|
||||
HyperfOrmLog::batchUpdated($model, $oldData, $values);
|
||||
} else {
|
||||
HyperfOrmLog::updated($model, (array) $oldData[0], $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::update($values);
|
||||
}
|
||||
|
||||
public function delete($id = null): int
|
||||
{
|
||||
$this->deleteLog($id);
|
||||
|
||||
return parent::delete($id);
|
||||
}
|
||||
|
||||
public function truncate(): void
|
||||
{
|
||||
$this->deleteLog();
|
||||
parent::truncate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate model object.
|
||||
*/
|
||||
private function generateModel(): Model
|
||||
{
|
||||
$name = $this->from;
|
||||
|
||||
/** @var Connection $connection */
|
||||
$connection = $this->getConnection();
|
||||
$database = $connection->getDatabaseName();
|
||||
$table = $connection->getTablePrefix() . $name;
|
||||
|
||||
$mapping = [
|
||||
OperationLog::getTableModelMapping(),
|
||||
include __DIR__ . '/../../../cache/table-model-mapping.php',
|
||||
];
|
||||
foreach ($mapping as $map) {
|
||||
if (is_array($map) && isset($map[$database][$table]) && class_exists($map[$database][$table])) {
|
||||
return new $map[$database][$table]();
|
||||
}
|
||||
}
|
||||
|
||||
$modelNamespace = $connection->getConfig('modelNamespace') ?: 'app\\model';
|
||||
$className = trim($modelNamespace, '\\') . '\\' . Str::studly($name);
|
||||
if (class_exists($className)) {
|
||||
$model = new $className();
|
||||
} else {
|
||||
$model = new DbModel();
|
||||
$model->setQueryObj($connection);
|
||||
$model->setTable($name);
|
||||
$model->logKey = $connection->getConfig('logKey') ?: $model->getKeyName();
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
private function insertLog(array $values): void
|
||||
{
|
||||
if (HyperfOrmLog::status()) {
|
||||
$model = $this->generateModel();
|
||||
if (is_array(reset($values))) {
|
||||
HyperfOrmLog::batchCreated($model, $values);
|
||||
} else {
|
||||
/** @var Connection $connection */
|
||||
$connection = $this->getConnection();
|
||||
$id = $connection->getPdo()->lastInsertId();
|
||||
$pk = $model->getKeyName();
|
||||
$values[$pk] = $id;
|
||||
HyperfOrmLog::created($model, $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteLog($id = null): void
|
||||
{
|
||||
if (HyperfOrmLog::status()) {
|
||||
if (!empty($id)) {
|
||||
$data = [(array) $this->find($id)];
|
||||
} else {
|
||||
$data = $this->get()->toArray();
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
$model = $this->generateModel();
|
||||
if (count($data) > 1) {
|
||||
HyperfOrmLog::batchDeleted($model, $data);
|
||||
} else {
|
||||
HyperfOrmLog::deleted($model, (array) $data[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/chance-fyi/operation-log/src/orm/hyperf/ConfigProvider.php
vendored
Normal file
33
vendor/chance-fyi/operation-log/src/orm/hyperf/ConfigProvider.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2023/8/3 17:15.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\hyperf;
|
||||
|
||||
use Chance\Log\orm\hyperf\aspect\NewBaseQueryBuilderAspect;
|
||||
use Hyperf\Database\Connection;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
Connection::resolverFor('mysql', function ($connection, $database, $prefix, $config) {
|
||||
return new MySqlConnection($connection, $database, $prefix, $config);
|
||||
});
|
||||
|
||||
return [
|
||||
'annotations' => [
|
||||
'scan' => [
|
||||
'paths' => [
|
||||
__DIR__,
|
||||
],
|
||||
],
|
||||
],
|
||||
'aspects' => [
|
||||
NewBaseQueryBuilderAspect::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
28
vendor/chance-fyi/operation-log/src/orm/hyperf/DbModel.php
vendored
Normal file
28
vendor/chance-fyi/operation-log/src/orm/hyperf/DbModel.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2023/7/11 15:18.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\hyperf;
|
||||
|
||||
use Hyperf\Database\ConnectionInterface as Query;
|
||||
use Hyperf\Database\Model\Model;
|
||||
|
||||
class DbModel extends Model
|
||||
{
|
||||
// The primary key name of the log record
|
||||
public string $logKey = 'id';
|
||||
|
||||
private Query $query;
|
||||
|
||||
public function setQueryObj(Query $query): void
|
||||
{
|
||||
$this->query = $query;
|
||||
}
|
||||
|
||||
public function getQueryObj(): Query
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
}
|
175
vendor/chance-fyi/operation-log/src/orm/hyperf/Log.php
vendored
Normal file
175
vendor/chance-fyi/operation-log/src/orm/hyperf/Log.php
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2023/7/11 15:15.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\hyperf;
|
||||
|
||||
use Chance\Log\OperationLog;
|
||||
use Chance\Log\OperationLogInterface;
|
||||
use Hyperf\Database\Model\Model;
|
||||
use Hyperf\Stringable\Str;
|
||||
|
||||
class Log extends OperationLog implements OperationLogInterface
|
||||
{
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getPk($model): string
|
||||
{
|
||||
return $model->getKeyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getTableName($model): string
|
||||
{
|
||||
return $model->getConnection()->getTablePrefix() . $model->getTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getDatabaseName($model): string
|
||||
{
|
||||
if (method_exists($model, 'getQueryObj')) {
|
||||
return $model->getQueryObj()->getDatabaseName();
|
||||
}
|
||||
|
||||
return $model->getConnection()->getDatabaseName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function executeSQL($model, string $sql): array
|
||||
{
|
||||
if (method_exists($model, 'getQueryObj')) {
|
||||
return $model->getQueryObj()->select($sql);
|
||||
}
|
||||
|
||||
return $model->getConnection()->select($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getAttributes($model): array
|
||||
{
|
||||
return $model->getAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getChangedAttributes($model): array
|
||||
{
|
||||
return $model->getChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getValue($model, string $key): string
|
||||
{
|
||||
$keyText = $key . '_text';
|
||||
$value = $model->{$keyText} ?? $model->{$key};
|
||||
|
||||
if (is_array($value)) {
|
||||
return json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getOldValue($model, string $key): string
|
||||
{
|
||||
if (str_contains($key, '->')) {
|
||||
[$key, $jsonKey] = explode('->', $key, 2);
|
||||
}
|
||||
|
||||
$keyText = $key . '_text';
|
||||
$attributeFun = 'get' . Str::studly(Str::lower($keyText)) . 'Attribute';
|
||||
$value = (string) (method_exists($model, $attributeFun) ? $model->{$attributeFun}($model->getOriginal($key)) : $model->getOriginal($key));
|
||||
|
||||
$val = json_decode($value, true);
|
||||
if (!isset($jsonKey) || is_null($val) || !is_array($val)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
foreach (explode('->', $jsonKey) as $k) {
|
||||
$val = $val[$k];
|
||||
}
|
||||
|
||||
return (string) $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function created($model, array $data): void
|
||||
{
|
||||
$model->setRawAttributes($data);
|
||||
$this->generateLog($model, self::CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function updated($model, array $oldData, array $data): void
|
||||
{
|
||||
$model->setRawAttributes($oldData, true);
|
||||
$model->setRawAttributes(array_merge($oldData, $data));
|
||||
$model->syncChanges();
|
||||
$this->generateLog($model, self::UPDATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function deleted($model, array $data): void
|
||||
{
|
||||
$model->setRawAttributes($data);
|
||||
$this->generateLog($model, self::DELETED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function batchCreated($model, array $data): void
|
||||
{
|
||||
foreach ($data as $item) {
|
||||
$model->setRawAttributes($item);
|
||||
$this->generateLog($model, self::BATCH_CREATED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function batchUpdated($model, array $oldData, array $data): void
|
||||
{
|
||||
foreach ($oldData as $item) {
|
||||
$model->setRawAttributes((array) $item, true);
|
||||
$model->setRawAttributes(array_merge((array) $item, $data));
|
||||
$model->syncChanges();
|
||||
$this->generateLog($model, self::BATCH_UPDATED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function batchDeleted($model, array $data): void
|
||||
{
|
||||
foreach ($data as $item) {
|
||||
$model->setRawAttributes((array) $item);
|
||||
$this->generateLog($model, self::BATCH_DELETED);
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/chance-fyi/operation-log/src/orm/hyperf/MySqlConnection.php
vendored
Normal file
33
vendor/chance-fyi/operation-log/src/orm/hyperf/MySqlConnection.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2023/7/11 15:09.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\hyperf;
|
||||
|
||||
use Chance\Log\facades\HyperfOrmLog;
|
||||
|
||||
class MySqlConnection extends \Hyperf\Database\MySqlConnection
|
||||
{
|
||||
public function query(): Builder
|
||||
{
|
||||
return new Builder(
|
||||
$this,
|
||||
$this->getQueryGrammar(),
|
||||
$this->getPostProcessor()
|
||||
);
|
||||
}
|
||||
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
HyperfOrmLog::beginTransaction();
|
||||
parent::beginTransaction();
|
||||
}
|
||||
|
||||
public function rollBack($toLevel = null): void
|
||||
{
|
||||
HyperfOrmLog::rollBackTransaction(is_null($toLevel) ? $this->transactions : $toLevel);
|
||||
parent::rollBack($toLevel);
|
||||
}
|
||||
}
|
29
vendor/chance-fyi/operation-log/src/orm/hyperf/aspect/NewBaseQueryBuilderAspect.php
vendored
Normal file
29
vendor/chance-fyi/operation-log/src/orm/hyperf/aspect/NewBaseQueryBuilderAspect.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2023/7/12 10:25.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\hyperf\aspect;
|
||||
|
||||
use Chance\Log\orm\hyperf\Builder;
|
||||
use Hyperf\Database\Query\Builder as QueryBuilder;
|
||||
use Hyperf\Di\Annotation\Aspect;
|
||||
use Hyperf\Di\Aop\AbstractAspect;
|
||||
use Hyperf\Di\Aop\ProceedingJoinPoint;
|
||||
|
||||
#[Aspect]
|
||||
class NewBaseQueryBuilderAspect extends AbstractAspect
|
||||
{
|
||||
public array $classes = [
|
||||
'Hyperf\Database\Model\Model::newBaseQueryBuilder',
|
||||
];
|
||||
|
||||
public function process(ProceedingJoinPoint $proceedingJoinPoint): Builder
|
||||
{
|
||||
/** @var QueryBuilder $query */
|
||||
$query = $proceedingJoinPoint->process();
|
||||
|
||||
return new Builder($query->getConnection(), $query->getGrammar(), $query->getProcessor());
|
||||
}
|
||||
}
|
146
vendor/chance-fyi/operation-log/src/orm/illuminate/Builder.php
vendored
Normal file
146
vendor/chance-fyi/operation-log/src/orm/illuminate/Builder.php
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/10/8 9:56.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\illuminate;
|
||||
|
||||
use Chance\Log\facades\IlluminateOrmLog;
|
||||
use Chance\Log\facades\OperationLog;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Builder extends \Illuminate\Database\Query\Builder
|
||||
{
|
||||
public function insert(array $values): bool
|
||||
{
|
||||
$result = parent::insert($values);
|
||||
|
||||
$this->insertLog($values);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function insertGetId(array $values, $sequence = null): int
|
||||
{
|
||||
$id = parent::insertGetId($values, $sequence);
|
||||
|
||||
$this->insertLog($values);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function insertOrIgnore(array $values): int
|
||||
{
|
||||
$result = parent::insertOrIgnore($values);
|
||||
|
||||
$this->insertLog($values);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function update(array $values): int
|
||||
{
|
||||
if (IlluminateOrmLog::status()) {
|
||||
$oldData = $this->get()->toArray();
|
||||
if (!empty($oldData)) {
|
||||
$model = $this->generateModel();
|
||||
if (count($oldData) > 1) {
|
||||
IlluminateOrmLog::batchUpdated($model, $oldData, $values);
|
||||
} else {
|
||||
IlluminateOrmLog::updated($model, (array) $oldData[0], $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::update($values);
|
||||
}
|
||||
|
||||
public function delete($id = null): int
|
||||
{
|
||||
$this->deleteLog($id);
|
||||
|
||||
return parent::delete($id);
|
||||
}
|
||||
|
||||
public function truncate(): void
|
||||
{
|
||||
$this->deleteLog();
|
||||
parent::truncate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate model object.
|
||||
*/
|
||||
private function generateModel(): Model
|
||||
{
|
||||
$name = $this->from;
|
||||
|
||||
/** @var Connection $connection */
|
||||
$connection = $this->getConnection();
|
||||
$database = $connection->getDatabaseName();
|
||||
$table = $connection->getTablePrefix() . $name;
|
||||
|
||||
$mapping = [
|
||||
OperationLog::getTableModelMapping(),
|
||||
include __DIR__ . '/../../../cache/table-model-mapping.php',
|
||||
];
|
||||
foreach ($mapping as $map) {
|
||||
if (is_array($map) && isset($map[$database][$table]) && class_exists($map[$database][$table])) {
|
||||
return new $map[$database][$table]();
|
||||
}
|
||||
}
|
||||
|
||||
$modelNamespace = $connection->getConfig('modelNamespace') ?: 'app\\model';
|
||||
$className = trim($modelNamespace, '\\') . '\\' . Str::studly($name);
|
||||
if (class_exists($className)) {
|
||||
$model = new $className();
|
||||
} else {
|
||||
$model = new DbModel();
|
||||
$model->setQuery($connection);
|
||||
$model->setTable($name);
|
||||
$model->logKey = $connection->getConfig('logKey') ?: $model->getKeyName();
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
private function insertLog(array $values): void
|
||||
{
|
||||
if (IlluminateOrmLog::status()) {
|
||||
$model = $this->generateModel();
|
||||
if (is_array(reset($values))) {
|
||||
IlluminateOrmLog::batchCreated($model, $values);
|
||||
} else {
|
||||
/** @var Connection $connection */
|
||||
$connection = $this->getConnection();
|
||||
$id = $connection->getPdo()->lastInsertId();
|
||||
$pk = $model->getKeyName();
|
||||
$values[$pk] = $id;
|
||||
IlluminateOrmLog::created($model, $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteLog($id = null): void
|
||||
{
|
||||
if (IlluminateOrmLog::status()) {
|
||||
if (!empty($id)) {
|
||||
$data = [(array) $this->find($id)];
|
||||
} else {
|
||||
$data = $this->get()->toArray();
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
$model = $this->generateModel();
|
||||
if (count($data) > 1) {
|
||||
IlluminateOrmLog::batchDeleted($model, $data);
|
||||
} else {
|
||||
IlluminateOrmLog::deleted($model, (array) $data[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
vendor/chance-fyi/operation-log/src/orm/illuminate/DbModel.php
vendored
Normal file
28
vendor/chance-fyi/operation-log/src/orm/illuminate/DbModel.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/10/8 10:24.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\illuminate;
|
||||
|
||||
use Illuminate\Database\ConnectionInterface as Query;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class DbModel extends Model
|
||||
{
|
||||
// The primary key name of the log record
|
||||
public string $logKey = 'id';
|
||||
|
||||
private Query $query;
|
||||
|
||||
public function setQuery(Query $query): void
|
||||
{
|
||||
$this->query = $query;
|
||||
}
|
||||
|
||||
public function getQuery(): Query
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
}
|
200
vendor/chance-fyi/operation-log/src/orm/illuminate/Log.php
vendored
Normal file
200
vendor/chance-fyi/operation-log/src/orm/illuminate/Log.php
vendored
Normal file
@ -0,0 +1,200 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* IUser Chance
|
||||
* Date 2021/12/31 11:10.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\illuminate;
|
||||
|
||||
use Chance\Log\OperationLog;
|
||||
use Chance\Log\OperationLogInterface;
|
||||
use Illuminate\Database\Eloquent\Casts\ArrayObject;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Query\Expression;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Log extends OperationLog implements OperationLogInterface
|
||||
{
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getPk($model): string
|
||||
{
|
||||
return $model->getKeyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getTableName($model): string
|
||||
{
|
||||
return $model->getConnection()->getTablePrefix() . $model->getTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getDatabaseName($model): string
|
||||
{
|
||||
if (method_exists($model, 'getQuery')) {
|
||||
return $model->getQuery()->getDatabaseName();
|
||||
}
|
||||
|
||||
return $model->getConnection()->getDatabaseName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function executeSQL($model, string $sql): array
|
||||
{
|
||||
if (method_exists($model, 'getQuery')) {
|
||||
return $model->getQuery()->select($sql);
|
||||
}
|
||||
|
||||
return $model->getConnection()->select($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getAttributes($model): array
|
||||
{
|
||||
return $model->getAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getChangedAttributes($model): array
|
||||
{
|
||||
return $model->getChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getValue($model, string $key): string
|
||||
{
|
||||
$keyText = $key . '_text';
|
||||
$value = $model->{$keyText} ?? $model->{$key};
|
||||
|
||||
if ($value instanceof ArrayObject) {
|
||||
$value = $value->toArray();
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
if (is_object($value) && $value instanceof Expression) {
|
||||
// Compatible with version 10.x
|
||||
// @phpstan-ignore-next-line
|
||||
return $value->getValue($model->getConnection()->getQueryGrammar());
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getOldValue($model, string $key): string
|
||||
{
|
||||
if (str_contains($key, '->')) {
|
||||
[$key, $jsonKey] = explode('->', $key, 2);
|
||||
}
|
||||
|
||||
$keyText = $key . '_text';
|
||||
$attributeFun = 'get' . Str::studly(Str::lower($keyText)) . 'Attribute';
|
||||
$value = (method_exists($model, $attributeFun) ? $model->{$attributeFun}($model->getOriginal($key)) : $model->getOriginal($key));
|
||||
|
||||
if ($value instanceof ArrayObject) {
|
||||
$value = $value->toArray();
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
$val = json_decode((string) $value, true);
|
||||
if (!isset($jsonKey) || is_null($val) || !is_array($val)) {
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
foreach (explode('->', $jsonKey) as $k) {
|
||||
$val = $val[$k];
|
||||
}
|
||||
|
||||
return (string) $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function created($model, array $data): void
|
||||
{
|
||||
$model->setRawAttributes($data);
|
||||
$this->generateLog($model, self::CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function updated($model, array $oldData, array $data): void
|
||||
{
|
||||
$data = array_map(function ($value) {
|
||||
return is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
|
||||
}, $data);
|
||||
|
||||
$model->setRawAttributes($oldData, true);
|
||||
$model->setRawAttributes(array_merge($oldData, $data));
|
||||
$model->syncChanges();
|
||||
$this->generateLog($model, self::UPDATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function deleted($model, array $data): void
|
||||
{
|
||||
$model->setRawAttributes($data);
|
||||
$this->generateLog($model, self::DELETED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function batchCreated($model, array $data): void
|
||||
{
|
||||
foreach ($data as $item) {
|
||||
$model->setRawAttributes($item);
|
||||
$this->generateLog($model, self::BATCH_CREATED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function batchUpdated($model, array $oldData, array $data): void
|
||||
{
|
||||
foreach ($oldData as $item) {
|
||||
$model->setRawAttributes((array) $item, true);
|
||||
$model->setRawAttributes(array_merge((array) $item, $data));
|
||||
$model->syncChanges();
|
||||
$this->generateLog($model, self::BATCH_UPDATED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function batchDeleted($model, array $data): void
|
||||
{
|
||||
foreach ($data as $item) {
|
||||
$model->setRawAttributes((array) $item);
|
||||
$this->generateLog($model, self::BATCH_DELETED);
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/chance-fyi/operation-log/src/orm/illuminate/MySqlConnection.php
vendored
Normal file
33
vendor/chance-fyi/operation-log/src/orm/illuminate/MySqlConnection.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/10/8 9:54.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\illuminate;
|
||||
|
||||
use Chance\Log\facades\IlluminateOrmLog;
|
||||
|
||||
class MySqlConnection extends \Illuminate\Database\MySqlConnection
|
||||
{
|
||||
public function query(): Builder
|
||||
{
|
||||
return new Builder(
|
||||
$this,
|
||||
$this->getQueryGrammar(),
|
||||
$this->getPostProcessor()
|
||||
);
|
||||
}
|
||||
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
IlluminateOrmLog::beginTransaction();
|
||||
parent::beginTransaction();
|
||||
}
|
||||
|
||||
public function rollBack($toLevel = null): void
|
||||
{
|
||||
IlluminateOrmLog::rollBackTransaction(is_null($toLevel) ? $this->transactions : $toLevel);
|
||||
parent::rollBack($toLevel);
|
||||
}
|
||||
}
|
34
vendor/chance-fyi/operation-log/src/orm/think/DbModel.php
vendored
Normal file
34
vendor/chance-fyi/operation-log/src/orm/think/DbModel.php
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/10/7 11:44.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\think;
|
||||
|
||||
use think\db\BaseQuery as Query;
|
||||
use think\Model;
|
||||
|
||||
class DbModel extends Model
|
||||
{
|
||||
// The primary key name of the log record
|
||||
public string $logKey = 'id';
|
||||
|
||||
private Query $query;
|
||||
|
||||
public function __construct(string $table, array $data = [])
|
||||
{
|
||||
$this->table = $table;
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
public function setQuery(Query $query): void
|
||||
{
|
||||
$this->query = $query;
|
||||
}
|
||||
|
||||
public function getQuery(): Query
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
}
|
183
vendor/chance-fyi/operation-log/src/orm/think/Log.php
vendored
Normal file
183
vendor/chance-fyi/operation-log/src/orm/think/Log.php
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/3/9 11:18.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\think;
|
||||
|
||||
use Chance\Log\OperationLog;
|
||||
use Chance\Log\OperationLogInterface;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\PDOConnection;
|
||||
use think\db\Raw;
|
||||
use think\helper\Str;
|
||||
use think\Model;
|
||||
|
||||
class Log extends OperationLog implements OperationLogInterface
|
||||
{
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getPk($model): string
|
||||
{
|
||||
return $model->getPk();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getTableName($model): string
|
||||
{
|
||||
return $model->getTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getDatabaseName($model): string
|
||||
{
|
||||
if (method_exists($model, 'getQuery')) {
|
||||
return $model->getQuery()->getConfig('database');
|
||||
}
|
||||
|
||||
return $model->getConfig('database');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*
|
||||
* @throws DbException
|
||||
*/
|
||||
public function executeSQL($model, string $sql): mixed
|
||||
{
|
||||
if (method_exists($model, 'getQuery')) {
|
||||
return $model->getQuery()->getConnection()->query($sql);
|
||||
}
|
||||
|
||||
/** @var PDOConnection $connection */
|
||||
$connection = $model->db()->getConnection();
|
||||
|
||||
return $connection->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getAttributes($model): array
|
||||
{
|
||||
return $model->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getChangedAttributes($model): array
|
||||
{
|
||||
return $model->getChangedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getValue($model, string $key): string
|
||||
{
|
||||
$keyText = $key . '_text';
|
||||
$value = $model->{$keyText} ?? $model->{$key};
|
||||
|
||||
if ($value instanceof Raw) {
|
||||
return $value->getValue();
|
||||
}
|
||||
if (is_array($value) || is_object($value)) {
|
||||
return json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function getOldValue($model, string $key): string
|
||||
{
|
||||
if (str_contains($key, '->')) {
|
||||
$value = $model->getOrigin(vsprintf("json_extract(`json`, '$.name')", explode('->', $key, 2)));
|
||||
|
||||
return trim($value, '"');
|
||||
}
|
||||
|
||||
$keyText = $key . '_text';
|
||||
$attributeFun = 'get' . Str::studly(Str::lower($keyText)) . 'Attr';
|
||||
$value = method_exists($model, $attributeFun) ? $model->{$attributeFun}($model->getOrigin($key)) : $model->getOrigin($key);
|
||||
|
||||
if (is_array($value) || is_object($value)) {
|
||||
return json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function created($model, array $data): void
|
||||
{
|
||||
$model->setAttrs($data);
|
||||
$this->generateLog($model, self::CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function updated($model, array $oldData, array $data): void
|
||||
{
|
||||
$model->setAttrs($oldData);
|
||||
$model->refreshOrigin();
|
||||
$model->setAttrs($data);
|
||||
$this->generateLog($model, self::UPDATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function deleted($model, array $data): void
|
||||
{
|
||||
$model->setAttrs($data);
|
||||
$this->generateLog($model, self::DELETED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function batchCreated($model, array $data): void
|
||||
{
|
||||
foreach ($data as $item) {
|
||||
$model->setAttrs($item);
|
||||
$this->generateLog($model, self::BATCH_CREATED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function batchUpdated($model, array $oldData, array $data): void
|
||||
{
|
||||
foreach ($oldData as $item) {
|
||||
$model->setAttrs($item);
|
||||
$model->refreshOrigin();
|
||||
$model->setAttrs($data);
|
||||
$this->generateLog($model, self::BATCH_UPDATED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
*/
|
||||
public function batchDeleted($model, array $data): void
|
||||
{
|
||||
foreach ($data as $item) {
|
||||
$model->setAttrs($item);
|
||||
$this->generateLog($model, self::BATCH_DELETED);
|
||||
}
|
||||
}
|
||||
}
|
25
vendor/chance-fyi/operation-log/src/orm/think/MySqlConnection.php
vendored
Normal file
25
vendor/chance-fyi/operation-log/src/orm/think/MySqlConnection.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/12/21 17:24.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\think;
|
||||
|
||||
use Chance\Log\facades\ThinkOrmLog;
|
||||
use think\db\connector\Mysql;
|
||||
|
||||
class MySqlConnection extends Mysql
|
||||
{
|
||||
public function startTrans(): void
|
||||
{
|
||||
ThinkOrmLog::beginTransaction();
|
||||
parent::startTrans();
|
||||
}
|
||||
|
||||
public function rollback(): void
|
||||
{
|
||||
ThinkOrmLog::rollBackTransaction($this->transTimes);
|
||||
parent::rollback();
|
||||
}
|
||||
}
|
140
vendor/chance-fyi/operation-log/src/orm/think/Query.php
vendored
Normal file
140
vendor/chance-fyi/operation-log/src/orm/think/Query.php
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm
|
||||
* Date 2022/10/7 16:19.
|
||||
*/
|
||||
|
||||
namespace Chance\Log\orm\think;
|
||||
|
||||
use Chance\Log\facades\OperationLog;
|
||||
use Chance\Log\facades\ThinkOrmLog;
|
||||
use think\helper\Str;
|
||||
use think\Model;
|
||||
|
||||
class Query extends \think\db\Query
|
||||
{
|
||||
public function insert(array $data = [], bool $getLastInsID = false): int|string
|
||||
{
|
||||
$result = parent::insert($data, $getLastInsID);
|
||||
|
||||
if (ThinkOrmLog::status()) {
|
||||
if ($getLastInsID) {
|
||||
$id = $result;
|
||||
} else {
|
||||
$id = $this->getLastInsID();
|
||||
}
|
||||
|
||||
$model = $this->generateModel();
|
||||
$pk = $this->getPk();
|
||||
$data = $data ?: $this->getOptions('data');
|
||||
$data[$pk] = $id;
|
||||
ThinkOrmLog::created($model, $data);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function insertAll(array $dataSet = [], int $limit = 0): int
|
||||
{
|
||||
$result = parent::insertAll($dataSet, $limit);
|
||||
|
||||
if (ThinkOrmLog::status()) {
|
||||
$model = $this->generateModel();
|
||||
ThinkOrmLog::batchCreated($model, $dataSet);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function update(array $data = []): int
|
||||
{
|
||||
if (ThinkOrmLog::status()) {
|
||||
$model = $this->generateModel();
|
||||
$newData = $data ?: $this->getOptions('data');
|
||||
$field = array_keys($newData);
|
||||
$field[] = $model->logKey ?? $model->getPk();
|
||||
|
||||
$pk = $model->getPk();
|
||||
if (isset($data[$pk])) {
|
||||
// 包含主键只更新一条
|
||||
$oldData = $this->find($data[$pk]);
|
||||
if (!empty($oldData)) {
|
||||
$oldData = [is_array($oldData) ? $oldData : $oldData->toArray()];
|
||||
}
|
||||
} else {
|
||||
// 条件查询或许是多条
|
||||
$oldData = $this->field($field)->select()->toArray();
|
||||
}
|
||||
if (!empty($oldData)) {
|
||||
if (count($oldData) > 1) {
|
||||
ThinkOrmLog::batchUpdated($model, $oldData, $newData);
|
||||
} else {
|
||||
ThinkOrmLog::updated($model, $oldData[0], $newData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::update($data);
|
||||
}
|
||||
|
||||
public function delete($data = null): int
|
||||
{
|
||||
if (ThinkOrmLog::status()) {
|
||||
$model = $this->generateModel();
|
||||
if (!empty($data)) {
|
||||
$pk = $model->getPk();
|
||||
$delData = $this->whereIn($pk, $data)->select()->toArray();
|
||||
} else {
|
||||
$delData = $this->select()->toArray();
|
||||
}
|
||||
|
||||
if (!empty($delData)) {
|
||||
if (count($delData) > 1) {
|
||||
ThinkOrmLog::batchDeleted($model, $delData);
|
||||
} else {
|
||||
ThinkOrmLog::deleted($model, $delData[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::delete($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate model object.
|
||||
*/
|
||||
private function generateModel(): Model
|
||||
{
|
||||
if ($this->getModel()) {
|
||||
return $this->getModel();
|
||||
}
|
||||
|
||||
$database = $this->getConfig('database');
|
||||
$table = $this->getTable();
|
||||
|
||||
$mapping = [
|
||||
OperationLog::getTableModelMapping(),
|
||||
include __DIR__ . '/../../../cache/table-model-mapping.php',
|
||||
];
|
||||
foreach ($mapping as $map) {
|
||||
if (is_array($map) && isset($map[$database][$table]) && class_exists($map[$database][$table])) {
|
||||
return new $map[$database][$table]();
|
||||
}
|
||||
}
|
||||
|
||||
$name = ltrim(Str::lower($table), Str::lower($this->prefix));
|
||||
$modelNamespace = $this->getConfig('modelNamespace') ?: 'app\\model';
|
||||
$className = trim($modelNamespace, '\\') . '\\' . Str::studly($name);
|
||||
if (class_exists($className)) {
|
||||
$model = new $className();
|
||||
} else {
|
||||
$model = new DbModel($table);
|
||||
$model->table($table);
|
||||
$model->setQuery($this);
|
||||
$model->logKey = $this->getConfig('logKey') ?: $model->getPk();
|
||||
$model->pk($this->getPk());
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
}
|
1
vendor/composer/autoload_psr4.php
vendored
1
vendor/composer/autoload_psr4.php
vendored
@ -112,6 +112,7 @@ return array(
|
||||
'DI\\' => array($vendorDir . '/php-di/php-di/src'),
|
||||
'Cron\\' => array($vendorDir . '/dragonmantank/cron-expression/src/Cron'),
|
||||
'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'),
|
||||
'Chance\\Log\\' => array($vendorDir . '/chance-fyi/operation-log/src'),
|
||||
'Carbon\\Doctrine\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'),
|
||||
'Carbon\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'),
|
||||
'App\\' => array($baseDir . '/app'),
|
||||
|
5
vendor/composer/autoload_static.php
vendored
5
vendor/composer/autoload_static.php
vendored
@ -218,6 +218,7 @@ class ComposerStaticInitcefecbcff919f3c1c8084830bbb72adc
|
||||
array (
|
||||
'Cron\\' => 5,
|
||||
'Complex\\' => 8,
|
||||
'Chance\\Log\\' => 11,
|
||||
'Carbon\\Doctrine\\' => 16,
|
||||
'Carbon\\' => 7,
|
||||
),
|
||||
@ -658,6 +659,10 @@ class ComposerStaticInitcefecbcff919f3c1c8084830bbb72adc
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/markbaker/complex/classes/src',
|
||||
),
|
||||
'Chance\\Log\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/chance-fyi/operation-log/src',
|
||||
),
|
||||
'Carbon\\Doctrine\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine',
|
||||
|
64
vendor/composer/installed.json
vendored
64
vendor/composer/installed.json
vendored
@ -120,6 +120,70 @@
|
||||
],
|
||||
"install-path": "../carbonphp/carbon-doctrine-types"
|
||||
},
|
||||
{
|
||||
"name": "chance-fyi/operation-log",
|
||||
"version": "v3.0.7",
|
||||
"version_normalized": "3.0.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Chance-fyi/operation-log.git",
|
||||
"reference": "bfb73bc1c3dddf91772de4f37b42a41c519c67e5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Chance-fyi/operation-log/zipball/bfb73bc1c3dddf91772de4f37b42a41c519c67e5",
|
||||
"reference": "bfb73bc1c3dddf91772de4f37b42a41c519c67e5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.21@dev",
|
||||
"friendsofphp/php-cs-fixer": "dev-master",
|
||||
"hyperf/config": "^3.0@dev",
|
||||
"hyperf/database": "^3.0@dev",
|
||||
"hyperf/di": "^3.0@dev",
|
||||
"hyperf/pimple": "^2.1",
|
||||
"illuminate/database": "^8.0",
|
||||
"phpstan/phpstan": "1.11.x-dev",
|
||||
"phpunit/phpunit": "9.6.x-dev",
|
||||
"topthink/think-orm": "2.0.x-dev"
|
||||
},
|
||||
"time": "2023-12-22T08:06:25+00:00",
|
||||
"bin": [
|
||||
"bin/chance-fyi-operation-log"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"hyperf": {
|
||||
"config": "Chance\\Log\\orm\\hyperf\\ConfigProvider"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Chance\\Log\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "chance",
|
||||
"email": "ctx_ya@qq.com"
|
||||
}
|
||||
],
|
||||
"description": "Elegant logging of operations",
|
||||
"support": {
|
||||
"issues": "https://github.com/Chance-fyi/operation-log/issues",
|
||||
"source": "https://github.com/Chance-fyi/operation-log/tree/v3.0.7"
|
||||
},
|
||||
"install-path": "../chance-fyi/operation-log"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "1.14.3",
|
||||
|
9
vendor/composer/installed.php
vendored
9
vendor/composer/installed.php
vendored
@ -28,6 +28,15 @@
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'chance-fyi/operation-log' => array(
|
||||
'pretty_version' => 'v3.0.7',
|
||||
'version' => '3.0.7.0',
|
||||
'reference' => 'bfb73bc1c3dddf91772de4f37b42a41c519c67e5',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../chance-fyi/operation-log',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'doctrine/annotations' => array(
|
||||
'pretty_version' => '1.14.3',
|
||||
'version' => '1.14.3.0',
|
||||
|
Loading…
x
Reference in New Issue
Block a user