laravel-soar
laravel-soar copied to clipboard
SQL optimizer and rewriter for laravel. - laravel 的 SQL 优化器和重写器。
laravel-soar
SQL optimizer and rewriter for laravel. - laravel ç SQL ä¼åå¨åéåå¨ã
ç®ä½ä¸æ | ENGLISH
åè½
- æ¯æå¯åå¼ç®æ³è¯å¥ä¼å建议ãç´¢å¼ä¼å建议
- æ¯æ EXPLAIN ä¿¡æ¯ä¸°å¯è§£è¯»
- èªå¨çæ§è¾åº SQL ä¼å建议
- Debug barãSoar barãJSONãClockworkãConsoleãDumpãLogãèªå®ä¹è¾åºå¨(å¤ç§åºæ¯è¾åº)
- æ¯ææ¥è¯¢æ建å¨çæ SQL ä¼å建议
ç¸å ³é¡¹ç®
- https://github.com/XiaoMi/soar
- https://github.com/guanguans/soar-php
- https://github.com/huangdijia/laravel-web-soar
- https://github.com/wilbur-yu/hyperf-soar
- https://github.com/guanguans/think-soar
- https://github.com/Tinywan/webman-soar
ç¯å¢è¦æ±
- laravel >= 6.10
å®è£
$ composer require guanguans/laravel-soar --dev -vvv
é ç½®
注åæå¡
laravel
$ php artisan vendor:publish --provider="Guanguans\\LaravelSoar\\SoarServiceProvider"
lumen
å°ä»¥ä¸ä»£ç 段添å å° bootstrap/app.php
æ件ä¸ç Register Service Providers
é¨åä¸ï¼
$app->register(\Guanguans\LaravelSoar\SoarServiceProvider::class);
使ç¨
示ä¾ä»£ç
详æ
<?php
namespace App\Admin\Controllers;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class SoarController extends Controller
{
public function sqlScore()
{
// å建表
DB::select(
<<<SQL
CREATE TABLE `users` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`email_verified_at` timestamp NULL DEFAULT NULL,
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
SQL
);
// æå
¥æ°æ®
User::query()->insert([
'name' => 'soar',
'email' => '[email protected]',
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
'remember_token' => Str::random(10),
]);
// æ´æ°æ°æ®
User::query()->update([
'name' => 'name',
'password' => 'password',
]);
// æ¥è¯¢æ°æ®
User::query()->where('name', 'soar')->groupBy('name')->having('created_at', '>', now())->get();
// å é¤æ°æ®
User::query()->where('name', 'soar')->delete();
// å é¤è¡¨
DB::select('DROP table `users`;');
// return response()->json(['message' => 'ok']); // JSON ååº
return response('ok'); // HTML ååº
}
}
èªå¨çæ§è¾åº SQL ä¼å建议
Json ååº
{
"message": "ok",
"soar_scores": [
{
"Summary": "[âââââ|0å|3.56ms|select * from `users` where `name` = 'soar' group by `name` having `created_at` > '2022-04-19 18:24:33']",
"HeuristicRules": [
{
"Item": "CLA.008",
"Severity": "L2",
"Summary": "请为 GROUP BY æ¾ç¤ºæ·»å ORDER BY æ¡ä»¶",
"Content": "é»è®¤ MySQL ä¼å¯¹ 'GROUP BY col1, col2, ...' 请æ±æå¦ä¸é¡ºåºæåº 'ORDER BY col1, col2, ...'ãå¦æ GROUP BY è¯å¥ä¸æå® ORDER BY æ¡ä»¶ä¼å¯¼è´æ è°çæåºäº§çï¼å¦æä¸éè¦æåºå»ºè®®æ·»å 'ORDER BY NULL'ã",
"Case": "select c1,c2,c3 from t1 where c1='foo' group by c2",
"Position": 0
},
{
"Item": "CLA.013",
"Severity": "L3",
"Summary": "ä¸å»ºè®®ä½¿ç¨ HAVING åå¥",
"Content": "å°æ¥è¯¢ç HAVING åå¥æ¹å为 WHERE ä¸çæ¥è¯¢æ¡ä»¶ï¼å¯ä»¥å¨æ¥è¯¢å¤çæé´ä½¿ç¨ç´¢å¼ã",
"Case": "SELECT s.c_id,count(s.c_id) FROM s where c = test GROUP BY s.c_id HAVING s.c_id <> '1660' AND s.c_id <> '2' order by s.c_id",
"Position": 0
},
{
"Item": "COL.001",
"Severity": "L1",
"Summary": "ä¸å»ºè®®ä½¿ç¨ SELECT * ç±»åæ¥è¯¢",
"Content": "å½è¡¨ç»æåæ´æ¶ï¼ä½¿ç¨ * éé
符éæ©ææåå°å¯¼è´æ¥è¯¢çå«ä¹åè¡ä¸ºä¼åçæ´æ¹ï¼å¯è½å¯¼è´æ¥è¯¢è¿åæ´å¤çæ°æ®ã",
"Case": "select * from tbl where id=1",
"Position": 0
},
{
"Item": "ERR.002",
"Severity": "L8",
"Summary": "MySQL execute failed",
"Content": "Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'optimizer_220419182434_gwyshx8la4boulhu.users.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by",
"Case": "",
"Position": 0
},
{
"Item": "GRP.001",
"Severity": "L2",
"Summary": "ä¸å»ºè®®å¯¹çå¼æ¥è¯¢åä½¿ç¨ GROUP BY",
"Content": "GROUP BY ä¸çåå¨åé¢ç WHERE æ¡ä»¶ä¸ä½¿ç¨äºçå¼æ¥è¯¢ï¼å¯¹è¿æ ·çåè¿è¡ GROUP BY æä¹ä¸å¤§ã",
"Case": "select film_id, title from film where release_year='2006' group by release_year",
"Position": 0
},
{
"Item": "RES.001",
"Severity": "L4",
"Summary": "éç¡®å®æ§ç GROUP BY",
"Content": "SQLè¿åçåæ¢ä¸å¨èåå½æ°ä¸ä¹ä¸æ¯ GROUP BY 表达å¼çåä¸ï¼å æ¤è¿äºå¼çç»æå°æ¯éç¡®å®æ§çãå¦ï¼select a, b, c from tbl where foo=\"bar\" group by aï¼è¯¥ SQL è¿åçç»æå°±æ¯ä¸ç¡®å®çã",
"Case": "select c1,c2,c3 from t1 where c2='foo' group by c2",
"Position": 0
}
],
"IndexRules": [
{
"Item": "IDX.001",
"Severity": "L2",
"Summary": "为laravelåºçusers表添å ç´¢å¼",
"Content": "为ånameæ·»å ç´¢å¼;为åcreated_atæ·»å ç´¢å¼; ç±äºæªå¼å¯æ°æ®éæ ·ï¼ååå¨ç´¢å¼ä¸ç顺åºéè¦èªè¡è°æ´ã",
"Case": "ALTER TABLE `laravel`.`users` add index `idx_name_created_at` (`name`(191),`created_at`) ;\n",
"Position": 0
}
],
"Explain": [],
"Backtraces": [
"#13 /app/Admin/Controllers/HomeController.php:74",
"#55 /Users/yaozm/Documents/develop/laravel-soar/src/Http/Middleware/OutputSoarScoreMiddleware.php:45",
"#76 /public/index.php:55",
"#77 /server.php:21"
]
},
{
"Summary": "[â
â
â
â
â|75å|64.5ms|CREATE TABLE `users` (\n `id` bigint unsigned NOT NULL AUTO_INCREMENT,\n `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,\n `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,\n `email_verified_at` timestamp NULL DEFAULT NULL,\n `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,\n `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,\n `created_at` timestamp NULL DEFAULT NULL,\n `updated_at` timestamp NULL DEFAULT NULL,\n PRIMARY KEY (`id`),\n UNIQUE KEY `users_email_unique` (`email`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;]",
"HeuristicRules": [
{
"Item": "CLA.011",
"Severity": "L1",
"Summary": "建议为表添å 注é",
"Content": "为表添å 注éè½å¤ä½¿å¾è¡¨çæä¹æ´æç¡®ï¼ä»è为æ¥åçç»´æ¤å¸¦æ¥æ大ç便å©ã",
"Case": "CREATE TABLE `test1` (`ID` bigint(20) NOT NULL AUTO_INCREMENT,`c1` varchar(128) DEFAULT NULL,PRIMARY KEY (`ID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8",
"Position": 0
},
{
"Item": "COL.004",
"Severity": "L1",
"Summary": "请为åæ·»å é»è®¤å¼",
"Content": "请为åæ·»å é»è®¤å¼ï¼å¦ææ¯ ALTER æä½ï¼è¯·ä¸è¦å¿è®°å°åå段çé»è®¤å¼åä¸ãå段æ é»è®¤å¼ï¼å½è¡¨è¾å¤§æ¶æ æ³å¨çº¿åæ´è¡¨ç»æã",
"Case": "CREATE TABLE tbl (col int) ENGINE=InnoDB;",
"Position": 0
},
{
"Item": "COL.005",
"Severity": "L1",
"Summary": "åæªæ·»å 注é",
"Content": "建议对表ä¸æ¯ä¸ªåæ·»å 注éï¼æ¥æç¡®æ¯ä¸ªåå¨è¡¨ä¸çå«ä¹åä½ç¨ã",
"Case": "CREATE TABLE tbl (col int) ENGINE=InnoDB;",
"Position": 0
},
{
"Item": "COL.011",
"Severity": "L0",
"Summary": "å½éè¦å¯ä¸çº¦ææ¶æä½¿ç¨ NULLï¼ä»
å½åä¸è½æ缺失å¼æ¶æä½¿ç¨ NOT NULL",
"Content": "NULL å0æ¯ä¸åçï¼10ä¹ä»¥ NULL è¿æ¯ NULLãNULL å空å符串æ¯ä¸ä¸æ ·çãå°ä¸ä¸ªå符串åæ å SQL ä¸ç NULL èåèµ·æ¥çç»æè¿æ¯ NULLãNULL å FALSE ä¹æ¯ä¸åçãANDãOR å NOT è¿ä¸ä¸ªå¸å°æä½å¦ææ¶å NULLï¼å
¶ç»æä¹è®©å¾å¤äººæå°å°æãå½æ¨å°ä¸å声æ为 NOT NULL æ¶ï¼ä¹å°±æ¯è¯´è¿åä¸çæ¯ä¸ä¸ªå¼é½å¿
é¡»åå¨ä¸æ¯ææä¹çãä½¿ç¨ NULL æ¥è¡¨ç¤ºä»»æç±»åä¸åå¨ç空å¼ã å½æ¨å°ä¸å声æ为 NOT NULL æ¶ï¼ä¹å°±æ¯è¯´è¿åä¸çæ¯ä¸ä¸ªå¼é½å¿
é¡»åå¨ä¸æ¯ææä¹çã",
"Case": "select c1,c2,c3 from tbl where c4 is null or c4 <> 1",
"Position": 49
},
{
"Item": "KWR.003",
"Severity": "L1",
"Summary": "ä¸å»ºè®®ä½¿ç¨å¤æ°åååæ表å",
"Content": "表ååºè¯¥ä»
ä»
表示表éé¢çå®ä½å
容ï¼ä¸åºè¯¥è¡¨ç¤ºå®ä½æ°éï¼å¯¹åºäº DO ç±»åä¹æ¯åæ°å½¢å¼ï¼ç¬¦åè¡¨è¾¾ä¹ æ¯ã",
"Case": "CREATE TABLE tbl ( `books` int )",
"Position": 0
},
{
"Item": "SEC.002",
"Severity": "L0",
"Summary": "ä¸ä½¿ç¨ææåå¨å¯ç ",
"Content": "使ç¨ææåå¨å¯ç æè
使ç¨ææå¨ç½ç»ä¸ä¼ éå¯ç é½æ¯ä¸å®å
¨çãå¦ææ»å»è
è½å¤æªè·æ¨ç¨æ¥æå
¥å¯ç çSQLè¯å¥ï¼ä»ä»¬å°±è½ç´æ¥è¯»å°å¯ç ãå¦å¤ï¼å°ç¨æ·è¾å
¥çå符串以ææçå½¢å¼æå
¥å°çº¯SQLè¯å¥ä¸ï¼ä¹ä¼è®©æ»å»è
åç°å®ãå¦ææ¨è½å¤è¯»åå¯ç ï¼é»å®¢ä¹å¯ä»¥ã解å³æ¹æ¡æ¯ä½¿ç¨åååå¸å½æ°å¯¹åå§å¯ç è¿è¡å å¯ç¼ç ãåå¸æ¯æå°è¾å
¥å符串转åæå¦ä¸ä¸ªæ°çãä¸å¯è¯å«çå符串çå½æ°ã对å¯ç å å¯è¡¨è¾¾å¼å ç¹éæºä¸²æ¥é²å¾¡âåå
¸æ»å»âãä¸è¦å°ææå¯ç è¾å
¥å°SQLæ¥è¯¢è¯å¥ä¸ãå¨åºç¨ç¨åºä»£ç ä¸è®¡ç®åå¸ä¸²ï¼åªå¨SQLæ¥è¯¢ä¸ä½¿ç¨åå¸ä¸²ã",
"Case": "create table test(id int,name varchar(20) not null,password varchar(200)not null)",
"Position": 0
},
{
"Item": "STA.003",
"Severity": "L1",
"Summary": "ç´¢å¼èµ·åä¸è§è",
"Content": "建议æ®éäºçº§ç´¢å¼ä»¥idx_为åç¼ï¼å¯ä¸ç´¢å¼ä»¥uk_为åç¼ã",
"Case": "select col from now where type!=0",
"Position": 0
}
],
"IndexRules": [],
"Explain": [],
"Backtraces": [
"#9 /app/Admin/Controllers/HomeController.php:46",
"#51 /Users/yaozm/Documents/develop/laravel-soar/src/Http/Middleware/OutputSoarScoreMiddleware.php:45",
"#72 /public/index.php:55",
"#73 /server.php:21"
]
},
{
"Summary": "[â
â
â
â
â|80å|21.9ms|update `users` set `name` = 'name', `password` = 'password', `users`.`updated_at` = '2022-04-19 18:24:33']",
"HeuristicRules": [
{
"Item": "CLA.015",
"Severity": "L4",
"Summary": "UPDATE æªæå® WHERE æ¡ä»¶",
"Content": "UPDATE ä¸æå® WHERE æ¡ä»¶ä¸è¬æ¯è´å½çï¼è¯·æ¨ä¸æåè¡",
"Case": "update tbl set col=1",
"Position": 0
}
],
"IndexRules": [],
"Explain": {
"Item": "EXP.000",
"Severity": "L0",
"Summary": "Explainä¿¡æ¯",
"Content": [
"| id | select\\_type | table | partitions | type | possible_keys | key | key\\_len | ref | rows | filtered | scalability | Extra |",
"|---|---|---|---|---|---|---|---|---|---|---|---|---|",
"| 1 | UPDATE | *users* | NULL | index | NULL | PRIMARY | 8 | NULL | 1 | â ï¸ **100.00%** | O(n) | NULL |",
"",
""
],
"Case": [
"### Explainä¿¡æ¯è§£è¯»",
"",
"#### Typeä¿¡æ¯è§£è¯»",
"",
"* **index**: å
¨è¡¨æ«æ, åªæ¯æ«æ表çæ¶åæç
§ç´¢å¼æ¬¡åºè¿è¡èä¸æ¯è¡. 主è¦ä¼ç¹å°±æ¯é¿å
äºæåº, ä½æ¯å¼éä»ç¶é常大.",
""
],
"Position": 0
},
"Backtraces": [
"#10 /app/Admin/Controllers/HomeController.php:70",
"#52 /Users/yaozm/Documents/develop/laravel-soar/src/Http/Middleware/OutputSoarScoreMiddleware.php:45",
"#73 /public/index.php:55",
"#74 /server.php:21"
]
},
{
"Summary": "[â
â
â
â
â
|90å|4.5ms|delete from `users` where `name` = 'soar']",
"HeuristicRules": [
{
"Item": "SEC.003",
"Severity": "L0",
"Summary": "使ç¨DELETE/DROP/TRUNCATEçæä½æ¶æ³¨æå¤ä»½",
"Content": "å¨æ§è¡é«å±æä½ä¹å对æ°æ®è¿è¡å¤ä»½æ¯ååæå¿
è¦çã",
"Case": "delete from table where col = 'condition'",
"Position": 0
}
],
"IndexRules": [
{
"Item": "IDX.001",
"Severity": "L2",
"Summary": "为laravelåºçusers表添å ç´¢å¼",
"Content": "为ånameæ·»å ç´¢å¼; ç±äºæªå¼å¯æ°æ®éæ ·ï¼ååå¨ç´¢å¼ä¸ç顺åºéè¦èªè¡è°æ´ã",
"Case": "ALTER TABLE `laravel`.`users` add index `idx_name` (`name`(191)) ;\n",
"Position": 0
}
],
"Explain": {
"Item": "EXP.000",
"Severity": "L0",
"Summary": "Explainä¿¡æ¯",
"Content": [
"| id | select\\_type | table | partitions | type | possible_keys | key | key\\_len | ref | rows | filtered | scalability | Extra |",
"|---|---|---|---|---|---|---|---|---|---|---|---|---|",
"| 1 | DELETE | *users* | NULL | ALL | NULL | NULL | NULL | NULL | 1 | â ï¸ **100.00%** | O(n) | Using where |",
"",
""
],
"Case": [
"### Explainä¿¡æ¯è§£è¯»",
"",
"#### Typeä¿¡æ¯è§£è¯»",
"",
"* **ALL**: æåçæ
åµ, ä»å¤´å°å°¾å
¨è¡¨æ«æ.",
"",
"#### Extraä¿¡æ¯è§£è¯»",
"",
"* **Using where**: WHEREæ¡ä»¶ç¨äºçéåºä¸ä¸ä¸ä¸ªè¡¨å¹é
çæ°æ®ç¶åè¿åç»å®¢æ·ç«¯. é¤éæ
æåçå
¨è¡¨æ«æ, å¦åè¿æ¥ç±»åæ¯ALLæè
æ¯index, ä¸å¨Extraåçå¼ä¸æ²¡æUsing Where, å该æ¥è¯¢å¯è½æ¯æé®é¢ç.",
""
],
"Position": 0
},
"Backtraces": [
"#10 /app/Admin/Controllers/HomeController.php:76",
"#52 /Users/yaozm/Documents/develop/laravel-soar/src/Http/Middleware/OutputSoarScoreMiddleware.php:45",
"#73 /public/index.php:55",
"#74 /server.php:21"
]
},
{
"Summary": "[â
â
â
â
â
|100å|15.57ms|insert into `users` (`name`, `email`, `email_verified_at`, `password`, `remember_token`) values ('soar', '[email protected]', '2022-04-19 18:24:33', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'HecXUdevky')]",
"HeuristicRules": [],
"IndexRules": [],
"Explain": {
"Item": "EXP.000",
"Severity": "L0",
"Summary": "Explainä¿¡æ¯",
"Content": [
"| id | select\\_type | table | partitions | type | possible_keys | key | key\\_len | ref | rows | filtered | scalability | Extra |",
"|---|---|---|---|---|---|---|---|---|---|---|---|---|",
"| 1 | INSERT | *users* | NULL | ALL | NULL | NULL | NULL | NULL | 0 | 0.00% | O(n) | NULL |",
"",
""
],
"Case": [
"### Explainä¿¡æ¯è§£è¯»",
"",
"#### Typeä¿¡æ¯è§£è¯»",
"",
"* **ALL**: æåçæ
åµ, ä»å¤´å°å°¾å
¨è¡¨æ«æ.",
""
],
"Position": 0
},
"Backtraces": [
"#10 /app/Admin/Controllers/HomeController.php:66",
"#52 /Users/yaozm/Documents/develop/laravel-soar/src/Http/Middleware/OutputSoarScoreMiddleware.php:45",
"#73 /public/index.php:55",
"#74 /server.php:21"
]
}
]
}
Soar bar
Debug bar
Clockwork
Console
Dump
Log
èªå®ä¹è¾åºå¨
- å®ç°è¯¥æ¥å£
<?php
namespace Guanguans\LaravelSoar\Contracts;
use Illuminate\Support\Collection;
interface Output
{
public function output(Collection $scores, $dispatcher);
}
-
config/soar.php
ä¸é ç½®è¾åºå¨å³å¯
<?php
return [
...
'output' => [
// \Guanguans\LaravelSoar\Outputs\ClockworkOutput::class,
// \Guanguans\LaravelSoar\Outputs\ConsoleOutput::class,
// \Guanguans\LaravelSoar\Outputs\DumpOutput::class => ['exit' => false],
\Guanguans\LaravelSoar\Outputs\JsonOutput::class,
\Guanguans\LaravelSoar\Outputs\LogOutput::class => ['channel' => 'daily'],
\Guanguans\LaravelSoar\Outputs\DebugBarOutput::class,
\Guanguans\LaravelSoar\Outputs\SoarBarOutput::class,
],
...
];
Soar å®ä¾åæ¹æ³
详æ
soar(); // è·å Soar å®ä¾
app('soar'); // è·å Soar å®ä¾
/**
* Soar é¨é¢.
*
* @method static string score(string $sql) // SQL è¯å
* @method static array arrayScore(string $sql) // SQL æ°ç»æ ¼å¼è¯å
* @method static string jsonScore(string $sql) // SQL json æ ¼å¼è¯å
* @method static string htmlScore(string $sql) // SQL html æ ¼å¼è¯å
* @method static string mdScore(string $sql) // SQL markdown æ ¼å¼è¯å
* @method static string explain(string $sql) // explain 解读信æ¯
* @method static string mdExplain(string $sql) // markdown æ ¼å¼ explain 解读信æ¯
* @method static string htmlExplain(string $sql) // html æ ¼å¼ explain 解读信æ¯
* @method static null|string syntaxCheck(string $sql) // è¯æ³æ£æ¥
* @method static string fingerPrint(string $sql) // SQL æ纹
* @method static string pretty(string $sql) // æ ¼å¼å SQL
* @method static string md2html(string $sql) // markdown 转 html
* @method static string help() // Soar 帮å©
* @method static null|string exec(string $command) // æ§è¡ä»»æ Soar å½ä»¤
* @method static string getSoarPath() // è·å Soar è·¯å¾
* @method static array getOptions() // è·å Soar é
ç½®é项
* @method static Soar setSoarPath(string $soarPath) // 设置 Soar è·¯å¾
* @method static Soar setOption(string $key, $value) // 设置 Soar é
ç½®é项
* @method static Soar setOptions(array $options) // æ¹é设置 Soar é
ç½®é项
*
* @see \Guanguans\SoarPHP\Soar
* @see \Guanguans\LaravelSoar\Soar
*/
class Soar{}
æ¥è¯¢æ建å¨æ¹æ³
详æ
namespace Illuminate\Database\Eloquent {
/**
* @method string toRawSql()
* @method void dumpRawSql()
* @method void ddRawSql()
* @method array toSoarArrayScore()
* @method void dumpSoarArrayScore()
* @method void ddSoarArrayScore()
* @method string toSoarJsonScore()
* @method void dumpSoarJsonScore()
* @method void ddSoarJsonScore()
* @method string toSoarHtmlScore()
* @method void echoSoarHtmlScore()
* @method void exitSoarHtmlScore()
* @method string toSoarHtmlExplain()
* @method void echoSoarHtmlExplain()
* @method void exitSoarHtmlExplain()
*
* @see \Guanguans\LaravelSoar\Support\Macros\QueryBuilderMacro
*/
class Builder
{
}
}
æµè¯
$ composer test
åæ´æ¥å¿
请åé CHANGELOG è·åæè¿æå ³æ´æ¹çæ´å¤ä¿¡æ¯ã
è´¡ç®æå
请åé CONTRIBUTING æå ³è¯¦ç»ä¿¡æ¯ã
å®å ¨æ¼æ´
请æ¥çæ们çå®å ¨æ¿çäºè§£å¦ä½æ¥åå®å ¨æ¼æ´ã
è´¡ç®è
åè®®
MIT 许å¯è¯ï¼MITï¼ãæå ³æ´å¤ä¿¡æ¯ï¼è¯·åè§åè®®æ件ã