Runtime Analysis Tool for Doctrine ORM — Integrated into Symfony Web Profiler
|
Why Runtime Analysis? Unlike static analysis tools (PHPStan, Psalm) that analyze code without execution, Doctrine Doctor:
|
- Performance — 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-doctorStep 2: That's it!
Auto-configured via Symfony Flex. No YAML, no configuration files needed.
Step 3: See it in action
- Refresh any page in your Symfony app (in
devenvironment) - Open the Symfony Web Profiler (bottom toolbar)
- Click the "Doctrine Doctor" panel 🩺
Configure thresholds in config/packages/dev/doctrine_doctor.yaml:
doctrine_doctor:
analyzers:
n_plus_one:
threshold: 3
slow_query:
threshold: 50 # millisecondsEnable backtraces to see WHERE in your code issues originate:
# config/packages/dev/doctrine.yaml
doctrine:
dbal:
profiling_collect_backtrace: trueFull configuration reference →
| **Problem** | **Detection** | **Solution** |
|
Template triggers lazy loading // Controller
$users = $repository
->findAll();
// Template
{% for user in users %}
{{ user.profile.bio }}
{% endfor %}Triggers 100 queries |
Doctrine Doctor detects N+1 100 queries instead of 1 Shows exact query count, execution time, and suggests eager loading Real-time detection |
Eager load with JOIN $users = $repository
->createQueryBuilder('u')
->leftJoin('u.profile', 'p')
->addSelect('p')
->getQuery()
->getResult();Single query |
| Document | Description |
|---|---|
| Full Analyzers List | Complete catalog of all 66 analyzers covering performance, security, code quality, and configuration - find the perfect analyzer for your specific needs |
| Architecture Guide | Deep dive into system design, architecture patterns, and technical internals - understand how Doctrine Doctor works under the hood |
| Configuration Reference | Comprehensive guide to all configuration options - customize analyzers, thresholds, and outputs to match your workflow |
| Template Security | Essential security best practices for PHP templates - prevent XSS attacks and ensure safe template rendering |
See CONTRIBUTING.md for guidelines.
MIT License - see LICENSE for details.

