derafu/symfony-query-bundle
Symfony bundle that integrates derafu/query into Symfony applications. Provides easy service wiring and configuration to use query objects/patterns in your project. See derafu docs for setup, usage, and available options.
Installation
composer require derafu/symfony-query-bundle
Add the bundle to config/bundles.php:
return [
// ...
Derafu\SymfonyQueryBundle\DerafuSymfonyQueryBundle::class => ['all' => true],
];
Configuration Publish the default config:
php bin/console config:dump-reference DerafuSymfonyQueryBundle
Override in config/packages/derafu_symfony_query.yaml:
derafu_symfony_query:
default_locale: 'en'
query_builder: '@derafu.query_builder'
First Use Case Inject the query builder into a service/controller:
use Derafu\Query\QueryBuilder;
class ProductController extends AbstractController
{
public function __construct(
private QueryBuilder $queryBuilder
) {}
public function listProducts(): Response
{
$query = $this->queryBuilder->create()
->from(Product::class)
->select(['id', 'name', 'price']);
$results = $query->getQuery()->getResult();
// Render results...
}
}
Dynamic Query Building Chain methods for flexible queries:
$query = $this->queryBuilder->create()
->from('App\Entity\Product')
->where('price > :price', ['price' => 100])
->orderBy('name', 'ASC')
->limit(10);
Integration with Doctrine Use the built-in Doctrine adapter:
derafu_symfony_query:
adapters:
doctrine: true
Then leverage Doctrine’s DQL in queries:
$query->dql("SELECT p FROM App\Entity\Product p WHERE p.category = :cat")
->setParameter('cat', $category);
Pagination
$query->paginate(1, 20); // Page 1, 20 items/page
$results = $query->getQuery()->getResult();
$total = $query->getQuery()->getSingleScalarResult('SELECT COUNT(p.id) FROM App\Entity\Product p');
Multi-Entity Joins
$query->from(['p' => Product::class])
->join('p.category', 'c')
->select(['p.id', 'c.name as category']);
Dependency Injection Tag services for query building:
services:
App\Service\CustomQueryBuilder:
tags: ['derafu.query_builder']
Event Listeners Extend query behavior via events:
use Derafu\Query\Event\QueryEvent;
public function onQueryBuild(QueryEvent $event) {
$query = $event->getQuery();
$query->addWhere('active = 1');
}
Register in services.yaml:
App\EventListener\QueryListener:
tags:
- { name: kernel.event_listener, event: derafu.query.build, method: onQueryBuild }
API Platform Integration Use with API Platform filters:
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractFilter;
class CustomFilter extends AbstractFilter {
public function __construct(private QueryBuilder $queryBuilder) {}
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, ApiFilter $filter, array $context = []): void {
$queryBuilder->addWhere($property . ' = :val', ['val' => $value]);
}
}
Locale Mismatch
default_locale in config matches your app’s locale. Queries may fail silently if locales differ.Derafu\Query\Exception\LocaleException.Circular References in Joins
Product->Category->Product). Use ->join()->where() instead of direct associations.Parameter Binding
:param) for security. Raw values may lead to SQL injection:
// ❌ Vulnerable
$query->where("price > $userInput");
// ✅ Safe
$query->where("price > :price", ['price' => $userInput]);
Doctrine Adapter Quirks
id fields. The bundle assumes primary keys are named id.derafu_symfony_query:
adapters:
doctrine:
primary_key: 'uuid'
Query Logging
Enable SQL logging in config/packages/dev/doctrine.yaml:
doctrine:
dbal:
logging: true
profiling: true
Then inspect queries via Symfony’s profiler or var_dump($query->getQuery()->getSQL()).
Event Debugging Dump query events in a listener:
public function onQueryBuild(QueryEvent $event) {
\dump($event->getQuery()->getSQL());
}
Performance
->select() explicitly to avoid SELECT * queries.->indexBy() to reduce memory usage:
$query->indexBy('p.id');
Custom Adapters
Implement Derafu\Query\Adapter\AdapterInterface for non-Doctrine databases (e.g., MongoDB):
class MongoAdapter implements AdapterInterface {
public function createQueryBuilder(): QueryBuilder {
return new QueryBuilder($this);
}
// ...
}
Register in config:
derafu_symfony_query:
adapters:
mongo: App\Adapter\MongoAdapter
Query Macros Define reusable query snippets in a service:
class QueryMacros {
public function activeProducts(QueryBuilder $qb): QueryBuilder {
return $qb->addWhere('active = 1');
}
}
Use via dependency injection.
Validation Extend query validation with custom rules:
use Derafu\Query\Validator\Constraint\QueryConstraint;
#[QueryConstraint(maxDepth: 5)]
class ProductQuery {}
derafu_symfony_query:
cache:
enabled: true
provider: 'cache.app'
derafu_symfony_query:
strict_mode: true
How can I help you explore Laravel packages today?