A powerful and extensible base repository for Doctrine ORM providing simple array-based queries and advanced features for Symfony applications.
- Array-based filtering: Simple and complex criteria using arrays
- Specification pattern: Reusable, testable query specifications
- Join management: Automatic join handling with alias generation
- Filter functions: Chainable query modifications
- Parameter binding: Safe, isolated parameter management
- JSON/JSONB support: Query nested JSON data (PostgreSQL/MySQL 5.7+)
- Full-text search: PostgreSQL and MySQL full-text search integration
- Batch operations: Update and delete by criteria
- Soft delete support: Built-in soft delete filtering
- Multi-tenant support: Automatic tenant scoping
- Separation of concerns: Modular service-based architecture
- Dependency injection: ServiceEntityRepository support for DI
- Backward compatibility: Maintains full compatibility with v1 API
- Strong typing: PHP 7.4+ type hints and return types
composer require welshdev/doctrine-base-repository// Get all vehicles
$vehicles = $em->getRepository(Vehicle::class)->findByCriteria();
// Get all red vehicles
$vehicles = $em->getRepository(Vehicle::class)->findByCriteria([
"colour" => "red"
]);
// Get red vehicles older than 5 years
$vehicles = $em->getRepository(Vehicle::class)->findByCriteria([
"colour" => "red",
["age", "gt", 5]
]);
// Get one vehicle by ID
$vehicle = $em->getRepository(Vehicle::class)->findOneByCriteria([
"id" => 10
]);<?php
namespace App\Repository;
use WelshDev\DoctrineBaseRepository\BaseRepository;
use App\Entity\Vehicle;
class VehicleRepository extends BaseRepository
{
// Your custom methods here
}<?php
namespace App\Repository;
use WelshDev\DoctrineBaseRepository\EnhancedBaseRepository;
use App\Entity\Vehicle;
use Doctrine\Persistence\ManagerRegistry;
class VehicleRepository extends EnhancedBaseRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Vehicle::class);
}
}Create reusable query specifications:
use WelshDev\DoctrineBaseRepository\Contract\SpecificationInterface;
class ActiveVehiclesSpecification implements SpecificationInterface
{
public function apply(QueryBuilder $queryBuilder): void
{
$queryBuilder
->andWhere('v.deletedAt IS NULL')
->andWhere('v.status = :status')
->setParameter('status', 'active');
}
}
// Use the specification
$vehicles = $repository->findBySpecification(new ActiveVehiclesSpecification());Query nested JSON data:
// Query JSON field with -> notation
$users = $repository->findByCriteria([
['profile->preferences->theme', 'eq', 'dark']
]);
// Use JSON operators
$users = $repository->findByCriteria([
['metadata', 'json_contains', ['status' => 'active']]
]);// Update multiple records
$updatedCount = $repository->updateByCriteria(
['status' => 'pending'], // criteria
['status' => 'processed', 'processedAt' => new DateTime()] // updates
);
// Delete multiple records
$deletedCount = $repository->deleteByCriteria([
['createdAt', 'lt', new DateTime('-1 year')]
]);use WelshDev\DoctrineBaseRepository\Service\FullTextSearchService;
$searchService = new FullTextSearchService();
// PostgreSQL full-text search
$queryBuilder = $repository->createQueryBuilder('v');
$searchService->addPostgreSQLFullTextSearch(
$queryBuilder,
'search term',
['title', 'description'],
'v'
);
$results = $queryBuilder->getQuery()->getResult();
// MySQL full-text search with relevance scoring
$queryBuilder = $repository->createQueryBuilder('v');
$searchService->addRelevanceScoring(
$queryBuilder,
'search term',
['title', 'description'],
'v'
);
$results = $queryBuilder->getQuery()->getResult();Add reusable query modifications:
// Add a filter function
$repository->addFilterFunction(function($queryBuilder) {
return $queryBuilder->andWhere('v.deletedAt IS NULL');
});
// Results will automatically include the filter
$vehicles = $repository->findByCriteria(['colour' => 'red']);Use structured query setup instead of single callbacks:
use WelshDev\DoctrineBaseRepository\Contract\QuerySetupInterface;
class SoftDeleteQuerySetup implements QuerySetupInterface
{
public function setup(string $alias, QueryBuilder $queryBuilder): QueryBuilder
{
return $queryBuilder->andWhere($alias . '.deletedAt IS NULL');
}
}
$repository->addQuerySetup(new SoftDeleteQuerySetup());eq- Equalneq- Not equalgt- Greater thangte- Greater than or equallt- Less thanlte- Less than or equallike- SQL LIKEin- IN arraynot_in- NOT IN array (null-safe)is_null- IS NULLnot_null- IS NOT NULL
json_contains- JSON contains (MySQL/PostgreSQL)json_extract- JSON path extractionraw- Raw SQL expression
and- Logical AND groupingor- Logical OR grouping
$vehicles = $repository->findByCriteria([
'colour' => 'red',
['year', 'gte', 2020],
['or', [
['make', 'eq', 'Toyota'],
['make', 'eq', 'Honda']
]],
['features', 'json_contains', ['gps' => true]]
]);$vehicles = $repository->findByCriteria(
['status' => 'active'], // criteria
['year' => 'DESC', 'make' => 'ASC'], // ordering
10, // limit
20 // offset
);// These methods still work for backward compatibility
$vehicles = $repository->findFiltered(['colour' => 'red']);
$vehicle = $repository->findOneFiltered(['id' => 1]);
$count = $repository->countRows('id', ['status' => 'active']);The library maintains full backward compatibility. All existing v1 methods continue to work unchanged. New features are available through:
findByCriteria()instead offindFiltered()findOneByCriteria()instead offindOneFiltered()countByCriteria()instead ofcountRows()
- PHP 7.4+
- Doctrine ORM 2.10+
- Doctrine DBAL 3.2+