romdh4ne/laravel-querycraft
Composer 安装命令:
composer require romdh4ne/laravel-querycraft
包简介
Find and fix Laravel performance issues automatically
README 文档
README
A Laravel performance analysis dashboard for detecting N+1 queries, slow queries, missing indexes, and duplicate queries — in real time.
✨ Features
- 🔁 N+1 Detection — catches repeated query patterns caused by missing eager loading
- 🐢 Slow Query Detection — flags queries exceeding your configured time limit
- 🗂 Missing Index Detection — identifies full table scans using MySQL
EXPLAIN - 📋 Duplicate Query Detection — finds identical queries (including bindings) fired multiple times
- 📍 Source Location — shows the exact file and line number in your app that triggered the issue
- 💯 Performance Score — grades your endpoint from 0–100 with a letter grade (A–F)
- 🛠 Live Config Panel — toggle detectors and adjust thresholds from the dashboard UI
- 🌙 Dark Mode — built-in dark/light mode toggle
- 🚨 500 Error Inspector — displays full exception details with app-only stack trace
- ⌨️ Artisan Command — analyze endpoints directly from your terminal with full body and header support
📦 Installation
1. Require the package via Composer
composer require romdh4ne/laravel-querycraft
2. Publish the config file
php artisan vendor:publish --tag=querycraft-config
3. Publish the assets (logo, favicon)
php artisan vendor:publish --tag=querycraft-assets
4. Publish the views (optional — only if you want to customize the UI)
php artisan vendor:publish --tag=querycraft-views
5. Clear caches
php artisan config:clear php artisan view:clear
6. Visit the dashboard
http://your-app.test/querycraft
🖥 Web Dashboard
Opening the dashboard
http://your-app.test/querycraft
Or with a custom route prefix set in .env:
http://your-app.test/your-custom-prefix
Analyzing an endpoint
- Enter your endpoint URL (e.g.
/api/users) - Select the HTTP method (
GET,POST,PUT,PATCH,DELETE) - Optionally add custom headers (e.g.
Authorization: Bearer token) - Optionally add a JSON request body for
POST/PUTrequests - Click Analyze Request
QueryCraft fires an internal request to your endpoint, collects all queries, runs them through all detectors, and displays the results instantly.
Reading the results
| Element | Description |
|---|---|
| Score card | 0–100 performance grade with letter (A–F) and emoji indicator |
| Query count | Total number of queries executed by the endpoint |
| Total time | Combined execution time of all queries in milliseconds |
| Issue cards | Each problem with severity, stats, source location and fix suggestion |
| Source Location | Exact file path and line number in your app (vendor files filtered out) |
| All Queries | Collapsible list of every query fired with individual execution time |
500 Error Inspector
When your endpoint crashes, QueryCraft catches it and displays:
- Exception class (e.g.
ErrorException,QueryException) - Error message
- Exact file and line number in your app where it crashed
- Stack trace showing only your app files — no vendor noise
- Number of queries captured before the crash
Set
APP_DEBUG=truein your.envfor full exception details.
Client Error Display
When your endpoint returns a 4xx response (e.g. 422 validation error, 404), QueryCraft shows:
- The HTTP status code
- The error message returned by your API
- Suggestions for similar routes if 404
Config Panel
Click the ⚙️ icon in the top-right header to open the config panel:
- Toggle each detector on/off individually
- Adjust thresholds using sliders
- Tune score weights (must total 100%)
- Click Save — changes are written to your
.envimmediately - Click Reset to restore all defaults
⌨️ Artisan Command
Analyze endpoints directly from your terminal without opening a browser.
Signature
php artisan querycraft:analyze
{--url= : The endpoint URL to analyze}
{--method=GET : HTTP method (GET, POST, PUT, PATCH, DELETE)}
{--user= : Authenticate as a specific user ID}
{--show-queries : Print all executed queries in the output}
{--body= : JSON body as an inline string}
{--body-file= : Path to a JSON file to use as the request body}
{--header=* : Custom headers in Key:Value format (repeatable)}
Examples
# Simple GET php artisan querycraft:analyze --url=/users # With authentication php artisan querycraft:analyze --url=/dashboard --user=1 # POST with inline JSON body php artisan querycraft:analyze --url=/api/posts --method=POST \ --body='{"title":"Hello","body":"World","category_id":1}' # POST with many fields — use --body-file to keep it clean php artisan querycraft:analyze --url=/api/orders --method=POST \ --body-file=./payload.json # PUT with body and auth php artisan querycraft:analyze --url=/api/users/1 --method=PUT --user=1 \ --body='{"name":"John","email":"john@example.com"}' # With custom headers php artisan querycraft:analyze --url=/api/secret \ --header="Authorization:Bearer your-token" \ --header="X-Team-Id:42" # Everything combined php artisan querycraft:analyze --url=/api/orders --method=POST --user=1 \ --body-file=./payload.json \ --header="X-Source:querycraft" \ --show-queries
Sending a large body with --body-file
When your request has many fields, create a payload.json file instead of cramming everything inline:
{
"customer_id": 5,
"shipping_address": {
"street": "123 Main St",
"city": "Paris",
"zip": "75001"
},
"items": [
{ "product_id": 1, "qty": 2, "price": 29.99 },
{ "product_id": 3, "qty": 1, "price": 49.99 }
],
"coupon": "SAVE10",
"notes": "Leave at door"
}
Then run:
php artisan querycraft:analyze --url=/api/orders --method=POST \ --body-file=./payload.json --user=1 --show-queries
Use
--bodyfor small payloads. Use--body-filefor large or complex payloads — it avoids shell escaping issues and is much easier to read and reuse.
Example output
🔍 Analyzing: GET /users
✅ Response: 200
📊 Summary:
+----------------+----------+
| Metric | Value |
+----------------+----------+
| Total Queries | 23 |
| Total Time | 182.5 ms |
| Avg Query Time | 7.93 ms |
| Response Status| 200 |
+----------------+----------+
⚠️ Found 2 issue(s):
🔴 Issue #1: N+1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Severity: HIGH
Occurrences: 20
Total Time: 140ms
Location: /app/Http/Controllers/UserController.php:45
Query:
select * from `companies` where `id` = ?
💡 Suggestion:
Add eager loading: ->with('company')
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚡ Performance Score: 62/100 (Grade: D) 🟠
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🎯 Top Improvements:
• Too many queries (+25 points)
• 2 performance issues detected (+20 points)
If your endpoint requires authentication, pass
--user=1to run as a specific user. QueryCraft callsauth()->login($user)before firing the request.
⚙️ Configuration
After publishing, the config file is at config/querycraft.php. All values can be overridden via .env:
# Enable or disable the package entirely QUERY_DEBUGGER_ENABLED=true # Detectors — toggle individually QUERYCRAFT_DETECTOR_N1=true QUERYCRAFT_DETECTOR_SLOW_QUERY=true QUERYCRAFT_DETECTOR_MISSING_INDEX=true QUERYCRAFT_DETECTOR_DUPLICATE_QUERY=true # Thresholds QUERY_DEBUGGER_N1_THRESHOLD=5 # Flag N+1 after this many repetitions (default: 5) QUERY_DEBUGGER_SLOW_THRESHOLD=100 # Flag queries slower than this in ms (default: 100) QUERYCRAFT_DUPLICATE_COUNT=2 # Flag duplicates after this many repeats (default: 2) # Score weights — must total 100 QUERYCRAFT_WEIGHT_QUERY_COUNT=40 QUERYCRAFT_WEIGHT_QUERY_TIME=30 QUERYCRAFT_WEIGHT_ISSUES=30 # Dashboard route prefix (default: querycraft) QUERYCRAFT_DASHBOARD_ROUTE=querycraft
Full config reference
// config/querycraft.php return [ 'enabled' => env('QUERY_DEBUGGER_ENABLED', true), 'detectors' => [ 'n1' => env('QUERYCRAFT_DETECTOR_N1', true), 'slow_query' => env('QUERYCRAFT_DETECTOR_SLOW_QUERY', true), 'missing_index' => env('QUERYCRAFT_DETECTOR_MISSING_INDEX', true), 'duplicate_query'=> env('QUERYCRAFT_DETECTOR_DUPLICATE_QUERY', true), ], 'thresholds' => [ 'n1_count' => env('QUERY_DEBUGGER_N1_THRESHOLD', 5), 'slow_query_ms' => env('QUERY_DEBUGGER_SLOW_THRESHOLD', 100), 'duplicate_count' => env('QUERYCRAFT_DUPLICATE_COUNT', 2), ], 'weights' => [ 'query_count' => env('QUERYCRAFT_WEIGHT_QUERY_COUNT', 40), 'query_time' => env('QUERYCRAFT_WEIGHT_QUERY_TIME', 30), 'issues' => env('QUERYCRAFT_WEIGHT_ISSUES', 30), ], ];
Tip: All settings can also be changed from the dashboard ⚙️ config panel — changes are saved directly to your
.env.
🔬 How Detectors Work
🔁 N+1 Detection
Normalizes every query (replaces values with ?) and groups them by pattern. If the same pattern fires more than n1_count times, it's flagged. The exact file and line in your app that triggered the repeated query is shown.
Example:
// ❌ N+1 — fires one query per user $users = User::all(); foreach ($users as $user) { echo $user->company->name; } // ✅ Fix — one query total $users = User::with('company')->get();
| Count | Severity |
|---|---|
| 5–10× | low |
| 10–20× | medium |
| 20–50× | high |
| 50×+ | critical |
🐢 Slow Query Detection
Flags any query exceeding slow_query_ms milliseconds (default: 100ms). Automatically suggests a fix based on the query structure.
| Time | Severity |
|---|---|
| > 200ms | low |
| > 500ms | medium |
| > 1000ms | high |
| > 1000ms | critical |
Suggestions shown:
SELECT *→ use specific columnsORDER BYwithoutLIMIT→ add a limitLIKEqueries → consider full-text searchCOUNT(*)on large tables → consider caching
🗂 Missing Index Detection
Runs MySQL EXPLAIN on each query and flags full table scans, filesorts, and temporary table usage.
Triggers:
type = ALLwith more than 1,000 rows examinedExtracontainsUsing filesortExtracontainsUsing temporary
Example:
User::where('email', $email)->first(); // no index on email // Fix — in a migration: $table->index('email'); $table->index(['status', 'created_at']); // composite
| Rows examined | Severity |
|---|---|
| > 1,000 | low |
| > 10,000 | medium |
| > 100,000 | high |
| > 100,000 | critical |
📋 Duplicate Query Detection
Creates an md5 fingerprint of sql + bindings. If the exact same query with the same parameter values runs more than duplicate_count times (default: 2), it's flagged.
Example:
// ❌ Duplicate — same query + same values fired twice $settings = Setting::all(); // ... somewhere else in the same request ... $settings = Setting::all(); // ✅ Fix $settings = Cache::remember('settings', 3600, fn() => Setting::all());
💯 Performance Score
Calculated as a weighted average across three dimensions:
| Dimension | Default Weight | Description |
|---|---|---|
| Query Count | 40% | Fewer queries = higher score |
| Query Time | 30% | Faster total time = higher score |
| Issues Found | 30% | Fewer/lower severity issues = higher score |
| Score | Grade | Status |
|---|---|---|
| 90–100 | A 🟢 | Excellent |
| 80–89 | B 🟡 | Good |
| 70–79 | C 🟡 | Acceptable |
| 60–69 | D 🟠 | Below average |
| 0–59 | F 🔴 | Critical issues |
Weights are configurable from the dashboard config panel or via .env.
🔒 Security
QueryCraft is intended for local development only. Always disable it in production:
# .env.production QUERY_DEBUGGER_ENABLED=false
🔄 Updating
composer update romdh4ne/laravel-querycraft php artisan vendor:publish --tag=querycraft-views --force php artisan vendor:publish --tag=querycraft-assets --force php artisan config:clear php artisan view:clear
🗑 Uninstalling
composer remove romdh4ne/laravel-querycraft
rm config/querycraft.php
rm -rf resources/views/vendor/querycraft
rm -rf public/vendor/querycraft
# Remove QUERYCRAFT_* and QUERY_DEBUGGER_* lines from your .env
🤝 Contributing
Setup
git clone https://github.com/YOUR_USERNAME/laravel-querycraft.git
cd laravel-querycraft
composer install
Local test app (separate project)
In a separate Laravel app, add to composer.json:
"repositories": [ { "type": "path", "url": "../laravel-querycraft", "options": { "symlink": true } } ]
Then:
composer require romdh4ne/laravel-querycraft:@dev php artisan vendor:publish --tag=querycraft-config php artisan vendor:publish --tag=querycraft-assets php artisan config:clear php artisan serve
Visit http://localhost:8000/querycraft. Any change you make in the package reflects instantly thanks to the symlink.
📄 License
QueryCraft is open-source software licensed under the MIT license.
👨💻 Author
Made by Romdh4ne
If this package helps you, give it a ⭐ on GitHub!
romdh4ne/laravel-querycraft 适用场景与选型建议
romdh4ne/laravel-querycraft 是一款 基于 Blade 开发的 Composer 扩展包,目前已累计 23 次下载、GitHub Stars 达 22, 最近一次更新时间为 2026 年 02 月 14 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「database」 「performance」 「optimization」 「laravel」 「queries」 「n-plus-one」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 romdh4ne/laravel-querycraft 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 romdh4ne/laravel-querycraft 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 romdh4ne/laravel-querycraft 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Dibi is Database Abstraction Library for PHP
g4 application profiler package
CSS/Javascript Minificator, Compressor and Concatenator for TYPO3 - highly configurable frontend asset optimization for CSS/JS merging, minification and compression with optional body parsing, async/defer loading, inline output, data-ignore exclusions, SRI integrity validation/calculation, external
Image optimization / compression library. This library is able to optimize png, jpg and gif files in very easy and handy way. It uses optipng, pngquant, pngcrush, pngout, gifsicle, jpegoptim and jpegtran tools.
WordPress mu-plugin to remove jQuery Migrate from the list of jQuery dependencies and to allow jQuery to enqueue before </body> instead of in the <head>.
Store your language lines in the database, yaml or other sources
统计信息
- 总下载量: 23
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 23
- 点击次数: 25
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-02-14
