ahmed-bhs/doctrine-doctor
Doctrine Doctor is a runtime analysis tool for Doctrine ORM integrated into the Symfony Web Profiler. It detects real-world issues like N+1 queries, slow queries, missing indexes, hydration overhead, and injection risks, with actionable backtraces and suggestions.
{: .fs-9 }
Runtime Analysis Tool for Doctrine ORM — Integrated into Symfony Web Profiler {: .fs-6 .fw-300 }
Get started now{: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } View on GitHub{: .btn .fs-5 .mb-4 .mb-md-0 }
Unlike static analysis tools (PHPStan, Psalm) that analyze code without execution, Doctrine Doctor:
->addSelect(..) to eager load authorsPerformance — Detects N+1 queries, missing database indexes, slow queries, excessive hydration, findAll() without limits, setMaxResults() with collection joins, too many JOINs, and query caching opportunities
Security — Identifies DQL/SQL injection vulnerabilities, QueryBuilder SQL injection risks, sensitive data exposure in serialization, unprotected sensitive fields, and insecure random generators
Code Quality — Detects cascade configuration issues, bidirectional inconsistencies, missing orphan removal, type mismatches, float usage for money, uninitialized collections, EntityManager in entities, and architectural violations
Configuration — Validates database charset/collation settings, timezone handling, Gedmo trait configurations, MySQL strict mode, and other database-level configurations
Step 1: Install
composer require --dev ahmed-bhs/doctrine-doctor
Step 2: That's it!
Auto-configured via Symfony Flex. No YAML, no configuration files needed.
Step 3: See it in action
dev environment)Configure thresholds in config/packages/dev/doctrine_doctor.yaml:
doctrine_doctor:
analyzers:
n_plus_one:
threshold: 5 # default, lower to 3 to be stricter
slow_query:
threshold: 100 # milliseconds (default)
Enable backtraces to see WHERE in your code issues originate:
# config/packages/dev/doctrine.yaml
doctrine:
dbal:
profiling_collect_backtrace: true
Full configuration reference →
// Controller
$users = $repository->findAll();
// Template
{% raw %}{% for user in users %}
{{ user.profile.bio }}
{% endfor %}{% endraw %}
Triggers 100 queries
Real-time detection
$users = $repository
->createQueryBuilder('u')
->leftJoin('u.profile', 'p')
->addSelect('p')
->getQuery()
->getResult();
Single query
| Document | Description |
|---|---|
| Configuration Reference | Comprehensive guide to all configuration options - customize analyzers, thresholds, and outputs to match your workflow |
| Full Analyzers List | Complete catalog of all 90+ analyzers covering performance, security, code quality, and configuration |
| Architecture Guide | Deep dive into system design, architecture patterns, and technical internals |
| Template Security | Essential security best practices for PHP templates - prevent XSS attacks and ensure safe template rendering |
We welcome contributions! See our Contributing Guide for details.
MIT License - see LICENSE for details.
Created by Ahmed EBEN HASSINE
How can I help you explore Laravel packages today?