Install the package:
composer require arafat69/laravel-repository
Publish the stubs (optional but recommended for customization):
php artisan vendor:publish --provider="Arafat69\Repository\RepositoryServiceProvider" --tag="repository-stubs"
Generate a repository for your first model (e.g., User):
php artisan make:repository UserRepository --model=User
This creates:
app/Repositories/UserRepository.php (interface)app/Repositories/Eloquent/UserRepositoryEloquent.php (implementation)Register the repository in AppServiceProvider:
public function register()
{
$this->app->bind(
\App\Repositories\UserRepository::class,
\App\Repositories\Eloquent\UserRepositoryEloquent::class
);
}
Use the repository in a controller/service:
use App\Repositories\UserRepository;
public function index(UserRepository $repository)
{
$users = $repository->all();
return view('users.index', compact('users'));
}
Replace direct Eloquent calls in a controller with repository methods:
// Before (Controller)
public function store(Request $request)
{
return User::create($request->all());
}
// After (Controller)
public function store(Request $request, UserRepository $repository)
{
return $repository->create($request->all());
}
Repository Generation
make:repository for new models:
php artisan make:repository PostRepository --model=Post --with-transactions
--with-transactions: Auto-wraps create/update in DB transactions.--with-scopes: Generates scope methods (e.g., scopeActive()).Dependency Injection
public function __construct(private UserRepository $users) {}
public function __construct(
private UserRepository $users,
private RoleRepository $roles
) {}
Customizing Queries Extend the Eloquent implementation:
// app/Repositories/Eloquent/UserRepositoryEloquent.php
public function findActiveUsers()
{
return $this->model->where('active', true)->get();
}
Scopes Define reusable query constraints:
// UserRepository.php (interface)
public function scopeActive($query);
// UserRepositoryEloquent.php (implementation)
public function scopeActive($query)
{
return $query->where('active', true);
}
Usage:
$activeUsers = $repository->active()->get();
Transactions Wrap operations in a transaction block:
$repository->transaction(function (UserRepository $repo) {
$user = $repo->create([...]);
$repo->attachRole($user, 'admin');
});
Unit Testing Mock repositories in tests:
$this->mock(UserRepository::class, function ($mock) {
$mock->shouldReceive('find')
->once()
->andReturn(new User());
});
API Resources Combine repositories with API resources:
public function show(UserRepository $repository, $id)
{
return new UserResource($repository->find($id));
}
Event Dispatching Trigger events from repository methods:
public function create(array $attributes)
{
$model = $this->model->create($attributes);
event(new UserCreated($model));
return $model;
}
Caching Cache repository results:
public function all()
{
return Cache::remember('users.all', now()->addHours(1), function () {
return $this->model->all();
});
}
Validation Move validation logic to repositories:
public function create(array $attributes)
{
$validated = $this->validate($attributes);
return $this->model->create($validated);
}
protected function validate(array $data)
{
return Validator::make($data, [
'email' => 'required|email|unique:users',
])->validate();
}
Forgetting to Bind the Repository
BindingResolutionException when injecting the repository.AppServiceProvider or use Laravel’s auto-binding:
$this->app->bind(
'App\Repositories\UserRepository',
'App\Repositories\Eloquent\UserRepositoryEloquent'
);
Overusing Repositories for Simple Queries
find() or all() calls.Not Extending the Base Repository
findOrFail() or firstOrFail().Arafat69\Repository\Eloquent\BaseRepository:
class UserRepositoryEloquent extends BaseRepository
{
// Custom methods here
}
Transaction Conflicts
retryWhen:
$repository->transaction(function () {
// ...
}, 3, 100); // Retry 3 times with 100ms delay
Stub Customization
php artisan vendor:publish --tag="repository-stubs"
Edit files in resources/stubs/repository/.Log Repository Calls Add logging to the base repository:
// app/Repositories/Eloquent/BaseRepository.php
protected function logQuery($method, $args)
{
\Log::debug("Repository [$method] called with: " . json_encode($args));
}
Check for Missing Scopes
Call to undefined method when using scopes.Verify Model Binding
Model not found or BindingResolutionException.protected $model = \App\Models\User::class;
Custom Repository Types Extend the package to support non-Eloquent repositories (e.g., API clients):
namespace App\Repositories\Api;
class UserRepositoryApi implements UserRepository
{
public function all()
{
return Http::get('api/users')->json();
}
}
Dynamic Model Binding Bind models dynamically in the repository:
public function __construct(protected BaseRepository $repository)
{
$this->repository->setModel($this->model);
}
Repository Events Dispatch events for repository actions:
// app/Repositories/Eloquent/BaseRepository.php
protected function afterCreate($model)
{
event(new ModelCreated($model));
}
Repository Middleware Add middleware to repository methods:
public function find($id)
{
return $this->model->findOrFail($id);
}
// In a service provider:
$this->app->when(UserRepository::class)
->needs('$model')
->give(function ($repo) {
return tap($repo->model, function ($model) {
// Add global scopes/middleware
});
});
Repository Caching Layer Implement a caching decorator:
class CachedUserRepository implements UserRepository
{
public function __construct(private UserRepository $repository) {}
public function all()
{
return Cache::remember('users.all', now()->addHours(1), function () {
return $this->repository->all();
});
}
}
How can I help you explore Laravel packages today?