Installation:
composer require torann/laravel-repository
Publish the config (optional but recommended for customization):
php artisan vendor:publish --provider="Torann\Repository\RepositoryServiceProvider"
Define a Model and Repository:
php artisan make:repository UserRepository --model=User
This generates:
app/Repositories/UserRepository.php (interface)app/Repositories/Eloquent/UserRepositoryEloquent.php (implementation)First Use Case: Inject the repository into a service or controller:
use App\Repositories\UserRepository;
class UserService {
protected $users;
public function __construct(UserRepository $users) {
$this->users = $users;
}
public function getUser($id) {
return $this->users->find($id);
}
}
Key Files to Review:
config/repository.php (default configurations)app/Providers/RepositoryServiceProvider.php (binding custom repositories)app/Repositories/Eloquent/BaseRepositoryEloquent.php (base implementation)// Create
$user = $this->users->create(['name' => 'John', 'email' => 'john@example.com']);
// Read
$user = $this->users->find(1);
$users = $this->users->all();
// Update
$user = $this->users->update(1, ['name' => 'Updated Name']);
// Delete
$this->users->delete(1);
Use the scope* methods for reusable query constraints:
// Define in UserRepositoryEloquent
public function scopeActive($query) {
return $query->where('active', true);
}
// Usage
$activeUsers = $this->users->active()->get();
Leverage Eloquent methods via the repository:
$recentUsers = $this->users->latest()->take(10)->get();
$searchResults = $this->users->where('name', 'like', '%John%')->get();
Wrap operations in transactions:
$this->users->transaction(function ($repository) {
$user = $repository->create(['name' => 'Alice']);
$repository->create(['name' => 'Bob']);
// Both or none are created
});
Trigger model events via the repository:
$this->users->create(['name' => 'Event User']); // Triggers `created` event
Bind custom repositories in RepositoryServiceProvider:
$this->app->bind(
'App\Repositories\CustomUserRepository',
function ($app) {
return new \App\Repositories\Eloquent\CustomUserRepositoryEloquent(
new \App\Models\User,
$app['db']
);
}
);
Use repositories in API resources for consistent data shaping:
public function toArray($request) {
return [
'id' => $this->user->id,
'name' => $this->user->name,
// Use repository methods to fetch related data
'posts' => $this->user->posts()->count(),
];
}
Mock repositories in tests:
$mock = Mockery::mock('overload:' . UserRepository::class);
$mock->shouldReceive('find')->andReturn($user);
Over-Querying:
Avoid chaining multiple get() calls without constraints:
// Bad: Loads all users, then filters in memory
$activeUsers = $this->users->all()->filter(fn($u) => $u->active);
// Good: Push filtering to the database
$activeUsers = $this->users->active()->get();
N+1 Queries:
Use with() to eager-load relationships:
$users = $this->users->with('posts')->get();
Repository Bloat: Avoid putting business logic in repositories. Use services for complex workflows.
Model Binding: Ensure your repository’s model matches the actual Eloquent model class.
Query Logging: Enable Laravel’s query logging to inspect generated queries:
DB::enableQueryLog();
$this->users->all();
dd(DB::getQueryLog());
Repository Method Not Found: If a method isn’t found, check:
*RepositoryEloquent.php).*Repository.php).Transaction Rollbacks:
If a transaction fails silently, wrap in a try-catch:
try {
$this->users->transaction(...);
} catch (\Exception $e) {
// Handle rollback
}
Custom Scopes: Extend the base repository to add reusable scopes:
// app/Repositories/Eloquent/BaseRepositoryEloquent.php
public function scopeSearch($query, $term) {
return $query->where('name', 'like', "%{$term}%");
}
Repository Events:
Listen for repository events (e.g., repository.created) in EventServiceProvider:
protected $listen = [
'repository.created' => [
'App\Listeners\LogRepositoryCreation',
],
];
Performance:
Use cursor() for large datasets to reduce memory usage:
foreach ($this->users->cursor() as $user) {
// Process one user at a time
}
Soft Deletes: Enable soft deletes in the repository:
public function __construct(Model $model) {
parent::__construct($model);
$this->model->usesSoftDeletes();
}
Caching: Cache repository results for read-heavy operations:
$users = Cache::remember('users.all', now()->addHours(1), function () {
return $this->users->all();
});
API Versioning: Use repositories to abstract versioned API logic:
// v1/UserRepository.php
// v2/UserRepository.php
Repository Interfaces: Always implement interfaces to enforce contracts and enable mocking:
class UserRepository implements UserRepositoryInterface {
// ...
}
Mass Assignment:
Use $fillable or $guarded in the repository’s create/update methods:
public function create(array $attributes) {
return $this->model->create(array_merge($this->getFillable(), $attributes));
}
How can I help you explore Laravel packages today?