salehhashemi/laravel-repository
Installation:
composer require salehhashemi/laravel-repository
Generate Repository Structure:
Use the make:repository Artisan command to scaffold a repository, interface, and filter for your model:
php artisan make:repository User
This creates:
UserRepository (extends BaseEloquentRepository)UserRepositoryInterface (defines contract)UserFilter (for dynamic filtering)Bind Repository in Service Provider:
Register the binding in app/Providers/RepositoryServiceProvider.php:
$this->app->bind(
App\Repositories\UserRepositoryInterface::class,
App\Repositories\UserRepository::class
);
First Usage in Controller: Inject the repository interface into a controller method:
public function index(UserRepositoryInterface $userRepository)
{
$users = $userRepository->paginate(10);
return view('users.index', compact('users'));
}
Basic CRUD Operations:
// Fetch single record
$user = $userRepository->findOne(1);
// Fetch all with pagination
$users = $userRepository->paginate(15);
// Fetch with eager loading
$users = $userRepository->with('roles')->findAll();
Dynamic Filtering:
$userRepository->getFilterManager()->applyFilter($request->all());
$filteredUsers = $userRepository->findAll();
$userRepository->addCriteria(new ActiveUserCriteria());
$activeUsers = $userRepository->findAll();
Search Functionality:
$searchResults = $userRepository->search($request->query(), 10);
Custom Query Methods:
// In UserRepository
public function findAdmins(): Collection
{
return $this->scopeQuery(function ($query) {
return $query->where('role', 'admin');
})->get();
}
Use Interfaces for Dependency Injection:
Always inject UserRepositoryInterface instead of concrete UserRepository for better testability and flexibility.
Leverage Traits for Reusability:
The package provides traits like Searchable for common functionality:
use Salehhashemi\Repository\Traits\Searchable;
Combine Filters and Criteria: Use filters for dynamic runtime queries (e.g., user input) and criteria for static business rules.
Eager Loading:
Chain with() methods for relationships:
$users = $userRepository->with('posts', 'roles')->findAll();
Pagination:
Use paginate() for consistent pagination across the app:
$users = $userRepository->paginate($request->input('per_page', 15));
Criteria Order Matters:
Criteria are applied in the order they are added. Use resetCriteria() to clear all criteria if needed.
Filter Manager Initialization:
Ensure getFilterManager() returns a properly initialized filter with the correct query:
protected function getFilterManager(): UserFilter
{
$filterManager = new UserFilter();
$filterManager->setQuery($this->getQuery());
return $filterManager;
}
Model Class Configuration:
Override getModelClass() in your repository if not following Laravel's autoloading conventions:
protected function getModelClass(): string
{
return \App\Models\User::class;
}
Pagination Defaults:
The default pagination limit is configurable via config/repository.php. Override it per request:
$users = $userRepository->paginate($request->input('per_page', config('repository.pagination_limit')));
Searchable Trait Requirements:
The Searchable trait requires implementing getSearchableFields() in your filter class:
protected function getSearchableFields(): array
{
return ['name', 'email'];
}
Query Logging: Enable Laravel's query logging to inspect generated queries:
\DB::enableQueryLog();
$users = $userRepository->findAll();
dd(\DB::getQueryLog());
Criteria Debugging:
Use toSql() to inspect the query before execution:
$query = $userRepository->getQuery();
dd($query->toSql(), $query->getBindings());
Filter Validation: Validate filter inputs before applying them to avoid SQL errors:
if ($request->has('status') && !in_array($request->status, ['active', 'inactive'])) {
throw new \InvalidArgumentException('Invalid status value');
}
Custom Filter Methods:
Extend BaseFilter to add reusable filter methods:
class UserFilter extends BaseFilter
{
public function filterByRole(string $role): self
{
$this->where('role', $role);
return $this;
}
}
Custom Criteria: Create domain-specific criteria for complex queries:
class PremiumUserCriteria implements CriteriaInterface
{
public function apply(Model $model, Builder $query): Builder
{
return $query->where('subscription_tier', '>=', 3);
}
}
Repository Events:
Listen to repository events (e.g., retrieving, retrieved) for logging or side effects:
$repository->on('retrieved', function ($models) {
logger()->info("Retrieved {$models->count()} models");
});
Override Base Methods: Customize behavior by overriding base repository methods:
public function findAll(array $options = [])
{
$options['orderBy'] = ['name' => 'asc'];
return parent::findAll($options);
}
Pagination Limit:
The default pagination limit can be set in .env:
REPOSITORY_PAGINATION_LIMIT=20
Or published config file (config/repository.php).
Searchable Fields: Define searchable fields in your filter class:
protected function getSearchableFields(): array
{
return ['name', 'email', 'bio'];
}
Wildcard Search:
Use WILD_BOTH, WILD_LEFT, or WILD_RIGHT for partial matches:
$this->whereLike('name', $searchTerm, self::WILD_BOTH);
How can I help you explore Laravel packages today?